voxcity 0.3.3__tar.gz → 0.3.5__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 (54) hide show
  1. {voxcity-0.3.3 → voxcity-0.3.5}/PKG-INFO +6 -5
  2. {voxcity-0.3.3 → voxcity-0.3.5}/README.md +4 -4
  3. {voxcity-0.3.3 → voxcity-0.3.5}/pyproject.toml +2 -1
  4. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/download/eubucco.py +9 -17
  5. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/download/gee.py +4 -3
  6. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/download/mbfp.py +7 -7
  7. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/download/oemj.py +22 -22
  8. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/download/omt.py +10 -10
  9. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/download/osm.py +23 -21
  10. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/download/overture.py +7 -15
  11. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/file/envimet.py +4 -4
  12. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/file/geojson.py +25 -39
  13. voxcity-0.3.5/src/voxcity/geo/__init_.py +4 -0
  14. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/geo/draw.py +41 -45
  15. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/geo/grid.py +68 -145
  16. voxcity-0.3.5/src/voxcity/geo/network.py +193 -0
  17. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/geo/utils.py +79 -66
  18. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/sim/solar.py +5 -5
  19. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/sim/view.py +5 -5
  20. voxcity-0.3.5/src/voxcity/utils/__init_.py +4 -0
  21. voxcity-0.3.5/src/voxcity/utils/material.py +139 -0
  22. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/utils/visualization.py +128 -354
  23. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/utils/weather.py +7 -7
  24. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/voxcity.py +56 -8
  25. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity.egg-info/PKG-INFO +6 -5
  26. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity.egg-info/SOURCES.txt +2 -0
  27. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity.egg-info/requires.txt +1 -0
  28. voxcity-0.3.3/src/voxcity/geo/__init_.py +0 -3
  29. voxcity-0.3.3/src/voxcity/utils/__init_.py +0 -3
  30. {voxcity-0.3.3 → voxcity-0.3.5}/AUTHORS.rst +0 -0
  31. {voxcity-0.3.3 → voxcity-0.3.5}/CONTRIBUTING.rst +0 -0
  32. {voxcity-0.3.3 → voxcity-0.3.5}/HISTORY.rst +0 -0
  33. {voxcity-0.3.3 → voxcity-0.3.5}/LICENSE +0 -0
  34. {voxcity-0.3.3 → voxcity-0.3.5}/MANIFEST.in +0 -0
  35. {voxcity-0.3.3 → voxcity-0.3.5}/docs/Makefile +0 -0
  36. {voxcity-0.3.3 → voxcity-0.3.5}/docs/archive/README.rst +0 -0
  37. {voxcity-0.3.3 → voxcity-0.3.5}/docs/authors.rst +0 -0
  38. {voxcity-0.3.3 → voxcity-0.3.5}/docs/conf.py +0 -0
  39. {voxcity-0.3.3 → voxcity-0.3.5}/docs/index.rst +0 -0
  40. {voxcity-0.3.3 → voxcity-0.3.5}/docs/make.bat +0 -0
  41. {voxcity-0.3.3 → voxcity-0.3.5}/setup.cfg +0 -0
  42. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/__init__.py +0 -0
  43. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/download/__init__.py +0 -0
  44. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/download/utils.py +0 -0
  45. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/file/__init_.py +0 -0
  46. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/file/magicavoxel.py +0 -0
  47. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/file/obj.py +0 -0
  48. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/sim/__init_.py +0 -0
  49. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/sim/utils.py +0 -0
  50. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity/utils/lc.py +0 -0
  51. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity.egg-info/dependency_links.txt +0 -0
  52. {voxcity-0.3.3 → voxcity-0.3.5}/src/voxcity.egg-info/top_level.txt +0 -0
  53. {voxcity-0.3.3 → voxcity-0.3.5}/tests/__init__.py +0 -0
  54. {voxcity-0.3.3 → voxcity-0.3.5}/tests/voxelcity.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: voxcity
3
- Version: 0.3.3
3
+ Version: 0.3.5
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>
@@ -48,6 +48,7 @@ Requires-Dist: overturemaps
48
48
  Requires-Dist: protobuf==3.20.3
49
49
  Requires-Dist: timezonefinder
50
50
  Requires-Dist: astral
51
+ Requires-Dist: osmnx
51
52
  Provides-Extra: dev
52
53
  Requires-Dist: coverage; extra == "dev"
53
54
  Requires-Dist: mypy; extra == "dev"
@@ -164,10 +165,10 @@ Define the target area by directly specifying the coordinates of the rectangle v
164
165
 
165
166
  ```python
166
167
  rectangle_vertices = [
167
- (47.59830044521263, -122.33587348582083), # Southwest corner (latitude, longitude)
168
- (47.60279755390168, -122.33587348582083), # Northwest corner (latitude, longitude)
169
- (47.60279755390168, -122.32922451417917), # Northeast corner (latitude, longitude)
170
- (47.59830044521263, -122.32922451417917) # Southeast corner (latitude, longitude)
168
+ (-122.33587348582083, 47.59830044521263), # Southwest corner (longitude, latitude)
169
+ (-122.33587348582083, 47.60279755390168), # Northwest corner (longitude, latitude)
170
+ (-122.32922451417917, 47.60279755390168), # Northeast corner (longitude, latitude)
171
+ (-122.32922451417917, 47.59830044521263) # Southeast corner (longitude, latitude)
171
172
  ]
172
173
  ```
173
174
 
@@ -108,10 +108,10 @@ Define the target area by directly specifying the coordinates of the rectangle v
108
108
 
109
109
  ```python
110
110
  rectangle_vertices = [
111
- (47.59830044521263, -122.33587348582083), # Southwest corner (latitude, longitude)
112
- (47.60279755390168, -122.33587348582083), # Northwest corner (latitude, longitude)
113
- (47.60279755390168, -122.32922451417917), # Northeast corner (latitude, longitude)
114
- (47.59830044521263, -122.32922451417917) # Southeast corner (latitude, longitude)
111
+ (-122.33587348582083, 47.59830044521263), # Southwest corner (longitude, latitude)
112
+ (-122.33587348582083, 47.60279755390168), # Northwest corner (longitude, latitude)
113
+ (-122.32922451417917, 47.60279755390168), # Northeast corner (longitude, latitude)
114
+ (-122.32922451417917, 47.59830044521263) # Southeast corner (longitude, latitude)
115
115
  ]
116
116
  ```
117
117
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "voxcity"
3
- version = "0.3.3"
3
+ version = "0.3.5"
4
4
  requires-python = ">=3.10,<3.13"
5
5
  classifiers = [
6
6
  "Programming Language :: Python :: 3.10",
@@ -50,6 +50,7 @@ dependencies = [
50
50
  "protobuf==3.20.3",
51
51
  "timezonefinder",
52
52
  "astral",
53
+ "osmnx",
53
54
  ]
54
55
 
55
56
  [project.optional-dependencies]
@@ -68,16 +68,11 @@ def filter_and_convert_gdf_to_geojson_eubucco(gpkg_file, layer_name, rectangle_v
68
68
  Parameters:
69
69
  - gpkg_file (str): Path to the GeoPackage file.
70
70
  - layer_name (str): Name of the layer within the GeoPackage to process.
71
- - rectangle_vertices (list of tuples): List of (latitude, longitude) tuples defining the rectangle.
71
+ - rectangle_vertices (list of tuples): List of (longitude, latitude) tuples defining the rectangle.
72
72
  - output_geojson (str): Path to the output GeoJSON file.
73
73
  """
74
- # Convert rectangle vertices from (lat,lon) to (lon,lat) format and create polygon
75
- rectangle_vertices_lonlat = [(lon, lat) for lat, lon in rectangle_vertices]
76
- rectangle_polygon = Polygon(rectangle_vertices_lonlat)
77
-
78
- # Helper function to swap coordinate order
79
- def swap_coordinates_gdf(x, y, z=None):
80
- return y, x
74
+ # Create polygon from rectangle vertices (already in lon,lat format)
75
+ rectangle_polygon = Polygon(rectangle_vertices)
81
76
 
82
77
  # Get Shapely version for compatibility checks
83
78
  shapely_version = shapely.__version__
@@ -165,13 +160,10 @@ def filter_and_convert_gdf_to_geojson_eubucco(gpkg_file, layer_name, rectangle_v
165
160
  else:
166
161
  shapely_transformed_poly = poly
167
162
 
168
- # Swap coordinates to (lat,lon) format
169
- swapped_poly = transform(swap_coordinates_gdf, shapely_transformed_poly)
170
-
171
- # Extract polygon coordinates
163
+ # Extract polygon coordinates (already in lon,lat format)
172
164
  coords = []
173
- coords.append(list(swapped_poly.exterior.coords)) # Exterior ring
174
- for interior in swapped_poly.interiors: # Interior rings (holes)
165
+ coords.append(list(shapely_transformed_poly.exterior.coords)) # Exterior ring
166
+ for interior in shapely_transformed_poly.interiors: # Interior rings (holes)
175
167
  coords.append(list(interior.coords))
176
168
 
177
169
  # Create GeoJSON geometry
@@ -259,7 +251,7 @@ def save_geojson_from_eubucco(rectangle_vertices, country_links, output_dir, fil
259
251
  Downloads, extracts, filters, and converts GeoPackage data to GeoJSON based on the rectangle vertices.
260
252
 
261
253
  Parameters:
262
- - rectangle_vertices (list of tuples): List of (latitude, longitude) tuples defining the rectangle.
254
+ - rectangle_vertices (list of tuples): List of (longitude, latitude) tuples defining the rectangle.
263
255
  - country_links (dict): Dictionary mapping country names to their respective GeoPackage URLs.
264
256
  - output_dir (str): Directory to save output files
265
257
  - file_name (str): Name for output GeoJSON file
@@ -268,7 +260,7 @@ def save_geojson_from_eubucco(rectangle_vertices, country_links, output_dir, fil
268
260
  - None: Writes the output to a GeoJSON file.
269
261
  """
270
262
  # Determine country based on first vertex
271
- country_name = get_country_name(rectangle_vertices[0][0], rectangle_vertices[0][1])
263
+ country_name = get_country_name(rectangle_vertices[0][0], rectangle_vertices[0][1]) # Swap order for get_country_name
272
264
  if country_name in country_links:
273
265
  url = country_links[country_name]
274
266
  else:
@@ -304,7 +296,7 @@ def load_geojson_from_eubucco(rectangle_vertices, output_dir):
304
296
  Downloads EUBUCCO data and loads it as GeoJSON.
305
297
 
306
298
  Parameters:
307
- - rectangle_vertices (list of tuples): List of (latitude, longitude) tuples defining the area
299
+ - rectangle_vertices (list of tuples): List of (longitude, latitude) tuples defining the area
308
300
  - output_dir (str): Directory to save intermediate files
309
301
 
310
302
  Returns:
@@ -11,7 +11,7 @@ import ee
11
11
  import geemap
12
12
 
13
13
  # Local imports
14
- from ..geo.utils import convert_format_lat_lon
14
+ # from ..geo.utils import convert_format_lat_lon
15
15
 
16
16
  def initialize_earth_engine():
17
17
  """Initialize the Earth Engine API."""
@@ -21,12 +21,13 @@ def get_roi(input_coords):
21
21
  """Create an Earth Engine region of interest polygon from coordinates.
22
22
 
23
23
  Args:
24
- input_coords: List of coordinate pairs defining the polygon vertices
24
+ input_coords: List of coordinate pairs defining the polygon vertices in (lon, lat) format
25
25
 
26
26
  Returns:
27
27
  ee.Geometry.Polygon: Earth Engine polygon geometry
28
28
  """
29
- coords = convert_format_lat_lon(input_coords)
29
+ coords = input_coords.copy()
30
+ coords.append(input_coords[0])
30
31
  return ee.Geometry.Polygon(coords)
31
32
 
32
33
  def get_center_point(roi):
@@ -40,13 +40,13 @@ def get_geojson_links(output_dir):
40
40
  df_links = pd.read_csv(filepath, dtype=data_types)
41
41
  return df_links
42
42
 
43
- def find_row_for_location(df, lat, lon):
44
- """Find the dataset row containing building data for a given lat/lon coordinate.
43
+ def find_row_for_location(df, lon, lat):
44
+ """Find the dataset row containing building data for a given lon/lat coordinate.
45
45
 
46
46
  Args:
47
47
  df: DataFrame containing dataset links
48
- lat: Latitude coordinate to search for
49
48
  lon: Longitude coordinate to search for
49
+ lat: Latitude coordinate to search for
50
50
 
51
51
  Returns:
52
52
  pandas.Series: Matching row from DataFrame, or None if no match found
@@ -57,7 +57,7 @@ def find_row_for_location(df, lat, lon):
57
57
  continue
58
58
 
59
59
  try:
60
- # Convert lat/lon to tile coordinates at the quadkey's zoom level
60
+ # Convert lon/lat to tile coordinates at the quadkey's zoom level
61
61
  loc_tile_x, loc_tile_y = tile_from_lat_lon(lat, lon, len(quadkey))
62
62
  qk_tile_x, qk_tile_y, _ = quadkey_to_tile(quadkey)
63
63
 
@@ -73,7 +73,7 @@ def get_mbfp_geojson(output_dir, rectangle_vertices):
73
73
 
74
74
  Args:
75
75
  output_dir: Directory to save downloaded files
76
- rectangle_vertices: List of (lat, lon) tuples defining the rectangle corners
76
+ rectangle_vertices: List of (lon, lat) tuples defining the rectangle corners
77
77
 
78
78
  Returns:
79
79
  dict: GeoJSON data containing building footprints
@@ -84,8 +84,8 @@ def get_mbfp_geojson(output_dir, rectangle_vertices):
84
84
  # Find and download files for each vertex of the rectangle
85
85
  filenames = []
86
86
  for vertex in rectangle_vertices:
87
- lat, lon = vertex
88
- row = find_row_for_location(df_links, lat, lon)
87
+ lon, lat = vertex
88
+ row = find_row_for_location(df_links, lon, lat)
89
89
  if row is not None:
90
90
  # Construct filename and download if not already downloaded
91
91
  location = row["Location"]
@@ -15,12 +15,12 @@ import numpy as np
15
15
  from osgeo import gdal, osr
16
16
  import pyproj
17
17
 
18
- def deg2num(lat_deg, lon_deg, zoom):
19
- """Convert latitude/longitude coordinates to tile coordinates.
18
+ def deg2num(lon_deg, lat_deg, zoom):
19
+ """Convert longitude/latitude coordinates to tile coordinates.
20
20
 
21
21
  Args:
22
- lat_deg (float): Latitude in degrees
23
22
  lon_deg (float): Longitude in degrees
23
+ lat_deg (float): Latitude in degrees
24
24
  zoom (int): Zoom level
25
25
 
26
26
  Returns:
@@ -33,7 +33,7 @@ def deg2num(lat_deg, lon_deg, zoom):
33
33
  return (xtile, ytile)
34
34
 
35
35
  def num2deg(xtile, ytile, zoom):
36
- """Convert tile coordinates to latitude/longitude coordinates.
36
+ """Convert tile coordinates to longitude/latitude coordinates.
37
37
 
38
38
  Args:
39
39
  xtile (float): X tile coordinate
@@ -41,19 +41,19 @@ def num2deg(xtile, ytile, zoom):
41
41
  zoom (int): Zoom level
42
42
 
43
43
  Returns:
44
- tuple: (latitude, longitude) in degrees
44
+ tuple: (longitude, latitude) in degrees
45
45
  """
46
46
  n = 2.0 ** zoom
47
47
  lon_deg = xtile / n * 360.0 - 180.0
48
48
  lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))
49
49
  lat_deg = math.degrees(lat_rad)
50
- return (lat_deg, lon_deg)
50
+ return (lon_deg, lat_deg)
51
51
 
52
52
  def download_tiles(polygon, zoom):
53
53
  """Download satellite imagery tiles covering a polygon region.
54
54
 
55
55
  Args:
56
- polygon (list): List of (lat, lon) coordinates defining the region
56
+ polygon (list): List of (lon, lat) coordinates defining the region
57
57
  zoom (int): Zoom level for tile detail
58
58
 
59
59
  Returns:
@@ -62,14 +62,14 @@ def download_tiles(polygon, zoom):
62
62
  print(f"Downloading tiles")
63
63
 
64
64
  # Find bounding box of polygon
65
- min_lat = min(p[0] for p in polygon)
66
- max_lat = max(p[0] for p in polygon)
67
- min_lon = min(p[1] for p in polygon)
68
- max_lon = max(p[1] for p in polygon)
65
+ min_lon = min(p[0] for p in polygon)
66
+ max_lon = max(p[0] for p in polygon)
67
+ min_lat = min(p[1] for p in polygon)
68
+ max_lat = max(p[1] for p in polygon)
69
69
 
70
70
  # Convert to tile coordinates
71
- min_x, max_y = map(math.floor, deg2num(max_lat, min_lon, zoom))
72
- max_x, min_y = map(math.ceil, deg2num(min_lat, max_lon, zoom))
71
+ min_x, max_y = map(math.floor, deg2num(min_lon, max_lat, zoom))
72
+ max_x, min_y = map(math.ceil, deg2num(max_lon, min_lat, zoom))
73
73
 
74
74
  # Download tiles within bounds
75
75
  tiles = {}
@@ -108,7 +108,7 @@ def crop_image(image, polygon, bounds, zoom):
108
108
 
109
109
  Args:
110
110
  image (Image): PIL Image to crop
111
- polygon (list): List of (lat, lon) coordinates
111
+ polygon (list): List of (lon, lat) coordinates
112
112
  bounds (tuple): (min_x, min_y, max_x, max_y) tile bounds
113
113
  zoom (int): Zoom level
114
114
 
@@ -120,8 +120,8 @@ def crop_image(image, polygon, bounds, zoom):
120
120
 
121
121
  # Convert polygon coordinates to pixel coordinates
122
122
  polygon_pixels = []
123
- for lat, lon in polygon:
124
- x, y = deg2num(lat, lon, zoom)
123
+ for lon, lat in polygon:
124
+ x, y = deg2num(lon, lat, zoom)
125
125
  px = (x - min_x) * 256
126
126
  py = (y - min_y) * 256
127
127
  polygon_pixels.append((px, py))
@@ -143,7 +143,7 @@ def save_as_geotiff(image, polygon, zoom, bbox, bounds, output_path):
143
143
 
144
144
  Args:
145
145
  image (Image): PIL Image to save
146
- polygon (list): List of (lat, lon) coordinates
146
+ polygon (list): List of (lon, lat) coordinates
147
147
  zoom (int): Zoom level
148
148
  bbox (tuple): Bounding box of cropped image
149
149
  bounds (tuple): (min_x, min_y, max_x, max_y) tile bounds
@@ -152,8 +152,8 @@ def save_as_geotiff(image, polygon, zoom, bbox, bounds, output_path):
152
152
  min_x, min_y, max_x, max_y = bounds
153
153
 
154
154
  # Calculate georeferencing coordinates
155
- upper_left_lat, upper_left_lon = num2deg(min_x + bbox[0]/256, min_y + bbox[1]/256, zoom)
156
- lower_right_lat, lower_right_lon = num2deg(min_x + bbox[2]/256, min_y + bbox[3]/256, zoom)
155
+ lon_upper_left, lat_upper_left = num2deg(min_x + bbox[0]/256, min_y + bbox[1]/256, zoom)
156
+ lon_lower_right, lat_lower_right = num2deg(min_x + bbox[2]/256, min_y + bbox[3]/256, zoom)
157
157
 
158
158
  # Create transformation from WGS84 to Web Mercator
159
159
  wgs84 = pyproj.CRS('EPSG:4326')
@@ -161,8 +161,8 @@ def save_as_geotiff(image, polygon, zoom, bbox, bounds, output_path):
161
161
  transformer = pyproj.Transformer.from_crs(wgs84, web_mercator, always_xy=True)
162
162
 
163
163
  # Transform coordinates to Web Mercator
164
- upper_left_x, upper_left_y = transformer.transform(upper_left_lon, upper_left_lat)
165
- lower_right_x, lower_right_y = transformer.transform(lower_right_lon, lower_right_lat)
164
+ upper_left_x, upper_left_y = transformer.transform(lon_upper_left, lat_upper_left)
165
+ lower_right_x, lower_right_y = transformer.transform(lon_lower_right, lat_lower_right)
166
166
 
167
167
  # Calculate pixel size
168
168
  pixel_size_x = (lower_right_x - upper_left_x) / image.width
@@ -190,7 +190,7 @@ def save_oemj_as_geotiff(polygon, filepath, zoom=16):
190
190
  """Download and save OpenEarthMap Japan imagery as GeoTIFF.
191
191
 
192
192
  Args:
193
- polygon (list): List of (lat, lon) coordinates defining region
193
+ polygon (list): List of (lon, lat) coordinates defining region
194
194
  filepath (str): Output path for GeoTIFF
195
195
  zoom (int, optional): Zoom level for detail. Defaults to 16.
196
196
  """
@@ -20,20 +20,20 @@ def load_geojsons_from_openmaptiles(rectangle_vertices, API_KEY):
20
20
  """Download and process building footprint data from OpenMapTiles vector tiles.
21
21
 
22
22
  Args:
23
- rectangle_vertices: List of (lat, lon) coordinates defining the bounding box
23
+ rectangle_vertices: List of (lon, lat) coordinates defining the bounding box
24
24
  API_KEY: OpenMapTiles API key for authentication
25
25
 
26
26
  Returns:
27
27
  list: List of GeoJSON features containing building footprints with standardized properties
28
28
  """
29
- # Extract latitudes and longitudes from vertices to find bounding box
30
- lats = [coord[0] for coord in rectangle_vertices]
31
- lons = [coord[1] for coord in rectangle_vertices]
29
+ # Extract longitudes and latitudes from vertices to find bounding box
30
+ lons = [coord[0] for coord in rectangle_vertices]
31
+ lats = [coord[1] for coord in rectangle_vertices]
32
32
 
33
- min_lat = min(lats)
34
- max_lat = max(lats)
35
33
  min_lon = min(lons)
36
34
  max_lon = max(lons)
35
+ min_lat = min(lats)
36
+ max_lat = max(lats)
37
37
 
38
38
  # Use zoom level 15 which provides good detail for buildings while keeping data size manageable
39
39
  zoom = 15
@@ -183,10 +183,10 @@ def convert_geojson_format(features):
183
183
  ring_properties['is_inner'] = j > 0
184
184
  ring_properties['role'] = 'inner' if j > 0 else 'outer'
185
185
 
186
- # Create new geometry with swapped coordinate order (lon,lat) -> (lat,lon)
186
+ # Create new geometry keeping coordinate order as (lon,lat)
187
187
  new_geometry = {
188
188
  'type': 'Polygon',
189
- 'coordinates': [[(coord[1], coord[0]) for coord in ring]]
189
+ 'coordinates': [ring]
190
190
  }
191
191
 
192
192
  new_feature = {
@@ -204,10 +204,10 @@ def convert_geojson_format(features):
204
204
  ring_properties['is_inner'] = i > 0
205
205
  ring_properties['role'] = 'inner' if i > 0 else 'outer'
206
206
 
207
- # Create new geometry with swapped coordinate order
207
+ # Create new geometry keeping coordinate order as (lon,lat)
208
208
  new_geometry = {
209
209
  'type': 'Polygon',
210
- 'coordinates': [[(coord[1], coord[0]) for coord in ring]]
210
+ 'coordinates': [ring]
211
211
  }
212
212
 
213
213
  new_feature = {
@@ -26,16 +26,16 @@ def load_geojsons_from_openstreetmap(rectangle_vertices):
26
26
  """Download and process building footprint data from OpenStreetMap.
27
27
 
28
28
  Args:
29
- rectangle_vertices: List of (lat, lon) coordinates defining the bounding box
29
+ rectangle_vertices: List of (lon, lat) coordinates defining the bounding box
30
30
 
31
31
  Returns:
32
32
  list: List of GeoJSON features containing building footprints with standardized properties
33
33
  """
34
34
  # Create a bounding box from the rectangle vertices
35
- min_lat = min(v[0] for v in rectangle_vertices)
36
- max_lat = max(v[0] for v in rectangle_vertices)
37
- min_lon = min(v[1] for v in rectangle_vertices)
38
- max_lon = max(v[1] for v in rectangle_vertices)
35
+ min_lon = min(v[0] for v in rectangle_vertices)
36
+ max_lon = max(v[0] for v in rectangle_vertices)
37
+ min_lat = min(v[1] for v in rectangle_vertices)
38
+ max_lat = max(v[1] for v in rectangle_vertices)
39
39
 
40
40
  # Enhanced Overpass API query with recursive member extraction
41
41
  overpass_url = "http://overpass-api.de/api/interpreter"
@@ -73,7 +73,7 @@ def load_geojsons_from_openstreetmap(rectangle_vertices):
73
73
  Returns:
74
74
  list: Processed coordinate pairs with reversed order
75
75
  """
76
- return [coord[::-1] for coord in geometry]
76
+ return [coord for coord in geometry] # Keep original order since already (lon, lat)
77
77
 
78
78
  def get_height_from_properties(properties):
79
79
  """Helper function to extract height from properties.
@@ -253,7 +253,7 @@ def convert_feature(feature):
253
253
  for coord in ring:
254
254
  # Swap the order if needed (assuming original is [lat, lon])
255
255
  lat, lon = coord
256
- new_ring.append((lat, lon))
256
+ new_ring.append((lon, lat)) # Changed to (lon, lat)
257
257
  new_coordinates.append(new_ring)
258
258
 
259
259
  new_feature['geometry']['type'] = 'Polygon'
@@ -460,9 +460,8 @@ def swap_coordinates(geom_mapping):
460
460
  if isinstance(coord_list[0], (list, tuple)):
461
461
  return [swap_coords(c) for c in coord_list]
462
462
  else:
463
- # Swap lon/lat to lat/lon
464
- lon, lat = coord_list
465
- return [lat, lon]
463
+ # Keep original order since already (lon, lat)
464
+ return coord_list
466
465
 
467
466
  geom_mapping['coordinates'] = swap_coords(coords)
468
467
  return geom_mapping
@@ -471,7 +470,7 @@ def load_land_cover_geojson_from_osm(rectangle_vertices_ori):
471
470
  """Load land cover data from OpenStreetMap within a given rectangular area.
472
471
 
473
472
  Args:
474
- rectangle_vertices_ori (list): List of (lat, lon) coordinates defining the rectangle
473
+ rectangle_vertices_ori (list): List of (lon, lat) coordinates defining the rectangle
475
474
 
476
475
  Returns:
477
476
  list: List of GeoJSON features with land cover classifications
@@ -480,8 +479,11 @@ def load_land_cover_geojson_from_osm(rectangle_vertices_ori):
480
479
  rectangle_vertices = rectangle_vertices_ori.copy()
481
480
  rectangle_vertices.append(rectangle_vertices_ori[0])
482
481
 
483
- # Convert vertices to space-separated string for Overpass query
484
- polygon_coords = ' '.join(f"{lat} {lon}" for lat, lon in rectangle_vertices)
482
+ # Instead of using poly:"lat lon lat lon...", use area coordinates
483
+ min_lat = min(lat for lon, lat in rectangle_vertices)
484
+ max_lat = max(lat for lon, lat in rectangle_vertices)
485
+ min_lon = min(lon for lon, lat in rectangle_vertices)
486
+ max_lon = max(lon for lon, lat in rectangle_vertices)
485
487
 
486
488
  # Initialize dictionary to store OSM keys and their allowed values
487
489
  osm_keys_values = defaultdict(list)
@@ -504,16 +506,16 @@ def load_land_cover_geojson_from_osm(rectangle_vertices_ori):
504
506
  for key, values in osm_keys_values.items():
505
507
  if values:
506
508
  if values == ['*']:
507
- # Query for any value of this key
508
- query_parts.append(f'way["{key}"](poly:"{polygon_coords}");')
509
- query_parts.append(f'relation["{key}"](poly:"{polygon_coords}");')
509
+ # Query for any value of this key using bounding box
510
+ query_parts.append(f'way["{key}"]({min_lat},{min_lon},{max_lat},{max_lon});')
511
+ query_parts.append(f'relation["{key}"]({min_lat},{min_lon},{max_lat},{max_lon});')
510
512
  else:
511
513
  # Remove duplicate values
512
514
  values = list(set(values))
513
515
  # Build regex pattern for specific values
514
516
  values_regex = '|'.join(values)
515
- query_parts.append(f'way["{key}"~"^{values_regex}$"](poly:"{polygon_coords}");')
516
- query_parts.append(f'relation["{key}"~"^{values_regex}$"](poly:"{polygon_coords}");')
517
+ query_parts.append(f'way["{key}"~"^{values_regex}$"]({min_lat},{min_lon},{max_lat},{max_lon});')
518
+ query_parts.append(f'relation["{key}"~"^{values_regex}$"]({min_lat},{min_lon},{max_lat},{max_lon});')
517
519
 
518
520
  # Combine query parts into complete Overpass query
519
521
  query_body = "\n ".join(query_parts)
@@ -541,11 +543,11 @@ def load_land_cover_geojson_from_osm(rectangle_vertices_ori):
541
543
  geojson_data = json2geojson(data)
542
544
 
543
545
  # Create shapely polygon from rectangle vertices (in lon,lat order)
544
- rectangle_polygon = Polygon([(lon, lat) for lat, lon in rectangle_vertices])
546
+ rectangle_polygon = Polygon(rectangle_vertices)
545
547
 
546
548
  # Calculate center point for projection
547
- center_lat = sum(lat for lat, lon in rectangle_vertices) / len(rectangle_vertices)
548
- center_lon = sum(lon for lat, lon in rectangle_vertices) / len(rectangle_vertices)
549
+ center_lat = sum(lat for lon, lat in rectangle_vertices) / len(rectangle_vertices)
550
+ center_lon = sum(lon for lon, lat in rectangle_vertices) / len(rectangle_vertices)
549
551
 
550
552
  # Set up coordinate reference systems for projection
551
553
  wgs84 = pyproj.CRS('EPSG:4326') # Standard lat/lon
@@ -64,7 +64,7 @@ def is_valid_value(value):
64
64
 
65
65
  def convert_gdf_to_geojson(gdf):
66
66
  """
67
- Convert GeoDataFrame to GeoJSON format with coordinates in (lat, lon) order.
67
+ Convert GeoDataFrame to GeoJSON format with coordinates in (lon, lat) order.
68
68
  Extracts all columns as properties except for 'geometry' and 'bbox'.
69
69
  Sets height and min_height to 0 if not present and handles arrays.
70
70
 
@@ -81,14 +81,6 @@ def convert_gdf_to_geojson(gdf):
81
81
  # Convert Shapely geometry to GeoJSON format
82
82
  geom = mapping(row['geometry'])
83
83
 
84
- # Swap coordinate ordering from (lon, lat) to (lat, lon)
85
- if geom['type'] == 'Polygon':
86
- new_coordinates = []
87
- for ring in geom['coordinates']:
88
- new_ring = [[coord[1], coord[0]] for coord in ring]
89
- new_coordinates.append(new_ring)
90
- geom['coordinates'] = new_coordinates
91
-
92
84
  # Initialize properties dictionary for this feature
93
85
  properties = {}
94
86
 
@@ -125,18 +117,18 @@ def convert_gdf_to_geojson(gdf):
125
117
 
126
118
  def rectangle_to_bbox(vertices):
127
119
  """
128
- Convert rectangle vertices in (lat, lon) format to a GeoDataFrame bbox
120
+ Convert rectangle vertices in (lon, lat) format to a GeoDataFrame bbox
129
121
  with Shapely box geometry in (minx, miny, maxx, maxy) format
130
122
 
131
123
  Args:
132
- vertices (list): List of tuples containing (lat, lon) coordinates
124
+ vertices (list): List of tuples containing (lon, lat) coordinates
133
125
 
134
126
  Returns:
135
127
  tuple: Bounding box coordinates (min_lon, min_lat, max_lon, max_lat)
136
128
  """
137
- # Extract lat, lon values from vertices
138
- lats = [vertex[0] for vertex in vertices]
139
- lons = [vertex[1] for vertex in vertices]
129
+ # Extract lon, lat values from vertices
130
+ lons = [vertex[0] for vertex in vertices]
131
+ lats = [vertex[1] for vertex in vertices]
140
132
 
141
133
  # Calculate bounding box extents
142
134
  min_lat = min(lats)
@@ -192,7 +184,7 @@ def load_geojsons_from_overture(rectangle_vertices):
192
184
  Download and process building footprint data from Overture Maps.
193
185
 
194
186
  Args:
195
- rectangle_vertices (list): List of (lat, lon) coordinates defining the bounding box
187
+ rectangle_vertices (list): List of (lon, lat) coordinates defining the bounding box
196
188
 
197
189
  Returns:
198
190
  list: List of GeoJSON features containing building footprints with standardized properties
@@ -231,10 +231,10 @@ def create_xml_content(building_height_grid, building_id_grid, land_cover_veg_gr
231
231
  city_country_name = get_city_country_name_from_rectangle(rectangle_vertices)
232
232
 
233
233
  # Calculate center coordinates of the model area
234
- latitudes = [coord[0] for coord in rectangle_vertices]
235
- longitudes = [coord[1] for coord in rectangle_vertices]
236
- center_lat = str(sum(latitudes) / len(latitudes))
237
- center_lon = str(sum(longitudes) / len(longitudes))
234
+ longitudes = [coord[0] for coord in rectangle_vertices] # Changed order from lat to lon
235
+ latitudes = [coord[1] for coord in rectangle_vertices] # Changed order from lat to lon
236
+ center_lon = str(sum(longitudes) / len(longitudes)) # Changed order
237
+ center_lat = str(sum(latitudes) / len(latitudes)) # Changed order
238
238
 
239
239
  timezone_info = get_timezone_info(rectangle_vertices)
240
240