126 lines
3.4 KiB
TypeScript

import { Polygon } from "../geometry/polygon.ts";
import { SplineSegment } from "../geometry/spline.ts";
import { Vector } from "../geometry/vector.ts";
import { CircleLike } from "./circular.ts";
export function satCollisionSpline(p: Polygon, spline: SplineSegment): boolean {
const numSegments = 100; // You can adjust the number of segments based on your needs
for (let i = 0; i < numSegments; i++) {
const t1 = i / numSegments;
const t2 = (i + 1) / numSegments;
const segmentStart = spline.getPointAtT(t1);
const segmentEnd = spline.getPointAtT(t2);
if (segmentIntersectsPolygon(p, segmentStart, segmentEnd)) {
return true;
}
}
return false;
}
export function satCollisionPolygon(poly: Polygon, poly2: Polygon): boolean {
for (const edge of poly.getEdges()) {
const axis = edge.copy().normal().normalize();
const proj1 = projectPolygonOntoAxis(poly, axis);
const proj2 = projectPolygonOntoAxis(poly2, axis);
if (!overlap(proj1, proj2)) return false;
}
for (const edge of poly2.getEdges()) {
const axis = edge.copy().normal().normalize();
const proj1 = projectPolygonOntoAxis(poly, axis);
const proj2 = projectPolygonOntoAxis(poly2, axis);
if (!overlap(proj1, proj2)) return false;
}
return true;
}
export function satCollisionCircle(p: Polygon, circle: CircleLike): boolean {
for (const edge of p.getEdges()) {
const axis = edge.copy().normal().normalize();
const proj1 = projectPolygonOntoAxis(p, axis);
const proj2 = projectCircleOntoAxis(circle, axis);
if (!overlap(proj1, proj2)) return false;
}
const center = new Vector(circle.center);
const nearest = p.getNearestPoint(center);
const axis = nearest.copy().normal(center).normalize();
const proj1 = projectPolygonOntoAxis(p, axis);
const proj2 = projectCircleOntoAxis(circle, axis);
if (!overlap(proj1, proj2)) return false;
return true;
}
function segmentIntersectsPolygon(
p: Polygon,
start: Vector,
end: Vector,
): boolean {
const edges = p.getEdges();
for (const edge of edges) {
// const axis = new Vector(-edge.y, edge.x).normalize();
const axis = edge.copy().normal().normalize();
const proj1 = projectPolygonOntoAxis(p, axis);
const proj2 = projectSegmentOntoAxis(start, end, axis);
if (!overlap(proj1, proj2)) {
return false; // No overlap, no intersection
}
}
return true; // Overlapping on all axes, intersection detected
}
function projectPolygonOntoAxis(
p: Polygon,
axis: Vector,
): { min: number; max: number } {
let min = Infinity;
let max = -Infinity;
for (const point of p.points) {
const dotProduct = point.copy().add(p.center).dot(axis);
min = Math.min(min, dotProduct);
max = Math.max(max, dotProduct);
}
return { min, max };
}
function projectSegmentOntoAxis(
start: Vector,
end: Vector,
axis: Vector,
): { min: number; max: number } {
const dotProductStart = start.dot(axis);
const dotProductEnd = end.dot(axis);
return {
min: Math.min(dotProductStart, dotProductEnd),
max: Math.max(dotProductStart, dotProductEnd),
};
}
function projectCircleOntoAxis(
c: CircleLike,
axis: Vector,
): { min: number; max: number } {
const dot = new Vector(c.center).dot(axis);
const min = dot - c.radius;
const max = dot + c.radius;
return { min, max };
}
function overlap(
proj1: { min: number; max: number },
proj2: { min: number; max: number },
): boolean {
return proj1.min <= proj2.max && proj1.max >= proj2.min;
}