Functional Weave
Code in Python

geo.point-in-polygon@1.0.0

README.md

1,942 bytes · view raw

# 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.