voxcity 0.5.24__tar.gz → 0.5.25__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.5.24 → voxcity-0.5.25}/PKG-INFO +2 -1
  2. {voxcity-0.5.24 → voxcity-0.5.25}/pyproject.toml +3 -2
  3. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/geoprocessor/mesh.py +46 -2
  4. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/utils/visualization.py +2 -1
  5. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity.egg-info/PKG-INFO +2 -1
  6. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity.egg-info/requires.txt +1 -0
  7. {voxcity-0.5.24 → voxcity-0.5.25}/AUTHORS.rst +0 -0
  8. {voxcity-0.5.24 → voxcity-0.5.25}/CONTRIBUTING.rst +0 -0
  9. {voxcity-0.5.24 → voxcity-0.5.25}/HISTORY.rst +0 -0
  10. {voxcity-0.5.24 → voxcity-0.5.25}/LICENSE +0 -0
  11. {voxcity-0.5.24 → voxcity-0.5.25}/MANIFEST.in +0 -0
  12. {voxcity-0.5.24 → voxcity-0.5.25}/README.md +0 -0
  13. {voxcity-0.5.24 → voxcity-0.5.25}/docs/Makefile +0 -0
  14. {voxcity-0.5.24 → voxcity-0.5.25}/docs/_static/logo.png +0 -0
  15. {voxcity-0.5.24 → voxcity-0.5.25}/docs/conf.py +0 -0
  16. {voxcity-0.5.24 → voxcity-0.5.25}/docs/logo.png +0 -0
  17. {voxcity-0.5.24 → voxcity-0.5.25}/docs/make.bat +0 -0
  18. {voxcity-0.5.24 → voxcity-0.5.25}/setup.cfg +0 -0
  19. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/__init__.py +0 -0
  20. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/downloader/__init__.py +0 -0
  21. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/downloader/citygml.py +0 -0
  22. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/downloader/eubucco.py +0 -0
  23. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/downloader/gee.py +0 -0
  24. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/downloader/mbfp.py +0 -0
  25. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/downloader/oemj.py +0 -0
  26. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/downloader/osm.py +0 -0
  27. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/downloader/overture.py +0 -0
  28. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/downloader/utils.py +0 -0
  29. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/exporter/__init__.py +0 -0
  30. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/exporter/envimet.py +0 -0
  31. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/exporter/magicavoxel.py +0 -0
  32. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/exporter/obj.py +0 -0
  33. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/generator.py +0 -0
  34. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/geoprocessor/__init__.py +0 -0
  35. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/geoprocessor/draw.py +0 -0
  36. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/geoprocessor/grid.py +0 -0
  37. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/geoprocessor/network.py +0 -0
  38. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/geoprocessor/polygon.py +0 -0
  39. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/geoprocessor/utils.py +0 -0
  40. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/simulator/__init__.py +0 -0
  41. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/simulator/solar.py +0 -0
  42. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/simulator/utils.py +0 -0
  43. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/simulator/view.py +0 -0
  44. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/utils/__init__.py +0 -0
  45. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/utils/lc.py +0 -0
  46. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/utils/material.py +0 -0
  47. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity/utils/weather.py +0 -0
  48. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity.egg-info/SOURCES.txt +0 -0
  49. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity.egg-info/dependency_links.txt +0 -0
  50. {voxcity-0.5.24 → voxcity-0.5.25}/src/voxcity.egg-info/top_level.txt +0 -0
  51. {voxcity-0.5.24 → voxcity-0.5.25}/tests/__init__.py +0 -0
  52. {voxcity-0.5.24 → voxcity-0.5.25}/tests/voxelcity.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: voxcity
3
- Version: 0.5.24
3
+ Version: 0.5.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>
@@ -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"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "voxcity"
3
- version = "0.5.24"
3
+ version = "0.5.25"
4
4
  requires-python = ">=3.10,<3.13"
5
5
  classifiers = [
6
6
  "Programming Language :: Python :: 3.10",
@@ -53,7 +53,8 @@ dependencies = [
53
53
  "trimesh",
54
54
  "pyvista",
55
55
  "IPython",
56
- "lxml"
56
+ "lxml",
57
+ "scikit-learn"
57
58
  ]
58
59
 
59
60
  [project.optional-dependencies]
@@ -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
- # Create unique materials for each unique face color
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
@@ -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
- obj_path, mtl_path = save_obj_from_colored_mesh(meshes, output_directory, output_file_name)
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.24
3
+ Version: 0.5.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>
@@ -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"
@@ -35,6 +35,7 @@ trimesh
35
35
  pyvista
36
36
  IPython
37
37
  lxml
38
+ scikit-learn
38
39
 
39
40
  [dev]
40
41
  coverage
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