voxcity 0.6.12__tar.gz → 0.6.14__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.

Files changed (37) hide show
  1. {voxcity-0.6.12 → voxcity-0.6.14}/PKG-INFO +1 -1
  2. {voxcity-0.6.12 → voxcity-0.6.14}/pyproject.toml +1 -1
  3. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/geoprocessor/draw.py +95 -6
  4. {voxcity-0.6.12 → voxcity-0.6.14}/AUTHORS.rst +0 -0
  5. {voxcity-0.6.12 → voxcity-0.6.14}/LICENSE +0 -0
  6. {voxcity-0.6.12 → voxcity-0.6.14}/README.md +0 -0
  7. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/__init__.py +0 -0
  8. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/downloader/__init__.py +0 -0
  9. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/downloader/citygml.py +0 -0
  10. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/downloader/eubucco.py +0 -0
  11. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/downloader/gee.py +0 -0
  12. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/downloader/mbfp.py +0 -0
  13. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/downloader/oemj.py +0 -0
  14. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/downloader/osm.py +0 -0
  15. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/downloader/overture.py +0 -0
  16. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/downloader/utils.py +0 -0
  17. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/exporter/__init__.py +0 -0
  18. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/exporter/cityles.py +0 -0
  19. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/exporter/envimet.py +0 -0
  20. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/exporter/magicavoxel.py +0 -0
  21. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/exporter/obj.py +0 -0
  22. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/generator.py +0 -0
  23. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/geoprocessor/__init__.py +0 -0
  24. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/geoprocessor/grid.py +0 -0
  25. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/geoprocessor/mesh.py +0 -0
  26. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/geoprocessor/network.py +0 -0
  27. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/geoprocessor/polygon.py +0 -0
  28. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/geoprocessor/utils.py +0 -0
  29. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/simulator/__init__.py +0 -0
  30. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/simulator/solar.py +0 -0
  31. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/simulator/utils.py +0 -0
  32. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/simulator/view.py +0 -0
  33. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/utils/__init__.py +0 -0
  34. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/utils/lc.py +0 -0
  35. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/utils/material.py +0 -0
  36. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/utils/visualization.py +0 -0
  37. {voxcity-0.6.12 → voxcity-0.6.14}/src/voxcity/utils/weather.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: voxcity
3
- Version: 0.6.12
3
+ Version: 0.6.14
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
  Author: Kunihiko Fujiwara
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "voxcity"
3
- version = "0.6.12"
3
+ version = "0.6.14"
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"
@@ -33,12 +33,13 @@ from ipyleaflet import (
33
33
  WidgetControl,
34
34
  Circle,
35
35
  basemaps,
36
- basemap_to_tiles
36
+ basemap_to_tiles,
37
+ TileLayer
37
38
  )
38
39
  from geopy import distance
39
40
  import shapely.geometry as geom
40
41
  import geopandas as gpd
41
- from ipywidgets import VBox, HBox, Button, FloatText, Label, Output, HTML
42
+ from ipywidgets import VBox, HBox, Button, FloatText, Label, Output, HTML, Checkbox
42
43
  import pandas as pd
43
44
  from IPython.display import display, clear_output
44
45
 
@@ -885,12 +886,21 @@ def draw_additional_trees(tree_gdf=None, initial_center=None, zoom=17, rectangle
885
886
 
886
887
  # Create map
887
888
  m = Map(center=(center_lat, center_lon), zoom=zoom, scroll_wheel_zoom=True)
888
- # Add aerial/satellite basemap
889
+ # Add Google Satellite basemap with Esri fallback
889
890
  try:
890
- m.add_layer(basemap_to_tiles(basemaps.Esri.WorldImagery))
891
+ google_sat = TileLayer(
892
+ url='https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}',
893
+ name='Google Satellite',
894
+ attribution='Google Satellite'
895
+ )
896
+ # Replace default base layer with Google Satellite
897
+ m.layers = tuple([google_sat])
891
898
  except Exception:
892
- # Fallback silently if basemap cannot be added
893
- pass
899
+ try:
900
+ m.layers = tuple([basemap_to_tiles(basemaps.Esri.WorldImagery)])
901
+ except Exception:
902
+ # Fallback silently if basemap cannot be added
903
+ pass
894
904
 
895
905
  # If rectangle_vertices provided, draw its edges on the map
896
906
  if rectangle_vertices is not None and len(rectangle_vertices) >= 4:
@@ -924,6 +934,7 @@ def draw_additional_trees(tree_gdf=None, initial_center=None, zoom=17, rectangle
924
934
  top_height_input = FloatText(value=10.0, description='Top height (m):', disabled=False, style={'description_width': 'initial'})
925
935
  bottom_height_input = FloatText(value=4.0, description='Bottom height (m):', disabled=False, style={'description_width': 'initial'})
926
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)
927
938
 
928
939
  add_mode_button = Button(description='Add', button_style='success')
929
940
  remove_mode_button = Button(description='Remove', button_style='')
@@ -937,6 +948,7 @@ def draw_additional_trees(tree_gdf=None, initial_center=None, zoom=17, rectangle
937
948
  top_height_input,
938
949
  bottom_height_input,
939
950
  crown_diameter_input,
951
+ fixed_prop_checkbox,
940
952
  hover_info,
941
953
  status_output
942
954
  ])
@@ -946,6 +958,83 @@ def draw_additional_trees(tree_gdf=None, initial_center=None, zoom=17, rectangle
946
958
 
947
959
  # State for mode
948
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')
949
1038
 
950
1039
  def set_mode(new_mode):
951
1040
  nonlocal mode
File without changes
File without changes
File without changes