lunar_toolkit.geometry

Search regions and AOI polygons (lon/lat, 0–360 east; polar stereographic past ±60°).

Aoi(polygons, source='') dataclass

Area of interest: one or more lon/lat polygons (degrees, positive east).

polygons holds, per polygon, its exterior ring followed by any holes. Rings are open (no repeated closing vertex), densified and longitude unwrapped so consecutive vertices never jump across the 0/360 seam (values may lie outside 0..360). A ring whose longitudes wind once around the globe encloses a pole.

wkt property

MULTIPOLYGON WKT of the (unwrapped) rings.

ps_xy(lat, lon, hemi)

Polar stereographic (x, y) in metres; mirrors the SQL _ps_* macros.

query_region(lat=None, lon=None, point=None, radius_km=0.0)

Normalise a bbox or point+radius into lat range, lon arc and PS boxes.

region_bbox(region)

(west, south, east, north) of a query_region (east may be < west).

load_aoi(source, densify_deg=1.0)

Load an area of interest from GeoJSON, WKT or a box / circle region.

Parameters:
  • source ((str, Path, dict or Aoi)) –

    A .geojson / .json file (Feature, FeatureCollection or bare Geometry), a .wkt (or any text) file, a raw WKT string, a GeoJSON mapping, a region dict {"point": (lat, lon), "radius_km": r} (spherical cap) or {"lat": (south, north), "lon": (west, east)} (west > east crosses 0/360; omit lon for all longitudes), or an existing Aoi (returned unchanged). Only Polygon / MultiPolygon parts are used (also inside GeometryCollections); coordinates are lon/lat degrees, positive east, in either −180..180 or 0..360. Polygons may cross the 0/360 (or ±180) seam or wind around a pole.

  • densify_deg (float, default: 1.0 ) –

    Insert vertices so no edge spans more than this many degrees of latitude or longitude. Edges are taken as straight in lon/lat (as in GeoJSON); densifying keeps them that way once projected to polar stereographic. None keeps the input vertices.

Returns:

aoi_region(aoi)

Bounding region of an AOI, in query_region form.

Returns {"lat": (s, n), "west", "span", "ps"} so the bbox prefilter used for boxes and circles applies unchanged; refine the prefiltered rows with filter_aoi.

ps_projection(hemi)

Ring projection to polar stereographic (ps_xy) for hemisphere hemi.

aoi_geometry(aoi, proj=None)

AOI as one shapely geometry: rings projected by proj, else seam-replicated lon/lat.

footprint_geometry(rings_list, proj)

Footprint polygons (per polygon: lon/lat exterior, *holes) as shapely geometry.

Rings are projected by proj (e.g. ps_projection), else kept in lon/lat (pole-enclosing rings closed via the pole) starting in 0..360.

footprint_rings(row, wkt_column=None)

Footprint of a result row as lon/lat rings (per polygon: exterior, *holes).

Source: the wkt_column WKT, else the four corner lat/lon columns, else the FP_* / min_lat…lon_east bounding box; None if none.

row_footprint(row, wkt_column=None, proj=None)

Shapely footprint (footprint_geometry) of a result row, or None.

aoi_mask(df, aoi, wkt_column=None)

Per-row flag: does the row's footprint intersect the AOI exactly?

Footprint source, per row: the WKT column (FP_WKT for CumIndex, footprint_wkt for observations, or wkt_column), else the four corner lat/lon columns, else the FP_* / min_lat…lon_east bounding box. Rows with no geometry at all are kept.

aoi is anything load_aoi accepts. Regions entirely poleward of ±60° (POLAR_LAT_THRESHOLD) are intersected in polar stereographic (ps_xy, footprint edges straight in the projection); others in lon/lat with the AOI replicated at ±360° so footprints across the 0/360 seam match.

filter_aoi(df, aoi, wkt_column=None)

Keep only rows whose footprint intersects the AOI (see aoi_mask).