voxcity 0.5.24__py3-none-any.whl → 0.5.26__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/exporter/envimet.py +3 -3
- voxcity/geoprocessor/mesh.py +46 -2
- voxcity/utils/visualization.py +2 -1
- {voxcity-0.5.24.dist-info → voxcity-0.5.26.dist-info}/METADATA +2 -1
- {voxcity-0.5.24.dist-info → voxcity-0.5.26.dist-info}/RECORD +9 -9
- {voxcity-0.5.24.dist-info → voxcity-0.5.26.dist-info}/WHEEL +0 -0
- {voxcity-0.5.24.dist-info → voxcity-0.5.26.dist-info}/licenses/AUTHORS.rst +0 -0
- {voxcity-0.5.24.dist-info → voxcity-0.5.26.dist-info}/licenses/LICENSE +0 -0
- {voxcity-0.5.24.dist-info → voxcity-0.5.26.dist-info}/top_level.txt +0 -0
voxcity/exporter/envimet.py
CHANGED
|
@@ -147,8 +147,8 @@ def prepare_grids(building_height_grid_ori, building_id_grid_ori, canopy_height_
|
|
|
147
147
|
veg_translation_dict = {
|
|
148
148
|
1: '', # Bareland
|
|
149
149
|
2: '0200XX', # Rangeland
|
|
150
|
-
3: '', # Shrub
|
|
151
|
-
4: '', # Moss and lichen
|
|
150
|
+
3: '0200H1', # Shrub
|
|
151
|
+
4: '0200XX', # Moss and lichen
|
|
152
152
|
5: '0200XX', # Agriculture land
|
|
153
153
|
6: '', # Tree
|
|
154
154
|
7: '0200XX', # Wet land
|
|
@@ -171,7 +171,7 @@ def prepare_grids(building_height_grid_ori, building_id_grid_ori, canopy_height_
|
|
|
171
171
|
11: '0200PG', # Developed space
|
|
172
172
|
12: '0200ST', # Road
|
|
173
173
|
13: '000000', # Building
|
|
174
|
-
14: '
|
|
174
|
+
14: '000000', # No Data
|
|
175
175
|
}
|
|
176
176
|
land_cover_mat_grid = translate_array(land_cover_grid, mat_translation_dict)
|
|
177
177
|
|
voxcity/geoprocessor/mesh.py
CHANGED
|
@@ -590,7 +590,7 @@ def split_vertices_manual(mesh):
|
|
|
590
590
|
out_mesh = trimesh.util.concatenate(new_meshes)
|
|
591
591
|
return out_mesh
|
|
592
592
|
|
|
593
|
-
def save_obj_from_colored_mesh(meshes, output_path, base_filename):
|
|
593
|
+
def save_obj_from_colored_mesh(meshes, output_path, base_filename, max_materials=None):
|
|
594
594
|
"""
|
|
595
595
|
Save a collection of colored meshes as OBJ and MTL files with material support.
|
|
596
596
|
|
|
@@ -620,6 +620,12 @@ def save_obj_from_colored_mesh(meshes, output_path, base_filename):
|
|
|
620
620
|
- {base_filename}.obj : The main geometry file
|
|
621
621
|
- {base_filename}.mtl : The material definitions file
|
|
622
622
|
|
|
623
|
+
max_materials : int, optional
|
|
624
|
+
Maximum number of materials/colors to create. If specified and the number
|
|
625
|
+
of unique colors exceeds this limit, colors will be quantized using
|
|
626
|
+
k-means clustering to reduce them to the specified number.
|
|
627
|
+
If None (default), all unique colors are preserved as separate materials.
|
|
628
|
+
|
|
623
629
|
Returns
|
|
624
630
|
-------
|
|
625
631
|
tuple
|
|
@@ -644,6 +650,11 @@ def save_obj_from_colored_mesh(meshes, output_path, base_filename):
|
|
|
644
650
|
... meshes, 'output/models', 'city'
|
|
645
651
|
... )
|
|
646
652
|
|
|
653
|
+
Limiting materials to 5:
|
|
654
|
+
>>> obj_path, mtl_path = save_obj_from_colored_mesh(
|
|
655
|
+
... meshes, 'output/models', 'city', max_materials=5
|
|
656
|
+
... )
|
|
657
|
+
|
|
647
658
|
Notes
|
|
648
659
|
-----
|
|
649
660
|
- Creates unique materials for each distinct face color
|
|
@@ -653,6 +664,9 @@ def save_obj_from_colored_mesh(meshes, output_path, base_filename):
|
|
|
653
664
|
- Vertices are written in OBJ's 1-based indexing format
|
|
654
665
|
- Faces are grouped by material for efficient rendering
|
|
655
666
|
- The MTL file is automatically referenced in the OBJ file
|
|
667
|
+
- If max_materials is specified, k-means clustering is used for color quantization
|
|
668
|
+
- Color quantization preserves the overall color distribution while reducing material count
|
|
669
|
+
- Requires scikit-learn package when max_materials is specified (install with: pip install scikit-learn)
|
|
656
670
|
|
|
657
671
|
File Format Details
|
|
658
672
|
-----------------
|
|
@@ -674,8 +688,38 @@ def save_obj_from_colored_mesh(meshes, output_path, base_filename):
|
|
|
674
688
|
combined_mesh = trimesh.util.concatenate(list(meshes.values()))
|
|
675
689
|
combined_mesh = split_vertices_manual(combined_mesh)
|
|
676
690
|
|
|
677
|
-
#
|
|
691
|
+
# Get face colors
|
|
678
692
|
face_colors = combined_mesh.visual.face_colors
|
|
693
|
+
|
|
694
|
+
# Apply color quantization if max_materials is specified
|
|
695
|
+
if max_materials is not None:
|
|
696
|
+
try:
|
|
697
|
+
from sklearn.cluster import KMeans
|
|
698
|
+
except ImportError:
|
|
699
|
+
raise ImportError("scikit-learn is required for color quantization. "
|
|
700
|
+
"Install it with: pip install scikit-learn")
|
|
701
|
+
|
|
702
|
+
# Prepare colors for clustering (use only RGB, not alpha)
|
|
703
|
+
colors_rgb = face_colors[:, :3].astype(float)
|
|
704
|
+
|
|
705
|
+
# Perform k-means clustering
|
|
706
|
+
kmeans = KMeans(n_clusters=max_materials, random_state=42, n_init=10)
|
|
707
|
+
color_labels = kmeans.fit_predict(colors_rgb)
|
|
708
|
+
|
|
709
|
+
# Get the cluster centers as the new colors
|
|
710
|
+
quantized_colors_rgb = kmeans.cluster_centers_.astype(np.uint8)
|
|
711
|
+
|
|
712
|
+
# Create new face colors with quantized RGB and original alpha
|
|
713
|
+
quantized_face_colors = np.zeros_like(face_colors)
|
|
714
|
+
# Assign each face to its nearest cluster center
|
|
715
|
+
quantized_face_colors[:, :3] = quantized_colors_rgb[color_labels]
|
|
716
|
+
quantized_face_colors[:, 3] = face_colors[:, 3] # Preserve original alpha
|
|
717
|
+
|
|
718
|
+
# Update the mesh with quantized colors
|
|
719
|
+
combined_mesh.visual.face_colors = quantized_face_colors
|
|
720
|
+
face_colors = quantized_face_colors
|
|
721
|
+
|
|
722
|
+
# Create unique materials for each unique face color
|
|
679
723
|
unique_colors = np.unique(face_colors, axis=0)
|
|
680
724
|
|
|
681
725
|
# Write MTL file
|
voxcity/utils/visualization.py
CHANGED
|
@@ -2504,7 +2504,8 @@ def visualize_voxcity_with_sim_meshes(voxel_array, meshsize, custom_meshes=None,
|
|
|
2504
2504
|
if save_obj:
|
|
2505
2505
|
output_directory = kwargs.get('output_directory', 'output')
|
|
2506
2506
|
output_file_name = kwargs.get('output_file_name', 'voxcity_mesh')
|
|
2507
|
-
|
|
2507
|
+
max_materials = kwargs.get('max_materials', 20)
|
|
2508
|
+
obj_path, mtl_path = save_obj_from_colored_mesh(meshes, output_directory, output_file_name, max_materials=max_materials)
|
|
2508
2509
|
print(f"Saved mesh files to:\n {obj_path}\n {mtl_path}")
|
|
2509
2510
|
|
|
2510
2511
|
if show_views:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voxcity
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.26
|
|
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>
|
|
@@ -52,6 +52,7 @@ Requires-Dist: trimesh
|
|
|
52
52
|
Requires-Dist: pyvista
|
|
53
53
|
Requires-Dist: IPython
|
|
54
54
|
Requires-Dist: lxml
|
|
55
|
+
Requires-Dist: scikit-learn
|
|
55
56
|
Provides-Extra: dev
|
|
56
57
|
Requires-Dist: coverage; extra == "dev"
|
|
57
58
|
Requires-Dist: mypy; extra == "dev"
|
|
@@ -10,13 +10,13 @@ voxcity/downloader/osm.py,sha256=kXiUedT7dwPOQ_4nxXptfeqNb5RKTIsQLG5km7Q8kKk,416
|
|
|
10
10
|
voxcity/downloader/overture.py,sha256=4YG2DMwUSSyZKUw_o8cGhMmAkPJon82aPqOFBvrre-Y,11987
|
|
11
11
|
voxcity/downloader/utils.py,sha256=tz6wt4B9BhEOyvoF5OYXlr8rUd5cBEDedWL3j__oT70,3099
|
|
12
12
|
voxcity/exporter/__init__.py,sha256=2htEXMrq6knO8JMROtfz-0HFGddsAJkXqNUB2_MhqvM,70
|
|
13
|
-
voxcity/exporter/envimet.py,sha256=
|
|
13
|
+
voxcity/exporter/envimet.py,sha256=Sh7s1JdQ6SgT_L2Xd_c4gtEGWK2hTS87bccaoIqik-s,31105
|
|
14
14
|
voxcity/exporter/magicavoxel.py,sha256=SfGEgTZRlossKx3Xrv9d3iKSX-HmfQJEL9lZHgWMDX4,12782
|
|
15
15
|
voxcity/exporter/obj.py,sha256=h1_aInpemcsu96fSTwjKMqX2VZAFYbZbElWd4M1ogyI,27973
|
|
16
16
|
voxcity/geoprocessor/__init__.py,sha256=JzPVhhttxBWvaZ0IGX2w7OWL5bCo_TIvpHefWeNXruA,133
|
|
17
17
|
voxcity/geoprocessor/draw.py,sha256=lcBtf4VAWXjk46cInPdSBeiLCTESdxzLOayr_0YOnus,22184
|
|
18
18
|
voxcity/geoprocessor/grid.py,sha256=Uy8Oz4iL7vnPMqp_qtp4dQrs00yd2L9CSIPmF5KnbtI,63961
|
|
19
|
-
voxcity/geoprocessor/mesh.py,sha256=
|
|
19
|
+
voxcity/geoprocessor/mesh.py,sha256=ElqAE2MA8KZs7yD7B1P88XYmryC6F9nkkP6cXv7FzIk,30777
|
|
20
20
|
voxcity/geoprocessor/network.py,sha256=YynqR0nq_NUra_cQ3Z_56KxfRia1b6-hIzGCj3QT-wE,25137
|
|
21
21
|
voxcity/geoprocessor/polygon.py,sha256=-LonxtW5du3UP61oygqtDJl6GGsCYnUuN9KYwl1UFdc,53707
|
|
22
22
|
voxcity/geoprocessor/utils.py,sha256=DVg3EMRytLQLEQeXLvNgjt1Ynoa689EsD-To-14xgSQ,30369
|
|
@@ -27,11 +27,11 @@ voxcity/simulator/view.py,sha256=F2c-XFdRN811_RJvsznRjbUu5Uv7C6iniezsUMD-Olw,594
|
|
|
27
27
|
voxcity/utils/__init__.py,sha256=Q-NYCqYnAAaF80KuNwpqIjbE7Ec3Gr4y_khMLIMhJrg,68
|
|
28
28
|
voxcity/utils/lc.py,sha256=h2yOWLUIrrummkyMyhRK5VbyrsPtslS0MJov_y0WGIQ,18925
|
|
29
29
|
voxcity/utils/material.py,sha256=H8K8Lq4wBL6dQtgj7esUW2U6wLCOTeOtelkTDJoRgMo,10007
|
|
30
|
-
voxcity/utils/visualization.py,sha256=
|
|
30
|
+
voxcity/utils/visualization.py,sha256=T-jKrCA4UMm93p-1O678RWM7e99iE0_Lj4wD07efcwI,112918
|
|
31
31
|
voxcity/utils/weather.py,sha256=2Jtg-rIVJcsTtiKE-KuDnhIqS1-MSS16_zFRzj6zmu4,36435
|
|
32
|
-
voxcity-0.5.
|
|
33
|
-
voxcity-0.5.
|
|
34
|
-
voxcity-0.5.
|
|
35
|
-
voxcity-0.5.
|
|
36
|
-
voxcity-0.5.
|
|
37
|
-
voxcity-0.5.
|
|
32
|
+
voxcity-0.5.26.dist-info/licenses/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
|
|
33
|
+
voxcity-0.5.26.dist-info/licenses/LICENSE,sha256=s_jE1Df1nTPL4A_5GCGic5Zwex0CVaPKcAmSilxJPPE,1089
|
|
34
|
+
voxcity-0.5.26.dist-info/METADATA,sha256=EdbTSCTEB_oW67EK3cHHmBB5V7LrlDECoEsB5ATGgVI,26724
|
|
35
|
+
voxcity-0.5.26.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
36
|
+
voxcity-0.5.26.dist-info/top_level.txt,sha256=00b2U-LKfDllt6RL1R33MXie5MvxzUFye0NGD96t_8I,8
|
|
37
|
+
voxcity-0.5.26.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|