voxcity 0.3.27__py3-none-any.whl → 0.4.2__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/obj.py +2 -2
- voxcity/geoprocessor/grid.py +5 -1
- voxcity/geoprocessor/mesh.py +21 -1
- voxcity/geoprocessor/polygon.py +95 -1
- voxcity/simulator/solar.py +656 -7
- voxcity/simulator/view.py +635 -2
- voxcity/utils/visualization.py +780 -168
- voxcity/utils/weather.py +98 -5
- {voxcity-0.3.27.dist-info → voxcity-0.4.2.dist-info}/METADATA +12 -12
- {voxcity-0.3.27.dist-info → voxcity-0.4.2.dist-info}/RECORD +14 -14
- {voxcity-0.3.27.dist-info → voxcity-0.4.2.dist-info}/WHEEL +1 -1
- {voxcity-0.3.27.dist-info → voxcity-0.4.2.dist-info}/AUTHORS.rst +0 -0
- {voxcity-0.3.27.dist-info → voxcity-0.4.2.dist-info}/LICENSE +0 -0
- {voxcity-0.3.27.dist-info → voxcity-0.4.2.dist-info}/top_level.txt +0 -0
voxcity/utils/weather.py
CHANGED
|
@@ -164,7 +164,7 @@ def process_epw(epw_path: Union[str, Path]) -> Tuple[pd.DataFrame, Dict]:
|
|
|
164
164
|
return df, headers
|
|
165
165
|
|
|
166
166
|
def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float, output_dir: str = "./", max_distance: Optional[float] = None,
|
|
167
|
-
extract_zip: bool = True, load_data: bool = True) -> Tuple[Optional[str], Optional[pd.DataFrame], Optional[Dict]]:
|
|
167
|
+
extract_zip: bool = True, load_data: bool = True, region: Optional[Union[str, List[str]]] = None) -> Tuple[Optional[str], Optional[pd.DataFrame], Optional[Dict]]:
|
|
168
168
|
"""
|
|
169
169
|
Download and process EPW weather file from Climate.OneBuilding.Org based on coordinates.
|
|
170
170
|
|
|
@@ -175,6 +175,8 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
|
|
|
175
175
|
max_distance (float, optional): Maximum distance in kilometers to search for stations
|
|
176
176
|
extract_zip (bool): Whether to extract the ZIP file (default True)
|
|
177
177
|
load_data (bool): Whether to load the EPW data into a DataFrame (default True)
|
|
178
|
+
region (str or List[str], optional): Specific region(s) to scan for stations (e.g., "Asia", ["Europe", "Africa"])
|
|
179
|
+
If None, will auto-detect region based on coordinates.
|
|
178
180
|
|
|
179
181
|
Returns:
|
|
180
182
|
Tuple containing:
|
|
@@ -197,6 +199,66 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
|
|
|
197
199
|
"Europe": "https://climate.onebuilding.org/sources/Region6_Europe_TMYx_EPW_Processing_locations.kml",
|
|
198
200
|
"Antarctica": "https://climate.onebuilding.org/sources/Region7_Antarctica_TMYx_EPW_Processing_locations.kml"
|
|
199
201
|
}
|
|
202
|
+
|
|
203
|
+
# Define approximate geographical boundaries for regions
|
|
204
|
+
REGION_BOUNDS = {
|
|
205
|
+
"Africa": {"lon_min": -20, "lon_max": 55, "lat_min": -35, "lat_max": 40},
|
|
206
|
+
"Asia": {"lon_min": 25, "lon_max": 150, "lat_min": 0, "lat_max": 55},
|
|
207
|
+
"Japan": {"lon_min": 127, "lon_max": 146, "lat_min": 24, "lat_max": 46},
|
|
208
|
+
"India": {"lon_min": 68, "lon_max": 97, "lat_min": 6, "lat_max": 36},
|
|
209
|
+
"Argentina": {"lon_min": -75, "lon_max": -53, "lat_min": -55, "lat_max": -22},
|
|
210
|
+
"Canada": {"lon_min": -141, "lon_max": -52, "lat_min": 42, "lat_max": 83},
|
|
211
|
+
"USA": {"lon_min": -170, "lon_max": -65, "lat_min": 20, "lat_max": 72},
|
|
212
|
+
"Caribbean": {"lon_min": -90, "lon_max": -59, "lat_min": 10, "lat_max": 27},
|
|
213
|
+
"Southwest_Pacific": {"lon_min": 110, "lon_max": 180, "lat_min": -50, "lat_max": 0},
|
|
214
|
+
"Europe": {"lon_min": -25, "lon_max": 40, "lat_min": 35, "lat_max": 72},
|
|
215
|
+
"Antarctica": {"lon_min": -180, "lon_max": 180, "lat_min": -90, "lat_max": -60}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
def detect_regions(lon: float, lat: float) -> List[str]:
|
|
219
|
+
"""Detect which region(s) the coordinates belong to."""
|
|
220
|
+
matching_regions = []
|
|
221
|
+
|
|
222
|
+
# Handle special case of longitude wrap around 180/-180
|
|
223
|
+
lon_adjusted = lon
|
|
224
|
+
if lon < -180:
|
|
225
|
+
lon_adjusted = lon + 360
|
|
226
|
+
elif lon > 180:
|
|
227
|
+
lon_adjusted = lon - 360
|
|
228
|
+
|
|
229
|
+
for region_name, bounds in REGION_BOUNDS.items():
|
|
230
|
+
# Check if point is within region bounds
|
|
231
|
+
if (bounds["lon_min"] <= lon_adjusted <= bounds["lon_max"] and
|
|
232
|
+
bounds["lat_min"] <= lat <= bounds["lat_max"]):
|
|
233
|
+
matching_regions.append(region_name)
|
|
234
|
+
|
|
235
|
+
# If no regions matched, check the closest regions
|
|
236
|
+
if not matching_regions:
|
|
237
|
+
# Calculate "distance" to each region's boundary (simplified)
|
|
238
|
+
region_distances = []
|
|
239
|
+
for region_name, bounds in REGION_BOUNDS.items():
|
|
240
|
+
# Calculate distance to closest edge of region bounds
|
|
241
|
+
lon_dist = 0
|
|
242
|
+
if lon_adjusted < bounds["lon_min"]:
|
|
243
|
+
lon_dist = bounds["lon_min"] - lon_adjusted
|
|
244
|
+
elif lon_adjusted > bounds["lon_max"]:
|
|
245
|
+
lon_dist = lon_adjusted - bounds["lon_max"]
|
|
246
|
+
|
|
247
|
+
lat_dist = 0
|
|
248
|
+
if lat < bounds["lat_min"]:
|
|
249
|
+
lat_dist = bounds["lat_min"] - lat
|
|
250
|
+
elif lat > bounds["lat_max"]:
|
|
251
|
+
lat_dist = lat - bounds["lat_max"]
|
|
252
|
+
|
|
253
|
+
# Simple distance metric (not actual distance)
|
|
254
|
+
distance = (lon_dist**2 + lat_dist**2)**0.5
|
|
255
|
+
region_distances.append((region_name, distance))
|
|
256
|
+
|
|
257
|
+
# Get 3 closest regions
|
|
258
|
+
closest_regions = sorted(region_distances, key=lambda x: x[1])[:3]
|
|
259
|
+
matching_regions = [r[0] for r in closest_regions]
|
|
260
|
+
|
|
261
|
+
return matching_regions
|
|
200
262
|
|
|
201
263
|
def try_decode(content: bytes) -> str:
|
|
202
264
|
"""Try different encodings to decode content."""
|
|
@@ -353,15 +415,46 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
|
|
|
353
415
|
# Create output directory if it doesn't exist
|
|
354
416
|
Path(output_dir).mkdir(parents=True, exist_ok=True)
|
|
355
417
|
|
|
356
|
-
#
|
|
418
|
+
# Determine which regions to scan
|
|
419
|
+
regions_to_scan = {}
|
|
420
|
+
if region is None:
|
|
421
|
+
# Auto-detect regions based on coordinates
|
|
422
|
+
detected_regions = detect_regions(longitude, latitude)
|
|
423
|
+
|
|
424
|
+
if detected_regions:
|
|
425
|
+
print(f"Auto-detected regions: {', '.join(detected_regions)}")
|
|
426
|
+
for r in detected_regions:
|
|
427
|
+
regions_to_scan[r] = KML_SOURCES[r]
|
|
428
|
+
else:
|
|
429
|
+
# Fallback to all regions if detection fails
|
|
430
|
+
print("Could not determine region from coordinates. Scanning all regions.")
|
|
431
|
+
regions_to_scan = KML_SOURCES
|
|
432
|
+
elif isinstance(region, str):
|
|
433
|
+
# Handle string input
|
|
434
|
+
if region.lower() == "all":
|
|
435
|
+
regions_to_scan = KML_SOURCES
|
|
436
|
+
elif region in KML_SOURCES:
|
|
437
|
+
regions_to_scan[region] = KML_SOURCES[region]
|
|
438
|
+
else:
|
|
439
|
+
valid_regions = ", ".join(KML_SOURCES.keys())
|
|
440
|
+
raise ValueError(f"Invalid region: '{region}'. Valid regions are: {valid_regions}")
|
|
441
|
+
else:
|
|
442
|
+
# Handle list input
|
|
443
|
+
for r in region:
|
|
444
|
+
if r not in KML_SOURCES:
|
|
445
|
+
valid_regions = ", ".join(KML_SOURCES.keys())
|
|
446
|
+
raise ValueError(f"Invalid region: '{r}'. Valid regions are: {valid_regions}")
|
|
447
|
+
regions_to_scan[r] = KML_SOURCES[r]
|
|
448
|
+
|
|
449
|
+
# Get stations from selected KML sources
|
|
357
450
|
print("Fetching weather station data from Climate.OneBuilding.Org...")
|
|
358
451
|
all_stations = []
|
|
359
452
|
|
|
360
|
-
for
|
|
361
|
-
print(f"Scanning {
|
|
453
|
+
for region_name, url in regions_to_scan.items():
|
|
454
|
+
print(f"Scanning {region_name}...")
|
|
362
455
|
stations = get_stations_from_kml(url)
|
|
363
456
|
all_stations.extend(stations)
|
|
364
|
-
print(f"Found {len(stations)} stations in {
|
|
457
|
+
print(f"Found {len(stations)} stations in {region_name}")
|
|
365
458
|
|
|
366
459
|
print(f"\nTotal stations found: {len(all_stations)}")
|
|
367
460
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: voxcity
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.2
|
|
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>
|
|
@@ -69,7 +69,7 @@ Requires-Dist: ruff; extra == "dev"
|
|
|
69
69
|
|
|
70
70
|
# VoxCity
|
|
71
71
|
|
|
72
|
-
**
|
|
72
|
+
**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.
|
|
73
73
|
|
|
74
74
|
<!-- <p align="center">
|
|
75
75
|
<picture>
|
|
@@ -180,7 +180,7 @@ rectangle_vertices = [
|
|
|
180
180
|
Use the GUI map interface to draw a rectangular domain of interest.
|
|
181
181
|
|
|
182
182
|
```python
|
|
183
|
-
from voxcity.
|
|
183
|
+
from voxcity.geoprocessor.draw import draw_rectangle_map_cityname
|
|
184
184
|
|
|
185
185
|
cityname = "tokyo"
|
|
186
186
|
m, rectangle_vertices = draw_rectangle_map_cityname(cityname, zoom=15)
|
|
@@ -191,7 +191,7 @@ m
|
|
|
191
191
|
Choose the width and height in meters and select the center point on the map.
|
|
192
192
|
|
|
193
193
|
```python
|
|
194
|
-
from voxcity.
|
|
194
|
+
from voxcity.geoprocessor.draw import center_location_map_cityname
|
|
195
195
|
|
|
196
196
|
width = 500
|
|
197
197
|
height = 500
|
|
@@ -224,7 +224,7 @@ kwargs = {
|
|
|
224
224
|
Generate voxel data grids and corresponding building geoJSON:
|
|
225
225
|
|
|
226
226
|
```python
|
|
227
|
-
from voxcity import get_voxcity
|
|
227
|
+
from voxcity.generator import get_voxcity
|
|
228
228
|
|
|
229
229
|
voxcity_grid, building_height_grid, building_min_height_grid, \
|
|
230
230
|
building_id_grid, canopy_height_grid, land_cover_grid, dem_grid, \
|
|
@@ -245,7 +245,7 @@ building_gdf = get_voxcity(
|
|
|
245
245
|
[ENVI-MET](https://www.envi-met.com/) is an advanced microclimate simulation software specialized in modeling urban environments. It simulates the interactions between buildings, vegetation, and various climate parameters like temperature, wind flow, humidity, and radiation. The software is used widely in urban planning, architecture, and environmental studies (Commercial, offers educational licenses).
|
|
246
246
|
|
|
247
247
|
```python
|
|
248
|
-
from voxcity.
|
|
248
|
+
from voxcity.exporter.envimet import export_inx, generate_edb_file
|
|
249
249
|
|
|
250
250
|
envimet_kwargs = {
|
|
251
251
|
"output_directory": "output", # Directory where output files will be saved
|
|
@@ -271,7 +271,7 @@ generate_edb_file(**envimet_kwargs)
|
|
|
271
271
|
#### OBJ Files:
|
|
272
272
|
|
|
273
273
|
```python
|
|
274
|
-
from voxcity.
|
|
274
|
+
from voxcity.exporter.obj import export_obj
|
|
275
275
|
|
|
276
276
|
output_directory = "output" # Directory where output files will be saved
|
|
277
277
|
output_file_name = "voxcity" # Base name for the output OBJ file
|
|
@@ -295,7 +295,7 @@ The generated OBJ files can be opened and rendered in the following 3D visualiza
|
|
|
295
295
|
[MagicaVoxel](https://ephtracy.github.io/) is a lightweight and user-friendly voxel art editor. It allows users to create, edit, and render voxel-based 3D models with an intuitive interface, making it perfect for modifying and visualizing voxelized city models. The software is free and available for Windows and Mac.
|
|
296
296
|
|
|
297
297
|
```python
|
|
298
|
-
from voxcity.
|
|
298
|
+
from voxcity.exporter.magicavoxel import export_magicavoxel_vox
|
|
299
299
|
|
|
300
300
|
output_path = "output"
|
|
301
301
|
base_filename = "voxcity"
|
|
@@ -313,7 +313,7 @@ export_magicavoxel_vox(voxcity_grid, output_path, base_filename=base_filename)
|
|
|
313
313
|
#### Compute Solar Irradiance:
|
|
314
314
|
|
|
315
315
|
```python
|
|
316
|
-
from voxcity.
|
|
316
|
+
from voxcity.simulator.solar import get_global_solar_irradiance_using_epw
|
|
317
317
|
|
|
318
318
|
solar_kwargs = {
|
|
319
319
|
"download_nearest_epw": True, # Whether to automatically download nearest EPW weather file based on location from Climate.OneBuilding.Org
|
|
@@ -369,7 +369,7 @@ cum_solar_grid = get_global_solar_irradiance_using_epw(
|
|
|
369
369
|
#### Compute Green View Index (GVI) and Sky View Index (SVI):
|
|
370
370
|
|
|
371
371
|
```python
|
|
372
|
-
from voxcity.
|
|
372
|
+
from voxcity.simulator.view import get_view_index
|
|
373
373
|
|
|
374
374
|
view_kwargs = {
|
|
375
375
|
"view_point_height": 1.5, # Height of observer viewpoint in meters
|
|
@@ -401,7 +401,7 @@ svi_grid = get_view_index(voxcity_grid, meshsize, mode='sky', **view_kwargs)
|
|
|
401
401
|
#### Landmark Visibility Map:
|
|
402
402
|
|
|
403
403
|
```python
|
|
404
|
-
from voxcity.
|
|
404
|
+
from voxcity.simulator.view import get_landmark_visibility_map
|
|
405
405
|
|
|
406
406
|
# Dictionary of parameters for landmark visibility analysis
|
|
407
407
|
landmark_kwargs = {
|
|
@@ -425,7 +425,7 @@ landmark_vis_map = get_landmark_visibility_map(voxcity_grid, building_id_grid, b
|
|
|
425
425
|
#### Network Analysis:
|
|
426
426
|
|
|
427
427
|
```python
|
|
428
|
-
from voxcity.
|
|
428
|
+
from voxcity.geoprocessor.network import get_network_values
|
|
429
429
|
|
|
430
430
|
network_kwargs = {
|
|
431
431
|
"network_type": "walk", # Type of network to download from OSM (walk, drive, all, etc.)
|
|
@@ -12,26 +12,26 @@ voxcity/downloader/utils.py,sha256=z6MdPxM96FWQVqvZW2Eg5pMewVHVysUP7F6ueeCwMfI,1
|
|
|
12
12
|
voxcity/exporter/__init_.py,sha256=cVyNyE6axEpSd3CT5hGuMOAlOyU1p8lVP4jkF1-0Ad8,94
|
|
13
13
|
voxcity/exporter/envimet.py,sha256=m-y2IYw-yp45AT2wN9UIlxvMjvDvupTKzyfRJl057fE,24300
|
|
14
14
|
voxcity/exporter/magicavoxel.py,sha256=Fsv7yGRXeKmp82xcG3rOb0t_HtoqltNq2tHl08xVlqY,7500
|
|
15
|
-
voxcity/exporter/obj.py,sha256=
|
|
15
|
+
voxcity/exporter/obj.py,sha256=0RBFPMKGRH6uNmCLIwAoYFko1bOZKtTSwg7QnoPMud0,21593
|
|
16
16
|
voxcity/geoprocessor/__init_.py,sha256=JzPVhhttxBWvaZ0IGX2w7OWL5bCo_TIvpHefWeNXruA,133
|
|
17
17
|
voxcity/geoprocessor/draw.py,sha256=8Em2NvazFpYfFJUqG9LofNXaxdghKLL_rNuztmPwn8Q,13911
|
|
18
|
-
voxcity/geoprocessor/grid.py,sha256=
|
|
19
|
-
voxcity/geoprocessor/mesh.py,sha256=
|
|
18
|
+
voxcity/geoprocessor/grid.py,sha256=t-KAdYOk1iUeBuOMcoAb5e4hzJjMIfVItTdFP6FJs1A,44340
|
|
19
|
+
voxcity/geoprocessor/mesh.py,sha256=z6e-BigN_K1CGpS9mopkf121pbCnBFJMu32XYfqpLI4,10506
|
|
20
20
|
voxcity/geoprocessor/network.py,sha256=opb_kpUCAxDd1qtrWPStqR5reYZtVe96XxazNSen7Lk,18851
|
|
21
|
-
voxcity/geoprocessor/polygon.py,sha256=
|
|
21
|
+
voxcity/geoprocessor/polygon.py,sha256=wXU3K-lghAlAOe_C-m1YD4_75DvCWzdszuWieenP5mA,37208
|
|
22
22
|
voxcity/geoprocessor/utils.py,sha256=1BRHp-DDeOA8HG8jplY7Eo75G3oXkVGL6DGONL4BA8A,19815
|
|
23
23
|
voxcity/simulator/__init_.py,sha256=APdkcdaovj0v_RPOaA4SBvFUKT2RM7Hxuuz3Sux4gCo,65
|
|
24
|
-
voxcity/simulator/solar.py,sha256=
|
|
24
|
+
voxcity/simulator/solar.py,sha256=7IGmCCYsAnBguID2IT2xjzfbK7msxakaJ0_0Eu0cvX0,58607
|
|
25
25
|
voxcity/simulator/utils.py,sha256=sEYBB2-hLJxTiXQps1_-Fi7t1HN3-1OPOvBCWtgIisA,130
|
|
26
|
-
voxcity/simulator/view.py,sha256=
|
|
26
|
+
voxcity/simulator/view.py,sha256=iNJxeY3HH3YNAF0nh6HxthyW001HNH4wvLZFp7_YkS8,63669
|
|
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=
|
|
31
|
-
voxcity/utils/weather.py,sha256=
|
|
32
|
-
voxcity-0.
|
|
33
|
-
voxcity-0.
|
|
34
|
-
voxcity-0.
|
|
35
|
-
voxcity-0.
|
|
36
|
-
voxcity-0.
|
|
37
|
-
voxcity-0.
|
|
30
|
+
voxcity/utils/visualization.py,sha256=8r7ffnvBCAmvEYnJQ4KKh18aaah3G9ARoV9EDXUyo8I,85255
|
|
31
|
+
voxcity/utils/weather.py,sha256=CFPtoqRTajwMRswswDChwQ3BW1cGsnA3orgWHgz7Ehg,26304
|
|
32
|
+
voxcity-0.4.2.dist-info/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
|
|
33
|
+
voxcity-0.4.2.dist-info/LICENSE,sha256=-hGliOFiwUrUSoZiB5WF90xXGqinKyqiDI2t6hrnam8,1087
|
|
34
|
+
voxcity-0.4.2.dist-info/METADATA,sha256=LKhFX_8JNN3pafmDgzH2f5ZhIBryTgql-BL9HxrdA28,25527
|
|
35
|
+
voxcity-0.4.2.dist-info/WHEEL,sha256=EaM1zKIUYa7rQnxGiOCGhzJABRwy4WO57rWMR3_tj4I,91
|
|
36
|
+
voxcity-0.4.2.dist-info/top_level.txt,sha256=00b2U-LKfDllt6RL1R33MXie5MvxzUFye0NGD96t_8I,8
|
|
37
|
+
voxcity-0.4.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|