File size: 1,827 Bytes
f49f471
 
 
ab42110
f49f471
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ab42110
f49f471
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
"""Generate a regular grid over the water area."""

import numpy as np
from shapely import contains_xy


# Approximate meters per degree at ~60°N latitude
METERS_PER_DEG_LAT = 111_320.0
METERS_PER_DEG_LON = 55_660.0  # 111320 * cos(60°)


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
    # Extend slightly to catch boundary cells
    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))