voxcity 0.3.15__tar.gz → 0.3.17__tar.gz

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.

Files changed (52) hide show
  1. {voxcity-0.3.15 → voxcity-0.3.17}/PKG-INFO +1 -1
  2. {voxcity-0.3.15 → voxcity-0.3.17}/pyproject.toml +1 -1
  3. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/downloader/gee.py +32 -1
  4. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/generator.py +13 -4
  5. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/geoprocessor/draw.py +35 -25
  6. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/geoprocessor/grid.py +8 -1
  7. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity.egg-info/PKG-INFO +1 -1
  8. {voxcity-0.3.15 → voxcity-0.3.17}/AUTHORS.rst +0 -0
  9. {voxcity-0.3.15 → voxcity-0.3.17}/CONTRIBUTING.rst +0 -0
  10. {voxcity-0.3.15 → voxcity-0.3.17}/HISTORY.rst +0 -0
  11. {voxcity-0.3.15 → voxcity-0.3.17}/LICENSE +0 -0
  12. {voxcity-0.3.15 → voxcity-0.3.17}/MANIFEST.in +0 -0
  13. {voxcity-0.3.15 → voxcity-0.3.17}/README.md +0 -0
  14. {voxcity-0.3.15 → voxcity-0.3.17}/docs/Makefile +0 -0
  15. {voxcity-0.3.15 → voxcity-0.3.17}/docs/archive/README.rst +0 -0
  16. {voxcity-0.3.15 → voxcity-0.3.17}/docs/authors.rst +0 -0
  17. {voxcity-0.3.15 → voxcity-0.3.17}/docs/conf.py +0 -0
  18. {voxcity-0.3.15 → voxcity-0.3.17}/docs/index.rst +0 -0
  19. {voxcity-0.3.15 → voxcity-0.3.17}/docs/make.bat +0 -0
  20. {voxcity-0.3.15 → voxcity-0.3.17}/setup.cfg +0 -0
  21. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/__init__.py +0 -0
  22. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/downloader/__init__.py +0 -0
  23. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/downloader/eubucco.py +0 -0
  24. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/downloader/mbfp.py +0 -0
  25. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/downloader/oemj.py +0 -0
  26. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/downloader/omt.py +0 -0
  27. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/downloader/osm.py +0 -0
  28. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/downloader/overture.py +0 -0
  29. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/downloader/utils.py +0 -0
  30. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/exporter/__init_.py +0 -0
  31. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/exporter/envimet.py +0 -0
  32. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/exporter/magicavoxel.py +0 -0
  33. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/exporter/obj.py +0 -0
  34. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/geoprocessor/__init_.py +0 -0
  35. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/geoprocessor/network.py +0 -0
  36. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/geoprocessor/polygon.py +0 -0
  37. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/geoprocessor/utils.py +0 -0
  38. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/simulator/__init_.py +0 -0
  39. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/simulator/solar.py +0 -0
  40. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/simulator/utils.py +0 -0
  41. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/simulator/view.py +0 -0
  42. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/utils/__init_.py +0 -0
  43. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/utils/lc.py +0 -0
  44. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/utils/material.py +0 -0
  45. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/utils/visualization.py +0 -0
  46. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity/utils/weather.py +0 -0
  47. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity.egg-info/SOURCES.txt +0 -0
  48. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity.egg-info/dependency_links.txt +0 -0
  49. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity.egg-info/requires.txt +0 -0
  50. {voxcity-0.3.15 → voxcity-0.3.17}/src/voxcity.egg-info/top_level.txt +0 -0
  51. {voxcity-0.3.15 → voxcity-0.3.17}/tests/__init__.py +0 -0
  52. {voxcity-0.3.15 → voxcity-0.3.17}/tests/voxelcity.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: voxcity
3
- Version: 0.3.15
3
+ Version: 0.3.17
4
4
  Summary: voxcity is an easy and one-stop tool to output 3d city models for microclimate simulation by integrating multiple geospatial open-data
5
5
  Author-email: Kunihiko Fujiwara <kunihiko@nus.edu.sg>
6
6
  Maintainer-email: Kunihiko Fujiwara <kunihiko@nus.edu.sg>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "voxcity"
3
- version = "0.3.15"
3
+ version = "0.3.17"
4
4
  requires-python = ">=3.10,<3.13"
5
5
  classifiers = [
6
6
  "Programming Language :: Python :: 3.10",
@@ -393,4 +393,35 @@ def save_geotiff_open_buildings_temporal(aoi, geotiff_path):
393
393
  scale=4,
394
394
  region=aoi,
395
395
  file_per_band=False
396
- )
396
+ )
397
+
398
+ def save_geotiff_england_dsm_minus_dtm(roi, geotiff_path, meshsize):
399
+ """Get the height difference between DSM and DTM from England 1m terrain data.
400
+
401
+ Args:
402
+ roi: Earth Engine geometry defining area of interest
403
+ geotiff_path: Output path for GeoTIFF file
404
+ meshsize: Size of each grid cell in meters
405
+
406
+ Returns:
407
+ ee.Image: Image representing DSM minus DTM (building/vegetation heights)
408
+ """
409
+ # Initialize Earth Engine
410
+ ee.Initialize()
411
+
412
+ # Add buffer around ROI to ensure smooth interpolation at edges
413
+ buffer_distance = 100
414
+ roi_buffered = roi.buffer(buffer_distance)
415
+
416
+ collection_name = 'UK/EA/ENGLAND_1M_TERRAIN/2022'
417
+ dtm = ee.Image(collection_name).select('dtm')
418
+ dsm = ee.Image(collection_name).select('dsm_first')
419
+
420
+ # Subtract DTM from DSM to get height difference
421
+ height_diff = dsm.subtract(dtm)
422
+
423
+ # Clip to buffered ROI
424
+ image = height_diff.clip(roi_buffered)
425
+
426
+ # Export as GeoTIFF using meshsize as scale
427
+ save_geotiff(image, geotiff_path, scale=meshsize, region=roi_buffered, crs='EPSG:4326')
@@ -34,7 +34,8 @@ from .downloader.gee import (
34
34
  save_geotiff_esa_land_cover,
35
35
  save_geotiff_esri_landcover,
36
36
  save_geotiff_dynamic_world_v1,
37
- save_geotiff_open_buildings_temporal
37
+ save_geotiff_open_buildings_temporal,
38
+ save_geotiff_england_dsm_minus_dtm
38
39
  )
39
40
  from .geoprocessor.grid import (
40
41
  group_and_label_cells,
@@ -185,11 +186,12 @@ def get_building_height_grid(rectangle_vertices, meshsize, source, output_dir, *
185
186
 
186
187
  # Check for complementary building data source
187
188
  building_complementary_source = kwargs.get("building_complementary_source")
189
+ building_complement_height = kwargs.get("building_complement_height")
188
190
 
189
191
  if (building_complementary_source is None) or (building_complementary_source=='None'):
190
192
  # Use only primary source
191
193
  if source != "Open Building 2.5D Temporal":
192
- building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices)
194
+ building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices, complement_height=building_complement_height)
193
195
  else:
194
196
  # Handle complementary source
195
197
  if building_complementary_source == "Open Building 2.5D Temporal":
@@ -198,7 +200,14 @@ def get_building_height_grid(rectangle_vertices, meshsize, source, output_dir, *
198
200
  os.makedirs(output_dir, exist_ok=True)
199
201
  geotiff_path_comp = os.path.join(output_dir, "building_height.tif")
200
202
  save_geotiff_open_buildings_temporal(roi, geotiff_path_comp)
201
- building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices, geotiff_path_comp=geotiff_path_comp)
203
+ building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices, geotiff_path_comp=geotiff_path_comp, complement_height=building_complement_height)
204
+ elif building_complementary_source == "England 1m DSM - DTM":
205
+ # Special case: use temporal height data as complement
206
+ roi = get_roi(rectangle_vertices)
207
+ os.makedirs(output_dir, exist_ok=True)
208
+ geotiff_path_comp = os.path.join(output_dir, "building_height.tif")
209
+ save_geotiff_england_dsm_minus_dtm(roi, geotiff_path_comp, meshsize)
210
+ building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices, geotiff_path_comp=geotiff_path_comp, complement_height=building_complement_height)
202
211
  else:
203
212
  # Get complementary data from other sources
204
213
  if building_complementary_source == 'Microsoft Building Footprints':
@@ -220,7 +229,7 @@ def get_building_height_grid(rectangle_vertices, meshsize, source, output_dir, *
220
229
 
221
230
  # Option to complement footprints only or both footprints and heights
222
231
  complement_building_footprints = kwargs.get("complement_building_footprints")
223
- building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices, gdf_comp=gdf_comp, complement_building_footprints=complement_building_footprints)
232
+ building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices, gdf_comp=gdf_comp, complement_building_footprints=complement_building_footprints, complement_height=building_complement_height)
224
233
 
225
234
  # Visualize grid if requested
226
235
  grid_vis = kwargs.get("gridvis", True)
@@ -223,15 +223,16 @@ def center_location_map_cityname(cityname, east_west_length, north_south_length,
223
223
 
224
224
  return m, rectangle_vertices
225
225
 
226
- def display_buildings_and_draw_polygon(building_gdf, zoom=17):
226
+ def display_buildings_and_draw_polygon(building_gdf=None, rectangle_vertices=None, zoom=17):
227
227
  """
228
228
  Displays building footprints (in Lon-Lat order) on an ipyleaflet map,
229
229
  and allows the user to draw a polygon whose vertices are returned
230
230
  in a Python list (also in Lon-Lat).
231
231
 
232
232
  Args:
233
- building_gdf (GeoDataFrame): A GeoDataFrame containing building footprints,
234
- with geometry in [lon, lat] order.
233
+ building_gdf (GeoDataFrame, optional): A GeoDataFrame containing building footprints,
234
+ with geometry in [lon, lat] order.
235
+ rectangle_vertices (list, optional): List of [lon, lat] coordinates defining rectangle corners.
235
236
  zoom (int): Initial zoom level for the map. Default=17.
236
237
 
237
238
  Returns:
@@ -243,39 +244,48 @@ def display_buildings_and_draw_polygon(building_gdf, zoom=17):
243
244
  # ---------------------------------------------------------
244
245
  # 1. Determine a suitable map center via bounding box logic
245
246
  # ---------------------------------------------------------
246
- if len(building_gdf) == 0:
247
- # Fallback: If no footprints or invalid data, pick a default
248
- center_lon, center_lat = -100.0, 40.0
249
- else:
247
+ if rectangle_vertices is not None:
248
+ # Get bounds from rectangle vertices
249
+ lons = [v[0] for v in rectangle_vertices]
250
+ lats = [v[1] for v in rectangle_vertices]
251
+ min_lon, max_lon = min(lons), max(lons)
252
+ min_lat, max_lat = min(lats), max(lats)
253
+ center_lon = (min_lon + max_lon) / 2
254
+ center_lat = (min_lat + max_lat) / 2
255
+ elif building_gdf is not None and len(building_gdf) > 0:
250
256
  # Get bounds from GeoDataFrame
251
257
  bounds = building_gdf.total_bounds # Returns [minx, miny, maxx, maxy]
252
258
  min_lon, min_lat, max_lon, max_lat = bounds
253
259
  center_lon = (min_lon + max_lon) / 2
254
260
  center_lat = (min_lat + max_lat) / 2
261
+ else:
262
+ # Fallback: If no inputs or invalid data, pick a default
263
+ center_lon, center_lat = -100.0, 40.0
255
264
 
256
265
  # Create the ipyleaflet map (needs lat,lon)
257
266
  m = Map(center=(center_lat, center_lon), zoom=zoom, scroll_wheel_zoom=True)
258
267
 
259
268
  # -----------------------------------------
260
- # 2. Add each building footprint to the map
269
+ # 2. Add building footprints to the map if provided
261
270
  # -----------------------------------------
262
- for idx, row in building_gdf.iterrows():
263
- # Only handle simple Polygons
264
- if isinstance(row.geometry, geom.Polygon):
265
- # Get coordinates from geometry
266
- coords = list(row.geometry.exterior.coords)
267
- # Convert to (lat,lon) for ipyleaflet, skip last repeated coordinate
268
- lat_lon_coords = [(c[1], c[0]) for c in coords[:-1]]
269
-
270
- # Create the polygon layer
271
- bldg_layer = LeafletPolygon(
272
- locations=lat_lon_coords,
273
- color="blue",
274
- fill_color="blue",
275
- fill_opacity=0.2,
276
- weight=2
277
- )
278
- m.add_layer(bldg_layer)
271
+ if building_gdf is not None:
272
+ for idx, row in building_gdf.iterrows():
273
+ # Only handle simple Polygons
274
+ if isinstance(row.geometry, geom.Polygon):
275
+ # Get coordinates from geometry
276
+ coords = list(row.geometry.exterior.coords)
277
+ # Convert to (lat,lon) for ipyleaflet, skip last repeated coordinate
278
+ lat_lon_coords = [(c[1], c[0]) for c in coords[:-1]]
279
+
280
+ # Create the polygon layer
281
+ bldg_layer = LeafletPolygon(
282
+ locations=lat_lon_coords,
283
+ color="blue",
284
+ fill_color="blue",
285
+ fill_opacity=0.2,
286
+ weight=2
287
+ )
288
+ m.add_layer(bldg_layer)
279
289
 
280
290
  # -----------------------------------------------------------------
281
291
  # 3. Enable drawing of polygons, capturing the vertices in Lon-Lat
@@ -480,7 +480,8 @@ def create_building_height_grid_from_gdf_polygon(
480
480
  rectangle_vertices,
481
481
  gdf_comp=None,
482
482
  geotiff_path_comp=None,
483
- complement_building_footprints=None
483
+ complement_building_footprints=None,
484
+ complement_height=None
484
485
  ):
485
486
  """
486
487
  Create a building height grid from GeoDataFrame data within a polygon boundary.
@@ -492,6 +493,7 @@ def create_building_height_grid_from_gdf_polygon(
492
493
  gdf_comp (geopandas.GeoDataFrame, optional): Complementary GeoDataFrame
493
494
  geotiff_path_comp (str, optional): Path to complementary GeoTIFF file
494
495
  complement_building_footprints (bool, optional): Whether to complement footprints
496
+ complement_height (float, optional): Height value to use for buildings with height=0
495
497
 
496
498
  Returns:
497
499
  tuple: (building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings)
@@ -558,6 +560,11 @@ def create_building_height_grid_from_gdf_polygon(
558
560
  for idx_b, row in filtered_gdf.iterrows():
559
561
  polygon = row.geometry
560
562
  height = row.get('height', None)
563
+
564
+ # Replace height=0 with complement_height if specified
565
+ if complement_height is not None and (height == 0 or height is None):
566
+ height = complement_height
567
+
561
568
  min_height = row.get('min_height', 0)
562
569
  is_inner = row.get('is_inner', False)
563
570
  feature_id = row.get('id', idx_b)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: voxcity
3
- Version: 0.3.15
3
+ Version: 0.3.17
4
4
  Summary: voxcity is an easy and one-stop tool to output 3d city models for microclimate simulation by integrating multiple geospatial open-data
5
5
  Author-email: Kunihiko Fujiwara <kunihiko@nus.edu.sg>
6
6
  Maintainer-email: Kunihiko Fujiwara <kunihiko@nus.edu.sg>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes