voxcity 0.6.6__py3-none-any.whl → 0.6.7__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.

@@ -263,14 +263,19 @@ def calculate_grid_size(side_1, side_2, u_vec, v_vec, meshsize):
263
263
  >>> mesh = 10 # Desired 10-unit mesh
264
264
  >>> grid_size, adj_mesh = calculate_grid_size(side1, side2, u, v, mesh)
265
265
  """
266
- # Calculate number of cells needed in each direction, rounding to nearest integer
267
- grid_size_0 = int(np.linalg.norm(side_1) / np.linalg.norm(meshsize * u_vec) + 0.5)
268
- grid_size_1 = int(np.linalg.norm(side_2) / np.linalg.norm(meshsize * v_vec) + 0.5)
269
-
270
- # Adjust mesh sizes to exactly fit the desired area with the calculated number of cells
271
- adjusted_mesh_size_0 = meshsize * np.linalg.norm(meshsize * u_vec) * grid_size_0 / np.linalg.norm(side_1)
272
- adjusted_mesh_size_1 = meshsize * np.linalg.norm(meshsize * v_vec) * grid_size_1 / np.linalg.norm(side_2)
273
-
266
+ # Calculate total side lengths in meters using the relationship between side vectors and unit vectors
267
+ # u_vec and v_vec represent degrees per meter along each side direction
268
+ dist_side_1_m = np.linalg.norm(side_1) / (np.linalg.norm(u_vec) + 1e-12)
269
+ dist_side_2_m = np.linalg.norm(side_2) / (np.linalg.norm(v_vec) + 1e-12)
270
+
271
+ # Calculate number of cells (nx along u, ny along v), rounding to nearest integer and ensuring at least 1
272
+ grid_size_0 = max(1, int(dist_side_1_m / meshsize + 0.5))
273
+ grid_size_1 = max(1, int(dist_side_2_m / meshsize + 0.5))
274
+
275
+ # Adjust mesh sizes (in meters) to exactly fit the sides with the calculated number of cells
276
+ adjusted_mesh_size_0 = dist_side_1_m / grid_size_0
277
+ adjusted_mesh_size_1 = dist_side_2_m / grid_size_1
278
+
274
279
  return (grid_size_0, grid_size_1), (adjusted_mesh_size_0, adjusted_mesh_size_1)
275
280
 
276
281
  def create_coordinate_mesh(origin, grid_size, adjusted_meshsize, u_vec, v_vec):
@@ -908,12 +913,19 @@ def _process_with_rasterio(filtered_gdf, grid_size, adjusted_meshsize, origin, u
908
913
  Process buildings using fast rasterio-based approach.
909
914
  Faster but less precise for overlapping footprints.
910
915
  """
911
- # Set up transform for rasterio
912
- min_x, min_y = origin[0], origin[1]
913
- max_corner = origin + grid_size[0] * adjusted_meshsize[0] * u_vec + grid_size[1] * adjusted_meshsize[1] * v_vec
914
- max_x, max_y = max_corner[0], max_corner[1]
915
-
916
- transform = from_bounds(min_x, min_y, max_x, max_y, grid_size[0], grid_size[1])
916
+ # Set up transform for rasterio using rotated basis defined by u_vec and v_vec
917
+ # Step vectors in coordinate units (degrees) per cell
918
+ u_step = adjusted_meshsize[0] * u_vec
919
+ v_step = adjusted_meshsize[1] * v_vec
920
+
921
+ # Define the top-left corner so that row=0 is the northern edge
922
+ top_left = origin + grid_size[1] * v_step
923
+
924
+ # Affine transform mapping (col, row) -> (x, y)
925
+ # x = a*col + b*row + c ; y = d*col + e*row + f
926
+ # col increases along u_step; row increases southward, hence -v_step
927
+ transform = Affine(u_step[0], -v_step[0], top_left[0],
928
+ u_step[1], -v_step[1], top_left[1])
917
929
 
918
930
  # Process buildings data
919
931
  filtered_gdf = filtered_gdf.copy()
@@ -934,9 +946,9 @@ def _process_with_rasterio(filtered_gdf, grid_size, adjusted_meshsize, origin, u
934
946
  regular_buildings = filtered_gdf[~filtered_gdf['is_inner']].copy()
935
947
  regular_buildings = regular_buildings.sort_values('height', ascending=True, na_position='first')
936
948
 
937
- # Initialize grids
938
- building_height_grid = np.zeros(grid_size, dtype=np.float64)
939
- building_id_grid = np.zeros(grid_size, dtype=np.float64)
949
+ # Temporary raster grids in rasterio's (rows=ny, cols=nx) order
950
+ height_raster = np.zeros((grid_size[1], grid_size[0]), dtype=np.float64)
951
+ id_raster = np.zeros((grid_size[1], grid_size[0]), dtype=np.float64)
940
952
 
941
953
  # Vectorized rasterization
942
954
  if len(regular_buildings) > 0:
@@ -949,9 +961,9 @@ def _process_with_rasterio(filtered_gdf, grid_size, adjusted_meshsize, origin, u
949
961
  if pd.notna(height) and height > 0]
950
962
 
951
963
  if height_shapes:
952
- building_height_grid = features.rasterize(
964
+ height_raster = features.rasterize(
953
965
  height_shapes,
954
- out_shape=grid_size,
966
+ out_shape=(grid_size[1], grid_size[0]),
955
967
  transform=transform,
956
968
  fill=0,
957
969
  dtype=np.float64
@@ -962,9 +974,9 @@ def _process_with_rasterio(filtered_gdf, grid_size, adjusted_meshsize, origin, u
962
974
  zip(valid_buildings.geometry, valid_buildings['id'])]
963
975
 
964
976
  if id_shapes:
965
- building_id_grid = features.rasterize(
977
+ id_raster = features.rasterize(
966
978
  id_shapes,
967
- out_shape=grid_size,
979
+ out_shape=(grid_size[1], grid_size[0]),
968
980
  transform=transform,
969
981
  fill=0,
970
982
  dtype=np.float64
@@ -977,17 +989,17 @@ def _process_with_rasterio(filtered_gdf, grid_size, adjusted_meshsize, origin, u
977
989
  if inner_shapes:
978
990
  inner_mask = features.rasterize(
979
991
  inner_shapes,
980
- out_shape=grid_size,
992
+ out_shape=(grid_size[1], grid_size[0]),
981
993
  transform=transform,
982
994
  fill=0,
983
995
  dtype=np.uint8
984
996
  )
985
- building_height_grid[inner_mask > 0] = 0
986
- building_id_grid[inner_mask > 0] = 0
997
+ height_raster[inner_mask > 0] = 0
998
+ id_raster[inner_mask > 0] = 0
987
999
 
988
1000
  # Simplified min_height grid
989
1001
  building_min_height_grid = np.empty(grid_size, dtype=object)
990
- min_heights = np.zeros(grid_size, dtype=np.float64)
1002
+ min_heights_raster = np.zeros((grid_size[1], grid_size[0]), dtype=np.float64)
991
1003
 
992
1004
  if len(regular_buildings) > 0:
993
1005
  valid_buildings = regular_buildings[regular_buildings.geometry.is_valid].copy()
@@ -997,27 +1009,27 @@ def _process_with_rasterio(filtered_gdf, grid_size, adjusted_meshsize, origin, u
997
1009
  if pd.notna(min_h)]
998
1010
 
999
1011
  if min_height_shapes:
1000
- min_heights = features.rasterize(
1012
+ min_heights_raster = features.rasterize(
1001
1013
  min_height_shapes,
1002
- out_shape=grid_size,
1014
+ out_shape=(grid_size[1], grid_size[0]),
1003
1015
  transform=transform,
1004
1016
  fill=0,
1005
1017
  dtype=np.float64
1006
1018
  )
1007
1019
 
1008
1020
  # Convert to list format (simplified)
1021
+ # Convert raster (ny, nx) to internal orientation (nx, ny) with north-up
1022
+ building_height_grid = np.flipud(height_raster).T
1023
+ building_id_grid = np.flipud(id_raster).T
1024
+ min_heights = np.flipud(min_heights_raster).T
1025
+
1009
1026
  for i in range(grid_size[0]):
1010
1027
  for j in range(grid_size[1]):
1011
1028
  if building_height_grid[i, j] > 0:
1012
1029
  building_min_height_grid[i, j] = [[min_heights[i, j], building_height_grid[i, j]]]
1013
1030
  else:
1014
1031
  building_min_height_grid[i, j] = []
1015
-
1016
- # Fix north-south orientation by flipping grids
1017
- building_height_grid = np.flipud(building_height_grid)
1018
- building_id_grid = np.flipud(building_id_grid)
1019
- building_min_height_grid = np.flipud(building_min_height_grid)
1020
-
1032
+
1021
1033
  return building_height_grid, building_min_height_grid, building_id_grid, filtered_gdf
1022
1034
 
1023
1035
  def create_building_height_grid_from_open_building_temporal_polygon(meshsize, rectangle_vertices, output_dir):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: voxcity
3
- Version: 0.6.6
3
+ Version: 0.6.7
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
  License: MIT
6
6
  Author: Kunihiko Fujiwara
@@ -16,7 +16,7 @@ voxcity/exporter/obj.py,sha256=h1_aInpemcsu96fSTwjKMqX2VZAFYbZbElWd4M1ogyI,27973
16
16
  voxcity/generator.py,sha256=J61i6-bvgOlNQWgxlkSvOZ7CLAjRgh_XRYwslWkKxVM,55756
17
17
  voxcity/geoprocessor/__init__.py,sha256=WYxcAQrjGucIvGHF0JTC6rONZzL3kCms1S2vpzS6KaU,127
18
18
  voxcity/geoprocessor/draw.py,sha256=avXQwbGQWG3ZPPI8mwy0YN0K_aG4NMBdXI0vDg7yad0,35837
19
- voxcity/geoprocessor/grid.py,sha256=wrlOsX8cD0W5xCnOS5IOHy8DNqDGTM1I2270eVs787c,70602
19
+ voxcity/geoprocessor/grid.py,sha256=D4sqoIGK2P1U8uuVQZ-447SD0Yrv6qS_zlmDtKoLDe8,71257
20
20
  voxcity/geoprocessor/mesh.py,sha256=A7uaCMWfm82KEoYPfQYpxv6xMtQKaU2PBVDfKTpngqg,32027
21
21
  voxcity/geoprocessor/network.py,sha256=YynqR0nq_NUra_cQ3Z_56KxfRia1b6-hIzGCj3QT-wE,25137
22
22
  voxcity/geoprocessor/polygon.py,sha256=DfzXf6R-qoWXEZv1z1aHCVfr-DCuCFw6lieQT5cNHPA,61188
@@ -30,8 +30,8 @@ voxcity/utils/lc.py,sha256=722Gz3lPbgAp0mmTZ-g-QKBbAnbxrcgaYwb1sa7q8Sk,16189
30
30
  voxcity/utils/material.py,sha256=H8K8Lq4wBL6dQtgj7esUW2U6wLCOTeOtelkTDJoRgMo,10007
31
31
  voxcity/utils/visualization.py,sha256=ZR9N-XKfydeSStO53IM2hGXyZJoeBiAyIMWw9Cb2MPM,116449
32
32
  voxcity/utils/weather.py,sha256=2Jtg-rIVJcsTtiKE-KuDnhIqS1-MSS16_zFRzj6zmu4,36435
33
- voxcity-0.6.6.dist-info/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
34
- voxcity-0.6.6.dist-info/LICENSE,sha256=s_jE1Df1nTPL4A_5GCGic5Zwex0CVaPKcAmSilxJPPE,1089
35
- voxcity-0.6.6.dist-info/METADATA,sha256=5LiF0gG85QUFhEMuBEbnnWp0X2icylygNS0QlEGEsPY,26091
36
- voxcity-0.6.6.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
37
- voxcity-0.6.6.dist-info/RECORD,,
33
+ voxcity-0.6.7.dist-info/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
34
+ voxcity-0.6.7.dist-info/LICENSE,sha256=s_jE1Df1nTPL4A_5GCGic5Zwex0CVaPKcAmSilxJPPE,1089
35
+ voxcity-0.6.7.dist-info/METADATA,sha256=lICJOYiGbMdF2Lee90GLEP-KBz3S71jHDaHucZrYs7g,26091
36
+ voxcity-0.6.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
37
+ voxcity-0.6.7.dist-info/RECORD,,