voxcity 0.5.14__py3-none-any.whl → 0.5.15__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.

@@ -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
- rectangle_vertices (list): List of (lon, lat) tuples defining the rectangle vertices
21
- angle (float): Rotation angle in degrees
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. Defaults to (40, -100).
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 rectangle vertices when drawn
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 rectangle vertices when drawn
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
- east_west_length (float): Width of the rectangle in meters
152
- north_south_length (float): Height of the rectangle in meters
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 rectangle vertices when a point is clicked
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 (in Lon-Lat order) on an ipyleaflet map,
229
- and allows the user to draw a polygon whose vertices are returned
230
- in a Python list (also in Lon-Lat).
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
- with geometry in [lon, lat] order.
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
- - map_object: ipyleaflet Map instance
241
- - drawn_polygon_vertices: a Python list that gets updated whenever
242
- a new polygon is created. The list is in (lon, lat) order.
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
@@ -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
- Zero values remain unchanged.
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
- dem_grid (numpy.ndarray): Grid of elevation values
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: Grid size (tuple of ints) and adjusted mesh size (tuple of floats)
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: Coordinate mesh
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
- """Converts a 2D grid to a GeoDataFrame with cell polygons and values.
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
- grid: 2D numpy array containing grid values
889
- rectangle_vertices: List of [lon, lat] coordinates defining area corners
890
- meshsize: Size of each grid cell in meters
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
- """Converts a 2D grid to a GeoDataFrame with point geometries at cell centers and values.
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
- grid: 2D numpy array containing grid values
958
- rectangle_vertices: List of [lon, lat] coordinates defining area corners
959
- meshsize: Size of each grid cell in meters
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->bottom
1363
+ ys = np.linspace(top, bottom, num_cells_y) # topbottom
1224
1364
  X, Y = np.meshgrid(xs, ys)
1225
1365
 
1226
1366
  # Flatten for convenience