aboutsummaryrefslogtreecommitdiffstats
path: root/packages/math/polygon.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/math/polygon.ts')
-rw-r--r--packages/math/polygon.ts72
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]);
+}