voxcity 0.6.28__py3-none-any.whl → 0.6.30__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/downloader/oemj.py +80 -8
- voxcity/exporter/obj.py +26 -22
- voxcity/generator.py +1340 -1316
- voxcity/geoprocessor/grid.py +25 -8
- voxcity/utils/visualization.py +68 -10
- {voxcity-0.6.28.dist-info → voxcity-0.6.30.dist-info}/METADATA +21 -2
- {voxcity-0.6.28.dist-info → voxcity-0.6.30.dist-info}/RECORD +10 -10
- {voxcity-0.6.28.dist-info → voxcity-0.6.30.dist-info}/WHEEL +0 -0
- {voxcity-0.6.28.dist-info → voxcity-0.6.30.dist-info}/licenses/AUTHORS.rst +0 -0
- {voxcity-0.6.28.dist-info → voxcity-0.6.30.dist-info}/licenses/LICENSE +0 -0
voxcity/geoprocessor/grid.py
CHANGED
|
@@ -1542,18 +1542,35 @@ def create_dem_grid_from_gdf_polygon(terrain_gdf, mesh_size, polygon):
|
|
|
1542
1542
|
|
|
1543
1543
|
# ------------------------------------------------------------------------
|
|
1544
1544
|
# 4. Nearest-neighbor join from terrain_gdf to grid points
|
|
1545
|
+
# Use a projected CRS (UTM zone from polygon centroid) for robust distances
|
|
1545
1546
|
# ------------------------------------------------------------------------
|
|
1546
1547
|
if 'elevation' not in terrain_gdf.columns:
|
|
1547
1548
|
raise ValueError("terrain_gdf must have an 'elevation' column.")
|
|
1548
1549
|
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1550
|
+
try:
|
|
1551
|
+
centroid = poly.centroid
|
|
1552
|
+
lon_c, lat_c = float(centroid.x), float(centroid.y)
|
|
1553
|
+
zone = int((lon_c + 180.0) // 6) + 1
|
|
1554
|
+
epsg_proj = 32600 + zone if lat_c >= 0 else 32700 + zone
|
|
1555
|
+
terrain_proj = terrain_gdf.to_crs(epsg=epsg_proj)
|
|
1556
|
+
grid_points_proj = grid_points.to_crs(epsg=epsg_proj)
|
|
1557
|
+
|
|
1558
|
+
grid_points_elev = gpd.sjoin_nearest(
|
|
1559
|
+
grid_points_proj,
|
|
1560
|
+
terrain_proj[['elevation', 'geometry']],
|
|
1561
|
+
how="left",
|
|
1562
|
+
distance_col="dist_to_terrain"
|
|
1563
|
+
)
|
|
1564
|
+
# Keep original index mapping
|
|
1565
|
+
grid_points_elev.index = grid_points.index
|
|
1566
|
+
except Exception:
|
|
1567
|
+
# Fallback to geographic join if projection fails
|
|
1568
|
+
grid_points_elev = gpd.sjoin_nearest(
|
|
1569
|
+
grid_points,
|
|
1570
|
+
terrain_gdf[['elevation', 'geometry']],
|
|
1571
|
+
how="left",
|
|
1572
|
+
distance_col="dist_to_terrain"
|
|
1573
|
+
)
|
|
1557
1574
|
|
|
1558
1575
|
# ------------------------------------------------------------------------
|
|
1559
1576
|
# 5. Build the final 2D height array
|
voxcity/utils/visualization.py
CHANGED
|
@@ -2502,7 +2502,30 @@ def visualize_voxcity_plotly(
|
|
|
2502
2502
|
if max_dim > max_dimension:
|
|
2503
2503
|
stride = int(np.ceil(max_dim / max_dimension))
|
|
2504
2504
|
if stride > 1:
|
|
2505
|
-
|
|
2505
|
+
# Surface-aware downsampling:
|
|
2506
|
+
# - Stride in X and Y for speed
|
|
2507
|
+
# - Along Z, choose the topmost non-zero within each stride window
|
|
2508
|
+
orig = voxel_array
|
|
2509
|
+
nx0, ny0, nz0 = orig.shape
|
|
2510
|
+
xs = orig[::stride, ::stride, :]
|
|
2511
|
+
nx_ds, ny_ds, _ = xs.shape
|
|
2512
|
+
nz_ds = int(np.ceil(nz0 / float(stride)))
|
|
2513
|
+
vox = np.zeros((nx_ds, ny_ds, nz_ds), dtype=orig.dtype)
|
|
2514
|
+
for k in range(nz_ds):
|
|
2515
|
+
z0w = k * stride
|
|
2516
|
+
z1w = min(z0w + stride, nz0)
|
|
2517
|
+
W = xs[:, :, z0w:z1w]
|
|
2518
|
+
if W.size == 0:
|
|
2519
|
+
continue
|
|
2520
|
+
nz_mask = (W != 0)
|
|
2521
|
+
has_any = nz_mask.any(axis=2)
|
|
2522
|
+
# find topmost index within window where any class exists
|
|
2523
|
+
rev_mask = nz_mask[:, :, ::-1]
|
|
2524
|
+
idx_rev = rev_mask.argmax(axis=2)
|
|
2525
|
+
real_idx = (W.shape[2] - 1) - idx_rev
|
|
2526
|
+
# gather labels at that topmost index
|
|
2527
|
+
gathered = np.take_along_axis(W, real_idx[..., None], axis=2).squeeze(-1)
|
|
2528
|
+
vox[:, :, k] = np.where(has_any, gathered, 0)
|
|
2506
2529
|
|
|
2507
2530
|
nx, ny, nz = vox.shape
|
|
2508
2531
|
|
|
@@ -2534,19 +2557,54 @@ def visualize_voxcity_plotly(
|
|
|
2534
2557
|
else:
|
|
2535
2558
|
vox_dict = get_voxel_color_map(voxel_color_map)
|
|
2536
2559
|
|
|
2537
|
-
def
|
|
2538
|
-
|
|
2539
|
-
|
|
2560
|
+
def _bool_max_pool_3d(arr_bool, sx):
|
|
2561
|
+
"""Max-pool a 3D boolean array with cubic window of size sx.
|
|
2562
|
+
|
|
2563
|
+
Pads with False so the output shape equals ceil(n/sx) per axis.
|
|
2564
|
+
"""
|
|
2565
|
+
if isinstance(sx, (tuple, list, np.ndarray)):
|
|
2566
|
+
sx, sy, sz = int(sx[0]), int(sx[1]), int(sx[2])
|
|
2567
|
+
else:
|
|
2568
|
+
sy = sz = int(sx)
|
|
2569
|
+
sx = int(sx)
|
|
2570
|
+
|
|
2571
|
+
a = np.asarray(arr_bool, dtype=bool)
|
|
2572
|
+
nx, ny, nz = a.shape
|
|
2573
|
+
px = (sx - (nx % sx)) % sx
|
|
2574
|
+
py = (sy - (ny % sy)) % sy
|
|
2575
|
+
pz = (sz - (nz % sz)) % sz
|
|
2576
|
+
if px or py or pz:
|
|
2577
|
+
a = np.pad(a, ((0, px), (0, py), (0, pz)), constant_values=False)
|
|
2578
|
+
nxp, nyp, nzp = a.shape
|
|
2579
|
+
a = a.reshape(nxp // sx, sx, nyp // sy, sy, nzp // sz, sz)
|
|
2580
|
+
a = a.max(axis=1).max(axis=2).max(axis=4)
|
|
2581
|
+
return a
|
|
2582
|
+
|
|
2583
|
+
# Build an occluder mask that represents occupancy of any class, including those not rendered.
|
|
2584
|
+
# During downsampling, use max-pooling so omitted classes within a block still occlude neighbors.
|
|
2585
|
+
occluder = None
|
|
2586
|
+
if vox is not None:
|
|
2587
|
+
if stride > 1:
|
|
2588
|
+
try:
|
|
2589
|
+
occluder = _bool_max_pool_3d((voxel_array != 0), stride)
|
|
2590
|
+
except Exception:
|
|
2591
|
+
occluder = (vox != 0)
|
|
2592
|
+
else:
|
|
2593
|
+
occluder = (vox != 0)
|
|
2594
|
+
|
|
2595
|
+
def exposed_face_masks(occ, occ_any):
|
|
2596
|
+
# occ, occ_any shape (nx, ny, nz)
|
|
2597
|
+
p = np.pad(occ_any, ((0,1),(0,0),(0,0)), constant_values=False)
|
|
2540
2598
|
posx = occ & (~p[1:,:,:])
|
|
2541
|
-
p = np.pad(
|
|
2599
|
+
p = np.pad(occ_any, ((1,0),(0,0),(0,0)), constant_values=False)
|
|
2542
2600
|
negx = occ & (~p[:-1,:,:])
|
|
2543
|
-
p = np.pad(
|
|
2601
|
+
p = np.pad(occ_any, ((0,0),(0,1),(0,0)), constant_values=False)
|
|
2544
2602
|
posy = occ & (~p[:,1:,:])
|
|
2545
|
-
p = np.pad(
|
|
2603
|
+
p = np.pad(occ_any, ((0,0),(1,0),(0,0)), constant_values=False)
|
|
2546
2604
|
negy = occ & (~p[:,:-1,:])
|
|
2547
|
-
p = np.pad(
|
|
2605
|
+
p = np.pad(occ_any, ((0,0),(0,0),(0,1)), constant_values=False)
|
|
2548
2606
|
posz = occ & (~p[:,:,1:])
|
|
2549
|
-
p = np.pad(
|
|
2607
|
+
p = np.pad(occ_any, ((0,0),(0,0),(1,0)), constant_values=False)
|
|
2550
2608
|
negz = occ & (~p[:,:,:-1])
|
|
2551
2609
|
return posx, negx, posy, negy, posz, negz
|
|
2552
2610
|
|
|
@@ -2639,7 +2697,7 @@ def visualize_voxcity_plotly(
|
|
|
2639
2697
|
if not np.any(vox == cls):
|
|
2640
2698
|
continue
|
|
2641
2699
|
occ = (vox == cls)
|
|
2642
|
-
posx, negx, posy, negy, posz, negz = exposed_face_masks(occ)
|
|
2700
|
+
posx, negx, posy, negy, posz, negz = exposed_face_masks(occ, occluder)
|
|
2643
2701
|
color_rgb = vox_dict.get(int(cls), [128,128,128])
|
|
2644
2702
|
add_faces(fig, posx, '+x', color_rgb)
|
|
2645
2703
|
add_faces(fig, negx, '-x', color_rgb)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voxcity
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.30
|
|
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
|
License-File: AUTHORS.rst
|
|
@@ -69,13 +69,15 @@ Description-Content-Type: text/markdown
|
|
|
69
69
|
<!-- [](https://creativecommons.org/licenses/by-sa/4.0/) -->
|
|
70
70
|
|
|
71
71
|
<p align="center">
|
|
72
|
-
Tutorial preview: <a href="https://colab.research.google.com/drive/1Lofd3RawKMr6QuUsamGaF48u2MN0hfrP?usp=sharing">[Google Colab]</a> | Documentation: <a href="https://voxcity.readthedocs.io/en/latest">[Read the Docs]</a>
|
|
72
|
+
Tutorial preview: <a href="https://colab.research.google.com/drive/1Lofd3RawKMr6QuUsamGaF48u2MN0hfrP?usp=sharing">[Google Colab]</a> | Documentation: <a href="https://voxcity.readthedocs.io/en/latest">[Read the Docs]</a> | Video tutorial: <a href="https://youtu.be/qHusvKB07qk">[Watch on YouTube]</a>
|
|
73
73
|
</p>
|
|
74
74
|
|
|
75
75
|
<p align="center">
|
|
76
76
|
<img src="https://raw.githubusercontent.com/kunifujiwara/VoxCity/main/images/logo.png" alt="Voxcity logo" width="550">
|
|
77
77
|
</p>
|
|
78
78
|
|
|
79
|
+
|
|
80
|
+
|
|
79
81
|
# VoxCity
|
|
80
82
|
|
|
81
83
|
**voxcity** is a Python package that provides a seamless solution for grid-based 3D city model generation and urban simulation for cities worldwide. VoxCity's generator module automatically downloads building heights, tree canopy heights, land cover, and terrain elevation within a specified target area, and voxelizes buildings, trees, land cover, and terrain to generate an integrated voxel city model. The simulator module enables users to conduct environmental simulations, including solar radiation and view index analyses. Users can export the generated models using several file formats compatible with external software, such as ENVI-met (INX), Blender, and Rhino (OBJ). Try it out using the [Google Colab Demo](https://colab.research.google.com/drive/1Lofd3RawKMr6QuUsamGaF48u2MN0hfrP?usp=sharing) or your local environment. For detailed documentation, API reference, and tutorials, visit our [Read the Docs](https://voxcity.readthedocs.io/en/latest) page.
|
|
@@ -90,6 +92,21 @@ Description-Content-Type: text/markdown
|
|
|
90
92
|
<img src="https://raw.githubusercontent.com/kunifujiwara/VoxCity/main/images/concept.png" alt="Conceptual Diagram of voxcity" width="800">
|
|
91
93
|
</p>
|
|
92
94
|
|
|
95
|
+
## Tutorial
|
|
96
|
+
|
|
97
|
+
- **Google Colab (interactive notebook)**: <a href="https://colab.research.google.com/drive/1Lofd3RawKMr6QuUsamGaF48u2MN0hfrP?usp=sharing">Open tutorial in Colab</a>
|
|
98
|
+
- **YouTube video (walkthrough)**: <a href="https://youtu.be/qHusvKB07qk">Watch on YouTube</a>
|
|
99
|
+
|
|
100
|
+
<p align="center">
|
|
101
|
+
<a href="https://youtu.be/qHusvKB07qk" title="Click to watch the VoxCity tutorial on YouTube">
|
|
102
|
+
<img src="images/youtube_thumbnail_play.png" alt="VoxCity Tutorial — Click to watch on YouTube" width="480">
|
|
103
|
+
</a>
|
|
104
|
+
</p>
|
|
105
|
+
|
|
106
|
+
<p align="center">
|
|
107
|
+
<em>Tutorial video by <a href="https://ual.sg/author/liang-xiucheng/">Xiucheng Liang</a></em>
|
|
108
|
+
</p>
|
|
109
|
+
|
|
93
110
|
|
|
94
111
|
## Key Features
|
|
95
112
|
|
|
@@ -524,6 +541,8 @@ Fujiwara K, Tsurumi R, Kiyono T, Fan Z, Liang X, Lei B, Yap W, Ito K, Biljecki F
|
|
|
524
541
|
|
|
525
542
|
## Credit
|
|
526
543
|
|
|
544
|
+
- Tutorial video by <a href="https://ual.sg/author/liang-xiucheng/">Xiucheng Liang</a>
|
|
545
|
+
|
|
527
546
|
This package was created with [Cookiecutter](https://github.com/audreyr/cookiecutter) and the [`audreyr/cookiecutter-pypackage`](https://github.com/audreyr/cookiecutter-pypackage) project template.
|
|
528
547
|
|
|
529
548
|
--------------------------------------------------------------------------------
|
|
@@ -5,7 +5,7 @@ voxcity/downloader/eubucco.py,sha256=ln1YNaaOgJfxNfCtVbYaMm775-bUvpAA_LDv60_i22w
|
|
|
5
5
|
voxcity/downloader/gba.py,sha256=b-VmlVS8IzCR0OYfWgtlMpuZrB5_0M4EpG8BEBj6YEY,7184
|
|
6
6
|
voxcity/downloader/gee.py,sha256=nvJvYqcSZyyontRtG2cFeb__ZJfeY4rRN1NBPORxLwQ,23557
|
|
7
7
|
voxcity/downloader/mbfp.py,sha256=UXDVjsO0fnb0fSal9yqrSFEIBThnRmnutnp08kZTmCA,6595
|
|
8
|
-
voxcity/downloader/oemj.py,sha256=
|
|
8
|
+
voxcity/downloader/oemj.py,sha256=SeMId9MvI-DnGyREpqu5-6D-xwRdMJdYIGcAPFD95rw,16432
|
|
9
9
|
voxcity/downloader/osm.py,sha256=7Wo6lSodci7gALMKLQ_0ricmn0ZrfUK90vKYQ-ayU2A,46285
|
|
10
10
|
voxcity/downloader/overture.py,sha256=hVxu-3Fmuu2E1tEzcDcNyU1cR-aE-6h6jkcxkuqN1-s,13343
|
|
11
11
|
voxcity/downloader/utils.py,sha256=tz6wt4B9BhEOyvoF5OYXlr8rUd5cBEDedWL3j__oT70,3099
|
|
@@ -14,11 +14,11 @@ voxcity/exporter/cityles.py,sha256=Kfl2PAn4WquqCdjOlyPrHysxPLaudh8QfsoC6WAXlvs,1
|
|
|
14
14
|
voxcity/exporter/envimet.py,sha256=Sh7s1JdQ6SgT_L2Xd_c4gtEGWK2hTS87bccaoIqik-s,31105
|
|
15
15
|
voxcity/exporter/magicavoxel.py,sha256=SfGEgTZRlossKx3Xrv9d3iKSX-HmfQJEL9lZHgWMDX4,12782
|
|
16
16
|
voxcity/exporter/netcdf.py,sha256=48rJ3wDsFhi9ANbElhMjXLxWMJoJzBt1gFbN0ekPp-A,7404
|
|
17
|
-
voxcity/exporter/obj.py,sha256=
|
|
18
|
-
voxcity/generator.py,sha256=
|
|
17
|
+
voxcity/exporter/obj.py,sha256=iNszT4gurZZQurdl7hGWDyIhuZt50w1gZyMOt5XY2Kk,59888
|
|
18
|
+
voxcity/generator.py,sha256=zJZSLcldMvfbRk2UGXzY25DJmJi1L4KZP0glPuMRFgg,69477
|
|
19
19
|
voxcity/geoprocessor/__init__.py,sha256=WYxcAQrjGucIvGHF0JTC6rONZzL3kCms1S2vpzS6KaU,127
|
|
20
20
|
voxcity/geoprocessor/draw.py,sha256=AZMWq23wxxDJygNloCbVzWAAr1JO7nC94umf9LSxJ5o,49248
|
|
21
|
-
voxcity/geoprocessor/grid.py,sha256=
|
|
21
|
+
voxcity/geoprocessor/grid.py,sha256=s64tCCY-pPiZjAWRWRJkBpb2FCkruOjq_nm1vD2unT8,77407
|
|
22
22
|
voxcity/geoprocessor/mesh.py,sha256=A7uaCMWfm82KEoYPfQYpxv6xMtQKaU2PBVDfKTpngqg,32027
|
|
23
23
|
voxcity/geoprocessor/network.py,sha256=YynqR0nq_NUra_cQ3Z_56KxfRia1b6-hIzGCj3QT-wE,25137
|
|
24
24
|
voxcity/geoprocessor/polygon.py,sha256=DfzXf6R-qoWXEZv1z1aHCVfr-DCuCFw6lieQT5cNHPA,61188
|
|
@@ -30,10 +30,10 @@ voxcity/simulator/view.py,sha256=k3FoS6gsibR-eDrTHJivJSQfvN3Tg8R8eSTeMqd9ans,939
|
|
|
30
30
|
voxcity/utils/__init__.py,sha256=Q-NYCqYnAAaF80KuNwpqIjbE7Ec3Gr4y_khMLIMhJrg,68
|
|
31
31
|
voxcity/utils/lc.py,sha256=722Gz3lPbgAp0mmTZ-g-QKBbAnbxrcgaYwb1sa7q8Sk,16189
|
|
32
32
|
voxcity/utils/material.py,sha256=H8K8Lq4wBL6dQtgj7esUW2U6wLCOTeOtelkTDJoRgMo,10007
|
|
33
|
-
voxcity/utils/visualization.py,sha256=
|
|
33
|
+
voxcity/utils/visualization.py,sha256=aI4ipzYCTuIIzi6PU-Chog2cHxNFn4bveBZ3ljnZD9g,123876
|
|
34
34
|
voxcity/utils/weather.py,sha256=cb6ZooL42Hc4214OtFiJ78cCgWYM6VE-DU8S3e-urRg,48449
|
|
35
|
-
voxcity-0.6.
|
|
36
|
-
voxcity-0.6.
|
|
37
|
-
voxcity-0.6.
|
|
38
|
-
voxcity-0.6.
|
|
39
|
-
voxcity-0.6.
|
|
35
|
+
voxcity-0.6.30.dist-info/licenses/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
|
|
36
|
+
voxcity-0.6.30.dist-info/licenses/LICENSE,sha256=s_jE1Df1nTPL4A_5GCGic5Zwex0CVaPKcAmSilxJPPE,1089
|
|
37
|
+
voxcity-0.6.30.dist-info/METADATA,sha256=6ns5bThD5uMWC05L8u2s4ZEJ_m5XTMEGQsrsmckA-B8,27039
|
|
38
|
+
voxcity-0.6.30.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
39
|
+
voxcity-0.6.30.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|