import { Polygon } from "../geometry/polygon.ts"; import { SplineSegment } from "../geometry/spline.ts"; import { Vector } from "../geometry/vector.ts"; import { axisAlignedBoundingBox } from "./aa.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().sub(center).normalize(); const proj1 = projectPolygonOntoAxis(p, axis); const proj2 = projectCircleOntoAxis(circle, axis); if (!overlap(proj1, proj2)) return false; return true; } export function satCollisionAABBCircle( aabb: axisAlignedBoundingBox, circle: CircleLike, ): boolean { const p = new Polygon([ { x: aabb.x, y: aabb.y }, { x: aabb.x + aabb.w, y: aabb.y }, { x: aabb.x + aabb.w, y: aabb.y + aabb.h }, { x: aabb.x, y: aabb.y + aabb.h }, ]); return satCollisionCircle(p, circle); } 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; }