remove geometry.ts
This commit is contained in:
@@ -1,147 +0,0 @@
|
|||||||
export interface Point {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Polygon = Point[];
|
|
||||||
|
|
||||||
export const signedDistanceToEdge = (edgeStart: Point, edgeEnd: Point, point: Point): number =>
|
|
||||||
(edgeEnd.x - edgeStart.x) * (point.y - edgeStart.y)
|
|
||||||
- (edgeEnd.y - edgeStart.y) * (point.x - edgeStart.x);
|
|
||||||
|
|
||||||
export const iterateEdges = (
|
|
||||||
polygon: Polygon,
|
|
||||||
callback: (current: Point, next: Point, index: number) => boolean | void,
|
|
||||||
): void => {
|
|
||||||
if (!Array.isArray(polygon) || polygon.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let index = 0; index < polygon.length; index += 1) {
|
|
||||||
const current = polygon[index];
|
|
||||||
const next = polygon[(index + 1) % polygon.length];
|
|
||||||
if (callback(current, next, index) === false) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const forEachVertex = (
|
|
||||||
polygon: Polygon,
|
|
||||||
callback: (current: Point, previous: Point, index: number) => boolean | void,
|
|
||||||
): void => {
|
|
||||||
if (!Array.isArray(polygon) || polygon.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let index = 0; index < polygon.length; index += 1) {
|
|
||||||
const current = polygon[index];
|
|
||||||
const prev = polygon[(index - 1 + polygon.length) % polygon.length];
|
|
||||||
if (callback(current, prev, index) === false) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const lineIntersection = (p1: Point, p2: Point, cp1: Point, cp2: Point): Point => {
|
|
||||||
const A1 = p2.y - p1.y;
|
|
||||||
const B1 = p1.x - p2.x;
|
|
||||||
const C1 = A1 * p1.x + B1 * p1.y;
|
|
||||||
|
|
||||||
const A2 = cp2.y - cp1.y;
|
|
||||||
const B2 = cp1.x - cp2.x;
|
|
||||||
const C2 = A2 * cp1.x + B2 * cp1.y;
|
|
||||||
|
|
||||||
const det = A1 * B2 - A2 * B1;
|
|
||||||
if (Math.abs(det) < 1e-6) {
|
|
||||||
return { x: cp1.x, y: cp1.y };
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
x: (B2 * C1 - B1 * C2) / det,
|
|
||||||
y: (A1 * C2 - A2 * C1) / det,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const clipPolygon = (subject: Polygon, clipper: Polygon): Polygon => {
|
|
||||||
if (!Array.isArray(subject) || !subject.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
let output = subject;
|
|
||||||
iterateEdges(clipper, (cp1, cp2) => {
|
|
||||||
const input = output;
|
|
||||||
output = [];
|
|
||||||
if (!Array.isArray(input) || !input.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
forEachVertex(input, (current, prev) => {
|
|
||||||
const currentInside = signedDistanceToEdge(cp1, cp2, current) >= 0;
|
|
||||||
const prevInside = signedDistanceToEdge(cp1, cp2, prev) >= 0;
|
|
||||||
if (currentInside) {
|
|
||||||
if (!prevInside) {
|
|
||||||
output.push(lineIntersection(prev, current, cp1, cp2));
|
|
||||||
}
|
|
||||||
output.push(current);
|
|
||||||
} else if (prevInside) {
|
|
||||||
output.push(lineIntersection(prev, current, cp1, cp2));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
return output.length > 0;
|
|
||||||
});
|
|
||||||
return output;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isPointInsideConvex = (point: Point, polygon: Polygon): boolean => {
|
|
||||||
if (!polygon?.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let sign = 0;
|
|
||||||
let inside = true;
|
|
||||||
iterateEdges(polygon, (a, b) => {
|
|
||||||
const cross = signedDistanceToEdge(a, b, point);
|
|
||||||
if (cross === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const currentSign = cross > 0 ? 1 : -1;
|
|
||||||
if (sign === 0) {
|
|
||||||
sign = currentSign;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (sign !== currentSign) {
|
|
||||||
inside = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
return inside;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const polygonCentroid = (polygon: Polygon): Point => {
|
|
||||||
if (!polygon?.length) {
|
|
||||||
return { x: 0, y: 0 };
|
|
||||||
}
|
|
||||||
let area = 0;
|
|
||||||
let cx = 0;
|
|
||||||
let cy = 0;
|
|
||||||
iterateEdges(polygon, (current, next) => {
|
|
||||||
const cross = current.x * next.y - next.x * current.y;
|
|
||||||
area += cross;
|
|
||||||
cx += (current.x + next.x) * cross;
|
|
||||||
cy += (current.y + next.y) * cross;
|
|
||||||
});
|
|
||||||
if (Math.abs(area) < 1e-6) {
|
|
||||||
let sumX = 0;
|
|
||||||
let sumY = 0;
|
|
||||||
forEachVertex(polygon, (point) => {
|
|
||||||
sumX += point.x;
|
|
||||||
sumY += point.y;
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
x: sumX / polygon.length,
|
|
||||||
y: sumY / polygon.length,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const areaFactor = 1 / (3 * area);
|
|
||||||
return {
|
|
||||||
x: cx * areaFactor,
|
|
||||||
y: cy * areaFactor,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user