diff options
Diffstat (limited to 'packages/math/polygon.ts')
| -rw-r--r-- | packages/math/polygon.ts | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/packages/math/polygon.ts b/packages/math/polygon.ts new file mode 100644 index 0000000..783bc4c --- /dev/null +++ b/packages/math/polygon.ts @@ -0,0 +1,72 @@ +import { pointsEqual } from "./point"; +import { lineSegment, pointOnLineSegment } from "./segment"; +import type { GlobalPoint, LocalPoint, Polygon } from "./types"; +import { PRECISION } from "./utils"; + +export function polygon<Point extends GlobalPoint | LocalPoint>( + ...points: Point[] +) { + return polygonClose(points) as Polygon<Point>; +} + +export function polygonFromPoints<Point extends GlobalPoint | LocalPoint>( + points: Point[], +) { + return polygonClose(points) as Polygon<Point>; +} + +export const polygonIncludesPoint = <Point extends LocalPoint | GlobalPoint>( + point: Point, + polygon: Polygon<Point>, +) => { + const x = point[0]; + const y = point[1]; + let inside = false; + + for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { + const xi = polygon[i][0]; + const yi = polygon[i][1]; + const xj = polygon[j][0]; + const yj = polygon[j][1]; + + if ( + ((yi > y && yj <= y) || (yi <= y && yj > y)) && + x < ((xj - xi) * (y - yi)) / (yj - yi) + xi + ) { + inside = !inside; + } + } + + return inside; +}; + +export const pointOnPolygon = <Point extends LocalPoint | GlobalPoint>( + p: Point, + poly: Polygon<Point>, + threshold = PRECISION, +) => { + let on = false; + + for (let i = 0, l = poly.length - 1; i < l; i++) { + if (pointOnLineSegment(p, lineSegment(poly[i], poly[i + 1]), threshold)) { + on = true; + break; + } + } + + return on; +}; + +function polygonClose<Point extends LocalPoint | GlobalPoint>( + polygon: Point[], +) { + return polygonIsClosed(polygon) + ? polygon + : ([...polygon, polygon[0]] as Polygon<Point>); +} + +function polygonIsClosed<Point extends LocalPoint | GlobalPoint>( + polygon: Point[], +) { + return pointsEqual(polygon[0], polygon[polygon.length - 1]); +} |
