/** * Point-in-polygon geometry for CAP (Common Alerting Protocol) alert areas. * * Pure, zero-I/O module — no imports beyond types (design pattern 6 in * CLAUDE.md: service fetches -> pure util computes -> handler renders). * * Coordinate order: ring points are `[lat, lon]` pairs, matching CAP's * `` coordinate order. Do not swap to lon/lat. * * **Precondition — no antimeridian handling.** Rings are assumed not to * cross +/-180 degrees longitude. This holds for the feeds this module was * built for (India, the Philippines, Indonesia), none of which have alert * polygons that straddle the antimeridian. * * **Revisit trigger:** adding a feed for a country whose alert polygons can * cross 180 degrees longitude (e.g. Fiji, New Zealand) — this module would * need antimeridian-aware longitude normalization before it could be reused * for that feed. */ /** * One polygon ring: an ordered list of `[lat, lon]` pairs. * * Declared `readonly` throughout so a caller may pass a frozen or generated * constant (e.g. `src/data/jmaAreas.ts`) without copying it. Nothing in this * module writes to a ring, so this is a type-level widening only — a mutable * `Array<[number, number]>` still satisfies it, and every existing caller is * unchanged. */ export type Ring = ReadonlyArray; /** * Test whether `(lat, lon)` lies inside (or exactly on the boundary of) a * single polygon ring. * * Algorithm: a cheap bounding-box rejection first, then an explicit * on-edge/on-vertex check (boundary points always count as inside), then * even-odd ray casting for the strict-interior case. The ray-casting * crossing test compares longitude against the test longitude, so an edge * with two consecutive points sharing a longitude (a vertical edge) is * always excluded from the intersect branch and never divides by zero — * this is the classic double-count/divide-by-zero trap for a naive * ray-casting implementation. * * A degenerate ring (fewer than 3 distinct points) returns `false`, as does * a `NaN` coordinate (every comparison against `NaN` is false), so malformed * geometry never throws. There is deliberately **no blanket `try/catch`**: * this is a matching predicate on safety data, and silently answering "not * inside" on an unexpected fault would drop a warning that does cover the * point — the fabricated-all-clear direction the project's contract posture * forbids. Malformed input is handled by the explicit guards above; a genuine * defect should surface loudly. */ export declare function pointInRing(lat: number, lon: number, ring: Ring): boolean; /** * Test whether `(lat, lon)` lies inside (or on the boundary of) any of the * given rings — used for a CAP `` with multiple `` elements. * * `rings` empty returns `false`. Never throws. */ export declare function pointInAnyRing(lat: number, lon: number, rings: readonly Ring[]): boolean; //# sourceMappingURL=pointInPolygon.d.ts.map