# geo.point-in-polygon
Whether a point lies inside a polygon: geofences, delivery zones, "is this
address in the congestion charge area".
## Rules
- **The boundary is inside.** A point exactly on an edge or a vertex returns
true. Plain ray casting answers boundary points inconsistently (a point on
the east edge of a square comes out outside, one on the west edge inside), so
every edge is checked first: zero cross product and within the edge's
extent.
- **Even-odd rule.** A ray is cast towards increasing longitude and crossings
are counted, with a half-open test on latitude so a ray passing exactly
through a vertex counts it once, not twice. For a self-intersecting polygon
the overlapping parts count as outside.
- **Rings.** Vertices in order, either winding. Closing the ring (repeating
the first vertex at the end) is optional. Fewer than 3 distinct vertices is
an error.
- **Coordinates** must be in -90..90 and -180..180.
## What it deliberately does not do
It works on the flat longitude/latitude plane, treating edges as straight
lines in degrees. That is how GeoJSON polygons and most map tools draw them,
and it is accurate for zones of city or county size. It does not handle holes
(test the outer ring, then each hole), polygons that cross the antimeridian
(split them), or polygons that contain a pole.
## Floating point
Only + − × ÷ and comparisons are used, in the same order in TypeScript,
Python and Rust, so all three give the same answer for every input, including
points so close to an edge that rounding decides them. Boundary detection is
exact when the coordinates' products are exact (integers, or few decimals at
small scale); for a point within about 1e-15 degrees of an edge given in
arbitrary decimals, rounding decides, identically in every language. On 4,000
random cases, half of them on an integer grid to hit edges and vertices, the
three languages agreed on every answer.