voxcity 0.3.3__py3-none-any.whl → 0.3.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of voxcity might be problematic. Click here for more details.
- voxcity/download/eubucco.py +9 -17
- voxcity/download/gee.py +4 -3
- voxcity/download/mbfp.py +7 -7
- voxcity/download/oemj.py +22 -22
- voxcity/download/omt.py +10 -10
- voxcity/download/osm.py +23 -21
- voxcity/download/overture.py +7 -15
- voxcity/file/envimet.py +4 -4
- voxcity/file/geojson.py +25 -39
- voxcity/geo/__init_.py +2 -1
- voxcity/geo/draw.py +41 -45
- voxcity/geo/grid.py +68 -145
- voxcity/geo/network.py +193 -0
- voxcity/geo/utils.py +79 -66
- voxcity/sim/solar.py +5 -5
- voxcity/sim/view.py +5 -5
- voxcity/utils/__init_.py +2 -1
- voxcity/utils/material.py +139 -0
- voxcity/utils/visualization.py +128 -354
- voxcity/utils/weather.py +7 -7
- voxcity/voxcity.py +56 -8
- {voxcity-0.3.3.dist-info → voxcity-0.3.5.dist-info}/METADATA +6 -5
- voxcity-0.3.5.dist-info/RECORD +36 -0
- {voxcity-0.3.3.dist-info → voxcity-0.3.5.dist-info}/WHEEL +1 -1
- voxcity-0.3.3.dist-info/RECORD +0 -34
- {voxcity-0.3.3.dist-info → voxcity-0.3.5.dist-info}/AUTHORS.rst +0 -0
- {voxcity-0.3.3.dist-info → voxcity-0.3.5.dist-info}/LICENSE +0 -0
- {voxcity-0.3.3.dist-info → voxcity-0.3.5.dist-info}/top_level.txt +0 -0
voxcity/file/geojson.py
CHANGED
|
@@ -28,7 +28,7 @@ def filter_and_convert_gdf_to_geojson(gdf, rectangle_vertices):
|
|
|
28
28
|
|
|
29
29
|
Args:
|
|
30
30
|
gdf (GeoDataFrame): Input GeoDataFrame containing building data
|
|
31
|
-
rectangle_vertices (list): List of (
|
|
31
|
+
rectangle_vertices (list): List of (lon, lat) tuples defining the bounding rectangle
|
|
32
32
|
|
|
33
33
|
Returns:
|
|
34
34
|
list: List of GeoJSON features within the bounding rectangle
|
|
@@ -43,9 +43,8 @@ def filter_and_convert_gdf_to_geojson(gdf, rectangle_vertices):
|
|
|
43
43
|
# Add 'confidence' column with default value
|
|
44
44
|
gdf['confidence'] = -1.0
|
|
45
45
|
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
rectangle_polygon = Polygon(rectangle_vertices_lonlat)
|
|
46
|
+
# Rectangle vertices already in (lon,lat) format for shapely
|
|
47
|
+
rectangle_polygon = Polygon(rectangle_vertices)
|
|
49
48
|
|
|
50
49
|
# Use spatial index to efficiently filter geometries that intersect with rectangle
|
|
51
50
|
gdf.sindex # Ensure spatial index is built
|
|
@@ -57,13 +56,6 @@ def filter_and_convert_gdf_to_geojson(gdf, rectangle_vertices):
|
|
|
57
56
|
# Delete intermediate data to save memory
|
|
58
57
|
del gdf, possible_matches, precise_matches
|
|
59
58
|
|
|
60
|
-
# Helper function to swap coordinate ordering from (lon,lat) to (lat,lon)
|
|
61
|
-
def swap_coordinates(coords):
|
|
62
|
-
if isinstance(coords[0][0], (float, int)):
|
|
63
|
-
return [[lat, lon] for lon, lat in coords]
|
|
64
|
-
else:
|
|
65
|
-
return [swap_coordinates(ring) for ring in coords]
|
|
66
|
-
|
|
67
59
|
# Create GeoJSON features from filtered geometries
|
|
68
60
|
features = []
|
|
69
61
|
for idx, row in filtered_gdf.iterrows():
|
|
@@ -78,7 +70,7 @@ def filter_and_convert_gdf_to_geojson(gdf, rectangle_vertices):
|
|
|
78
70
|
for polygon_coords in geom['coordinates']:
|
|
79
71
|
single_geom = {
|
|
80
72
|
'type': 'Polygon',
|
|
81
|
-
'coordinates':
|
|
73
|
+
'coordinates': polygon_coords
|
|
82
74
|
}
|
|
83
75
|
feature = {
|
|
84
76
|
'type': 'Feature',
|
|
@@ -87,7 +79,6 @@ def filter_and_convert_gdf_to_geojson(gdf, rectangle_vertices):
|
|
|
87
79
|
}
|
|
88
80
|
features.append(feature)
|
|
89
81
|
elif geom['type'] == 'Polygon':
|
|
90
|
-
geom['coordinates'] = swap_coordinates(geom['coordinates'])
|
|
91
82
|
feature = {
|
|
92
83
|
'type': 'Feature',
|
|
93
84
|
'properties': properties,
|
|
@@ -114,7 +105,7 @@ def get_geojson_from_gpkg(gpkg_path, rectangle_vertices):
|
|
|
114
105
|
|
|
115
106
|
Args:
|
|
116
107
|
gpkg_path (str): Path to the GeoPackage file
|
|
117
|
-
rectangle_vertices (list): List of (
|
|
108
|
+
rectangle_vertices (list): List of (lon, lat) tuples defining the bounding rectangle
|
|
118
109
|
|
|
119
110
|
Returns:
|
|
120
111
|
list: List of GeoJSON features within the bounding rectangle
|
|
@@ -404,9 +395,9 @@ def extract_building_heights_from_geotiff(geotiff_path, geojson_data):
|
|
|
404
395
|
for feature in geojson:
|
|
405
396
|
if (feature['geometry']['type'] == 'Polygon') & (feature['properties']['height']<=0):
|
|
406
397
|
count_0 += 1
|
|
407
|
-
# Transform coordinates from (
|
|
398
|
+
# Transform coordinates from (lon, lat) to raster CRS
|
|
408
399
|
coords = feature['geometry']['coordinates'][0]
|
|
409
|
-
transformed_coords = [transformer.transform(lon, lat) for
|
|
400
|
+
transformed_coords = [transformer.transform(lon, lat) for lon, lat in coords]
|
|
410
401
|
|
|
411
402
|
# Create polygon in raster CRS
|
|
412
403
|
polygon = shape({"type": "Polygon", "coordinates": [transformed_coords]})
|
|
@@ -447,7 +438,7 @@ def get_geojson_from_gpkg(gpkg_path, rectangle_vertices):
|
|
|
447
438
|
|
|
448
439
|
Args:
|
|
449
440
|
gpkg_path (str): Path to the GeoPackage file
|
|
450
|
-
rectangle_vertices (list): List of (
|
|
441
|
+
rectangle_vertices (list): List of (lon, lat) tuples defining the bounding rectangle
|
|
451
442
|
|
|
452
443
|
Returns:
|
|
453
444
|
list: List of GeoJSON features within the bounding rectangle
|
|
@@ -460,7 +451,7 @@ def get_geojson_from_gpkg(gpkg_path, rectangle_vertices):
|
|
|
460
451
|
|
|
461
452
|
def swap_coordinates(features):
|
|
462
453
|
"""
|
|
463
|
-
Swap coordinate ordering in GeoJSON features from (
|
|
454
|
+
Swap coordinate ordering in GeoJSON features from (lat, lon) to (lon, lat).
|
|
464
455
|
|
|
465
456
|
Args:
|
|
466
457
|
features (list): List of GeoJSON features to process
|
|
@@ -469,11 +460,11 @@ def swap_coordinates(features):
|
|
|
469
460
|
for feature in features:
|
|
470
461
|
if feature['geometry']['type'] == 'Polygon':
|
|
471
462
|
# Swap coordinates for simple polygons
|
|
472
|
-
new_coords = [[[
|
|
463
|
+
new_coords = [[[lon, lat] for lat, lon in polygon] for polygon in feature['geometry']['coordinates']]
|
|
473
464
|
feature['geometry']['coordinates'] = new_coords
|
|
474
465
|
elif feature['geometry']['type'] == 'MultiPolygon':
|
|
475
466
|
# Swap coordinates for multi-polygons (polygons with holes)
|
|
476
|
-
new_coords = [[[[
|
|
467
|
+
new_coords = [[[[lon, lat] for lat, lon in polygon] for polygon in multipolygon] for multipolygon in feature['geometry']['coordinates']]
|
|
477
468
|
feature['geometry']['coordinates'] = new_coords
|
|
478
469
|
|
|
479
470
|
def save_geojson(features, save_path):
|
|
@@ -506,20 +497,19 @@ def find_building_containing_point(features, target_point):
|
|
|
506
497
|
|
|
507
498
|
Args:
|
|
508
499
|
features (list): List of GeoJSON feature dictionaries
|
|
509
|
-
target_point (tuple): Tuple of (
|
|
500
|
+
target_point (tuple): Tuple of (lon, lat)
|
|
510
501
|
|
|
511
502
|
Returns:
|
|
512
503
|
list: List of building IDs containing the target point
|
|
513
504
|
"""
|
|
514
|
-
# Create Shapely point
|
|
515
|
-
point = Point(target_point[
|
|
505
|
+
# Create Shapely point
|
|
506
|
+
point = Point(target_point[0], target_point[1])
|
|
516
507
|
|
|
517
508
|
id_list = []
|
|
518
509
|
for feature in features:
|
|
519
510
|
# Get polygon coordinates and convert to Shapely polygon
|
|
520
511
|
coords = feature['geometry']['coordinates'][0]
|
|
521
|
-
|
|
522
|
-
polygon = Polygon(polygon_coords)
|
|
512
|
+
polygon = Polygon(coords)
|
|
523
513
|
|
|
524
514
|
# Check if point is within polygon
|
|
525
515
|
if polygon.contains(point):
|
|
@@ -530,8 +520,8 @@ def find_building_containing_point(features, target_point):
|
|
|
530
520
|
def get_buildings_in_drawn_polygon(building_geojson, drawn_polygon_vertices,
|
|
531
521
|
operation='within'):
|
|
532
522
|
"""
|
|
533
|
-
Given a list of building footprints
|
|
534
|
-
vertices (
|
|
523
|
+
Given a list of building footprints and a set of drawn polygon
|
|
524
|
+
vertices (in lon, lat), return the building IDs that fall within or
|
|
535
525
|
intersect the drawn polygon.
|
|
536
526
|
|
|
537
527
|
Args:
|
|
@@ -543,7 +533,7 @@ def get_buildings_in_drawn_polygon(building_geojson, drawn_polygon_vertices,
|
|
|
543
533
|
"type": "Polygon",
|
|
544
534
|
"coordinates": [
|
|
545
535
|
[
|
|
546
|
-
[
|
|
536
|
+
[lon1, lat1], [lon2, lat2], ...
|
|
547
537
|
]
|
|
548
538
|
]
|
|
549
539
|
},
|
|
@@ -552,10 +542,9 @@ def get_buildings_in_drawn_polygon(building_geojson, drawn_polygon_vertices,
|
|
|
552
542
|
...
|
|
553
543
|
}
|
|
554
544
|
}
|
|
555
|
-
Note: These coordinates are in (lat, lon) order, not standard (lon, lat).
|
|
556
545
|
|
|
557
546
|
drawn_polygon_vertices (list):
|
|
558
|
-
A list of (
|
|
547
|
+
A list of (lon, lat) tuples representing the polygon drawn by the user.
|
|
559
548
|
|
|
560
549
|
operation (str):
|
|
561
550
|
Determines how to include buildings.
|
|
@@ -566,27 +555,24 @@ def get_buildings_in_drawn_polygon(building_geojson, drawn_polygon_vertices,
|
|
|
566
555
|
list:
|
|
567
556
|
A list of building IDs (strings or ints) that satisfy the condition.
|
|
568
557
|
"""
|
|
569
|
-
#
|
|
570
|
-
|
|
571
|
-
# So we'll do (lon, lat) for each vertex.
|
|
572
|
-
drawn_polygon_shapely = Polygon([(lon, lat) for (lat, lon) in drawn_polygon_vertices])
|
|
558
|
+
# Create Shapely Polygon from drawn vertices
|
|
559
|
+
drawn_polygon_shapely = Polygon(drawn_polygon_vertices)
|
|
573
560
|
|
|
574
561
|
included_building_ids = []
|
|
575
562
|
|
|
576
|
-
#
|
|
563
|
+
# Check each building in the GeoJSON
|
|
577
564
|
for feature in building_geojson:
|
|
578
565
|
# Skip any feature that is not Polygon
|
|
579
566
|
if feature['geometry']['type'] != 'Polygon':
|
|
580
567
|
continue
|
|
581
568
|
|
|
582
|
-
# Extract coordinates
|
|
569
|
+
# Extract coordinates
|
|
583
570
|
coords = feature['geometry']['coordinates'][0]
|
|
584
571
|
|
|
585
572
|
# Create a Shapely polygon for the building
|
|
586
|
-
|
|
587
|
-
building_polygon = Polygon([(lon, lat) for (lat, lon) in coords])
|
|
573
|
+
building_polygon = Polygon(coords)
|
|
588
574
|
|
|
589
|
-
#
|
|
575
|
+
# Depending on the operation, check the relationship
|
|
590
576
|
if operation == 'intersect':
|
|
591
577
|
if building_polygon.intersects(drawn_polygon_shapely):
|
|
592
578
|
included_building_ids.append(feature['properties'].get('id', None))
|
voxcity/geo/__init_.py
CHANGED
voxcity/geo/draw.py
CHANGED
|
@@ -16,11 +16,11 @@ def rotate_rectangle(m, rectangle_vertices, angle):
|
|
|
16
16
|
|
|
17
17
|
Args:
|
|
18
18
|
m (ipyleaflet.Map): Map object to draw the rotated rectangle on
|
|
19
|
-
rectangle_vertices (list): List of (
|
|
19
|
+
rectangle_vertices (list): List of (lon, lat) tuples defining the rectangle vertices
|
|
20
20
|
angle (float): Rotation angle in degrees
|
|
21
21
|
|
|
22
22
|
Returns:
|
|
23
|
-
list: List of rotated (
|
|
23
|
+
list: List of rotated (lon, lat) tuples defining the new rectangle vertices
|
|
24
24
|
"""
|
|
25
25
|
if not rectangle_vertices:
|
|
26
26
|
print("Draw a rectangle first!")
|
|
@@ -31,7 +31,7 @@ def rotate_rectangle(m, rectangle_vertices, angle):
|
|
|
31
31
|
mercator = Proj(init='epsg:3857') # Web Mercator (projection used by most web maps)
|
|
32
32
|
|
|
33
33
|
# Project vertices from WGS84 to Web Mercator for proper distance calculations
|
|
34
|
-
projected_vertices = [transform(wgs84, mercator, lon, lat) for
|
|
34
|
+
projected_vertices = [transform(wgs84, mercator, lon, lat) for lon, lat in rectangle_vertices]
|
|
35
35
|
|
|
36
36
|
# Calculate the centroid to use as rotation center
|
|
37
37
|
centroid_x = sum(x for x, y in projected_vertices) / len(projected_vertices)
|
|
@@ -57,15 +57,12 @@ def rotate_rectangle(m, rectangle_vertices, angle):
|
|
|
57
57
|
|
|
58
58
|
rotated_vertices.append((new_x, new_y))
|
|
59
59
|
|
|
60
|
-
# Convert coordinates back to WGS84 (lat
|
|
60
|
+
# Convert coordinates back to WGS84 (lon/lat)
|
|
61
61
|
new_vertices = [transform(mercator, wgs84, x, y) for x, y in rotated_vertices]
|
|
62
62
|
|
|
63
|
-
# Reorder coordinates from (lon,lat) to (lat,lon) format
|
|
64
|
-
new_vertices = [(lat, lon) for lon, lat in new_vertices]
|
|
65
|
-
|
|
66
63
|
# Create and add new polygon layer to map
|
|
67
64
|
polygon = ipyleaflet.Polygon(
|
|
68
|
-
locations=new_vertices,
|
|
65
|
+
locations=[(lat, lon) for lon, lat in new_vertices], # Convert to (lat,lon) for ipyleaflet
|
|
69
66
|
color="red",
|
|
70
67
|
fill_color="red"
|
|
71
68
|
)
|
|
@@ -104,8 +101,8 @@ def draw_rectangle_map(center=(40, -100), zoom=4):
|
|
|
104
101
|
print("Vertices of the drawn rectangle:")
|
|
105
102
|
# Store all vertices except last (GeoJSON repeats first vertex at end)
|
|
106
103
|
for coord in coordinates[:-1]:
|
|
107
|
-
#
|
|
108
|
-
rectangle_vertices.append((coord[
|
|
104
|
+
# Keep GeoJSON (lon,lat) format
|
|
105
|
+
rectangle_vertices.append((coord[0], coord[1]))
|
|
109
106
|
print(f"Longitude: {coord[0]}, Latitude: {coord[1]}")
|
|
110
107
|
|
|
111
108
|
# Configure drawing controls - only enable rectangle drawing
|
|
@@ -179,9 +176,9 @@ def center_location_map_cityname(cityname, east_west_length, north_south_length,
|
|
|
179
176
|
|
|
180
177
|
# Process only if a point was drawn on the map
|
|
181
178
|
if action == 'created' and geo_json['geometry']['type'] == 'Point':
|
|
182
|
-
# Extract point coordinates
|
|
183
|
-
|
|
184
|
-
print(f"Point drawn at
|
|
179
|
+
# Extract point coordinates from GeoJSON (lon,lat)
|
|
180
|
+
lon, lat = geo_json['geometry']['coordinates'][0], geo_json['geometry']['coordinates'][1]
|
|
181
|
+
print(f"Point drawn at Longitude: {lon}, Latitude: {lat}")
|
|
185
182
|
|
|
186
183
|
# Calculate corner points using geopy's distance calculator
|
|
187
184
|
# Each point is calculated as a destination from center point using bearing
|
|
@@ -190,15 +187,15 @@ def center_location_map_cityname(cityname, east_west_length, north_south_length,
|
|
|
190
187
|
east = distance.distance(meters=east_west_length/2).destination((lat, lon), bearing=90)
|
|
191
188
|
west = distance.distance(meters=east_west_length/2).destination((lat, lon), bearing=270)
|
|
192
189
|
|
|
193
|
-
# Create rectangle vertices in counter-clockwise order
|
|
190
|
+
# Create rectangle vertices in counter-clockwise order (lon,lat)
|
|
194
191
|
rectangle_vertices.extend([
|
|
195
|
-
(
|
|
196
|
-
(
|
|
197
|
-
(
|
|
198
|
-
(
|
|
192
|
+
(west.longitude, south.latitude),
|
|
193
|
+
(west.longitude, north.latitude),
|
|
194
|
+
(east.longitude, north.latitude),
|
|
195
|
+
(east.longitude, south.latitude)
|
|
199
196
|
])
|
|
200
197
|
|
|
201
|
-
# Create and add new rectangle to map
|
|
198
|
+
# Create and add new rectangle to map (ipyleaflet expects lat,lon)
|
|
202
199
|
rectangle = Rectangle(
|
|
203
200
|
bounds=[(north.latitude, west.longitude), (south.latitude, east.longitude)],
|
|
204
201
|
color="red",
|
|
@@ -209,7 +206,7 @@ def center_location_map_cityname(cityname, east_west_length, north_south_length,
|
|
|
209
206
|
|
|
210
207
|
print("Rectangle vertices:")
|
|
211
208
|
for vertex in rectangle_vertices:
|
|
212
|
-
print(f"
|
|
209
|
+
print(f"Longitude: {vertex[0]}, Latitude: {vertex[1]}")
|
|
213
210
|
|
|
214
211
|
# Configure drawing controls - only enable point drawing
|
|
215
212
|
draw_control = DrawControl()
|
|
@@ -227,44 +224,44 @@ def center_location_map_cityname(cityname, east_west_length, north_south_length,
|
|
|
227
224
|
|
|
228
225
|
def display_buildings_and_draw_polygon(building_geojson, zoom=17):
|
|
229
226
|
"""
|
|
230
|
-
Displays building footprints (in Lat
|
|
227
|
+
Displays building footprints (in Lon-Lat order) on an ipyleaflet map,
|
|
231
228
|
and allows the user to draw a polygon whose vertices are returned
|
|
232
|
-
in a Python list (also in Lat
|
|
229
|
+
in a Python list (also in Lon-Lat).
|
|
233
230
|
|
|
234
231
|
Args:
|
|
235
232
|
building_geojson (list): A list of GeoJSON features (Polygons),
|
|
236
|
-
|
|
233
|
+
with coordinates in [lon, lat] order.
|
|
237
234
|
zoom (int): Initial zoom level for the map. Default=17.
|
|
238
235
|
|
|
239
236
|
Returns:
|
|
240
237
|
(map_object, drawn_polygon_vertices)
|
|
241
238
|
- map_object: ipyleaflet Map instance
|
|
242
239
|
- drawn_polygon_vertices: a Python list that gets updated whenever
|
|
243
|
-
a new polygon is created. The list is in (
|
|
240
|
+
a new polygon is created. The list is in (lon, lat) order.
|
|
244
241
|
"""
|
|
245
242
|
# ---------------------------------------------------------
|
|
246
243
|
# 1. Determine a suitable map center via bounding box logic
|
|
247
244
|
# ---------------------------------------------------------
|
|
248
|
-
all_lats = []
|
|
249
245
|
all_lons = []
|
|
246
|
+
all_lats = []
|
|
250
247
|
for feature in building_geojson:
|
|
251
248
|
# Handle only Polygons here; skip MultiPolygon if present
|
|
252
249
|
if feature['geometry']['type'] == 'Polygon':
|
|
253
|
-
# Coordinates in this data are [ [
|
|
250
|
+
# Coordinates in this data are [ [lon, lat], [lon, lat], ... ]
|
|
254
251
|
coords = feature['geometry']['coordinates'][0] # outer ring
|
|
255
|
-
|
|
256
|
-
|
|
252
|
+
all_lons.extend(pt[0] for pt in coords)
|
|
253
|
+
all_lats.extend(pt[1] for pt in coords)
|
|
257
254
|
|
|
258
255
|
if not all_lats or not all_lons:
|
|
259
256
|
# Fallback: If no footprints or invalid data, pick a default
|
|
260
|
-
|
|
257
|
+
center_lon, center_lat = -100.0, 40.0
|
|
261
258
|
else:
|
|
262
|
-
min_lat, max_lat = min(all_lats), max(all_lats)
|
|
263
259
|
min_lon, max_lon = min(all_lons), max(all_lons)
|
|
264
|
-
|
|
260
|
+
min_lat, max_lat = min(all_lats), max(all_lats)
|
|
265
261
|
center_lon = (min_lon + max_lon) / 2
|
|
262
|
+
center_lat = (min_lat + max_lat) / 2
|
|
266
263
|
|
|
267
|
-
# Create the ipyleaflet map
|
|
264
|
+
# Create the ipyleaflet map (needs lat,lon)
|
|
268
265
|
m = Map(center=(center_lat, center_lon), zoom=zoom, scroll_wheel_zoom=True)
|
|
269
266
|
|
|
270
267
|
# -----------------------------------------
|
|
@@ -274,8 +271,8 @@ def display_buildings_and_draw_polygon(building_geojson, zoom=17):
|
|
|
274
271
|
# Only handle simple Polygons
|
|
275
272
|
if feature['geometry']['type'] == 'Polygon':
|
|
276
273
|
coords = feature['geometry']['coordinates'][0]
|
|
277
|
-
#
|
|
278
|
-
lat_lon_coords = [(c[
|
|
274
|
+
# Convert to (lat,lon) for ipyleaflet
|
|
275
|
+
lat_lon_coords = [(c[1], c[0]) for c in coords]
|
|
279
276
|
|
|
280
277
|
# Create the polygon layer
|
|
281
278
|
bldg_layer = LeafletPolygon(
|
|
@@ -288,15 +285,15 @@ def display_buildings_and_draw_polygon(building_geojson, zoom=17):
|
|
|
288
285
|
m.add_layer(bldg_layer)
|
|
289
286
|
|
|
290
287
|
# -----------------------------------------------------------------
|
|
291
|
-
# 3. Enable drawing of polygons, capturing the vertices in Lat
|
|
288
|
+
# 3. Enable drawing of polygons, capturing the vertices in Lon-Lat
|
|
292
289
|
# -----------------------------------------------------------------
|
|
293
|
-
drawn_polygon_vertices = [] # We'll store the newly drawn polygon's vertices here (
|
|
290
|
+
drawn_polygon_vertices = [] # We'll store the newly drawn polygon's vertices here (lon, lat).
|
|
294
291
|
|
|
295
292
|
draw_control = DrawControl(
|
|
296
293
|
polygon={
|
|
297
294
|
"shapeOptions": {
|
|
298
|
-
"color": "
|
|
299
|
-
"fillColor": "
|
|
295
|
+
"color": "red",
|
|
296
|
+
"fillColor": "red",
|
|
300
297
|
"fillOpacity": 0.2
|
|
301
298
|
}
|
|
302
299
|
},
|
|
@@ -311,23 +308,22 @@ def display_buildings_and_draw_polygon(building_geojson, zoom=17):
|
|
|
311
308
|
"""
|
|
312
309
|
Callback for whenever a shape is created or edited.
|
|
313
310
|
ipyleaflet's DrawControl returns standard GeoJSON (lon, lat).
|
|
314
|
-
We'll
|
|
311
|
+
We'll keep them as (lon, lat).
|
|
315
312
|
"""
|
|
316
313
|
# Clear any previously stored vertices
|
|
317
314
|
drawn_polygon_vertices.clear()
|
|
318
315
|
|
|
319
316
|
if action == 'created' and geo_json['geometry']['type'] == 'Polygon':
|
|
320
|
-
# The polygon
|
|
317
|
+
# The polygon's first ring
|
|
321
318
|
coordinates = geo_json['geometry']['coordinates'][0]
|
|
322
|
-
print("Vertices of the drawn polygon (Lat
|
|
319
|
+
print("Vertices of the drawn polygon (Lon-Lat):")
|
|
323
320
|
|
|
324
|
-
#
|
|
325
|
-
# The last coordinate repeats the first -> skip it with [:-1]
|
|
321
|
+
# Keep GeoJSON (lon,lat) format, skip last repeated coordinate
|
|
326
322
|
for coord in coordinates[:-1]:
|
|
327
323
|
lon = coord[0]
|
|
328
324
|
lat = coord[1]
|
|
329
|
-
drawn_polygon_vertices.append((
|
|
330
|
-
print(f" - (
|
|
325
|
+
drawn_polygon_vertices.append((lon, lat))
|
|
326
|
+
print(f" - (lon, lat) = ({lon}, {lat})")
|
|
331
327
|
|
|
332
328
|
draw_control.on_draw(handle_draw)
|
|
333
329
|
m.add_control(draw_control)
|