Compare commits

...

2 Commits

Author SHA1 Message Date
Elf M. Sternberg f5a174710d Merge remote-tracking branch 'refs/remotes/origin/lit' into lit
* refs/remotes/origin/lit:
  Flyout begun.
  Cleaning up.
2024-11-22 10:43:33 -08:00
Elf M. Sternberg 9bd56da62d Added the axis code. 2024-11-22 10:43:26 -08:00
1 changed files with 76 additions and 108 deletions

View File

@ -1,21 +1,21 @@
// Copyright (c) 2012 Elf M. Sternberg // Copyright (c) 2012 Elf M. Sternberg
// //
// Much of the code here I would never have understood if it hadn't // Much of the code here I would never have understood if it hadn't
// been for the patient work of Caleb Helbling // been for the patient work of Caleb Helbling
// (http://www.propulsionjs.com/), as well as the Wikipedia pages for // (http://www.propulsionjs.com/), as well as the Wikipedia pages for
// the Separating Axis Theorem. It took me a week to wrap my head // the Separating Axis Theorem. It took me a week to wrap my head
// around these ideas. // around these ideas.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -32,112 +32,80 @@ class Vector {
this.x = x; this.x = x;
this.y = y; this.y = y;
} }
add: (v2: Vector) { add(v2: Vector) {
return new Vector(this.x + v2.x, this.y + v2.y); return new Vector(this.x + v2.x, this.y + v2.y);
} }
add: function (v1, v2) {
return {
x: v1.x + v2.x,
y: v1.y + v2.y,
};
},
scalar: function (v, s) {
return {
x: v.x * s,
y: v.y * s,
};
},
dot: function (v1, v2) {
return v1.x * v2.x + v1.y * v2.y;
},
magnitude2: function (v) {
var x, y;
x = v.x;
y = v.y;
return x * x + y * y;
},
magnitude: function (v) {
return Math.sqrt(Math.vector.magnitude2(v));
},
normalize: function (v) {
var mag;
mag = Math.vector.magnitude(v);
return {
x: v.x / mag,
y: v.y / mag,
};
},
leftNormal: function (v) {
return {
x: -v.y,
y: v.x,
};
},
};
this.colliding = function (shape1, shape2) { scalar(s: number) {
var axes, axes1, axes2, axis, genAxes, genProjection, j, len, proj1, proj2; return new Vector(this.x * s, this.y * s);
genAxes = function (shape) { }
var axis, i, j, ref, results;
if (shape.length < 3) { dot(v2: Vector) {
throw "Cannot handle non-polygons"; return this.x * v2.x + this.y * v2.y;
} }
axis = function (shape, pi) {
var edge, p1, p2; magnitude2() {
p1 = shape[pi]; return this.x * this.x + this.y * this.y;
p2 = shape[pi === shape.length - 1 ? 0 : pi + 1]; }
edge = {
x: p1.x - p2.x, magnitude() {
y: p1.y - p2.y, return Math.sqrt(this.magnitude2());
}; }
return Math.vector.normalize(Math.vector.leftNormal(edge));
}; normal() {
results = []; const mag = this.magnitude();
for (i = j = 0, ref = shape.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { return new Vector(this.x / mag, this.y / mag);
results.push(axis(shape, i)); }
}
return results; leftNormal() {
}; return new Vector(-1 * this.y, this.x);
genProjection = function (shape, axis) { }
var i, j, max, min, p, ref; }
min = Math.vector.dot(axis, shape[0]);
max = min; const vec = (x: number, y: number) => new Vector(x, y);
for (i = j = 1, ref = shape.length; 1 <= ref ? j < ref : j > ref; i = 1 <= ref ? ++j : --j) {
p = Math.vector.dot(axis, shape[i]); type Shape = Vector[];
if (p < min) {
min = p; type Projection = { min: number; max: number };
}
if (p > max) { function colliding(shape1: Shape, shape2: Shape) {
max = p; const genAxes = (shape: Shape) => {
} if (shape.length < 3) {
} throw new Error("A Shape must be a polygon.");
return {
min: min,
max: max,
};
};
axes1 = genAxes(shape1);
axes2 = genAxes(shape2);
axes = axes1.concat(axes2);
for (j = 0, len = axes.length; j < len; j++) {
axis = axes[j];
proj1 = genProjection(shape1, axis);
proj2 = genProjection(shape2, axis);
if (
!(
(proj1.min >= proj2.min && proj1.min <= proj2.max) ||
(proj1.max >= proj2.min && proj1.max <= proj2.max) ||
(proj2.min >= proj1.min && proj2.min <= proj1.max) ||
(proj2.max >= proj1.min && proj2.max <= proj1.max)
)
) {
return false;
}
} }
return true;
const axis = (idx: number) => {
const p1 = shape[idx];
const p2 = shape[idx === shape.length - 1 ? 0 : idx + 1];
return vec(p1.x - p2.x, p1.y - p2.y)
.normal()
.leftNormal();
};
return shape.map((_: Vector, idx: number) => axis(idx));
}; };
}).call(this);
const genProjection = (shape: Shape, axis: Vector) =>
shape.reduce(
({ min, max }: Projection, v: Vector) => {
const p = axis.dot(v);
return { min: p < min ? p : min, max: p > max ? p : max };
},
{ min: axis.dot(shape[0]), max: axis.dot(shape[0]) }
);
const axes = [...genAxes(shape1), ...genAxes(shape2)];
// The logic here may be wrong. I may have to invert the return on the whole expression.
return axes.some((axis) => {
const proj1 = genProjection(shape1, axis);
const proj2 = genProjection(shape2, axis);
return !(
(proj1.min >= proj2.min && proj1.min <= proj2.max) ||
(proj1.max >= proj2.min && proj1.max <= proj2.max) ||
(proj2.min >= proj1.min && proj2.min <= proj1.max) ||
(proj2.max >= proj1.min && proj2.max <= proj1.max)
);
});
}