voxcity 0.5.14__py3-none-any.whl → 0.5.16__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/downloader/citygml.py +202 -28
- voxcity/downloader/eubucco.py +91 -14
- voxcity/downloader/gee.py +164 -22
- voxcity/downloader/mbfp.py +55 -9
- voxcity/downloader/oemj.py +110 -24
- voxcity/downloader/omt.py +74 -7
- voxcity/downloader/osm.py +109 -23
- voxcity/downloader/overture.py +108 -23
- voxcity/downloader/utils.py +37 -7
- voxcity/exporter/envimet.py +180 -61
- voxcity/exporter/magicavoxel.py +138 -28
- voxcity/exporter/obj.py +159 -36
- voxcity/generator.py +159 -76
- voxcity/geoprocessor/draw.py +180 -27
- voxcity/geoprocessor/grid.py +178 -38
- voxcity/geoprocessor/mesh.py +347 -43
- voxcity/geoprocessor/network.py +196 -63
- voxcity/geoprocessor/polygon.py +365 -88
- voxcity/geoprocessor/utils.py +283 -72
- voxcity/simulator/solar.py +596 -201
- voxcity/simulator/view.py +278 -723
- voxcity/utils/lc.py +183 -0
- voxcity/utils/material.py +99 -32
- voxcity/utils/visualization.py +2578 -1988
- voxcity/utils/weather.py +816 -615
- {voxcity-0.5.14.dist-info → voxcity-0.5.16.dist-info}/METADATA +11 -13
- voxcity-0.5.16.dist-info/RECORD +38 -0
- {voxcity-0.5.14.dist-info → voxcity-0.5.16.dist-info}/WHEEL +1 -1
- voxcity-0.5.14.dist-info/RECORD +0 -38
- {voxcity-0.5.14.dist-info → voxcity-0.5.16.dist-info}/licenses/AUTHORS.rst +0 -0
- {voxcity-0.5.14.dist-info → voxcity-0.5.16.dist-info}/licenses/LICENSE +0 -0
- {voxcity-0.5.14.dist-info → voxcity-0.5.16.dist-info}/top_level.txt +0 -0
voxcity/geoprocessor/draw.py
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
"""
|
|
2
|
-
This module provides functions for drawing and manipulating rectangles on maps.
|
|
2
|
+
This module provides functions for drawing and manipulating rectangles and polygons on interactive maps.
|
|
3
|
+
It serves as a core component for defining geographical regions of interest in the VoxCity library.
|
|
4
|
+
|
|
5
|
+
Key Features:
|
|
6
|
+
- Interactive rectangle drawing on maps using ipyleaflet
|
|
7
|
+
- Rectangle rotation with coordinate system transformations
|
|
8
|
+
- City-centered map initialization
|
|
9
|
+
- Fixed-dimension rectangle creation from center points
|
|
10
|
+
- Building footprint visualization and polygon drawing
|
|
11
|
+
- Support for both WGS84 and Web Mercator projections
|
|
12
|
+
- Coordinate format handling between (lon,lat) and (lat,lon)
|
|
13
|
+
|
|
14
|
+
The module maintains consistent coordinate order conventions:
|
|
15
|
+
- Internal storage: (lon,lat) format to match GeoJSON standard
|
|
16
|
+
- ipyleaflet interface: (lat,lon) format as required by the library
|
|
17
|
+
- All return values: (lon,lat) format for consistency
|
|
18
|
+
|
|
19
|
+
Dependencies:
|
|
20
|
+
- ipyleaflet: For interactive map display and drawing controls
|
|
21
|
+
- pyproj: For coordinate system transformations
|
|
22
|
+
- geopy: For distance calculations
|
|
23
|
+
- shapely: For geometric operations
|
|
3
24
|
"""
|
|
4
25
|
|
|
5
26
|
import math
|
|
@@ -13,15 +34,36 @@ from .utils import get_coordinates_from_cityname
|
|
|
13
34
|
|
|
14
35
|
def rotate_rectangle(m, rectangle_vertices, angle):
|
|
15
36
|
"""
|
|
16
|
-
Project rectangle to Mercator, rotate, and re-project to lat-lon.
|
|
37
|
+
Project rectangle to Mercator, rotate, and re-project to lat-lon coordinates.
|
|
38
|
+
|
|
39
|
+
This function performs a rotation of a rectangle in geographic space by:
|
|
40
|
+
1. Converting coordinates from WGS84 (lat/lon) to Web Mercator projection
|
|
41
|
+
2. Performing the rotation in the projected space for accurate distance preservation
|
|
42
|
+
3. Converting back to WGS84 coordinates
|
|
43
|
+
4. Visualizing the result on the provided map
|
|
44
|
+
|
|
45
|
+
The rotation is performed around the rectangle's centroid using a standard 2D rotation matrix.
|
|
46
|
+
The function handles coordinate system transformations to ensure geometrically accurate rotations
|
|
47
|
+
despite the distortions inherent in geographic projections.
|
|
17
48
|
|
|
18
49
|
Args:
|
|
19
|
-
m (ipyleaflet.Map): Map object to draw the rotated rectangle on
|
|
20
|
-
|
|
21
|
-
|
|
50
|
+
m (ipyleaflet.Map): Map object to draw the rotated rectangle on.
|
|
51
|
+
The map must be initialized and have a valid center and zoom level.
|
|
52
|
+
rectangle_vertices (list): List of (lon, lat) tuples defining the rectangle vertices.
|
|
53
|
+
The vertices should be ordered in a counter-clockwise direction.
|
|
54
|
+
Example: [(lon1,lat1), (lon2,lat2), (lon3,lat3), (lon4,lat4)]
|
|
55
|
+
angle (float): Rotation angle in degrees.
|
|
56
|
+
Positive angles rotate counter-clockwise.
|
|
57
|
+
Negative angles rotate clockwise.
|
|
22
58
|
|
|
23
59
|
Returns:
|
|
24
|
-
list: List of rotated (lon, lat) tuples defining the new rectangle vertices
|
|
60
|
+
list: List of rotated (lon, lat) tuples defining the new rectangle vertices.
|
|
61
|
+
The vertices maintain their original ordering.
|
|
62
|
+
Returns None if no rectangle vertices are provided.
|
|
63
|
+
|
|
64
|
+
Note:
|
|
65
|
+
The function uses EPSG:4326 (WGS84) for geographic coordinates and
|
|
66
|
+
EPSG:3857 (Web Mercator) for the rotation calculations.
|
|
25
67
|
"""
|
|
26
68
|
if not rectangle_vertices:
|
|
27
69
|
print("Draw a rectangle first!")
|
|
@@ -73,16 +115,43 @@ def rotate_rectangle(m, rectangle_vertices, angle):
|
|
|
73
115
|
|
|
74
116
|
def draw_rectangle_map(center=(40, -100), zoom=4):
|
|
75
117
|
"""
|
|
76
|
-
Create an interactive map for drawing rectangles.
|
|
118
|
+
Create an interactive map for drawing rectangles with ipyleaflet.
|
|
119
|
+
|
|
120
|
+
This function initializes an interactive map that allows users to draw rectangles
|
|
121
|
+
by clicking and dragging on the map surface. The drawn rectangles are captured
|
|
122
|
+
and their vertices are stored in geographic coordinates.
|
|
123
|
+
|
|
124
|
+
The map interface provides:
|
|
125
|
+
- A rectangle drawing tool activated by default
|
|
126
|
+
- Real-time coordinate capture of drawn shapes
|
|
127
|
+
- Automatic vertex ordering in counter-clockwise direction
|
|
128
|
+
- Console output of vertex coordinates for verification
|
|
129
|
+
|
|
130
|
+
Drawing Controls:
|
|
131
|
+
- Click and drag to draw a rectangle
|
|
132
|
+
- Release to complete the rectangle
|
|
133
|
+
- Only one rectangle can be active at a time
|
|
134
|
+
- Drawing a new rectangle clears the previous one
|
|
77
135
|
|
|
78
136
|
Args:
|
|
79
|
-
center (tuple): Center coordinates (lat, lon) for the map view.
|
|
137
|
+
center (tuple): Center coordinates (lat, lon) for the map view.
|
|
138
|
+
Defaults to (40, -100) which centers on the continental United States.
|
|
139
|
+
Format: (latitude, longitude) in decimal degrees.
|
|
80
140
|
zoom (int): Initial zoom level for the map. Defaults to 4.
|
|
141
|
+
Range: 0 (most zoomed out) to 18 (most zoomed in).
|
|
142
|
+
Recommended: 3-6 for countries, 10-15 for cities.
|
|
81
143
|
|
|
82
144
|
Returns:
|
|
83
145
|
tuple: (Map object, list of rectangle vertices)
|
|
84
|
-
- Map object for displaying and interacting with the map
|
|
85
|
-
- Empty list that will be populated with
|
|
146
|
+
- Map object: ipyleaflet.Map instance for displaying and interacting with the map
|
|
147
|
+
- rectangle_vertices: Empty list that will be populated with (lon,lat) tuples
|
|
148
|
+
when a rectangle is drawn. Coordinates are stored in GeoJSON order (lon,lat).
|
|
149
|
+
|
|
150
|
+
Note:
|
|
151
|
+
The function disables all drawing tools except rectangles to ensure
|
|
152
|
+
consistent shape creation. The rectangle vertices are automatically
|
|
153
|
+
converted to (lon,lat) format when stored, regardless of the input
|
|
154
|
+
center coordinate order.
|
|
86
155
|
"""
|
|
87
156
|
# Initialize the map centered at specified coordinates
|
|
88
157
|
m = Map(center=center, zoom=zoom)
|
|
@@ -127,15 +196,34 @@ def draw_rectangle_map(center=(40, -100), zoom=4):
|
|
|
127
196
|
def draw_rectangle_map_cityname(cityname, zoom=15):
|
|
128
197
|
"""
|
|
129
198
|
Create an interactive map centered on a specified city for drawing rectangles.
|
|
199
|
+
|
|
200
|
+
This function extends draw_rectangle_map() by automatically centering the map
|
|
201
|
+
on a specified city using geocoding. It provides a convenient way to focus
|
|
202
|
+
the drawing interface on a particular urban area without needing to know
|
|
203
|
+
its exact coordinates.
|
|
204
|
+
|
|
205
|
+
The function uses the utils.get_coordinates_from_cityname() function to
|
|
206
|
+
geocode the city name and obtain its coordinates. The resulting map is
|
|
207
|
+
zoomed to an appropriate level for urban-scale analysis.
|
|
130
208
|
|
|
131
209
|
Args:
|
|
132
|
-
cityname (str): Name of the city to center the map on
|
|
210
|
+
cityname (str): Name of the city to center the map on.
|
|
211
|
+
Can include country or state for better accuracy.
|
|
212
|
+
Examples: "Tokyo, Japan", "New York, NY", "Paris, France"
|
|
133
213
|
zoom (int): Initial zoom level for the map. Defaults to 15.
|
|
214
|
+
Range: 0 (most zoomed out) to 18 (most zoomed in).
|
|
215
|
+
Default of 15 is optimized for city-level visualization.
|
|
134
216
|
|
|
135
217
|
Returns:
|
|
136
218
|
tuple: (Map object, list of rectangle vertices)
|
|
137
|
-
- Map object centered on the specified city
|
|
138
|
-
- Empty list that will be populated with
|
|
219
|
+
- Map object: ipyleaflet.Map instance centered on the specified city
|
|
220
|
+
- rectangle_vertices: Empty list that will be populated with (lon,lat)
|
|
221
|
+
tuples when a rectangle is drawn
|
|
222
|
+
|
|
223
|
+
Note:
|
|
224
|
+
If the city name cannot be geocoded, the function will raise an error.
|
|
225
|
+
For better results, provide specific city names with country/state context.
|
|
226
|
+
The function inherits all drawing controls and behavior from draw_rectangle_map().
|
|
139
227
|
"""
|
|
140
228
|
# Get coordinates for the specified city
|
|
141
229
|
center = get_coordinates_from_cityname(cityname)
|
|
@@ -145,17 +233,51 @@ def draw_rectangle_map_cityname(cityname, zoom=15):
|
|
|
145
233
|
def center_location_map_cityname(cityname, east_west_length, north_south_length, zoom=15):
|
|
146
234
|
"""
|
|
147
235
|
Create an interactive map centered on a city where clicking creates a rectangle of specified dimensions.
|
|
236
|
+
|
|
237
|
+
This function provides a specialized interface for creating fixed-size rectangles
|
|
238
|
+
centered on user-selected points. Instead of drawing rectangles by dragging,
|
|
239
|
+
users click a point on the map and a rectangle of the specified dimensions
|
|
240
|
+
is automatically created centered on that point.
|
|
241
|
+
|
|
242
|
+
The function handles:
|
|
243
|
+
- Automatic city geocoding and map centering
|
|
244
|
+
- Distance calculations in meters using geopy
|
|
245
|
+
- Conversion between geographic and metric distances
|
|
246
|
+
- Rectangle creation with specified dimensions
|
|
247
|
+
- Visualization of created rectangles
|
|
248
|
+
|
|
249
|
+
Workflow:
|
|
250
|
+
1. Map is centered on the specified city
|
|
251
|
+
2. User clicks a point on the map
|
|
252
|
+
3. A rectangle is created centered on that point
|
|
253
|
+
4. Rectangle dimensions are maintained in meters regardless of latitude
|
|
254
|
+
5. Previous rectangles are automatically cleared
|
|
148
255
|
|
|
149
256
|
Args:
|
|
150
|
-
cityname (str): Name of the city to center the map on
|
|
151
|
-
|
|
152
|
-
|
|
257
|
+
cityname (str): Name of the city to center the map on.
|
|
258
|
+
Can include country or state for better accuracy.
|
|
259
|
+
Examples: "Tokyo, Japan", "New York, NY"
|
|
260
|
+
east_west_length (float): Width of the rectangle in meters.
|
|
261
|
+
This is the dimension along the east-west direction.
|
|
262
|
+
The actual ground distance is maintained regardless of projection distortion.
|
|
263
|
+
north_south_length (float): Height of the rectangle in meters.
|
|
264
|
+
This is the dimension along the north-south direction.
|
|
265
|
+
The actual ground distance is maintained regardless of projection distortion.
|
|
153
266
|
zoom (int): Initial zoom level for the map. Defaults to 15.
|
|
267
|
+
Range: 0 (most zoomed out) to 18 (most zoomed in).
|
|
268
|
+
Default of 15 is optimized for city-level visualization.
|
|
154
269
|
|
|
155
270
|
Returns:
|
|
156
271
|
tuple: (Map object, list of rectangle vertices)
|
|
157
|
-
- Map object centered on the specified city
|
|
158
|
-
- Empty list that will be populated with
|
|
272
|
+
- Map object: ipyleaflet.Map instance centered on the specified city
|
|
273
|
+
- rectangle_vertices: Empty list that will be populated with (lon,lat)
|
|
274
|
+
tuples when a point is clicked and the rectangle is created
|
|
275
|
+
|
|
276
|
+
Note:
|
|
277
|
+
- Rectangle dimensions are specified in meters but stored as geographic coordinates
|
|
278
|
+
- The function uses geopy's distance calculations for accurate metric distances
|
|
279
|
+
- Only one rectangle can exist at a time; clicking a new point removes the previous rectangle
|
|
280
|
+
- Rectangle vertices are returned in GeoJSON (lon,lat) order
|
|
159
281
|
"""
|
|
160
282
|
|
|
161
283
|
# Get coordinates for the specified city
|
|
@@ -225,21 +347,52 @@ def center_location_map_cityname(cityname, east_west_length, north_south_length,
|
|
|
225
347
|
|
|
226
348
|
def display_buildings_and_draw_polygon(building_gdf=None, rectangle_vertices=None, zoom=17):
|
|
227
349
|
"""
|
|
228
|
-
Displays building footprints
|
|
229
|
-
|
|
230
|
-
|
|
350
|
+
Displays building footprints and enables polygon drawing on an interactive map.
|
|
351
|
+
|
|
352
|
+
This function creates an interactive map that visualizes building footprints and
|
|
353
|
+
allows users to draw arbitrary polygons. It's particularly useful for selecting
|
|
354
|
+
specific buildings or areas within an urban context.
|
|
355
|
+
|
|
356
|
+
The function provides three key features:
|
|
357
|
+
1. Building Footprint Visualization:
|
|
358
|
+
- Displays building polygons from a GeoDataFrame
|
|
359
|
+
- Uses consistent styling for all buildings
|
|
360
|
+
- Handles simple polygon geometries only
|
|
361
|
+
|
|
362
|
+
2. Interactive Polygon Drawing:
|
|
363
|
+
- Enables free-form polygon drawing
|
|
364
|
+
- Captures vertices in consistent (lon,lat) format
|
|
365
|
+
- Maintains GeoJSON compatibility
|
|
366
|
+
|
|
367
|
+
3. Map Initialization:
|
|
368
|
+
- Automatic centering based on input data
|
|
369
|
+
- Fallback to default location if no data provided
|
|
370
|
+
- Support for both building data and rectangle bounds
|
|
231
371
|
|
|
232
372
|
Args:
|
|
233
|
-
building_gdf (GeoDataFrame, optional): A GeoDataFrame containing building footprints
|
|
234
|
-
|
|
373
|
+
building_gdf (GeoDataFrame, optional): A GeoDataFrame containing building footprints.
|
|
374
|
+
Must have geometry column with Polygon type features.
|
|
375
|
+
Geometries should be in [lon, lat] coordinate order.
|
|
376
|
+
If None, only the base map is displayed.
|
|
235
377
|
rectangle_vertices (list, optional): List of [lon, lat] coordinates defining rectangle corners.
|
|
378
|
+
Used to set the initial map view extent.
|
|
379
|
+
Takes precedence over building_gdf for determining map center.
|
|
236
380
|
zoom (int): Initial zoom level for the map. Default=17.
|
|
381
|
+
Range: 0 (most zoomed out) to 18 (most zoomed in).
|
|
382
|
+
Default of 17 is optimized for building-level detail.
|
|
237
383
|
|
|
238
384
|
Returns:
|
|
239
|
-
(map_object, drawn_polygon_vertices)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
385
|
+
tuple: (map_object, drawn_polygon_vertices)
|
|
386
|
+
- map_object: ipyleaflet Map instance with building footprints and drawing controls
|
|
387
|
+
- drawn_polygon_vertices: List that gets updated with (lon,lat) coordinates
|
|
388
|
+
whenever a new polygon is drawn. Coordinates are in GeoJSON order.
|
|
389
|
+
|
|
390
|
+
Note:
|
|
391
|
+
- Building footprints are displayed in blue with 20% opacity
|
|
392
|
+
- Only simple Polygon geometries are supported (no MultiPolygons)
|
|
393
|
+
- Drawing tools are restricted to polygon creation only
|
|
394
|
+
- All coordinates are handled in (lon,lat) order internally
|
|
395
|
+
- The function automatically determines appropriate map bounds
|
|
243
396
|
"""
|
|
244
397
|
# ---------------------------------------------------------
|
|
245
398
|
# 1. Determine a suitable map center via bounding box logic
|
voxcity/geoprocessor/grid.py
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module provides functions for creating and manipulating grids of building heights, land cover, and elevation data.
|
|
3
|
+
It includes functionality for:
|
|
4
|
+
- Grid creation and manipulation for various data types (buildings, land cover, elevation)
|
|
5
|
+
- Coordinate transformations and spatial operations
|
|
6
|
+
- Data interpolation and aggregation
|
|
7
|
+
- Vector to raster conversion
|
|
3
8
|
"""
|
|
4
9
|
|
|
5
10
|
import numpy as np
|
|
@@ -44,7 +49,13 @@ from ..downloader.gee import (
|
|
|
44
49
|
|
|
45
50
|
def apply_operation(arr, meshsize):
|
|
46
51
|
"""
|
|
47
|
-
Applies a sequence of operations to an array based on a mesh size.
|
|
52
|
+
Applies a sequence of operations to an array based on a mesh size to normalize and discretize values.
|
|
53
|
+
|
|
54
|
+
This function performs the following sequence of operations:
|
|
55
|
+
1. Divides array by mesh size to normalize values
|
|
56
|
+
2. Adds 0.5 to round values to nearest integer
|
|
57
|
+
3. Floors the result to get integer values
|
|
58
|
+
4. Scales back to original units by multiplying by mesh size
|
|
48
59
|
|
|
49
60
|
Args:
|
|
50
61
|
arr (numpy.ndarray): Input array to transform
|
|
@@ -52,6 +63,11 @@ def apply_operation(arr, meshsize):
|
|
|
52
63
|
|
|
53
64
|
Returns:
|
|
54
65
|
numpy.ndarray: Transformed array after applying operations
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
>>> arr = np.array([1.2, 2.7, 3.4])
|
|
69
|
+
>>> meshsize = 0.5
|
|
70
|
+
>>> result = apply_operation(arr, meshsize)
|
|
55
71
|
"""
|
|
56
72
|
# Divide array by mesh size to normalize values
|
|
57
73
|
step1 = arr / meshsize
|
|
@@ -66,12 +82,22 @@ def translate_array(input_array, translation_dict):
|
|
|
66
82
|
"""
|
|
67
83
|
Translates values in an array according to a dictionary mapping.
|
|
68
84
|
|
|
85
|
+
This function creates a new array where each value from the input array
|
|
86
|
+
is replaced by its corresponding value from the translation dictionary.
|
|
87
|
+
Values not found in the dictionary are replaced with empty strings.
|
|
88
|
+
|
|
69
89
|
Args:
|
|
70
90
|
input_array (numpy.ndarray): Array containing values to translate
|
|
71
91
|
translation_dict (dict): Dictionary mapping input values to output values
|
|
72
92
|
|
|
73
93
|
Returns:
|
|
74
|
-
numpy.ndarray: Array with translated values
|
|
94
|
+
numpy.ndarray: Array with translated values, with same shape as input array
|
|
95
|
+
|
|
96
|
+
Example:
|
|
97
|
+
>>> arr = np.array([[1, 2], [3, 4]])
|
|
98
|
+
>>> trans_dict = {1: 'A', 2: 'B', 3: 'C', 4: 'D'}
|
|
99
|
+
>>> result = translate_array(arr, trans_dict)
|
|
100
|
+
>>> # result = array([['A', 'B'], ['C', 'D']], dtype=object)
|
|
75
101
|
"""
|
|
76
102
|
# Create empty array of same shape that can hold objects (e.g. strings)
|
|
77
103
|
translated_array = np.empty_like(input_array, dtype=object)
|
|
@@ -86,13 +112,22 @@ def translate_array(input_array, translation_dict):
|
|
|
86
112
|
def group_and_label_cells(array):
|
|
87
113
|
"""
|
|
88
114
|
Convert non-zero numbers in a 2D numpy array to sequential IDs starting from 1.
|
|
89
|
-
|
|
115
|
+
|
|
116
|
+
This function creates a new array where all non-zero values are replaced with
|
|
117
|
+
sequential IDs (1, 2, 3, etc.) while preserving zero values. This is useful
|
|
118
|
+
for labeling distinct regions or features in a grid.
|
|
90
119
|
|
|
91
120
|
Args:
|
|
92
|
-
array (numpy.ndarray): Input 2D array
|
|
121
|
+
array (numpy.ndarray): Input 2D array with non-zero values to be labeled
|
|
93
122
|
|
|
94
123
|
Returns:
|
|
95
|
-
numpy.ndarray: Array with non-zero values converted to sequential IDs
|
|
124
|
+
numpy.ndarray: Array with non-zero values converted to sequential IDs,
|
|
125
|
+
maintaining the same shape as input array
|
|
126
|
+
|
|
127
|
+
Example:
|
|
128
|
+
>>> arr = np.array([[0, 5, 5], [0, 5, 8], [0, 0, 8]])
|
|
129
|
+
>>> result = group_and_label_cells(arr)
|
|
130
|
+
>>> # result = array([[0, 1, 1], [0, 1, 2], [0, 0, 2]])
|
|
96
131
|
"""
|
|
97
132
|
# Create a copy to avoid modifying input
|
|
98
133
|
result = array.copy()
|
|
@@ -113,12 +148,25 @@ def process_grid(grid_bi, dem_grid):
|
|
|
113
148
|
"""
|
|
114
149
|
Process a binary grid and DEM grid to create averaged elevation values.
|
|
115
150
|
|
|
151
|
+
This function takes a binary grid identifying regions and a corresponding DEM
|
|
152
|
+
grid with elevation values. For each non-zero region in the binary grid, it
|
|
153
|
+
calculates the mean elevation from the DEM grid and assigns this average to
|
|
154
|
+
all cells in that region. The result is normalized by subtracting the minimum value.
|
|
155
|
+
|
|
116
156
|
Args:
|
|
117
|
-
grid_bi (numpy.ndarray): Binary grid indicating regions
|
|
118
|
-
|
|
157
|
+
grid_bi (numpy.ndarray): Binary grid indicating regions (0 for background,
|
|
158
|
+
non-zero for different regions)
|
|
159
|
+
dem_grid (numpy.ndarray): Grid of elevation values corresponding to the
|
|
160
|
+
same spatial extent as grid_bi
|
|
119
161
|
|
|
120
162
|
Returns:
|
|
121
|
-
numpy.ndarray: Processed grid with averaged elevation values
|
|
163
|
+
numpy.ndarray: Processed grid with averaged and normalized elevation values.
|
|
164
|
+
Same shape as input grids.
|
|
165
|
+
|
|
166
|
+
Example:
|
|
167
|
+
>>> binary_grid = np.array([[1, 1, 0], [1, 1, 2], [0, 2, 2]])
|
|
168
|
+
>>> elevation = np.array([[100, 110, 90], [105, 115, 120], [95, 125, 130]])
|
|
169
|
+
>>> result = process_grid(binary_grid, elevation)
|
|
122
170
|
"""
|
|
123
171
|
# Get unique non-zero region IDs
|
|
124
172
|
unique_ids = np.unique(grid_bi[grid_bi != 0])
|
|
@@ -137,15 +185,29 @@ def calculate_grid_size(side_1, side_2, u_vec, v_vec, meshsize):
|
|
|
137
185
|
"""
|
|
138
186
|
Calculate grid size and adjusted mesh size based on input parameters.
|
|
139
187
|
|
|
188
|
+
This function determines the number of grid cells needed in each direction and
|
|
189
|
+
adjusts the mesh size to exactly fit the desired area. The calculation takes into
|
|
190
|
+
account the input vectors and desired mesh size to ensure proper coverage.
|
|
191
|
+
|
|
140
192
|
Args:
|
|
141
|
-
side_1 (numpy.ndarray): First side vector
|
|
142
|
-
side_2 (numpy.ndarray): Second side vector
|
|
193
|
+
side_1 (numpy.ndarray): First side vector defining the grid extent
|
|
194
|
+
side_2 (numpy.ndarray): Second side vector defining the grid extent
|
|
143
195
|
u_vec (numpy.ndarray): Unit vector in first direction
|
|
144
196
|
v_vec (numpy.ndarray): Unit vector in second direction
|
|
145
|
-
meshsize (float): Desired mesh size
|
|
197
|
+
meshsize (float): Desired mesh size in the same units as the vectors
|
|
146
198
|
|
|
147
199
|
Returns:
|
|
148
|
-
tuple:
|
|
200
|
+
tuple: A tuple containing:
|
|
201
|
+
- grid_size (tuple of ints): Number of cells in each direction (nx, ny)
|
|
202
|
+
- adjusted_mesh_size (tuple of floats): Actual mesh sizes that fit the area exactly
|
|
203
|
+
|
|
204
|
+
Example:
|
|
205
|
+
>>> side1 = np.array([100, 0]) # 100 units in x direction
|
|
206
|
+
>>> side2 = np.array([0, 50]) # 50 units in y direction
|
|
207
|
+
>>> u = np.array([1, 0]) # Unit vector in x
|
|
208
|
+
>>> v = np.array([0, 1]) # Unit vector in y
|
|
209
|
+
>>> mesh = 10 # Desired 10-unit mesh
|
|
210
|
+
>>> grid_size, adj_mesh = calculate_grid_size(side1, side2, u, v, mesh)
|
|
149
211
|
"""
|
|
150
212
|
# Calculate number of cells needed in each direction, rounding to nearest integer
|
|
151
213
|
grid_size_0 = int(np.linalg.norm(side_1) / np.linalg.norm(meshsize * u_vec) + 0.5)
|
|
@@ -161,15 +223,29 @@ def create_coordinate_mesh(origin, grid_size, adjusted_meshsize, u_vec, v_vec):
|
|
|
161
223
|
"""
|
|
162
224
|
Create a coordinate mesh based on input parameters.
|
|
163
225
|
|
|
226
|
+
This function generates a 3D array representing a coordinate mesh, where each point
|
|
227
|
+
in the mesh is calculated by adding scaled vectors to the origin point. The mesh
|
|
228
|
+
is created using the specified grid size and adjusted mesh sizes.
|
|
229
|
+
|
|
164
230
|
Args:
|
|
165
|
-
origin (numpy.ndarray): Origin point coordinates
|
|
166
|
-
grid_size (tuple): Size of grid in each dimension
|
|
167
|
-
adjusted_meshsize (tuple): Adjusted mesh size in each dimension
|
|
231
|
+
origin (numpy.ndarray): Origin point coordinates (shape: (2,) or (3,))
|
|
232
|
+
grid_size (tuple): Size of grid in each dimension (nx, ny)
|
|
233
|
+
adjusted_meshsize (tuple): Adjusted mesh size in each dimension (dx, dy)
|
|
168
234
|
u_vec (numpy.ndarray): Unit vector in first direction
|
|
169
235
|
v_vec (numpy.ndarray): Unit vector in second direction
|
|
170
236
|
|
|
171
237
|
Returns:
|
|
172
|
-
numpy.ndarray:
|
|
238
|
+
numpy.ndarray: 3D array of shape (coord_dim, ny, nx) containing the coordinates
|
|
239
|
+
of each point in the mesh. coord_dim is the same as the
|
|
240
|
+
dimensionality of the input vectors.
|
|
241
|
+
|
|
242
|
+
Example:
|
|
243
|
+
>>> origin = np.array([0, 0])
|
|
244
|
+
>>> grid_size = (5, 4)
|
|
245
|
+
>>> mesh_size = (10, 10)
|
|
246
|
+
>>> u = np.array([1, 0])
|
|
247
|
+
>>> v = np.array([0, 1])
|
|
248
|
+
>>> coords = create_coordinate_mesh(origin, grid_size, mesh_size, u, v)
|
|
173
249
|
"""
|
|
174
250
|
# Create evenly spaced points along each axis
|
|
175
251
|
x = np.linspace(0, grid_size[0], grid_size[0])
|
|
@@ -189,16 +265,29 @@ def create_cell_polygon(origin, i, j, adjusted_meshsize, u_vec, v_vec):
|
|
|
189
265
|
"""
|
|
190
266
|
Create a polygon representing a grid cell.
|
|
191
267
|
|
|
268
|
+
This function generates a rectangular polygon for a specific grid cell by calculating
|
|
269
|
+
its four corners based on the cell indices and grid parameters. The polygon is
|
|
270
|
+
created in counter-clockwise order starting from the bottom-left corner.
|
|
271
|
+
|
|
192
272
|
Args:
|
|
193
|
-
origin (numpy.ndarray): Origin point coordinates
|
|
194
|
-
i (int): Row index
|
|
195
|
-
j (int): Column index
|
|
196
|
-
adjusted_meshsize (tuple): Adjusted mesh size in each dimension
|
|
273
|
+
origin (numpy.ndarray): Origin point coordinates (shape: (2,) or (3,))
|
|
274
|
+
i (int): Row index of the cell
|
|
275
|
+
j (int): Column index of the cell
|
|
276
|
+
adjusted_meshsize (tuple): Adjusted mesh size in each dimension (dx, dy)
|
|
197
277
|
u_vec (numpy.ndarray): Unit vector in first direction
|
|
198
278
|
v_vec (numpy.ndarray): Unit vector in second direction
|
|
199
279
|
|
|
200
280
|
Returns:
|
|
201
|
-
shapely.geometry.Polygon: Polygon representing the grid cell
|
|
281
|
+
shapely.geometry.Polygon: Polygon representing the grid cell, with vertices
|
|
282
|
+
ordered counter-clockwise from bottom-left
|
|
283
|
+
|
|
284
|
+
Example:
|
|
285
|
+
>>> origin = np.array([0, 0])
|
|
286
|
+
>>> i, j = 1, 2 # Cell at row 1, column 2
|
|
287
|
+
>>> mesh_size = (10, 10)
|
|
288
|
+
>>> u = np.array([1, 0])
|
|
289
|
+
>>> v = np.array([0, 1])
|
|
290
|
+
>>> cell_poly = create_cell_polygon(origin, i, j, mesh_size, u, v)
|
|
202
291
|
"""
|
|
203
292
|
# Calculate the four corners of the cell by adding scaled vectors
|
|
204
293
|
bottom_left = origin + i * adjusted_meshsize[0] * u_vec + j * adjusted_meshsize[1] * v_vec
|
|
@@ -213,11 +302,25 @@ def tree_height_grid_from_land_cover(land_cover_grid_ori):
|
|
|
213
302
|
"""
|
|
214
303
|
Convert a land cover grid to a tree height grid.
|
|
215
304
|
|
|
305
|
+
This function transforms a land cover classification grid into a grid of tree heights
|
|
306
|
+
by mapping land cover classes to predefined tree heights. The function first flips
|
|
307
|
+
the input grid vertically and adjusts class values, then applies a translation
|
|
308
|
+
dictionary to convert classes to heights.
|
|
309
|
+
|
|
310
|
+
Land cover class to tree height mapping:
|
|
311
|
+
- Class 4 (Forest): 10m height
|
|
312
|
+
- All other classes: 0m height
|
|
313
|
+
|
|
216
314
|
Args:
|
|
217
|
-
land_cover_grid_ori (numpy.ndarray): Original land cover grid
|
|
315
|
+
land_cover_grid_ori (numpy.ndarray): Original land cover grid with class values
|
|
218
316
|
|
|
219
317
|
Returns:
|
|
220
|
-
numpy.ndarray: Grid of tree heights
|
|
318
|
+
numpy.ndarray: Grid of tree heights in meters, with same dimensions as input
|
|
319
|
+
|
|
320
|
+
Example:
|
|
321
|
+
>>> lc_grid = np.array([[1, 4, 2], [4, 3, 4], [2, 1, 3]])
|
|
322
|
+
>>> tree_heights = tree_height_grid_from_land_cover(lc_grid)
|
|
323
|
+
>>> # Result: array([[0, 10, 0], [10, 0, 10], [0, 0, 0]])
|
|
221
324
|
"""
|
|
222
325
|
# Flip array vertically and add 1 to all values
|
|
223
326
|
land_cover_grid = np.flipud(land_cover_grid_ori) + 1
|
|
@@ -882,17 +985,35 @@ def create_dem_grid_from_geotiff_polygon(tiff_path, mesh_size, rectangle_vertice
|
|
|
882
985
|
return np.flipud(grid)
|
|
883
986
|
|
|
884
987
|
def grid_to_geodataframe(grid_ori, rectangle_vertices, meshsize):
|
|
885
|
-
"""
|
|
988
|
+
"""
|
|
989
|
+
Converts a 2D grid to a GeoDataFrame with cell polygons and values.
|
|
990
|
+
|
|
991
|
+
This function transforms a regular grid into a GeoDataFrame where each cell is
|
|
992
|
+
represented as a polygon. The transformation handles coordinate systems properly,
|
|
993
|
+
converting between WGS84 (EPSG:4326) and Web Mercator (EPSG:3857) for accurate
|
|
994
|
+
distance calculations.
|
|
886
995
|
|
|
887
996
|
Args:
|
|
888
|
-
|
|
889
|
-
rectangle_vertices: List of [lon, lat] coordinates defining area corners
|
|
890
|
-
|
|
997
|
+
grid_ori (numpy.ndarray): 2D array containing grid values
|
|
998
|
+
rectangle_vertices (list): List of [lon, lat] coordinates defining area corners.
|
|
999
|
+
Should be in WGS84 (EPSG:4326) format.
|
|
1000
|
+
meshsize (float): Size of each grid cell in meters
|
|
891
1001
|
|
|
892
1002
|
Returns:
|
|
893
|
-
GeoDataFrame with columns:
|
|
894
|
-
- geometry: Polygon geometry of each grid cell
|
|
895
|
-
- value: Value from the grid
|
|
1003
|
+
GeoDataFrame: A GeoDataFrame with columns:
|
|
1004
|
+
- geometry: Polygon geometry of each grid cell in WGS84 (EPSG:4326)
|
|
1005
|
+
- value: Value from the original grid
|
|
1006
|
+
|
|
1007
|
+
Example:
|
|
1008
|
+
>>> grid = np.array([[1, 2], [3, 4]])
|
|
1009
|
+
>>> vertices = [[lon1, lat1], [lon2, lat2], [lon3, lat3], [lon4, lat4]]
|
|
1010
|
+
>>> mesh_size = 100 # 100 meters
|
|
1011
|
+
>>> gdf = grid_to_geodataframe(grid, vertices, mesh_size)
|
|
1012
|
+
|
|
1013
|
+
Notes:
|
|
1014
|
+
- The input grid is flipped vertically before processing to match geographic
|
|
1015
|
+
orientation (north at top)
|
|
1016
|
+
- The output GeoDataFrame uses WGS84 (EPSG:4326) coordinate system
|
|
896
1017
|
"""
|
|
897
1018
|
grid = np.flipud(grid_ori.copy())
|
|
898
1019
|
|
|
@@ -951,17 +1072,36 @@ def grid_to_geodataframe(grid_ori, rectangle_vertices, meshsize):
|
|
|
951
1072
|
return gdf
|
|
952
1073
|
|
|
953
1074
|
def grid_to_point_geodataframe(grid_ori, rectangle_vertices, meshsize):
|
|
954
|
-
"""
|
|
1075
|
+
"""
|
|
1076
|
+
Converts a 2D grid to a GeoDataFrame with point geometries at cell centers and values.
|
|
1077
|
+
|
|
1078
|
+
This function transforms a regular grid into a GeoDataFrame where each cell is
|
|
1079
|
+
represented by a point at its center. The transformation handles coordinate systems
|
|
1080
|
+
properly, converting between WGS84 (EPSG:4326) and Web Mercator (EPSG:3857) for
|
|
1081
|
+
accurate distance calculations.
|
|
955
1082
|
|
|
956
1083
|
Args:
|
|
957
|
-
|
|
958
|
-
rectangle_vertices: List of [lon, lat] coordinates defining area corners
|
|
959
|
-
|
|
1084
|
+
grid_ori (numpy.ndarray): 2D array containing grid values
|
|
1085
|
+
rectangle_vertices (list): List of [lon, lat] coordinates defining area corners.
|
|
1086
|
+
Should be in WGS84 (EPSG:4326) format.
|
|
1087
|
+
meshsize (float): Size of each grid cell in meters
|
|
960
1088
|
|
|
961
1089
|
Returns:
|
|
962
|
-
GeoDataFrame with columns:
|
|
963
|
-
- geometry: Point geometry at center of each grid cell
|
|
964
|
-
- value: Value from the grid
|
|
1090
|
+
GeoDataFrame: A GeoDataFrame with columns:
|
|
1091
|
+
- geometry: Point geometry at center of each grid cell in WGS84 (EPSG:4326)
|
|
1092
|
+
- value: Value from the original grid
|
|
1093
|
+
|
|
1094
|
+
Example:
|
|
1095
|
+
>>> grid = np.array([[1, 2], [3, 4]])
|
|
1096
|
+
>>> vertices = [[lon1, lat1], [lon2, lat2], [lon3, lat3], [lon4, lat4]]
|
|
1097
|
+
>>> mesh_size = 100 # 100 meters
|
|
1098
|
+
>>> gdf = grid_to_point_geodataframe(grid, vertices, mesh_size)
|
|
1099
|
+
|
|
1100
|
+
Notes:
|
|
1101
|
+
- The input grid is flipped vertically before processing to match geographic
|
|
1102
|
+
orientation (north at top)
|
|
1103
|
+
- The output GeoDataFrame uses WGS84 (EPSG:4326) coordinate system
|
|
1104
|
+
- Points are placed at the center of each grid cell
|
|
965
1105
|
"""
|
|
966
1106
|
grid = np.flipud(grid_ori.copy())
|
|
967
1107
|
|
|
@@ -1220,7 +1360,7 @@ def create_dem_grid_from_gdf_polygon(terrain_gdf, mesh_size, polygon):
|
|
|
1220
1360
|
# (all points, not just inside the polygon)
|
|
1221
1361
|
# ------------------------------------------------------------------------
|
|
1222
1362
|
xs = np.linspace(left, right, num_cells_x)
|
|
1223
|
-
ys = np.linspace(top, bottom, num_cells_y) # top
|
|
1363
|
+
ys = np.linspace(top, bottom, num_cells_y) # top→bottom
|
|
1224
1364
|
X, Y = np.meshgrid(xs, ys)
|
|
1225
1365
|
|
|
1226
1366
|
# Flatten for convenience
|