voxcity 0.5.10__py3-none-any.whl → 0.5.12__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/generator.py CHANGED
@@ -689,6 +689,14 @@ def get_voxcity(rectangle_vertices, building_source, land_cover_source, canopy_h
689
689
  voxcity_grid_vis[-1, -1, -1] = -99 # Add marker to fix camera location and angle of view
690
690
  visualize_3d_voxel(voxcity_grid_vis, voxel_size=meshsize, save_path=kwargs["voxelvis_img_save_path"])
691
691
 
692
+ # Save all data if a save path is provided
693
+ save_voxcity = kwargs.get("save_voxctiy_data", True)
694
+ if save_voxcity:
695
+ save_path = kwargs.get("save_data_path", f"{output_dir}/voxcity_data.pkl")
696
+ save_voxcity_data(save_path, voxcity_grid, building_height_grid, building_min_height_grid,
697
+ building_id_grid, canopy_height_grid, land_cover_grid, dem_grid,
698
+ building_gdf, meshsize, rectangle_vertices)
699
+
692
700
  return voxcity_grid, building_height_grid, building_min_height_grid, building_id_grid, canopy_height_grid, land_cover_grid, dem_grid, building_gdf
693
701
 
694
702
  def get_voxcity_CityGML(rectangle_vertices, land_cover_source, canopy_height_source, meshsize, url_citygml=None, citygml_path=None, **kwargs):
@@ -817,6 +825,14 @@ def get_voxcity_CityGML(rectangle_vertices, land_cover_source, canopy_height_sou
817
825
  # Generate 3D voxel grid
818
826
  voxcity_grid = create_3d_voxel(building_height_grid, building_min_height_grid, building_id_grid, land_cover_grid, dem_grid, canopy_height_grid, meshsize, land_cover_source)
819
827
 
828
+ # Save all data if a save path is provided
829
+ save_voxcity = kwargs.get("save_voxctiy_data", True)
830
+ if save_voxcity:
831
+ save_path = kwargs.get("save_data_path", f"{output_dir}/voxcity_data.pkl")
832
+ save_voxcity_data(save_path, voxcity_grid, building_height_grid, building_min_height_grid,
833
+ building_id_grid, canopy_height_grid, land_cover_grid, dem_grid,
834
+ building_gdf, meshsize, rectangle_vertices)
835
+
820
836
  return voxcity_grid, building_height_grid, building_min_height_grid, building_id_grid, canopy_height_grid, land_cover_grid, dem_grid, filtered_buildings
821
837
 
822
838
  def replace_nan_in_nested(arr, replace_value=10.0):
@@ -844,4 +860,89 @@ def replace_nan_in_nested(arr, replace_value=10.0):
844
860
  if isinstance(arr[i][j][k][l], float) and np.isnan(arr[i][j][k][l]):
845
861
  arr[i][j][k][l] = replace_value
846
862
 
847
- return np.array(arr, dtype=object)
863
+ return np.array(arr, dtype=object)
864
+
865
+ def save_voxcity_data(output_path, voxcity_grid, building_height_grid, building_min_height_grid,
866
+ building_id_grid, canopy_height_grid, land_cover_grid, dem_grid,
867
+ building_gdf, meshsize, rectangle_vertices):
868
+ """Save voxcity data to a file for later loading.
869
+
870
+ Args:
871
+ output_path: Path to save the data file
872
+ voxcity_grid: 3D voxel grid of the complete city model
873
+ building_height_grid: 2D grid of building heights
874
+ building_min_height_grid: 2D grid of minimum building heights
875
+ building_id_grid: 2D grid of building IDs
876
+ canopy_height_grid: 2D grid of tree canopy heights
877
+ land_cover_grid: 2D grid of land cover classifications
878
+ dem_grid: 2D grid of ground elevation
879
+ building_gdf: GeoDataFrame of building footprints and metadata
880
+ meshsize: Size of each grid cell in meters
881
+ rectangle_vertices: List of coordinates defining the area of interest
882
+ """
883
+ import pickle
884
+ import os
885
+
886
+ # Create directory if it doesn't exist
887
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
888
+
889
+ # Create a dictionary with all the data
890
+ data_dict = {
891
+ 'voxcity_grid': voxcity_grid,
892
+ 'building_height_grid': building_height_grid,
893
+ 'building_min_height_grid': building_min_height_grid,
894
+ 'building_id_grid': building_id_grid,
895
+ 'canopy_height_grid': canopy_height_grid,
896
+ 'land_cover_grid': land_cover_grid,
897
+ 'dem_grid': dem_grid,
898
+ 'building_gdf': building_gdf,
899
+ 'meshsize': meshsize,
900
+ 'rectangle_vertices': rectangle_vertices
901
+ }
902
+
903
+ # Save the data to a file using pickle
904
+ with open(output_path, 'wb') as f:
905
+ pickle.dump(data_dict, f)
906
+
907
+ print(f"Voxcity data saved to {output_path}")
908
+
909
+ def load_voxcity_data(input_path):
910
+ """Load voxcity data from a saved file.
911
+
912
+ Args:
913
+ input_path: Path to the saved data file
914
+
915
+ Returns:
916
+ tuple: All the voxcity data components including:
917
+ - voxcity_grid: 3D voxel grid of the complete city model
918
+ - building_height_grid: 2D grid of building heights
919
+ - building_min_height_grid: 2D grid of minimum building heights
920
+ - building_id_grid: 2D grid of building IDs
921
+ - canopy_height_grid: 2D grid of tree canopy heights
922
+ - land_cover_grid: 2D grid of land cover classifications
923
+ - dem_grid: 2D grid of ground elevation
924
+ - building_gdf: GeoDataFrame of building footprints and metadata
925
+ - meshsize: Size of each grid cell in meters
926
+ - rectangle_vertices: List of coordinates defining the area of interest
927
+ """
928
+ import pickle
929
+
930
+ # Load the data from the file
931
+ with open(input_path, 'rb') as f:
932
+ data_dict = pickle.load(f)
933
+
934
+ print(f"Voxcity data loaded from {input_path}")
935
+
936
+ # Return all components as a tuple
937
+ return (
938
+ data_dict['voxcity_grid'],
939
+ data_dict['building_height_grid'],
940
+ data_dict['building_min_height_grid'],
941
+ data_dict['building_id_grid'],
942
+ data_dict['canopy_height_grid'],
943
+ data_dict['land_cover_grid'],
944
+ data_dict['dem_grid'],
945
+ data_dict['building_gdf'],
946
+ data_dict['meshsize'],
947
+ data_dict['rectangle_vertices']
948
+ )
@@ -1139,13 +1139,13 @@ def get_cumulative_building_solar_irradiance(
1139
1139
  cumulative_mesh.name = "Cumulative Solar Irradiance (Wh/m²)"
1140
1140
 
1141
1141
  # Optional export
1142
- obj_export = kwargs.get("obj_export", False)
1143
- if obj_export:
1144
- _export_solar_irradiance_mesh(
1145
- cumulative_mesh,
1146
- face_cum_global,
1147
- **kwargs
1148
- )
1142
+ # obj_export = kwargs.get("obj_export", False)
1143
+ # if obj_export:
1144
+ # _export_solar_irradiance_mesh(
1145
+ # cumulative_mesh,
1146
+ # face_cum_global,
1147
+ # **kwargs
1148
+ # )
1149
1149
 
1150
1150
  return cumulative_mesh
1151
1151
 
voxcity/simulator/view.py CHANGED
@@ -1499,7 +1499,8 @@ def compute_view_factor_for_all_faces(
1499
1499
  target_values,
1500
1500
  inclusion_mode,
1501
1501
  grid_bounds_real,
1502
- boundary_epsilon
1502
+ boundary_epsilon,
1503
+ ignore_downward=True
1503
1504
  ):
1504
1505
  """
1505
1506
  Compute a per-face "view factor" for a specified set of target voxel classes.
@@ -1527,6 +1528,7 @@ def compute_view_factor_for_all_faces(
1527
1528
  If False, hitting anything *not* in target_values (except -2 trees) blocks the ray.
1528
1529
  grid_bounds_real (np.ndarray): [[x_min,y_min,z_min],[x_max,y_max,z_max]] in real coords.
1529
1530
  boundary_epsilon (float): tolerance for marking boundary vertical faces.
1531
+ ignore_downward (bool): If True, only consider upward rays. If False, consider all outward rays.
1530
1532
 
1531
1533
  Returns:
1532
1534
  np.ndarray of shape (n_faces,):
@@ -1592,34 +1594,34 @@ def compute_view_factor_for_all_faces(
1592
1594
  angle
1593
1595
  )
1594
1596
 
1595
- # -- 3) Count how many directions are outward & upward
1597
+ # -- 3) Count valid directions based on ignore_downward setting
1596
1598
  total_outward = 0
1597
- num_upward = 0
1599
+ num_valid = 0
1598
1600
  for i in range(local_dirs.shape[0]):
1599
1601
  dvec = local_dirs[i]
1600
1602
  dp = dvec[0]*normal[0] + dvec[1]*normal[1] + dvec[2]*normal[2]
1601
1603
  if dp > 0.0:
1602
1604
  total_outward += 1
1603
- if dvec[2] > 0.0:
1604
- num_upward += 1
1605
+ if not ignore_downward or dvec[2] > 0.0:
1606
+ num_valid += 1
1605
1607
 
1606
1608
  # If no outward directions at all => view factor = 0
1607
1609
  if total_outward == 0:
1608
1610
  face_vf_values[fidx] = 0.0
1609
1611
  continue
1610
1612
 
1611
- # If no upward directions => view factor = 0
1612
- if num_upward == 0:
1613
+ # If no valid directions => view factor = 0
1614
+ if num_valid == 0:
1613
1615
  face_vf_values[fidx] = 0.0
1614
1616
  continue
1615
1617
 
1616
- # -- 4) Create an array for only the upward directions
1617
- valid_dirs_arr = np.empty((num_upward, 3), dtype=np.float64)
1618
+ # -- 4) Create an array for valid directions
1619
+ valid_dirs_arr = np.empty((num_valid, 3), dtype=np.float64)
1618
1620
  out_idx = 0
1619
1621
  for i in range(local_dirs.shape[0]):
1620
1622
  dvec = local_dirs[i]
1621
1623
  dp = dvec[0]*normal[0] + dvec[1]*normal[1] + dvec[2]*normal[2]
1622
- if dp > 0.0 and dvec[2] > 0.0:
1624
+ if dp > 0.0 and (not ignore_downward or dvec[2] > 0.0):
1623
1625
  valid_dirs_arr[out_idx, 0] = dvec[0]
1624
1626
  valid_dirs_arr[out_idx, 1] = dvec[1]
1625
1627
  valid_dirs_arr[out_idx, 2] = dvec[2]
@@ -1630,8 +1632,7 @@ def compute_view_factor_for_all_faces(
1630
1632
  ray_origin = (center / meshsize) + (normal / norm_n) * offset_vox
1631
1633
 
1632
1634
  # -- 6) Compute fraction of rays that "see" the target
1633
- # (in the old code, "seeing the sky" meant the ray was NOT blocked by non‐sky voxels)
1634
- upward_vf = compute_vi_generic(
1635
+ vf = compute_vi_generic(
1635
1636
  ray_origin,
1636
1637
  voxel_data,
1637
1638
  valid_dirs_arr,
@@ -1642,9 +1643,9 @@ def compute_view_factor_for_all_faces(
1642
1643
  inclusion_mode
1643
1644
  )
1644
1645
 
1645
- # Scale by fraction of directions that were outward
1646
- fraction_up = num_upward / total_outward
1647
- face_vf_values[fidx] = upward_vf * fraction_up
1646
+ # Scale by fraction of directions that were valid
1647
+ fraction_valid = num_valid / total_outward
1648
+ face_vf_values[fidx] = vf * fraction_valid
1648
1649
 
1649
1650
  return face_vf_values
1650
1651
 
@@ -1578,7 +1578,7 @@ def visualize_voxcity_multi_view(voxel_array, meshsize, **kwargs):
1578
1578
 
1579
1579
  # Display each view separately
1580
1580
  for view_name, img_file in image_files:
1581
- plt.figure(figsize=(12, 8))
1581
+ plt.figure(figsize=(24, 16))
1582
1582
  img = plt.imread(img_file)
1583
1583
  plt.imshow(img)
1584
1584
  plt.title(view_name.replace('_', ' ').title(), pad=20)
@@ -1699,7 +1699,7 @@ def visualize_voxcity_multi_view_with_multiple_sim_grids(voxel_array, meshsize,
1699
1699
 
1700
1700
  # Display each view separately
1701
1701
  for view_name, img_file in image_files:
1702
- plt.figure(figsize=(12, 8))
1702
+ plt.figure(figsize=(24, 16))
1703
1703
  img = plt.imread(img_file)
1704
1704
  plt.imshow(img)
1705
1705
  plt.title(view_name.replace('_', ' ').title(), pad=20)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: voxcity
3
- Version: 0.5.10
3
+ Version: 0.5.12
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>
@@ -42,7 +42,6 @@ Requires-Dist: mapbox_vector_tile
42
42
  Requires-Dist: numba
43
43
  Requires-Dist: reverse_geocoder
44
44
  Requires-Dist: pycountry
45
- Requires-Dist: osm2geojson
46
45
  Requires-Dist: seaborn
47
46
  Requires-Dist: overturemaps
48
47
  Requires-Dist: protobuf<6,>=4.21
@@ -73,7 +72,7 @@ Dynamic: license-file
73
72
  </p>
74
73
 
75
74
  <p align="center">
76
- <img src="https://raw.githubusercontent.com/kunifujiwara/VoxCity/main/images/logo.png" alt="Voxcity logo" width="800">
75
+ <img src="https://raw.githubusercontent.com/kunifujiwara/VoxCity/main/images/logo.png" alt="Voxcity logo" width="550">
77
76
  </p>
78
77
 
79
78
  # VoxCity
@@ -1,5 +1,5 @@
1
1
  voxcity/__init__.py,sha256=el9v3gfybHOF_GUYPeSOqN0-vCrTW0eU1mcvi0sEfeU,252
2
- voxcity/generator.py,sha256=Ae0dAqfrVMLmjeilO2oOm5s-TMPbnLo40Z4TFJaWf5A,42651
2
+ voxcity/generator.py,sha256=qWe2LJsbY2_IYUuI99ZJ5_rRNJ8IQrEIdxND7azYd-M,47045
3
3
  voxcity/downloader/__init__.py,sha256=OgGcGxOXF4tjcEL6DhOnt13DYPTvOigUelp5xIpTqM0,171
4
4
  voxcity/downloader/citygml.py,sha256=R3DvsYJz_S5OPkeA71eEI2U7fBDLcpqdludV6gO1ihw,30305
5
5
  voxcity/downloader/eubucco.py,sha256=XCkkdEPNuWdrnuxzL80Ext37WsgiCiZGueb-aQV5rvI,14476
@@ -7,7 +7,7 @@ voxcity/downloader/gee.py,sha256=hEN5OvQAltORYnrlPbmYcDequ6lKLmwyTbNaCZ81Vj8,160
7
7
  voxcity/downloader/mbfp.py,sha256=pGJuXXLRuRedlORXfg8WlgAVwmKI30jxki9t-v5NejY,3972
8
8
  voxcity/downloader/oemj.py,sha256=YlCuWBQfi40gfmwQcGDeHiPOs4Pk_jLZq65d5R3IGMU,7886
9
9
  voxcity/downloader/omt.py,sha256=ByFvoQDnBOJF4qdVYNkDjn7cMvEhWwtD0mIV_T-zMEs,9017
10
- voxcity/downloader/osm.py,sha256=0VpYuPRiO3iru3nHM_or0nTDFb8ytUUDZieFX6zxB9Q,26338
10
+ voxcity/downloader/osm.py,sha256=6oMkB-G4j8lLIhSwJei66PNQ_8kZ-Yw90Qv8B9g1x6Q,37972
11
11
  voxcity/downloader/overture.py,sha256=2m7pHymE60iaqxa3H4gxAMtJioHd831R5kCS73dxzW8,7821
12
12
  voxcity/downloader/utils.py,sha256=z6MdPxM96FWQVqvZW2Eg5pMewVHVysUP7F6ueeCwMfI,1375
13
13
  voxcity/exporter/__init_.py,sha256=cVyNyE6axEpSd3CT5hGuMOAlOyU1p8lVP4jkF1-0Ad8,94
@@ -22,17 +22,17 @@ voxcity/geoprocessor/network.py,sha256=opb_kpUCAxDd1qtrWPStqR5reYZtVe96XxazNSen7
22
22
  voxcity/geoprocessor/polygon.py,sha256=8Vb2AbkpKYhq1kk2hQMc-gitmUo9pFIe910v4p1vP2g,37772
23
23
  voxcity/geoprocessor/utils.py,sha256=1BRHp-DDeOA8HG8jplY7Eo75G3oXkVGL6DGONL4BA8A,19815
24
24
  voxcity/simulator/__init_.py,sha256=APdkcdaovj0v_RPOaA4SBvFUKT2RM7Hxuuz3Sux4gCo,65
25
- voxcity/simulator/solar.py,sha256=amJ5GJtzdG9NE7oxrLj4EMRxGvDY9s2BQdDJ2paFfn0,56709
25
+ voxcity/simulator/solar.py,sha256=HYLB_BxoMABpY6XwwwPm2xG5edmPTjG-elji9kEoOhg,56723
26
26
  voxcity/simulator/utils.py,sha256=sEYBB2-hLJxTiXQps1_-Fi7t1HN3-1OPOvBCWtgIisA,130
27
- voxcity/simulator/view.py,sha256=YufbLuDXrLg1d1dedM6pVyiJ7uHsqY8F2sLLnIoJvB4,74910
27
+ voxcity/simulator/view.py,sha256=3ls8pew8fLIM8YRHpJNYCF8AiC6CofFPSsa2c2XWHpg,74974
28
28
  voxcity/utils/__init_.py,sha256=nLYrj2huBbDBNMqfchCwexGP8Tlt9O_XluVDG7MoFkw,98
29
29
  voxcity/utils/lc.py,sha256=RwPd-VY3POV3gTrBhM7TubgGb9MCd3nVah_G8iUEF7k,11562
30
30
  voxcity/utils/material.py,sha256=Vt3IID5Ft54HNJcEC4zi31BCPqi_687X3CSp7rXaRVY,5907
31
- voxcity/utils/visualization.py,sha256=jsKfUoRRW0yRCmJ03I7ESK1Tic_Xk1tcliw-8syr3Y0,87228
31
+ voxcity/utils/visualization.py,sha256=bxMfpSQMPghzqAGM2EpNmVMlrQu_aOHtFtNk5aOPHlU,87230
32
32
  voxcity/utils/weather.py,sha256=CFPtoqRTajwMRswswDChwQ3BW1cGsnA3orgWHgz7Ehg,26304
33
- voxcity-0.5.10.dist-info/licenses/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
34
- voxcity-0.5.10.dist-info/licenses/LICENSE,sha256=s_jE1Df1nTPL4A_5GCGic5Zwex0CVaPKcAmSilxJPPE,1089
35
- voxcity-0.5.10.dist-info/METADATA,sha256=py17aZn67P-e2JouRMZVJqLFERDB-J7ccBRJ7Dc_9Jw,25885
36
- voxcity-0.5.10.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
37
- voxcity-0.5.10.dist-info/top_level.txt,sha256=00b2U-LKfDllt6RL1R33MXie5MvxzUFye0NGD96t_8I,8
38
- voxcity-0.5.10.dist-info/RECORD,,
33
+ voxcity-0.5.12.dist-info/licenses/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
34
+ voxcity-0.5.12.dist-info/licenses/LICENSE,sha256=s_jE1Df1nTPL4A_5GCGic5Zwex0CVaPKcAmSilxJPPE,1089
35
+ voxcity-0.5.12.dist-info/METADATA,sha256=QyRrTxuPisBfcK8yEYB42sObfE_vxK1xpwqU0EQpP94,25857
36
+ voxcity-0.5.12.dist-info/WHEEL,sha256=L0N565qmK-3nM2eBoMNFszYJ_MTx03_tQ0CQu1bHLYo,91
37
+ voxcity-0.5.12.dist-info/top_level.txt,sha256=00b2U-LKfDllt6RL1R33MXie5MvxzUFye0NGD96t_8I,8
38
+ voxcity-0.5.12.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (77.0.3)
2
+ Generator: setuptools (78.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5