voxcity 0.4.1__tar.gz → 0.4.2__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.
- {voxcity-0.4.1 → voxcity-0.4.2}/PKG-INFO +1 -1
- {voxcity-0.4.1 → voxcity-0.4.2}/pyproject.toml +1 -1
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/utils/visualization.py +23 -10
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/utils/weather.py +98 -5
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity.egg-info/PKG-INFO +1 -1
- {voxcity-0.4.1 → voxcity-0.4.2}/AUTHORS.rst +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/CONTRIBUTING.rst +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/HISTORY.rst +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/LICENSE +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/MANIFEST.in +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/README.md +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/docs/Makefile +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/docs/archive/README.rst +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/docs/authors.rst +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/docs/conf.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/docs/index.rst +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/docs/make.bat +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/setup.cfg +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/__init__.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/__init__.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/eubucco.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/gee.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/mbfp.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/oemj.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/omt.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/osm.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/overture.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/utils.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/exporter/__init_.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/exporter/envimet.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/exporter/magicavoxel.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/exporter/obj.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/generator.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/__init_.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/draw.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/grid.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/mesh.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/network.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/polygon.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/utils.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/simulator/__init_.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/simulator/solar.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/simulator/utils.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/simulator/view.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/utils/__init_.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/utils/lc.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/utils/material.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity.egg-info/SOURCES.txt +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity.egg-info/dependency_links.txt +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity.egg-info/requires.txt +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity.egg-info/top_level.txt +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/tests/__init__.py +0 -0
- {voxcity-0.4.1 → voxcity-0.4.2}/tests/voxelcity.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: voxcity
|
|
3
|
-
Version: 0.4.
|
|
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>
|
|
@@ -1811,6 +1811,18 @@ def visualize_voxcity_with_sim_meshes(voxel_array, meshsize, custom_meshes=None,
|
|
|
1811
1811
|
# Create a copy with colors
|
|
1812
1812
|
vis_mesh = custom_mesh.copy()
|
|
1813
1813
|
vis_mesh.visual.face_colors = face_colors
|
|
1814
|
+
|
|
1815
|
+
# Prepare the colormap and create colorbar
|
|
1816
|
+
norm = mcolors.Normalize(vmin=local_vmin, vmax=local_vmax)
|
|
1817
|
+
scalar_map = cm.ScalarMappable(norm=norm, cmap=cmap_name)
|
|
1818
|
+
|
|
1819
|
+
# Create a figure and axis for the colorbar but don't display
|
|
1820
|
+
fig, ax = plt.subplots(figsize=(6, 1))
|
|
1821
|
+
cbar = plt.colorbar(scalar_map, cax=ax, orientation='horizontal')
|
|
1822
|
+
if colorbar_title:
|
|
1823
|
+
cbar.set_label(colorbar_title)
|
|
1824
|
+
plt.tight_layout()
|
|
1825
|
+
plt.show()
|
|
1814
1826
|
|
|
1815
1827
|
if class_id in meshes:
|
|
1816
1828
|
print(f"Replacing voxel class {class_id} with colored custom simulation mesh")
|
|
@@ -1849,17 +1861,17 @@ def visualize_voxcity_with_sim_meshes(voxel_array, meshsize, custom_meshes=None,
|
|
|
1849
1861
|
if sim_mesh is not None:
|
|
1850
1862
|
meshes["sim_surface"] = sim_mesh
|
|
1851
1863
|
|
|
1852
|
-
# Prepare the colormap and create colorbar
|
|
1853
|
-
norm = mcolors.Normalize(vmin=vmin, vmax=vmax)
|
|
1854
|
-
scalar_map = cm.ScalarMappable(norm=norm, cmap=cmap_name)
|
|
1864
|
+
# # Prepare the colormap and create colorbar
|
|
1865
|
+
# norm = mcolors.Normalize(vmin=vmin, vmax=vmax)
|
|
1866
|
+
# scalar_map = cm.ScalarMappable(norm=norm, cmap=cmap_name)
|
|
1855
1867
|
|
|
1856
|
-
# Create a figure and axis for the colorbar but don't display
|
|
1857
|
-
fig, ax = plt.subplots(figsize=(6, 1))
|
|
1858
|
-
cbar = plt.colorbar(scalar_map, cax=ax, orientation='horizontal')
|
|
1859
|
-
if colorbar_title:
|
|
1860
|
-
|
|
1861
|
-
plt.tight_layout()
|
|
1862
|
-
plt.show()
|
|
1868
|
+
# # Create a figure and axis for the colorbar but don't display
|
|
1869
|
+
# fig, ax = plt.subplots(figsize=(6, 1))
|
|
1870
|
+
# cbar = plt.colorbar(scalar_map, cax=ax, orientation='horizontal')
|
|
1871
|
+
# if colorbar_title:
|
|
1872
|
+
# cbar.set_label(colorbar_title)
|
|
1873
|
+
# plt.tight_layout()
|
|
1874
|
+
# plt.show()
|
|
1863
1875
|
|
|
1864
1876
|
# Export if filename provided
|
|
1865
1877
|
if base_filename is not None:
|
|
@@ -1868,6 +1880,7 @@ def visualize_voxcity_with_sim_meshes(voxel_array, meshsize, custom_meshes=None,
|
|
|
1868
1880
|
os.makedirs(output_directory, exist_ok=True)
|
|
1869
1881
|
export_meshes(meshes, output_directory, base_filename)
|
|
1870
1882
|
|
|
1883
|
+
|
|
1871
1884
|
# Create and save multiple views
|
|
1872
1885
|
print("Creating multiple views...")
|
|
1873
1886
|
# Create output directory if it doesn't exist
|
|
@@ -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.4.
|
|
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>
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|