module exports
This commit is contained in:
parent
ea311a1787
commit
69ab471d22
363
bundle.js
363
bundle.js
@ -684,6 +684,184 @@ class OriginVector extends Vector {
|
|||||||
return new OriginVector(origin, v);
|
return new OriginVector(origin, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class SplineSegment {
|
||||||
|
points;
|
||||||
|
length;
|
||||||
|
constructor(points){
|
||||||
|
this.points = points;
|
||||||
|
this.length = this.calculateApproxLength(100);
|
||||||
|
}
|
||||||
|
draw(color) {
|
||||||
|
const [a, b, c, d] = this.points;
|
||||||
|
doodler.drawBezier(a, b, c, d, {
|
||||||
|
strokeColor: color || "#ffffff50"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getPointAtT(t) {
|
||||||
|
const [a, b, c, d] = this.points;
|
||||||
|
const res = a.copy();
|
||||||
|
res.add(Vector.add(a.copy().mult(-3), b.copy().mult(3)).mult(t));
|
||||||
|
res.add(Vector.add(Vector.add(a.copy().mult(3), b.copy().mult(-6)), c.copy().mult(3)).mult(Math.pow(t, 2)));
|
||||||
|
res.add(Vector.add(Vector.add(a.copy().mult(-1), b.copy().mult(3)), Vector.add(c.copy().mult(-3), d.copy())).mult(Math.pow(t, 3)));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
getClosestPoint(v) {
|
||||||
|
const resolution = 1 / 25;
|
||||||
|
let closest = this.points[0];
|
||||||
|
let closestDistance = this.points[0].dist(v);
|
||||||
|
let closestT = 0;
|
||||||
|
for(let i = 0; i < 25; i++){
|
||||||
|
const point = this.getPointAtT(i * resolution);
|
||||||
|
const distance = v.dist(point);
|
||||||
|
if (distance < closestDistance) {
|
||||||
|
closest = point;
|
||||||
|
closestDistance = distance;
|
||||||
|
closestT = i * resolution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
closest,
|
||||||
|
closestDistance,
|
||||||
|
closestT
|
||||||
|
];
|
||||||
|
}
|
||||||
|
getPointsWithinRadius(v, r) {
|
||||||
|
const points = [];
|
||||||
|
const resolution = 1 / 25;
|
||||||
|
for(let i = 0; i < 25 + 1; i++){
|
||||||
|
const point = this.getPointAtT(i * resolution);
|
||||||
|
const distance = v.dist(point);
|
||||||
|
if (distance < r) {
|
||||||
|
points.push([
|
||||||
|
i * resolution,
|
||||||
|
this
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
tangent(t) {
|
||||||
|
const [a, b, c, d] = this.points;
|
||||||
|
const res = Vector.sub(b, a).mult(3 * Math.pow(1 - t, 2));
|
||||||
|
res.add(Vector.add(Vector.sub(c, b).mult(6 * (1 - t) * t), Vector.sub(d, c).mult(3 * Math.pow(t, 2))));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
doesIntersectCircle(x, y, r) {
|
||||||
|
const v = new Vector(x, y);
|
||||||
|
const resolution = 1 / 25;
|
||||||
|
let distance = Infinity;
|
||||||
|
let t;
|
||||||
|
for(let i = 0; i < 25 - 1; i++){
|
||||||
|
const a = this.getPointAtT(i * resolution);
|
||||||
|
const b = this.getPointAtT((i + 1) * resolution);
|
||||||
|
const ac = Vector.sub(v, a);
|
||||||
|
const ab = Vector.sub(b, a);
|
||||||
|
const d = Vector.add(Vector.vectorProjection(ac, ab), a);
|
||||||
|
const ad = Vector.sub(d, a);
|
||||||
|
const k = Math.abs(ab.x) > Math.abs(ab.y) ? ad.x / ab.x : ad.y / ab.y;
|
||||||
|
let dist;
|
||||||
|
if (k <= 0.0) {
|
||||||
|
dist = Vector.hypot2(v, a);
|
||||||
|
} else if (k >= 1.0) {
|
||||||
|
dist = Vector.hypot2(v, b);
|
||||||
|
}
|
||||||
|
dist = Vector.hypot2(v, d);
|
||||||
|
if (dist < distance) {
|
||||||
|
distance = dist;
|
||||||
|
t = i * resolution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (distance < r) return t;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
intersectsCircle(circleCenter, radius) {
|
||||||
|
for(let i = 0; i < 100; i++){
|
||||||
|
const t1 = i / 100;
|
||||||
|
const t2 = (i + 1) / 100;
|
||||||
|
const segmentStart = this.getPointAtT(t1);
|
||||||
|
const segmentEnd = this.getPointAtT(t2);
|
||||||
|
const segmentLength = Math.sqrt((segmentEnd.x - segmentStart.x) ** 2 + (segmentEnd.y - segmentStart.y) ** 2);
|
||||||
|
const resolution = Math.max(10, Math.ceil(100 * (segmentLength / radius)));
|
||||||
|
for(let j = 0; j <= resolution; j++){
|
||||||
|
const t = j / resolution;
|
||||||
|
const point = this.getPointAtT(t);
|
||||||
|
const distance = Math.sqrt((point.x - circleCenter.x) ** 2 + (point.y - circleCenter.y) ** 2);
|
||||||
|
if (distance <= radius) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
calculateApproxLength(resolution = 25) {
|
||||||
|
const stepSize = 1 / resolution;
|
||||||
|
const points = [];
|
||||||
|
for(let i = 0; i <= resolution; i++){
|
||||||
|
const current = stepSize * i;
|
||||||
|
points.push(this.getPointAtT(current));
|
||||||
|
}
|
||||||
|
this.length = points.reduce((acc, cur)=>{
|
||||||
|
const prev = acc.prev;
|
||||||
|
acc.prev = cur;
|
||||||
|
if (!prev) return acc;
|
||||||
|
acc.length += cur.dist(prev);
|
||||||
|
return acc;
|
||||||
|
}, {
|
||||||
|
prev: undefined,
|
||||||
|
length: 0
|
||||||
|
}).length;
|
||||||
|
return this.length;
|
||||||
|
}
|
||||||
|
calculateEvenlySpacedPoints(spacing, resolution = 1) {
|
||||||
|
const points = [];
|
||||||
|
points.push(this.points[0]);
|
||||||
|
let prev = points[0];
|
||||||
|
let distSinceLastEvenPoint = 0;
|
||||||
|
let t = 0;
|
||||||
|
const div = Math.ceil(this.length * resolution * 10);
|
||||||
|
while(t < 1){
|
||||||
|
t += 1 / div;
|
||||||
|
const point = this.getPointAtT(t);
|
||||||
|
distSinceLastEvenPoint += prev.dist(point);
|
||||||
|
if (distSinceLastEvenPoint >= spacing) {
|
||||||
|
const overshoot = distSinceLastEvenPoint - spacing;
|
||||||
|
const evenPoint = Vector.add(point, Vector.sub(point, prev).normalize().mult(overshoot));
|
||||||
|
distSinceLastEvenPoint = overshoot;
|
||||||
|
points.push(evenPoint);
|
||||||
|
prev = evenPoint;
|
||||||
|
}
|
||||||
|
prev = point;
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
_aabb;
|
||||||
|
get AABB() {
|
||||||
|
if (!this._aabb) {
|
||||||
|
this._aabb = this.recalculateAABB();
|
||||||
|
}
|
||||||
|
return this._aabb;
|
||||||
|
}
|
||||||
|
recalculateAABB() {
|
||||||
|
let minX = Infinity;
|
||||||
|
let minY = Infinity;
|
||||||
|
let maxX = -Infinity;
|
||||||
|
let maxY = -Infinity;
|
||||||
|
for(let i = 0; i < 100; i++){
|
||||||
|
const t = i / 100;
|
||||||
|
const point = this.getPointAtT(t);
|
||||||
|
minX = Math.min(minX, point.x);
|
||||||
|
minY = Math.min(minY, point.y);
|
||||||
|
maxX = Math.max(maxX, point.x);
|
||||||
|
maxY = Math.max(maxY, point.y);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
x: minX,
|
||||||
|
y: minY,
|
||||||
|
w: maxX - minX,
|
||||||
|
h: maxY - minY
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
class Doodler {
|
class Doodler {
|
||||||
ctx;
|
ctx;
|
||||||
_canvas;
|
_canvas;
|
||||||
@ -1292,6 +1470,10 @@ class Polygon {
|
|||||||
color
|
color
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
doodler.dot(this.center, {
|
||||||
|
weight: 4,
|
||||||
|
color: "yellow"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
calcCenter() {
|
calcCenter() {
|
||||||
if (!this.points.length) return new Vector();
|
if (!this.points.length) return new Vector();
|
||||||
@ -1354,6 +1536,9 @@ class Polygon {
|
|||||||
poly.points.push(pt);
|
poly.points.push(pt);
|
||||||
}
|
}
|
||||||
poly.center = poly.calcCenter();
|
poly.center = poly.calcCenter();
|
||||||
|
for (const p of poly.points){
|
||||||
|
p.sub(poly.center);
|
||||||
|
}
|
||||||
return poly;
|
return poly;
|
||||||
}
|
}
|
||||||
getEdges() {
|
getEdges() {
|
||||||
@ -1413,184 +1598,6 @@ function projectCircleOntoAxis(c, axis) {
|
|||||||
function overlap(proj1, proj2) {
|
function overlap(proj1, proj2) {
|
||||||
return proj1.min <= proj2.max && proj1.max >= proj2.min;
|
return proj1.min <= proj2.max && proj1.max >= proj2.min;
|
||||||
}
|
}
|
||||||
class SplineSegment {
|
|
||||||
points;
|
|
||||||
length;
|
|
||||||
constructor(points){
|
|
||||||
this.points = points;
|
|
||||||
this.length = this.calculateApproxLength(100);
|
|
||||||
}
|
|
||||||
draw(color) {
|
|
||||||
const [a, b, c, d] = this.points;
|
|
||||||
doodler.drawBezier(a, b, c, d, {
|
|
||||||
strokeColor: color || "#ffffff50"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getPointAtT(t) {
|
|
||||||
const [a, b, c, d] = this.points;
|
|
||||||
const res = a.copy();
|
|
||||||
res.add(Vector.add(a.copy().mult(-3), b.copy().mult(3)).mult(t));
|
|
||||||
res.add(Vector.add(Vector.add(a.copy().mult(3), b.copy().mult(-6)), c.copy().mult(3)).mult(Math.pow(t, 2)));
|
|
||||||
res.add(Vector.add(Vector.add(a.copy().mult(-1), b.copy().mult(3)), Vector.add(c.copy().mult(-3), d.copy())).mult(Math.pow(t, 3)));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
getClosestPoint(v) {
|
|
||||||
const resolution = 1 / 25;
|
|
||||||
let closest = this.points[0];
|
|
||||||
let closestDistance = this.points[0].dist(v);
|
|
||||||
let closestT = 0;
|
|
||||||
for(let i = 0; i < 25; i++){
|
|
||||||
const point = this.getPointAtT(i * resolution);
|
|
||||||
const distance = v.dist(point);
|
|
||||||
if (distance < closestDistance) {
|
|
||||||
closest = point;
|
|
||||||
closestDistance = distance;
|
|
||||||
closestT = i * resolution;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
closest,
|
|
||||||
closestDistance,
|
|
||||||
closestT
|
|
||||||
];
|
|
||||||
}
|
|
||||||
getPointsWithinRadius(v, r) {
|
|
||||||
const points = [];
|
|
||||||
const resolution = 1 / 25;
|
|
||||||
for(let i = 0; i < 25 + 1; i++){
|
|
||||||
const point = this.getPointAtT(i * resolution);
|
|
||||||
const distance = v.dist(point);
|
|
||||||
if (distance < r) {
|
|
||||||
points.push([
|
|
||||||
i * resolution,
|
|
||||||
this
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return points;
|
|
||||||
}
|
|
||||||
tangent(t) {
|
|
||||||
const [a, b, c, d] = this.points;
|
|
||||||
const res = Vector.sub(b, a).mult(3 * Math.pow(1 - t, 2));
|
|
||||||
res.add(Vector.add(Vector.sub(c, b).mult(6 * (1 - t) * t), Vector.sub(d, c).mult(3 * Math.pow(t, 2))));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
doesIntersectCircle(x, y, r) {
|
|
||||||
const v = new Vector(x, y);
|
|
||||||
const resolution = 1 / 25;
|
|
||||||
let distance = Infinity;
|
|
||||||
let t;
|
|
||||||
for(let i = 0; i < 25 - 1; i++){
|
|
||||||
const a = this.getPointAtT(i * resolution);
|
|
||||||
const b = this.getPointAtT((i + 1) * resolution);
|
|
||||||
const ac = Vector.sub(v, a);
|
|
||||||
const ab = Vector.sub(b, a);
|
|
||||||
const d = Vector.add(Vector.vectorProjection(ac, ab), a);
|
|
||||||
const ad = Vector.sub(d, a);
|
|
||||||
const k = Math.abs(ab.x) > Math.abs(ab.y) ? ad.x / ab.x : ad.y / ab.y;
|
|
||||||
let dist;
|
|
||||||
if (k <= 0.0) {
|
|
||||||
dist = Vector.hypot2(v, a);
|
|
||||||
} else if (k >= 1.0) {
|
|
||||||
dist = Vector.hypot2(v, b);
|
|
||||||
}
|
|
||||||
dist = Vector.hypot2(v, d);
|
|
||||||
if (dist < distance) {
|
|
||||||
distance = dist;
|
|
||||||
t = i * resolution;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (distance < r) return t;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
intersectsCircle(circleCenter, radius) {
|
|
||||||
for(let i = 0; i < 100; i++){
|
|
||||||
const t1 = i / 100;
|
|
||||||
const t2 = (i + 1) / 100;
|
|
||||||
const segmentStart = this.getPointAtT(t1);
|
|
||||||
const segmentEnd = this.getPointAtT(t2);
|
|
||||||
const segmentLength = Math.sqrt((segmentEnd.x - segmentStart.x) ** 2 + (segmentEnd.y - segmentStart.y) ** 2);
|
|
||||||
const resolution = Math.max(10, Math.ceil(100 * (segmentLength / radius)));
|
|
||||||
for(let j = 0; j <= resolution; j++){
|
|
||||||
const t = j / resolution;
|
|
||||||
const point = this.getPointAtT(t);
|
|
||||||
const distance = Math.sqrt((point.x - circleCenter.x) ** 2 + (point.y - circleCenter.y) ** 2);
|
|
||||||
if (distance <= radius) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
calculateApproxLength(resolution = 25) {
|
|
||||||
const stepSize = 1 / resolution;
|
|
||||||
const points = [];
|
|
||||||
for(let i = 0; i <= resolution; i++){
|
|
||||||
const current = stepSize * i;
|
|
||||||
points.push(this.getPointAtT(current));
|
|
||||||
}
|
|
||||||
this.length = points.reduce((acc, cur)=>{
|
|
||||||
const prev = acc.prev;
|
|
||||||
acc.prev = cur;
|
|
||||||
if (!prev) return acc;
|
|
||||||
acc.length += cur.dist(prev);
|
|
||||||
return acc;
|
|
||||||
}, {
|
|
||||||
prev: undefined,
|
|
||||||
length: 0
|
|
||||||
}).length;
|
|
||||||
return this.length;
|
|
||||||
}
|
|
||||||
calculateEvenlySpacedPoints(spacing, resolution = 1) {
|
|
||||||
const points = [];
|
|
||||||
points.push(this.points[0]);
|
|
||||||
let prev = points[0];
|
|
||||||
let distSinceLastEvenPoint = 0;
|
|
||||||
let t = 0;
|
|
||||||
const div = Math.ceil(this.length * resolution * 10);
|
|
||||||
while(t < 1){
|
|
||||||
t += 1 / div;
|
|
||||||
const point = this.getPointAtT(t);
|
|
||||||
distSinceLastEvenPoint += prev.dist(point);
|
|
||||||
if (distSinceLastEvenPoint >= spacing) {
|
|
||||||
const overshoot = distSinceLastEvenPoint - spacing;
|
|
||||||
const evenPoint = Vector.add(point, Vector.sub(point, prev).normalize().mult(overshoot));
|
|
||||||
distSinceLastEvenPoint = overshoot;
|
|
||||||
points.push(evenPoint);
|
|
||||||
prev = evenPoint;
|
|
||||||
}
|
|
||||||
prev = point;
|
|
||||||
}
|
|
||||||
return points;
|
|
||||||
}
|
|
||||||
_aabb;
|
|
||||||
get AABB() {
|
|
||||||
if (!this._aabb) {
|
|
||||||
this._aabb = this.recalculateAABB();
|
|
||||||
}
|
|
||||||
return this._aabb;
|
|
||||||
}
|
|
||||||
recalculateAABB() {
|
|
||||||
let minX = Infinity;
|
|
||||||
let minY = Infinity;
|
|
||||||
let maxX = -Infinity;
|
|
||||||
let maxY = -Infinity;
|
|
||||||
for(let i = 0; i < 100; i++){
|
|
||||||
const t = i / 100;
|
|
||||||
const point = this.getPointAtT(t);
|
|
||||||
minX = Math.min(minX, point.x);
|
|
||||||
minY = Math.min(minY, point.y);
|
|
||||||
maxX = Math.max(maxX, point.x);
|
|
||||||
maxY = Math.max(maxY, point.y);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
x: minX,
|
|
||||||
y: minY,
|
|
||||||
w: maxX - minX,
|
|
||||||
h: maxY - minY
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
init({
|
init({
|
||||||
fillScreen: true,
|
fillScreen: true,
|
||||||
bg: "#333",
|
bg: "#333",
|
||||||
|
@ -20,6 +20,8 @@ export class Polygon {
|
|||||||
color,
|
color,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doodler.dot(this.center, { weight: 4, color: "yellow" });
|
||||||
}
|
}
|
||||||
|
|
||||||
calcCenter() {
|
calcCenter() {
|
||||||
@ -103,6 +105,9 @@ export class Polygon {
|
|||||||
poly.points.push(pt);
|
poly.points.push(pt);
|
||||||
}
|
}
|
||||||
poly.center = poly.calcCenter();
|
poly.center = poly.calcCenter();
|
||||||
|
for (const p of poly.points) {
|
||||||
|
p.sub(poly.center);
|
||||||
|
}
|
||||||
return poly;
|
return poly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
mod.ts
16
mod.ts
@ -1,5 +1,17 @@
|
|||||||
/// <reference types="./global.d.ts" />
|
/// <reference types="./global.d.ts" />
|
||||||
|
|
||||||
export { init as initializeDoodler } from "./init.ts";
|
export { GIFAnimation } from "./animation/gif.ts";
|
||||||
|
export { SpriteAnimation } from "./animation/sprite.ts";
|
||||||
|
export { axisAlignedCollision, axisAlignedContains } from "./collision/aa.ts";
|
||||||
|
export { circularCollision } from "./collision/circular.ts";
|
||||||
|
export {
|
||||||
|
satCollisionAABBCircle,
|
||||||
|
satCollisionCircle,
|
||||||
|
satCollisionPolygon,
|
||||||
|
satCollisionSpline,
|
||||||
|
} from "./collision/sat.ts";
|
||||||
export { Vector } from "./geometry/vector.ts";
|
export { Vector } from "./geometry/vector.ts";
|
||||||
|
export { Polygon } from "./geometry/polygon.ts";
|
||||||
|
export { SplineSegment } from "./geometry/spline.ts";
|
||||||
|
|
||||||
|
export { init as initializeDoodler } from "./init.ts";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user