voxcity.downloader.ocean¶
Ocean detection using OSM coastlines via Overpass API.
OSM handles oceans by the “absence of land” principle: 1. The renderer starts with a blue canvas 2. Land polygons (derived from natural=coastline) are drawn on top 3. Anything not covered by land is ocean
This module queries coastlines from Overpass API and determines land/ocean based on the coastline orientation rule: land is on the LEFT of the coastline.
For areas without coastlines, we check if the point is in the ocean using a simple heuristic based on nearby land features.
Attributes¶
Functions¶
|
Get the land polygon for a given area using OSM coastlines. |
|
Generate a cache filename based on the bounding box and grid shape. |
|
Query coastline ways from Overpass API. |
|
Build land polygons by splitting bbox with coastlines. |
|
Determine if a polygon is land based on coastline orientation. |
Quick check: if an area has buildings/roads/land-use features, it's not pure ocean. |
|
|
Create a boolean mask where True = land, False = ocean. |
|
Get the appropriate ocean/water class name for a given land cover source. |
|
Apply ocean detection to an existing land cover grid. |
Module Contents¶
- voxcity.downloader.ocean.CACHE_DIR¶
- voxcity.downloader.ocean.get_land_polygon_for_area(rectangle_vertices: List[Tuple[float, float]], use_cache: bool = False)¶
Get the land polygon for a given area using OSM coastlines.
This is the main entry point for ocean detection. It queries coastlines from Overpass API and builds a polygon representing land areas.
- Parameters:
rectangle_vertices – List of (lon, lat) tuples defining the area
use_cache – Whether to use disk cache (default False)
- Returns:
Shapely Polygon/MultiPolygon representing land, or None if no coastlines found
- voxcity.downloader.ocean.get_cache_path(rectangle_vertices: List[Tuple[float, float]], grid_shape: Tuple[int, int]) pathlib.Path¶
Generate a cache filename based on the bounding box and grid shape.
- voxcity.downloader.ocean.query_coastlines_from_overpass(min_lat: float, min_lon: float, max_lat: float, max_lon: float, buffer_deg: float = 0.1, max_retries: int = 2) Tuple[dict, bool]¶
Query coastline ways from Overpass API.
- Parameters:
min_lat – Bounding box
min_lon – Bounding box
max_lat – Bounding box
max_lon – Bounding box
buffer_deg – Buffer around bbox to catch coastlines that might affect the area
max_retries – Per-endpoint retry count for transient errors (e.g., 429/5xx)
- Returns:
Tuple
(data, ok)wheredatais the Overpass JSON response ({'elements': []}on failure) andokis True only if the API actually returned a successful response. Callers should treatok == Falseas “API failure” rather than “no coastlines in area”.
- voxcity.downloader.ocean.build_coastline_polygons(overpass_data: dict, bbox: Tuple[float, float, float, float])¶
Build land polygons by splitting bbox with coastlines.
Algorithm: 1. Merge bbox boundary with all clipped coastlines to form a network 2. Use polygonize to create all possible polygons 3. For each polygon, determine if it’s land by checking the coastline direction
(land is on the LEFT of coastline when walking along it)
- Returns:
Shapely polygon representing land area, or None if processing fails
- voxcity.downloader.ocean.is_polygon_land(polygon, coastline_segments)¶
Determine if a polygon is land based on coastline orientation.
OSM Rule: Land is on the LEFT of the coastline direction.
- Algorithm (orientation-match, robust to non-convex / harbor-shaped polygons):
Force the polygon’s exterior to CCW orientation. With CCW orientation, the polygon’s interior lies on the LEFT of every exterior edge as you walk around it.
Walk consecutive vertex pairs
(a, b)of the exterior.For each edge whose midpoint lies on a coastline (within a tiny tolerance), look up the coastline segment containing that midpoint and compare its direction to the polygon edge direction via dot product:
dot > 0 -> edge follows coastline forward -> interior on LEFT of coastline -> LAND vote.
dot < 0 -> edge runs against coastline -> interior on RIGHT of coastline -> WATER vote.
Majority vote across all coastline-coincident edges. Defaults to land on tie or when no coastline-coincident edges exist (e.g., a polygon bounded entirely by the bbox boundary).
- voxcity.downloader.ocean.check_if_area_is_ocean_via_land_features(rectangle_vertices: List[Tuple[float, float]]) bool¶
Quick check: if an area has buildings/roads/land-use features, it’s not pure ocean.
Returns True if the area appears to be mostly ocean (few land features).
- voxcity.downloader.ocean.get_land_mask_from_coastlines(rectangle_vertices: List[Tuple[float, float]], grid_shape: Tuple[int, int], use_cache: bool = True) numpy.ndarray¶
Create a boolean mask where True = land, False = ocean.
Uses Overpass API to query coastlines and determine land/ocean areas. Much faster than downloading the full 600MB land polygons file.
- Parameters:
rectangle_vertices – List of (lon, lat) tuples defining the area
grid_shape – (rows, cols) of the output grid
use_cache – Whether to cache the result
- Returns:
Boolean array where True = land, False = ocean
- Return type:
np.ndarray
- voxcity.downloader.ocean.get_land_mask_from_osm_land_polygons¶
- voxcity.downloader.ocean.get_ocean_class_for_source(source: str) str¶
Get the appropriate ocean/water class name for a given land cover source.
- voxcity.downloader.ocean.apply_ocean_mask_to_grid(grid: numpy.ndarray, rectangle_vertices: List[Tuple[float, float]], source: str = 'OpenStreetMap', ocean_class: str | None = None) numpy.ndarray¶
Apply ocean detection to an existing land cover grid.
Cells that are: 1. Currently set to the default class (e.g., ‘Developed space’) 2. Located in ocean areas (outside OSM land polygons)
Will be changed to the ocean/water class.
- Parameters:
grid – Land cover grid (2D array of class names)
rectangle_vertices – Area coordinates
source – Land cover source name
ocean_class – Override for ocean class name (auto-detected if None)
- Returns:
Updated grid with ocean areas classified as water