voxcity 0.6.13__tar.gz → 0.6.15__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.
- {voxcity-0.6.13 → voxcity-0.6.15}/PKG-INFO +1 -1
- {voxcity-0.6.13 → voxcity-0.6.15}/pyproject.toml +1 -1
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/geoprocessor/draw.py +84 -10
- {voxcity-0.6.13 → voxcity-0.6.15}/AUTHORS.rst +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/LICENSE +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/README.md +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/__init__.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/downloader/__init__.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/downloader/citygml.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/downloader/eubucco.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/downloader/gee.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/downloader/mbfp.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/downloader/oemj.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/downloader/osm.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/downloader/overture.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/downloader/utils.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/exporter/__init__.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/exporter/cityles.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/exporter/envimet.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/exporter/magicavoxel.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/exporter/obj.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/generator.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/geoprocessor/__init__.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/geoprocessor/grid.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/geoprocessor/mesh.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/geoprocessor/network.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/geoprocessor/polygon.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/geoprocessor/utils.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/simulator/__init__.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/simulator/solar.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/simulator/utils.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/simulator/view.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/utils/__init__.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/utils/lc.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/utils/material.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/utils/visualization.py +0 -0
- {voxcity-0.6.13 → voxcity-0.6.15}/src/voxcity/utils/weather.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "voxcity"
|
|
3
|
-
version = "0.6.
|
|
3
|
+
version = "0.6.15"
|
|
4
4
|
description = "voxcity is an easy and one-stop tool to output 3d city models for microclimate simulation by integrating multiple geospatial open-data"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -39,7 +39,7 @@ from ipyleaflet import (
|
|
|
39
39
|
from geopy import distance
|
|
40
40
|
import shapely.geometry as geom
|
|
41
41
|
import geopandas as gpd
|
|
42
|
-
from ipywidgets import VBox, HBox, Button, FloatText, Label, Output, HTML
|
|
42
|
+
from ipywidgets import VBox, HBox, Button, FloatText, Label, Output, HTML, Checkbox
|
|
43
43
|
import pandas as pd
|
|
44
44
|
from IPython.display import display, clear_output
|
|
45
45
|
|
|
@@ -934,6 +934,7 @@ def draw_additional_trees(tree_gdf=None, initial_center=None, zoom=17, rectangle
|
|
|
934
934
|
top_height_input = FloatText(value=10.0, description='Top height (m):', disabled=False, style={'description_width': 'initial'})
|
|
935
935
|
bottom_height_input = FloatText(value=4.0, description='Bottom height (m):', disabled=False, style={'description_width': 'initial'})
|
|
936
936
|
crown_diameter_input = FloatText(value=6.0, description='Crown diameter (m):', disabled=False, style={'description_width': 'initial'})
|
|
937
|
+
fixed_prop_checkbox = Checkbox(value=True, description='Fixed proportion', indent=False)
|
|
937
938
|
|
|
938
939
|
add_mode_button = Button(description='Add', button_style='success')
|
|
939
940
|
remove_mode_button = Button(description='Remove', button_style='')
|
|
@@ -947,6 +948,7 @@ def draw_additional_trees(tree_gdf=None, initial_center=None, zoom=17, rectangle
|
|
|
947
948
|
top_height_input,
|
|
948
949
|
bottom_height_input,
|
|
949
950
|
crown_diameter_input,
|
|
951
|
+
fixed_prop_checkbox,
|
|
950
952
|
hover_info,
|
|
951
953
|
status_output
|
|
952
954
|
])
|
|
@@ -956,6 +958,83 @@ def draw_additional_trees(tree_gdf=None, initial_center=None, zoom=17, rectangle
|
|
|
956
958
|
|
|
957
959
|
# State for mode
|
|
958
960
|
mode = 'add'
|
|
961
|
+
# Fixed proportion state
|
|
962
|
+
base_bottom_ratio = bottom_height_input.value / top_height_input.value if top_height_input.value else 0.4
|
|
963
|
+
base_crown_ratio = crown_diameter_input.value / top_height_input.value if top_height_input.value else 0.6
|
|
964
|
+
updating_params = False
|
|
965
|
+
|
|
966
|
+
def recompute_from_top(new_top: float):
|
|
967
|
+
nonlocal updating_params
|
|
968
|
+
if new_top <= 0:
|
|
969
|
+
return
|
|
970
|
+
new_bottom = max(0.0, base_bottom_ratio * new_top)
|
|
971
|
+
new_crown = max(0.0, base_crown_ratio * new_top)
|
|
972
|
+
updating_params = True
|
|
973
|
+
bottom_height_input.value = new_bottom
|
|
974
|
+
crown_diameter_input.value = new_crown
|
|
975
|
+
updating_params = False
|
|
976
|
+
|
|
977
|
+
def recompute_from_bottom(new_bottom: float):
|
|
978
|
+
nonlocal updating_params
|
|
979
|
+
if base_bottom_ratio <= 0:
|
|
980
|
+
return
|
|
981
|
+
new_top = max(0.0, new_bottom / base_bottom_ratio)
|
|
982
|
+
new_crown = max(0.0, base_crown_ratio * new_top)
|
|
983
|
+
updating_params = True
|
|
984
|
+
top_height_input.value = new_top
|
|
985
|
+
crown_diameter_input.value = new_crown
|
|
986
|
+
updating_params = False
|
|
987
|
+
|
|
988
|
+
def recompute_from_crown(new_crown: float):
|
|
989
|
+
nonlocal updating_params
|
|
990
|
+
if base_crown_ratio <= 0:
|
|
991
|
+
return
|
|
992
|
+
new_top = max(0.0, new_crown / base_crown_ratio)
|
|
993
|
+
new_bottom = max(0.0, base_bottom_ratio * new_top)
|
|
994
|
+
updating_params = True
|
|
995
|
+
top_height_input.value = new_top
|
|
996
|
+
bottom_height_input.value = new_bottom
|
|
997
|
+
updating_params = False
|
|
998
|
+
|
|
999
|
+
def on_toggle_fixed(change):
|
|
1000
|
+
nonlocal base_bottom_ratio, base_crown_ratio
|
|
1001
|
+
if change['name'] == 'value':
|
|
1002
|
+
if change['new']:
|
|
1003
|
+
# Capture current ratios as baseline
|
|
1004
|
+
top = float(top_height_input.value) or 1.0
|
|
1005
|
+
bot = float(bottom_height_input.value)
|
|
1006
|
+
crn = float(crown_diameter_input.value)
|
|
1007
|
+
base_bottom_ratio = max(0.0, bot / top)
|
|
1008
|
+
base_crown_ratio = max(0.0, crn / top)
|
|
1009
|
+
else:
|
|
1010
|
+
# Keep last ratios but do not auto-update
|
|
1011
|
+
pass
|
|
1012
|
+
|
|
1013
|
+
def on_top_change(change):
|
|
1014
|
+
if change['name'] == 'value' and fixed_prop_checkbox.value and not updating_params:
|
|
1015
|
+
try:
|
|
1016
|
+
recompute_from_top(float(change['new']))
|
|
1017
|
+
except Exception:
|
|
1018
|
+
pass
|
|
1019
|
+
|
|
1020
|
+
def on_bottom_change(change):
|
|
1021
|
+
if change['name'] == 'value' and fixed_prop_checkbox.value and not updating_params:
|
|
1022
|
+
try:
|
|
1023
|
+
recompute_from_bottom(float(change['new']))
|
|
1024
|
+
except Exception:
|
|
1025
|
+
pass
|
|
1026
|
+
|
|
1027
|
+
def on_crown_change(change):
|
|
1028
|
+
if change['name'] == 'value' and fixed_prop_checkbox.value and not updating_params:
|
|
1029
|
+
try:
|
|
1030
|
+
recompute_from_crown(float(change['new']))
|
|
1031
|
+
except Exception:
|
|
1032
|
+
pass
|
|
1033
|
+
|
|
1034
|
+
fixed_prop_checkbox.observe(on_toggle_fixed, names='value')
|
|
1035
|
+
top_height_input.observe(on_top_change, names='value')
|
|
1036
|
+
bottom_height_input.observe(on_bottom_change, names='value')
|
|
1037
|
+
crown_diameter_input.observe(on_crown_change, names='value')
|
|
959
1038
|
|
|
960
1039
|
def set_mode(new_mode):
|
|
961
1040
|
nonlocal mode
|
|
@@ -1017,10 +1096,7 @@ def draw_additional_trees(tree_gdf=None, initial_center=None, zoom=17, rectangle
|
|
|
1017
1096
|
|
|
1018
1097
|
tree_layers[next_tree_id] = circle
|
|
1019
1098
|
|
|
1020
|
-
|
|
1021
|
-
print(f"Tree {next_tree_id} added at (lon, lat)=({lon:.6f}, {lat:.6f})")
|
|
1022
|
-
print(f"Top: {new_row['top_height']} m, Bottom: {new_row['bottom_height']} m, Crown: {new_row['crown_diameter']} m")
|
|
1023
|
-
print(f"Total trees: {len(updated_trees)}")
|
|
1099
|
+
# Suppress status prints on add
|
|
1024
1100
|
else:
|
|
1025
1101
|
# Remove mode: find the nearest tree within its crown radius + 5m
|
|
1026
1102
|
candidate_id = None
|
|
@@ -1048,12 +1124,10 @@ def draw_additional_trees(tree_gdf=None, initial_center=None, zoom=17, rectangle
|
|
|
1048
1124
|
# Remove from gdf
|
|
1049
1125
|
updated_trees.drop(index=candidate_idx, inplace=True)
|
|
1050
1126
|
updated_trees.reset_index(drop=True, inplace=True)
|
|
1051
|
-
|
|
1052
|
-
print(f"Removed tree {candidate_id} (distance {candidate_dist:.2f} m)")
|
|
1053
|
-
print(f"Total trees: {len(updated_trees)}")
|
|
1127
|
+
# Suppress status prints on remove
|
|
1054
1128
|
else:
|
|
1055
|
-
|
|
1056
|
-
|
|
1129
|
+
# Suppress status prints when nothing to remove
|
|
1130
|
+
pass
|
|
1057
1131
|
elif kwargs.get('type') == 'mousemove':
|
|
1058
1132
|
lat, lon = kwargs.get('coordinates', (None, None))
|
|
1059
1133
|
if lat is None or lon is None:
|
|
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
|