| """Generate a regular grid over the water area.""" |
|
|
| import numpy as np |
| from shapely import contains_xy |
|
|
|
|
| |
| METERS_PER_DEG_LAT = 111_320.0 |
| METERS_PER_DEG_LON = 55_660.0 |
|
|
|
|
| def generate_grid( |
| water_polygon, |
| cell_size_m: float = 200.0, |
| ) -> tuple[np.ndarray, np.ndarray, float, float]: |
| """Generate grid points that lie within the water polygon. |
| |
| Parameters |
| ---------- |
| water_polygon : shapely geometry |
| Union of all water zone polygons. |
| cell_size_m : float |
| Grid cell size in meters. |
| |
| Returns |
| ------- |
| lats : ndarray of shape (N,) |
| Latitudes of water grid cells. |
| lons : ndarray of shape (N,) |
| Longitudes of water grid cells. |
| dlat : float |
| Grid step in latitude degrees. |
| dlon : float |
| Grid step in longitude degrees. |
| """ |
| dlat = cell_size_m / METERS_PER_DEG_LAT |
| dlon = cell_size_m / METERS_PER_DEG_LON |
|
|
| minx, miny, maxx, maxy = water_polygon.bounds |
| |
| lat_range = np.arange(miny, maxy + dlat, dlat) |
| lon_range = np.arange(minx, maxx + dlon, dlon) |
|
|
| lon_grid, lat_grid = np.meshgrid(lon_range, lat_range) |
| lon_flat = lon_grid.ravel() |
| lat_flat = lat_grid.ravel() |
|
|
| mask = contains_xy(water_polygon, lon_flat, lat_flat) |
|
|
| return lat_flat[mask], lon_flat[mask], dlat, dlon |
|
|
|
|
| def snap_to_grid( |
| lat: float, |
| lon: float, |
| grid_lats: np.ndarray, |
| grid_lons: np.ndarray, |
| ) -> int: |
| """Find the nearest grid cell index for a given coordinate. |
| |
| Uses approximate Euclidean distance weighted for latitude. |
| """ |
| dlat = grid_lats - lat |
| dlon = (grid_lons - lon) * (METERS_PER_DEG_LON / METERS_PER_DEG_LAT) |
| dist_sq = dlat**2 + dlon**2 |
| return int(np.argmin(dist_sq)) |
|
|