import { Polygon } from "../geometry/polygon.ts"; import { Point, Vector } from "../geometry/vector.ts"; import { CircleLike } from "./circular.ts"; export const satCollision = (s1: Polygon, s2: Polygon) => { const shape1 = s1.points.map((p) => new Vector(p).add(s1.center)); const shape2 = s2.points.map((p) => new Vector(p).add(s2.center)); if (shape1.length < 2 || shape2.length < 2) { throw "Insufficient shape data in satCollision"; } for (let i = 0; i < shape1.length; i++) { const axis = shape1[i].normal(shape1.at(i - 1)!); let [_, p1minDot] = Vector.vectorProjectionAndDot(shape1[0], axis); let p1maxDot = p1minDot; for (const point of shape1) { const [_, dot] = Vector.vectorProjectionAndDot(point, axis); p1minDot = Math.min(dot, p1minDot); p1maxDot = Math.max(dot, p1maxDot); } let [__, p2minDot] = Vector.vectorProjectionAndDot(shape2[0], axis); let p2maxDot = p2minDot; for (const point of shape2) { const [_, dot] = Vector.vectorProjectionAndDot(point, axis); p2minDot = Math.min(dot, p2minDot); p2maxDot = Math.max(dot, p2maxDot); } if (p1minDot - p2maxDot > 0 || p2minDot - p1maxDot > 0) { return false; } } for (let i = 0; i < shape2.length; i++) { const axis = shape2[i].normal(shape2.at(i - 1)!); let [_, p1minDot] = Vector.vectorProjectionAndDot(shape2[0], axis); let p1maxDot = p1minDot; for (const point of shape2) { const [_, dot] = Vector.vectorProjectionAndDot(point, axis); // p1min = dot < p1minDot ? projected : p1min; p1minDot = Math.min(dot, p1minDot); // p1max = dot > p1maxDot ? projected : p1max; p1maxDot = Math.max(dot, p1maxDot); } let [__, p2minDot] = Vector.vectorProjectionAndDot(shape1[0], axis); let p2maxDot = p2minDot; for (const point of shape1) { const [_, dot] = Vector.vectorProjectionAndDot(point, axis); // p2min = dot < p2minDot ? projected : p2min; p2minDot = Math.min(dot, p2minDot); // p2max = dot > p2maxDot ? projected : p2max; p2maxDot = Math.max(dot, p2maxDot); } if (p1minDot - p2maxDot > 0 || p2minDot - p1maxDot > 0) { return false; } } return true; }; export const satCollisionCircle = (s: Polygon, c: CircleLike) => { const shape = s.points.map((p) => new Vector(p).add(s.center)); if (shape.length < 2) { throw "Insufficient shape data in satCollisionCircle"; } for (let i = 0; i < shape.length; i++) { const axis = shape[i].normal(shape.at(i - 1)!); let [_, p1minDot] = Vector.vectorProjectionAndDot(shape[0], axis); let p1maxDot = p1minDot; for (const point of shape) { const [_, dot] = Vector.vectorProjectionAndDot(point, axis); p1minDot = Math.min(dot, p1minDot); p1maxDot = Math.max(dot, p1maxDot); } const [__, circleDot] = Vector.vectorProjectionAndDot( new Vector(c.center), axis, ); const p2minDot = circleDot - c.radius; const p2maxDot = circleDot + c.radius; if (p1minDot - p2maxDot > 0 || p2minDot - p1maxDot > 0) { return false; } } const center = new Vector(c.center); let nearest = shape[0]; for (const p of shape) { if (center.dist(p) < center.dist(nearest)) nearest = p; } const axis = center.sub(nearest); let [_, p1minDot] = Vector.vectorProjectionAndDot(shape[0], axis); let p1maxDot = p1minDot; for (const point of shape) { const [_, dot] = Vector.vectorProjectionAndDot(point, axis); p1minDot = Math.min(dot, p1minDot); p1maxDot = Math.max(dot, p1maxDot); } const [__, circleDot] = Vector.vectorProjectionAndDot( new Vector(c.center), axis, ); const p2minDot = circleDot - c.radius; const p2maxDot = circleDot + c.radius; if (p1minDot - p2maxDot > 0 || p2minDot - p1maxDot > 0) { return false; } return true; };