sat circle collision

This commit is contained in:
2023-11-03 05:46:50 -06:00
parent 62b13e49e7
commit 9d8a0fc7d2
4 changed files with 141 additions and 168 deletions

View File

@@ -1,5 +1,6 @@
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));
@@ -8,98 +9,105 @@ export const satCollision = (s1: Polygon, s2: Polygon) => {
if (shape1.length < 2 || shape2.length < 2) {
throw "Insufficient shape data in satCollision";
}
const offset = new Vector(s1.center).sub(s2.center);
// Take one side of the polygon and find the normal
let last: Vector[] = [];
for (let i = 0; i < shape1.length; i++) {
const axis = shape1[i].normal(shape1.at(i - 1)!);
// axis.draw();
let [p1min, p1minDot] = Vector.vectorProjectionAndDot(shape1[0], axis);
let [p1max, p1maxDot] = [p1min, p1minDot];
let [_, p1minDot] = Vector.vectorProjectionAndDot(shape1[0], axis);
let p1maxDot = p1minDot;
for (const point of shape1) {
const [projected, dot] = Vector.vectorProjectionAndDot(point, axis);
// projected.drawDot();
p1min = dot < p1minDot ? projected : p1min;
const [_, dot] = Vector.vectorProjectionAndDot(point, axis);
p1minDot = Math.min(dot, p1minDot);
p1max = dot > p1maxDot ? projected : p1max;
p1maxDot = Math.max(dot, p1maxDot);
}
let [p2min, p2minDot] = Vector.vectorProjectionAndDot(shape2[0], axis);
let [p2max, p2maxDot] = [p2min, p2minDot];
let [__, p2minDot] = Vector.vectorProjectionAndDot(shape2[0], axis);
let p2maxDot = p2minDot;
for (const point of shape2) {
const [projected, dot] = Vector.vectorProjectionAndDot(point, axis);
// projected.drawDot();
p2min = dot < p2minDot ? projected : p2min;
const [_, dot] = Vector.vectorProjectionAndDot(point, axis);
p2minDot = Math.min(dot, p2minDot);
p2max = dot > p2maxDot ? projected : p2max;
p2maxDot = Math.max(dot, p2maxDot);
}
// const scale = axis.dot(offset);
// p1max += scale;
// p1min += scale;
// let p2min = axis.dot(shape1[0]);
// let p2max = p2min;
// for (const point of shape2) {
// const dot = point.dot(axis);
// p2max = Math.max(p2max, dot);
// p2min = Math.min(p2min, dot);
// Vector.vectorProjection(point, axis).drawDot();
// }
if (p1minDot - p2maxDot > 0 || p2minDot - p1maxDot > 0) {
// axis.draw();
// p1max.drawDot("blue");
// p1min.drawDot("lime");
// p2max.drawDot("blue");
// p2min.drawDot("lime");
return false;
}
last = [axis, p1max, p1min, p2max, p2min];
}
for (let i = 0; i < shape2.length; i++) {
const axis = shape2[i].normal(shape2.at(i - 1)!);
// axis.draw();
let [p1min, p1minDot] = Vector.vectorProjectionAndDot(shape2[0], axis);
let [p1max, p1maxDot] = [p1min, p1minDot];
let [_, p1minDot] = Vector.vectorProjectionAndDot(shape2[0], axis);
let p1maxDot = p1minDot;
for (const point of shape2) {
const [projected, dot] = Vector.vectorProjectionAndDot(point, axis);
// projected.drawDot();
p1min = dot < p1minDot ? projected : p1min;
const [_, dot] = Vector.vectorProjectionAndDot(point, axis);
// p1min = dot < p1minDot ? projected : p1min;
p1minDot = Math.min(dot, p1minDot);
p1max = dot > p1maxDot ? projected : p1max;
// p1max = dot > p1maxDot ? projected : p1max;
p1maxDot = Math.max(dot, p1maxDot);
}
let [p2min, p2minDot] = Vector.vectorProjectionAndDot(shape1[0], axis);
let [p2max, p2maxDot] = [p2min, p2minDot];
let [__, p2minDot] = Vector.vectorProjectionAndDot(shape1[0], axis);
let p2maxDot = p2minDot;
for (const point of shape1) {
const [projected, dot] = Vector.vectorProjectionAndDot(point, axis);
// projected.drawDot();
p2min = dot < p2minDot ? projected : p2min;
const [_, dot] = Vector.vectorProjectionAndDot(point, axis);
// p2min = dot < p2minDot ? projected : p2min;
p2minDot = Math.min(dot, p2minDot);
p2max = dot > p2maxDot ? projected : p2max;
// p2max = dot > p2maxDot ? projected : p2max;
p2maxDot = Math.max(dot, p2maxDot);
}
if (p1minDot - p2maxDot > 0 || p2minDot - p1maxDot > 0) {
// axis.draw();
// p1max.drawDot("blue");
// p1min.drawDot("lime");
// p2max.drawDot("blue");
// p2min.drawDot("lime");
return false;
}
last = [axis, p1max, p1min, p2max, p2min];
}
// for (const [i, l] of last.entries()) {
// if (i === 0) {
// l.draw();
// } else {
// l.drawDot();
// }
// }
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;
};