voxcity 0.7.0__py3-none-any.whl → 1.0.13__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.
Files changed (81) hide show
  1. voxcity/__init__.py +14 -14
  2. voxcity/downloader/ocean.py +559 -0
  3. voxcity/exporter/__init__.py +12 -12
  4. voxcity/exporter/cityles.py +633 -633
  5. voxcity/exporter/envimet.py +733 -728
  6. voxcity/exporter/magicavoxel.py +333 -333
  7. voxcity/exporter/netcdf.py +238 -238
  8. voxcity/exporter/obj.py +1480 -1480
  9. voxcity/generator/__init__.py +47 -44
  10. voxcity/generator/api.py +727 -675
  11. voxcity/generator/grids.py +394 -379
  12. voxcity/generator/io.py +94 -94
  13. voxcity/generator/pipeline.py +582 -282
  14. voxcity/generator/update.py +429 -0
  15. voxcity/generator/voxelizer.py +18 -6
  16. voxcity/geoprocessor/__init__.py +75 -75
  17. voxcity/geoprocessor/draw.py +1494 -1219
  18. voxcity/geoprocessor/merge_utils.py +91 -91
  19. voxcity/geoprocessor/mesh.py +806 -806
  20. voxcity/geoprocessor/network.py +708 -708
  21. voxcity/geoprocessor/raster/__init__.py +2 -0
  22. voxcity/geoprocessor/raster/buildings.py +435 -428
  23. voxcity/geoprocessor/raster/core.py +31 -0
  24. voxcity/geoprocessor/raster/export.py +93 -93
  25. voxcity/geoprocessor/raster/landcover.py +178 -51
  26. voxcity/geoprocessor/raster/raster.py +1 -1
  27. voxcity/geoprocessor/utils.py +824 -824
  28. voxcity/models.py +115 -113
  29. voxcity/simulator/solar/__init__.py +66 -43
  30. voxcity/simulator/solar/integration.py +336 -336
  31. voxcity/simulator/solar/sky.py +668 -0
  32. voxcity/simulator/solar/temporal.py +792 -434
  33. voxcity/simulator_gpu/__init__.py +115 -0
  34. voxcity/simulator_gpu/common/__init__.py +9 -0
  35. voxcity/simulator_gpu/common/geometry.py +11 -0
  36. voxcity/simulator_gpu/core.py +322 -0
  37. voxcity/simulator_gpu/domain.py +262 -0
  38. voxcity/simulator_gpu/environment.yml +11 -0
  39. voxcity/simulator_gpu/init_taichi.py +154 -0
  40. voxcity/simulator_gpu/integration.py +15 -0
  41. voxcity/simulator_gpu/kernels.py +56 -0
  42. voxcity/simulator_gpu/radiation.py +28 -0
  43. voxcity/simulator_gpu/raytracing.py +623 -0
  44. voxcity/simulator_gpu/sky.py +9 -0
  45. voxcity/simulator_gpu/solar/__init__.py +178 -0
  46. voxcity/simulator_gpu/solar/core.py +66 -0
  47. voxcity/simulator_gpu/solar/csf.py +1249 -0
  48. voxcity/simulator_gpu/solar/domain.py +561 -0
  49. voxcity/simulator_gpu/solar/epw.py +421 -0
  50. voxcity/simulator_gpu/solar/integration.py +2953 -0
  51. voxcity/simulator_gpu/solar/radiation.py +3019 -0
  52. voxcity/simulator_gpu/solar/raytracing.py +686 -0
  53. voxcity/simulator_gpu/solar/reflection.py +533 -0
  54. voxcity/simulator_gpu/solar/sky.py +907 -0
  55. voxcity/simulator_gpu/solar/solar.py +337 -0
  56. voxcity/simulator_gpu/solar/svf.py +446 -0
  57. voxcity/simulator_gpu/solar/volumetric.py +1151 -0
  58. voxcity/simulator_gpu/solar/voxcity.py +2953 -0
  59. voxcity/simulator_gpu/temporal.py +13 -0
  60. voxcity/simulator_gpu/utils.py +25 -0
  61. voxcity/simulator_gpu/view.py +32 -0
  62. voxcity/simulator_gpu/visibility/__init__.py +109 -0
  63. voxcity/simulator_gpu/visibility/geometry.py +278 -0
  64. voxcity/simulator_gpu/visibility/integration.py +808 -0
  65. voxcity/simulator_gpu/visibility/landmark.py +753 -0
  66. voxcity/simulator_gpu/visibility/view.py +944 -0
  67. voxcity/utils/__init__.py +11 -0
  68. voxcity/utils/classes.py +194 -0
  69. voxcity/utils/lc.py +80 -39
  70. voxcity/utils/shape.py +230 -0
  71. voxcity/visualizer/__init__.py +24 -24
  72. voxcity/visualizer/builder.py +43 -43
  73. voxcity/visualizer/grids.py +141 -141
  74. voxcity/visualizer/maps.py +187 -187
  75. voxcity/visualizer/renderer.py +1146 -928
  76. {voxcity-0.7.0.dist-info → voxcity-1.0.13.dist-info}/METADATA +56 -52
  77. voxcity-1.0.13.dist-info/RECORD +116 -0
  78. voxcity-0.7.0.dist-info/RECORD +0 -77
  79. {voxcity-0.7.0.dist-info → voxcity-1.0.13.dist-info}/WHEEL +0 -0
  80. {voxcity-0.7.0.dist-info → voxcity-1.0.13.dist-info}/licenses/AUTHORS.rst +0 -0
  81. {voxcity-0.7.0.dist-info → voxcity-1.0.13.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,13 @@
1
+ """VoxCity-style `temporal` module (toplevel) for compatibility."""
2
+
3
+ from .solar.integration import (
4
+ get_solar_positions_astral,
5
+ get_cumulative_global_solar_irradiance,
6
+ get_cumulative_building_solar_irradiance,
7
+ )
8
+
9
+ __all__ = [
10
+ "get_solar_positions_astral",
11
+ "get_cumulative_global_solar_irradiance",
12
+ "get_cumulative_building_solar_irradiance",
13
+ ]
@@ -0,0 +1,25 @@
1
+ """Small compatibility module matching `voxcity.simulator.utils`.
2
+
3
+ VoxCity's `voxcity.simulator` flattens `utils` into the toplevel namespace.
4
+ Some user code may rely on these names existing after:
5
+
6
+ import simulator_gpu as simulator
7
+
8
+ This module keeps that behavior without pulling in VoxCity.
9
+ """
10
+
11
+ from datetime import datetime
12
+
13
+ import numpy as np
14
+
15
+ try:
16
+ import pandas as pd # type: ignore
17
+ except Exception: # pragma: no cover
18
+ pd = None # type: ignore
19
+
20
+
21
+ def dummy_function(test_string):
22
+ return test_string
23
+
24
+
25
+ __all__ = ["np", "pd", "datetime", "dummy_function"]
@@ -0,0 +1,32 @@
1
+ """Compatibility wrapper for the legacy VoxCity `view` module.
2
+
3
+ VoxCity exposes view-related functions both under:
4
+ - `voxcity.simulator.visibility.*` (newer)
5
+ - `voxcity.simulator.view.*` (legacy wrapper)
6
+
7
+ This module mirrors that pattern for `simulator_gpu` so code can do:
8
+ import simulator_gpu as simulator
9
+ simulator.view.get_view_index(...)
10
+ """
11
+
12
+ from .visibility import (
13
+ get_view_index,
14
+ get_sky_view_factor_map,
15
+ get_surface_view_factor,
16
+ get_landmark_visibility_map,
17
+ get_surface_landmark_visibility,
18
+ mark_building_by_id,
19
+ compute_landmark_visibility,
20
+ rotate_vector_axis_angle,
21
+ )
22
+
23
+ __all__ = [
24
+ "get_view_index",
25
+ "get_sky_view_factor_map",
26
+ "get_surface_view_factor",
27
+ "mark_building_by_id",
28
+ "compute_landmark_visibility",
29
+ "get_landmark_visibility_map",
30
+ "get_surface_landmark_visibility",
31
+ "rotate_vector_axis_angle",
32
+ ]
@@ -0,0 +1,109 @@
1
+ """
2
+ simulator_gpu.visibility: GPU-accelerated visibility analysis module.
3
+
4
+ This package emulates voxcity.simulator.visibility using Taichi GPU acceleration.
5
+
6
+ Features:
7
+ - View Index calculation (green view, sky view, custom targets)
8
+ - Sky View Factor calculation
9
+ - Landmark visibility analysis
10
+ - Surface view factor computation
11
+
12
+ API Compatibility:
13
+ This module provides GPU-accelerated versions of the voxcity.simulator.visibility
14
+ API functions. The main functions mirror the original API:
15
+
16
+ - get_view_index() -> GPU version of voxcity.simulator.visibility.get_view_index
17
+ - get_sky_view_factor_map() -> GPU version of voxcity.simulator.visibility.get_sky_view_factor_map
18
+ - get_surface_view_factor() -> GPU version of voxcity.simulator.visibility.get_surface_view_factor
19
+ - get_landmark_visibility_map() -> GPU version of voxcity.simulator.visibility.get_landmark_visibility_map
20
+ - get_surface_landmark_visibility() -> GPU version of voxcity.simulator.visibility.get_surface_landmark_visibility
21
+ - mark_building_by_id() -> Same as voxcity.simulator.visibility.mark_building_by_id
22
+
23
+ Usage:
24
+ from simulator_gpu.visibility import get_view_index, get_sky_view_factor_map
25
+
26
+ vi_map = get_view_index(voxcity, mode='green')
27
+ svf_map = get_sky_view_factor_map(voxcity)
28
+
29
+ # Or use the class-based API:
30
+ from simulator_gpu.visibility import ViewCalculator
31
+ calc = ViewCalculator(domain)
32
+ view_map = calc.compute_view_index(mode='green')
33
+ """
34
+
35
+ from .view import (
36
+ ViewCalculator,
37
+ compute_view_index_map,
38
+ compute_sky_view_factor_map,
39
+ SurfaceViewFactorCalculator,
40
+ )
41
+
42
+ from .landmark import (
43
+ LandmarkVisibilityCalculator,
44
+ compute_landmark_visibility_map,
45
+ mark_building_by_id,
46
+ SurfaceLandmarkVisibilityCalculator,
47
+ compute_landmark_visibility,
48
+ )
49
+
50
+ from .geometry import (
51
+ generate_ray_directions_grid,
52
+ generate_ray_directions_fibonacci,
53
+ rotate_vector_axis_angle,
54
+ )
55
+
56
+ from .integration import (
57
+ # VoxCity API-compatible functions (main interface)
58
+ get_view_index,
59
+ get_sky_view_factor_map,
60
+ get_surface_view_factor,
61
+ get_landmark_visibility_map,
62
+ get_surface_landmark_visibility,
63
+ # Legacy GPU-suffixed functions (backward compatibility)
64
+ get_view_index_gpu,
65
+ get_sky_view_factor_map_gpu,
66
+ get_landmark_visibility_map_gpu,
67
+ # Utility functions
68
+ create_domain_from_voxcity,
69
+ mark_building_by_id,
70
+ # Constants
71
+ VOXCITY_GROUND_CODE,
72
+ VOXCITY_TREE_CODE,
73
+ VOXCITY_BUILDING_CODE,
74
+ GREEN_VIEW_CODES,
75
+ )
76
+
77
+ __all__ = [
78
+ # VoxCity API-compatible functions (recommended)
79
+ 'get_view_index',
80
+ 'get_sky_view_factor_map',
81
+ 'get_surface_view_factor',
82
+ 'get_landmark_visibility_map',
83
+ 'get_surface_landmark_visibility',
84
+ 'mark_building_by_id',
85
+ 'compute_landmark_visibility',
86
+ # Geometry helpers (matches voxcity.simulator.common.geometry)
87
+ 'rotate_vector_axis_angle',
88
+ # Main calculators (class-based API)
89
+ 'ViewCalculator',
90
+ 'LandmarkVisibilityCalculator',
91
+ 'SurfaceViewFactorCalculator',
92
+ 'SurfaceLandmarkVisibilityCalculator',
93
+ # Functions
94
+ 'compute_view_index_map',
95
+ 'compute_sky_view_factor_map',
96
+ 'compute_landmark_visibility_map',
97
+ # Geometry helpers
98
+ 'generate_ray_directions_grid',
99
+ 'generate_ray_directions_fibonacci',
100
+ # VoxCity integration (legacy, backward compatibility)
101
+ 'create_domain_from_voxcity',
102
+ 'get_view_index_gpu',
103
+ 'get_sky_view_factor_map_gpu',
104
+ 'get_landmark_visibility_map_gpu',
105
+ 'VOXCITY_GROUND_CODE',
106
+ 'VOXCITY_TREE_CODE',
107
+ 'VOXCITY_BUILDING_CODE',
108
+ 'GREEN_VIEW_CODES',
109
+ ]
@@ -0,0 +1,278 @@
1
+ """
2
+ Geometry utilities for view analysis.
3
+
4
+ Provides ray direction generation using various sampling strategies:
5
+ - Grid-based sampling (uniform azimuth x elevation grid)
6
+ - Fibonacci spiral sampling (more uniform hemisphere coverage)
7
+ """
8
+
9
+ import numpy as np
10
+ import taichi as ti
11
+ from typing import Tuple
12
+
13
+
14
+ def generate_ray_directions_grid(
15
+ n_azimuth: int = 120,
16
+ n_elevation: int = 20,
17
+ elevation_min_degrees: float = -30.0,
18
+ elevation_max_degrees: float = 30.0
19
+ ) -> np.ndarray:
20
+ """
21
+ Generate ray directions using a regular grid sampling.
22
+
23
+ Args:
24
+ n_azimuth: Number of azimuthal divisions
25
+ n_elevation: Number of elevation divisions
26
+ elevation_min_degrees: Minimum elevation angle in degrees
27
+ elevation_max_degrees: Maximum elevation angle in degrees
28
+
29
+ Returns:
30
+ Array of shape (n_azimuth * n_elevation, 3) with unit direction vectors
31
+ """
32
+ azimuth_angles = np.linspace(0.0, 2.0 * np.pi, int(n_azimuth), endpoint=False)
33
+ elevation_angles = np.deg2rad(
34
+ np.linspace(float(elevation_min_degrees), float(elevation_max_degrees), int(n_elevation))
35
+ )
36
+
37
+ ray_directions = np.empty((len(azimuth_angles) * len(elevation_angles), 3), dtype=np.float32)
38
+ out_idx = 0
39
+
40
+ for elevation in elevation_angles:
41
+ cos_elev = np.cos(elevation)
42
+ sin_elev = np.sin(elevation)
43
+ for azimuth in azimuth_angles:
44
+ # x = east, y = north, z = up
45
+ dx = cos_elev * np.sin(azimuth)
46
+ dy = cos_elev * np.cos(azimuth)
47
+ dz = sin_elev
48
+ ray_directions[out_idx, 0] = dx
49
+ ray_directions[out_idx, 1] = dy
50
+ ray_directions[out_idx, 2] = dz
51
+ out_idx += 1
52
+
53
+ return ray_directions
54
+
55
+
56
+ def generate_ray_directions_fibonacci(
57
+ n_rays: int = 2400,
58
+ elevation_min_degrees: float = -30.0,
59
+ elevation_max_degrees: float = 30.0
60
+ ) -> np.ndarray:
61
+ """
62
+ Generate ray directions using Fibonacci spiral sampling.
63
+
64
+ This provides more uniform coverage of the hemisphere compared to grid sampling.
65
+
66
+ Args:
67
+ n_rays: Total number of rays
68
+ elevation_min_degrees: Minimum elevation angle in degrees
69
+ elevation_max_degrees: Maximum elevation angle in degrees
70
+
71
+ Returns:
72
+ Array of shape (n_rays, 3) with unit direction vectors
73
+ """
74
+ N = int(max(1, n_rays))
75
+ emin = np.deg2rad(float(elevation_min_degrees))
76
+ emax = np.deg2rad(float(elevation_max_degrees))
77
+
78
+ z_min = np.sin(min(emin, emax))
79
+ z_max = np.sin(max(emin, emax))
80
+
81
+ golden_angle = np.pi * (3.0 - np.sqrt(5.0))
82
+
83
+ i = np.arange(N, dtype=np.float64)
84
+ z = z_min + (i + 0.5) * (z_max - z_min) / N
85
+ phi = i * golden_angle
86
+
87
+ r = np.sqrt(np.clip(1.0 - z * z, 0.0, 1.0))
88
+ x = r * np.cos(phi)
89
+ y = r * np.sin(phi)
90
+
91
+ return np.stack((x, y, z), axis=1).astype(np.float32)
92
+
93
+
94
+ def generate_hemisphere_directions(
95
+ n_azimuth: int = 80,
96
+ n_elevation: int = 40
97
+ ) -> np.ndarray:
98
+ """
99
+ Generate ray directions covering the upper hemisphere.
100
+
101
+ Elevation goes from 0 (horizon) to 90 (zenith).
102
+
103
+ Args:
104
+ n_azimuth: Number of azimuthal divisions
105
+ n_elevation: Number of elevation divisions
106
+
107
+ Returns:
108
+ Array of shape (n_azimuth * n_elevation, 3) with unit direction vectors
109
+ """
110
+ return generate_ray_directions_grid(
111
+ n_azimuth=n_azimuth,
112
+ n_elevation=n_elevation,
113
+ elevation_min_degrees=0.0,
114
+ elevation_max_degrees=90.0
115
+ )
116
+
117
+
118
+ def rotate_vector_axis_angle(vec: np.ndarray, axis: np.ndarray, angle: float) -> np.ndarray:
119
+ """
120
+ Rotate a vector around an axis by a specified angle using Rodrigues' rotation formula.
121
+
122
+ This is a CPU implementation matching voxcity.simulator.common.geometry.rotate_vector_axis_angle.
123
+
124
+ Args:
125
+ vec: Vector to rotate (3,)
126
+ axis: Rotation axis (3,) - will be normalized
127
+ angle: Rotation angle in radians
128
+
129
+ Returns:
130
+ Rotated vector (3,)
131
+ """
132
+ axis_len = np.sqrt(axis[0]**2 + axis[1]**2 + axis[2]**2)
133
+ if axis_len < 1e-12:
134
+ return vec.copy()
135
+ ux, uy, uz = axis / axis_len
136
+ c = np.cos(angle)
137
+ s = np.sin(angle)
138
+ dot = vec[0]*ux + vec[1]*uy + vec[2]*uz
139
+ cross_x = uy*vec[2] - uz*vec[1]
140
+ cross_y = uz*vec[0] - ux*vec[2]
141
+ cross_z = ux*vec[1] - uy*vec[0]
142
+ v_rot = np.zeros(3, dtype=np.float64)
143
+ v_rot[0] = vec[0] * c + cross_x * s + ux * dot * (1.0 - c)
144
+ v_rot[1] = vec[1] * c + cross_y * s + uy * dot * (1.0 - c)
145
+ v_rot[2] = vec[2] * c + cross_z * s + uz * dot * (1.0 - c)
146
+ return v_rot
147
+
148
+
149
+ @ti.func
150
+ def rotate_vector_axis_angle_ti(vec: ti.template(), axis: ti.template(), angle: ti.f32) -> ti.template():
151
+ """
152
+ Taichi GPU kernel function for rotating a vector around an axis.
153
+
154
+ Uses Rodrigues' rotation formula.
155
+
156
+ Args:
157
+ vec: Vector to rotate (Vector3)
158
+ axis: Rotation axis (Vector3) - will be normalized
159
+ angle: Rotation angle in radians
160
+
161
+ Returns:
162
+ Rotated Vector3
163
+ """
164
+ result = vec
165
+ axis_len = axis.norm()
166
+ if axis_len > 1e-12:
167
+ u = axis / axis_len
168
+ c = ti.cos(angle)
169
+ s = ti.sin(angle)
170
+ dot = vec.dot(u)
171
+ cross = u.cross(vec)
172
+ result = vec * c + cross * s + u * dot * (1.0 - c)
173
+ return result
174
+
175
+
176
+ def build_face_basis(normal: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
177
+ """
178
+ Build orthonormal basis (u, v, n) for a surface normal.
179
+
180
+ Matches voxcity.simulator.common.geometry._build_face_basis.
181
+
182
+ Args:
183
+ normal: Surface normal vector (3,)
184
+
185
+ Returns:
186
+ Tuple of (u, v, n) orthonormal vectors
187
+ """
188
+ nx, ny, nz = normal
189
+ nrm = np.sqrt(nx*nx + ny*ny + nz*nz)
190
+ if nrm < 1e-12:
191
+ return (np.array([1.0, 0.0, 0.0]),
192
+ np.array([0.0, 1.0, 0.0]),
193
+ np.array([0.0, 0.0, 1.0]))
194
+ invn = 1.0 / nrm
195
+ nx *= invn
196
+ ny *= invn
197
+ nz *= invn
198
+ n = np.array([nx, ny, nz])
199
+
200
+ # Choose helper vector to cross with normal
201
+ if abs(nz) < 0.999:
202
+ helper = np.array([0.0, 0.0, 1.0])
203
+ else:
204
+ helper = np.array([1.0, 0.0, 0.0])
205
+
206
+ # u = helper x n (normalized)
207
+ u = np.cross(helper, n)
208
+ ul = np.linalg.norm(u)
209
+ if ul < 1e-12:
210
+ u = np.array([1.0, 0.0, 0.0])
211
+ else:
212
+ u = u / ul
213
+
214
+ # v = n x u
215
+ v = np.cross(n, u)
216
+
217
+ return u, v, n
218
+
219
+
220
+ @ti.func
221
+ def build_face_basis_ti(normal: ti.template()) -> ti.template():
222
+ """
223
+ Taichi GPU kernel function to build orthonormal basis for a surface normal.
224
+
225
+ Args:
226
+ normal: Surface normal Vector3
227
+
228
+ Returns:
229
+ Tuple of (u, v, n) orthonormal Vector3s
230
+ """
231
+ nrm = normal.norm()
232
+ n = normal
233
+ u = ti.Vector([1.0, 0.0, 0.0])
234
+ v = ti.Vector([0.0, 1.0, 0.0])
235
+
236
+ if nrm > 1e-12:
237
+ n = normal / nrm
238
+
239
+ # Choose helper vector
240
+ helper = ti.Vector([0.0, 0.0, 1.0])
241
+ if ti.abs(n[2]) >= 0.999:
242
+ helper = ti.Vector([1.0, 0.0, 0.0])
243
+
244
+ # u = helper x n
245
+ u = helper.cross(n)
246
+ ul = u.norm()
247
+ if ul > 1e-12:
248
+ u = u / ul
249
+ else:
250
+ u = ti.Vector([1.0, 0.0, 0.0])
251
+
252
+ # v = n x u
253
+ v = n.cross(u)
254
+
255
+ return u, v, n
256
+
257
+
258
+ @ti.data_oriented
259
+ class RayDirectionField:
260
+ """
261
+ GPU-accessible ray direction field for batch processing.
262
+ """
263
+
264
+ def __init__(self, directions: np.ndarray):
265
+ """
266
+ Initialize with numpy array of directions.
267
+
268
+ Args:
269
+ directions: Array of shape (n_rays, 3)
270
+ """
271
+ self.n_rays = directions.shape[0]
272
+ self.directions = ti.Vector.field(3, dtype=ti.f32, shape=(self.n_rays,))
273
+ self._init_from_numpy(directions)
274
+
275
+ @ti.kernel
276
+ def _init_from_numpy(self, dirs: ti.types.ndarray()):
277
+ for i in range(self.n_rays):
278
+ self.directions[i] = ti.Vector([dirs[i, 0], dirs[i, 1], dirs[i, 2]])