voxcity 0.3.23__py3-none-any.whl → 0.3.25__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/utils/visualization.py +133 -4
- {voxcity-0.3.23.dist-info → voxcity-0.3.25.dist-info}/METADATA +1 -1
- {voxcity-0.3.23.dist-info → voxcity-0.3.25.dist-info}/RECORD +7 -7
- {voxcity-0.3.23.dist-info → voxcity-0.3.25.dist-info}/AUTHORS.rst +0 -0
- {voxcity-0.3.23.dist-info → voxcity-0.3.25.dist-info}/LICENSE +0 -0
- {voxcity-0.3.23.dist-info → voxcity-0.3.25.dist-info}/WHEEL +0 -0
- {voxcity-0.3.23.dist-info → voxcity-0.3.25.dist-info}/top_level.txt +0 -0
voxcity/utils/visualization.py
CHANGED
|
@@ -923,9 +923,14 @@ def visualize_point_grid_on_basemap(point_gdf, value_name='value', **kwargs):
|
|
|
923
923
|
plt.tight_layout()
|
|
924
924
|
plt.show()
|
|
925
925
|
|
|
926
|
-
def create_multi_view_scene(meshes, output_directory="output"):
|
|
926
|
+
def create_multi_view_scene(meshes, output_directory="output", projection_type="perspective", distance_factor=1.0):
|
|
927
927
|
"""
|
|
928
928
|
Create multiple views of the scene from different angles.
|
|
929
|
+
|
|
930
|
+
Args:
|
|
931
|
+
meshes: Dictionary of meshes to visualize
|
|
932
|
+
output_directory: Directory to save output images
|
|
933
|
+
projection_type: Either "perspective" or "orthographic" (default: "perspective")
|
|
929
934
|
"""
|
|
930
935
|
# Compute overall bounding box across all meshes
|
|
931
936
|
vertices_list = [mesh.vertices for mesh in meshes.values()]
|
|
@@ -939,8 +944,11 @@ def create_multi_view_scene(meshes, output_directory="output"):
|
|
|
939
944
|
center = (bbox[1] + bbox[0]) / 2
|
|
940
945
|
diagonal = np.linalg.norm(bbox[1] - bbox[0])
|
|
941
946
|
|
|
942
|
-
#
|
|
943
|
-
|
|
947
|
+
# Adjust distance based on projection type
|
|
948
|
+
if projection_type.lower() == "orthographic":
|
|
949
|
+
distance = diagonal * 5 # Increase distance for orthographic to capture full scene
|
|
950
|
+
else:
|
|
951
|
+
distance = diagonal * 1.8 * distance_factor # Original distance for perspective
|
|
944
952
|
|
|
945
953
|
# Define the isometric viewing angles
|
|
946
954
|
iso_angles = {
|
|
@@ -972,6 +980,15 @@ def create_multi_view_scene(meshes, output_directory="output"):
|
|
|
972
980
|
for view_name, camera_pos in camera_positions.items():
|
|
973
981
|
# Create new plotter for each view
|
|
974
982
|
plotter = pv.Plotter(notebook=True, off_screen=True)
|
|
983
|
+
|
|
984
|
+
# Set the projection type
|
|
985
|
+
if projection_type.lower() == "orthographic":
|
|
986
|
+
plotter.enable_parallel_projection()
|
|
987
|
+
# Set parallel scale to ensure the whole scene is visible
|
|
988
|
+
plotter.camera.parallel_scale = diagonal * 0.4 * distance_factor # Adjust this factor as needed
|
|
989
|
+
|
|
990
|
+
elif projection_type.lower() != "perspective":
|
|
991
|
+
print(f"Warning: Unknown projection_type '{projection_type}'. Using perspective projection.")
|
|
975
992
|
|
|
976
993
|
# Add each mesh to the scene
|
|
977
994
|
for class_id, mesh in meshes.items():
|
|
@@ -1038,6 +1055,8 @@ def visualize_voxcity_multi_view(voxel_array, meshsize, **kwargs):
|
|
|
1038
1055
|
cmap_name = kwargs.get("colormap", "viridis")
|
|
1039
1056
|
vmin = kwargs.get("vmin", np.nanmin(sim_grid))
|
|
1040
1057
|
vmax = kwargs.get("vmax", np.nanmax(sim_grid))
|
|
1058
|
+
projection_type = kwargs.get("projection_type", "perspective")
|
|
1059
|
+
distance_factor = kwargs.get("distance_factor", 1.0)
|
|
1041
1060
|
|
|
1042
1061
|
# Create meshes
|
|
1043
1062
|
print("Creating voxel meshes...")
|
|
@@ -1078,7 +1097,115 @@ def visualize_voxcity_multi_view(voxel_array, meshsize, **kwargs):
|
|
|
1078
1097
|
print("Creating multiple views...")
|
|
1079
1098
|
# Create output directory if it doesn't exist
|
|
1080
1099
|
os.makedirs(output_directory, exist_ok=True)
|
|
1081
|
-
image_files = create_multi_view_scene(meshes, output_directory=output_directory)
|
|
1100
|
+
image_files = create_multi_view_scene(meshes, output_directory=output_directory, projection_type=projection_type, distance_factor=distance_factor)
|
|
1101
|
+
|
|
1102
|
+
# Display each view separately
|
|
1103
|
+
for view_name, img_file in image_files:
|
|
1104
|
+
plt.figure(figsize=(12, 8))
|
|
1105
|
+
img = plt.imread(img_file)
|
|
1106
|
+
plt.imshow(img)
|
|
1107
|
+
plt.title(view_name.replace('_', ' ').title(), pad=20)
|
|
1108
|
+
plt.axis('off')
|
|
1109
|
+
plt.show()
|
|
1110
|
+
plt.close()
|
|
1111
|
+
|
|
1112
|
+
def visualize_voxcity_multi_view_with_multiple_sim_grids(voxel_array, meshsize, sim_configs, **kwargs):
|
|
1113
|
+
"""
|
|
1114
|
+
Create multiple views of the voxel city data with multiple simulation grids.
|
|
1115
|
+
|
|
1116
|
+
Args:
|
|
1117
|
+
voxel_array: 3D numpy array containing voxel data
|
|
1118
|
+
meshsize: Size of each voxel/cell
|
|
1119
|
+
sim_configs: List of dictionaries, each containing configuration for a simulation grid:
|
|
1120
|
+
{
|
|
1121
|
+
'sim_grid': 2D numpy array of simulation values,
|
|
1122
|
+
'z_offset': height offset in meters (default: 1.5),
|
|
1123
|
+
'cmap_name': colormap name (default: 'viridis'),
|
|
1124
|
+
'vmin': minimum value for colormap (optional),
|
|
1125
|
+
'vmax': maximum value for colormap (optional),
|
|
1126
|
+
'label': label for the colorbar (optional)
|
|
1127
|
+
}
|
|
1128
|
+
**kwargs: Additional arguments including:
|
|
1129
|
+
- vox_dict: Dictionary mapping voxel values to colors
|
|
1130
|
+
- output_directory: Directory to save output images
|
|
1131
|
+
- output_file_name: Base filename for exports
|
|
1132
|
+
- dem_grid: DEM grid for height information
|
|
1133
|
+
- projection_type: 'perspective' or 'orthographic'
|
|
1134
|
+
- distance_factor: Factor to adjust camera distance
|
|
1135
|
+
"""
|
|
1136
|
+
os.system('Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &')
|
|
1137
|
+
os.environ['DISPLAY'] = ':99'
|
|
1138
|
+
|
|
1139
|
+
# Configure PyVista settings
|
|
1140
|
+
pv.set_plot_theme('document')
|
|
1141
|
+
pv.global_theme.background = 'white'
|
|
1142
|
+
pv.global_theme.window_size = [1024, 768]
|
|
1143
|
+
pv.global_theme.jupyter_backend = 'static'
|
|
1144
|
+
|
|
1145
|
+
# Parse general kwargs
|
|
1146
|
+
vox_dict = kwargs.get("vox_dict", get_default_voxel_color_map())
|
|
1147
|
+
output_directory = kwargs.get("output_directory", 'output')
|
|
1148
|
+
base_filename = kwargs.get("output_file_name", None)
|
|
1149
|
+
dem_grid_ori = kwargs.get("dem_grid", None)
|
|
1150
|
+
projection_type = kwargs.get("projection_type", "perspective")
|
|
1151
|
+
distance_factor = kwargs.get("distance_factor", 1.0)
|
|
1152
|
+
|
|
1153
|
+
if dem_grid_ori is not None:
|
|
1154
|
+
dem_grid = dem_grid_ori - np.min(dem_grid_ori)
|
|
1155
|
+
|
|
1156
|
+
# Create meshes
|
|
1157
|
+
print("Creating voxel meshes...")
|
|
1158
|
+
meshes = create_city_meshes(voxel_array, vox_dict, meshsize=meshsize)
|
|
1159
|
+
|
|
1160
|
+
# Process each simulation grid
|
|
1161
|
+
for i, config in enumerate(sim_configs):
|
|
1162
|
+
sim_grid = config['sim_grid']
|
|
1163
|
+
if sim_grid is None or dem_grid is None:
|
|
1164
|
+
continue
|
|
1165
|
+
|
|
1166
|
+
z_offset = config.get('z_offset', 1.5)
|
|
1167
|
+
cmap_name = config.get('cmap_name', 'viridis')
|
|
1168
|
+
vmin = config.get('vmin', np.nanmin(sim_grid))
|
|
1169
|
+
vmax = config.get('vmax', np.nanmax(sim_grid))
|
|
1170
|
+
label = config.get('label', f'Simulation {i+1}')
|
|
1171
|
+
|
|
1172
|
+
print(f"Creating sim_grid surface mesh for {label}...")
|
|
1173
|
+
sim_mesh = create_sim_surface_mesh(
|
|
1174
|
+
sim_grid, dem_grid,
|
|
1175
|
+
meshsize=meshsize,
|
|
1176
|
+
z_offset=z_offset,
|
|
1177
|
+
cmap_name=cmap_name,
|
|
1178
|
+
vmin=vmin,
|
|
1179
|
+
vmax=vmax
|
|
1180
|
+
)
|
|
1181
|
+
|
|
1182
|
+
if sim_mesh is not None:
|
|
1183
|
+
meshes[f"sim_surface_{i}"] = sim_mesh
|
|
1184
|
+
|
|
1185
|
+
# Create colorbar for this simulation
|
|
1186
|
+
norm = mcolors.Normalize(vmin=vmin, vmax=vmax)
|
|
1187
|
+
scalar_map = cm.ScalarMappable(norm=norm, cmap=cmap_name)
|
|
1188
|
+
|
|
1189
|
+
fig, ax = plt.subplots(figsize=(6, 1))
|
|
1190
|
+
plt.colorbar(scalar_map, cax=ax, orientation='horizontal', label=label)
|
|
1191
|
+
plt.tight_layout()
|
|
1192
|
+
plt.show()
|
|
1193
|
+
|
|
1194
|
+
# Export if filename provided
|
|
1195
|
+
if base_filename is not None:
|
|
1196
|
+
print(f"Exporting files to '{base_filename}.*' ...")
|
|
1197
|
+
os.makedirs(output_directory, exist_ok=True)
|
|
1198
|
+
export_meshes(meshes, output_directory, base_filename)
|
|
1199
|
+
|
|
1200
|
+
# Create and save multiple views
|
|
1201
|
+
print("Creating multiple views...")
|
|
1202
|
+
os.makedirs(output_directory, exist_ok=True)
|
|
1203
|
+
image_files = create_multi_view_scene(
|
|
1204
|
+
meshes,
|
|
1205
|
+
output_directory=output_directory,
|
|
1206
|
+
projection_type=projection_type,
|
|
1207
|
+
distance_factor=distance_factor
|
|
1208
|
+
)
|
|
1082
1209
|
|
|
1083
1210
|
# Display each view separately
|
|
1084
1211
|
for view_name, img_file in image_files:
|
|
@@ -1090,6 +1217,8 @@ def visualize_voxcity_multi_view(voxel_array, meshsize, **kwargs):
|
|
|
1090
1217
|
plt.show()
|
|
1091
1218
|
plt.close()
|
|
1092
1219
|
|
|
1220
|
+
return meshes
|
|
1221
|
+
|
|
1093
1222
|
# def create_interactive_scene(meshes):
|
|
1094
1223
|
# scene = trimesh.Scene()
|
|
1095
1224
|
# scene.ambient_light = np.array([0.1, 0.1, 0.1, 1.0])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: voxcity
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.25
|
|
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>
|
|
@@ -27,11 +27,11 @@ voxcity/simulator/view.py,sha256=zNbfTLQ2Jo0V5-rFA3-xamRjOuw3H3MBrLKpQp8x3hY,367
|
|
|
27
27
|
voxcity/utils/__init_.py,sha256=nLYrj2huBbDBNMqfchCwexGP8Tlt9O_XluVDG7MoFkw,98
|
|
28
28
|
voxcity/utils/lc.py,sha256=RwPd-VY3POV3gTrBhM7TubgGb9MCd3nVah_G8iUEF7k,11562
|
|
29
29
|
voxcity/utils/material.py,sha256=Vt3IID5Ft54HNJcEC4zi31BCPqi_687X3CSp7rXaRVY,5907
|
|
30
|
-
voxcity/utils/visualization.py,sha256=
|
|
30
|
+
voxcity/utils/visualization.py,sha256=ufS6aMIaDUmFNTiqQS5If7SgHxMm6unKIIOkFdnSkOQ,54253
|
|
31
31
|
voxcity/utils/weather.py,sha256=P6s1y_EstBL1OGP_MR_6u3vr-t6Uawg8uDckJnoI7FI,21482
|
|
32
|
-
voxcity-0.3.
|
|
33
|
-
voxcity-0.3.
|
|
34
|
-
voxcity-0.3.
|
|
35
|
-
voxcity-0.3.
|
|
36
|
-
voxcity-0.3.
|
|
37
|
-
voxcity-0.3.
|
|
32
|
+
voxcity-0.3.25.dist-info/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
|
|
33
|
+
voxcity-0.3.25.dist-info/LICENSE,sha256=-hGliOFiwUrUSoZiB5WF90xXGqinKyqiDI2t6hrnam8,1087
|
|
34
|
+
voxcity-0.3.25.dist-info/METADATA,sha256=-ACnXtIlIX4rZdBuReFW4yBujdzDcSrmTtyTEs1HdO0,25186
|
|
35
|
+
voxcity-0.3.25.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
36
|
+
voxcity-0.3.25.dist-info/top_level.txt,sha256=00b2U-LKfDllt6RL1R33MXie5MvxzUFye0NGD96t_8I,8
|
|
37
|
+
voxcity-0.3.25.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|