import { axisAlignedBoundingBox } from "../collision/aa.ts"; import { CircleLike } from "../collision/circular.ts"; import { Vector } from "../mod.ts"; import { Point } from "./vector.ts"; export class Polygon { points: Vector[]; center: Vector; constructor(points: Point[]) { this.points = points.map((p) => new Vector(p)); this.center = this.calcCenter(); } draw(color?: string) { for (let i = 0; i < this.points.length; i++) { const p1 = this.points[i]; const p2 = this.points.at(i - this.points.length + 1)!; doodler.line(p1.copy().add(this.center), p2.copy().add(this.center), { color, }); } } calcCenter() { if (!this.points.length) return new Vector(); const center = new Vector(); for (const point of this.points) { center.add(point); } center.div(this.points.length); return center; } get circularHitbox(): CircleLike { let greatestDistance = 0; for (const p of this.points) { greatestDistance = Math.max( p.copy().add(this.center).dist(this.center), greatestDistance, ); } return { center: this.center.copy(), radius: greatestDistance, }; } _aabb?: axisAlignedBoundingBox; get AABB(): axisAlignedBoundingBox { if (!this._aabb) { this._aabb = this.recalculateAABB(); } return this._aabb; } recalculateAABB(): axisAlignedBoundingBox { let smallestX, biggestX, smallestY, biggestY; smallestX = smallestY = Infinity; biggestX = biggestY = -Infinity; for (const p of this.points) { const temp = p.copy().add(this.center); smallestX = Math.min(temp.x, smallestX); biggestX = Math.max(temp.x, biggestX); smallestY = Math.min(temp.y, smallestY); biggestY = Math.max(temp.y, biggestY); } return { x: smallestX, y: smallestY, w: biggestX - smallestX, h: biggestY - smallestY, }; } static createPolygon(sides = 3, radius = 100) { sides = Math.round(sides); if (sides < 3) { throw "You need at least 3 sides for a polygon"; } const poly = new Polygon([]); // figure out the angles required const rotangle = (Math.PI * 2) / sides; let angle = 0; // loop through and generate each point for (let i = 0; i < sides; i++) { angle = (i * rotangle) + ((Math.PI - rotangle) * 0.5); const pt = new Vector(Math.cos(angle) * radius, Math.sin(angle) * radius); poly.points.push(pt); } poly.center = poly.calcCenter(); return poly; } getEdges(): Vector[] { const edges: Vector[] = []; for (let i = 0; i < this.points.length; i++) { const nextIndex = (i + 1) % this.points.length; const edge = this.points[nextIndex].copy().add(this.center).sub( this.points[i].copy().add(this.center), ); edges.push(edge); } return edges; } getNearestPoint(p: Vector) { let nearest = this.points[0]; for (const point of this.points) { if (p.dist(point) < p.dist(nearest)) nearest = point; } return nearest; } }