Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
Elf M. Sternberg | 83a7fe7610 | |
Elf M. Sternberg | 9e740bb702 |
15
Makefile
15
Makefile
|
@ -2,6 +2,7 @@
|
|||
|
||||
HAML=/usr/bin/haml
|
||||
COFFEE = coffee
|
||||
TSC=tsc
|
||||
LESSCSS=lessc
|
||||
SED=sed
|
||||
COMPILER=uglifyjs
|
||||
|
@ -11,14 +12,20 @@ INCLUDES= js/jquery-1.6.2.min.js js/underscore.js js/backbone.js js/jquery-ui-1.
|
|||
all: index.html style.css js/magnets.js js/sat.js js/wordlist.js
|
||||
|
||||
js/magnets.js: src/magnets.coffee
|
||||
$(COFFEE) --compile --lint --output js/ $<
|
||||
$(COFFEE) --compile --output js/ $<
|
||||
|
||||
js/wordlist.js: src/wordlist.coffee
|
||||
$(COFFEE) --compile --lint --bare --output js/ $<
|
||||
$(COFFEE) --compile --no-header --bare --output js/ $<
|
||||
$(SED) -i -e '$$ s/;$$//' $@
|
||||
|
||||
js/sat.js: src/sat.coffee
|
||||
$(COFFEE) --compile --lint --output js/ $<
|
||||
js/sat.js: src/sat.ts
|
||||
$(TSC) $< --outDir js/ --module "commonjs"
|
||||
|
||||
js/test_sat.js: src/test_sat.ts
|
||||
$(TSC) $< --outDir js/ --module "commonjs"
|
||||
|
||||
test: js/test_sat.js js/sat.js
|
||||
node_modules/nodeunit/bin/nodeunit js/test_sat.js
|
||||
|
||||
style.css: src/style.less
|
||||
$(LESSCSS) $< $@
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
Copyright (c) 2012, 2016 Elf M. Sternberg
|
||||
|
||||
Much of the code here I would never have understood if it hadn't been
|
||||
for the patient work of Caleb Helbling (http://www.propulsionjs.com/),
|
||||
as well as the Wikipedia pages for the Separating Axis Theorem. It
|
||||
took me a week to wrap my head around these ideas.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
class Vector {
|
||||
x: number;
|
||||
y; number;
|
||||
|
||||
constructor(x: number, y: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
add(v2: Vector) {
|
||||
return new Vector(this.x + v2.x, this.y + v2.y);
|
||||
}
|
||||
|
||||
scalar(s: number) {
|
||||
return new Vector(this.x * s, this.y * s);
|
||||
}
|
||||
|
||||
magnitude2 () {
|
||||
return this.x * this.x + this.y * this.y;
|
||||
}
|
||||
|
||||
magnitude() {
|
||||
return Math.sqrt(this.magnitude2());
|
||||
}
|
||||
|
||||
normalize() {
|
||||
const mag = this.magnitude();
|
||||
return new Vector(this.x / mag, this.y / mag);
|
||||
}
|
||||
|
||||
leftNormal() {
|
||||
return new Vector(this.y * -1, this.x)
|
||||
}
|
||||
}
|
||||
|
||||
var range = (function() {
|
||||
var memos = {}
|
||||
var range = (length) => {
|
||||
if (memos[length]) {
|
||||
return memos[length];
|
||||
}
|
||||
return memos[length] = Array.apply(null, {length: length}).map(Number.call, Number);
|
||||
}
|
||||
return range;
|
||||
})();
|
||||
|
||||
var colliding = (shape1, shape2) => {
|
||||
var genAxes = (shape) => {
|
||||
if (shape.length < 3) {
|
||||
throw "Cannot handle non-polygons";
|
||||
}
|
||||
|
||||
var axis = (pi) => {
|
||||
const p1 = shape[pi];
|
||||
const p2 = shape[pi == (shape.length - 1) ? 0 : pi + 1];
|
||||
return (new Vector(p1.x - p2.x, p1.y - p2.y)).normalize();
|
||||
}
|
||||
|
||||
return range(shape.length).map(axis);
|
||||
}
|
||||
|
||||
var genProjection = (shape, axis) => {
|
||||
var min = axis.dot(shape[0]);
|
||||
var max = min;
|
||||
for (let i of range(shape.length()).shift()) {
|
||||
var p = axis.dot(shape[i])
|
||||
if (p < min) { min = p; }
|
||||
if (p > max) { max = p; }
|
||||
}
|
||||
return {min: min, max: max}
|
||||
}
|
||||
|
||||
var axes1 = genAxes(shape1);
|
||||
var axes2 = genAxes(shape2);
|
||||
var axes = axes1.concat(axes);
|
||||
for (let axis of axes) {
|
||||
var proj1 = genProjection(shape1, axis);
|
||||
var 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;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Vector: Vector,
|
||||
colliding: colliding
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
var testCase = require('nodeunit').testCase;
|
||||
var Vector = require('./sat').Vector;
|
||||
|
||||
module.exports = testCase({
|
||||
"TestAddition": (test) => {
|
||||
var m = (new Vector(1, 1)).add(new Vector(-1, -1));
|
||||
test.ok(m.x == 0 && m.y == 0);
|
||||
var n = (new Vector(1, 1)).add(new Vector(1, 1));
|
||||
test.ok(n.x == 2 && n.y == 2);
|
||||
test.done();
|
||||
},
|
||||
|
||||
"TestScalar": (test) => {
|
||||
var m = (new Vector(2, 2)).scalar(2);
|
||||
test.ok(m.x == 4 && m.y == 4);
|
||||
test.done();
|
||||
},
|
||||
|
||||
"TestMag2": (test) => {
|
||||
var m = (new Vector(2, 2)).magnitude2();
|
||||
test.ok(m == 8);
|
||||
test.done();
|
||||
},
|
||||
|
||||
"TestMag": (test) => {
|
||||
var m = (new Vector(2, 2)).magnitude();
|
||||
test.ok(m == Math.sqrt(8));
|
||||
test.done();
|
||||
},
|
||||
|
||||
"TestNormalize": (test) => {
|
||||
var m = (new Vector(5, 0)).normalize();
|
||||
test.ok(m.x == 1 && m.y == 0);
|
||||
m = (new Vector(0, 5)).normalize();
|
||||
test.ok(m.x == 0 && m.y == 1);
|
||||
m = (new Vector(4, 3)).normalize().magnitude2();
|
||||
test.ok(m == 1);
|
||||
test.done();
|
||||
}
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
// types option has been previously configured
|
||||
"types": [
|
||||
// add node as an option
|
||||
"node"
|
||||
],
|
||||
// typeroots option has been previously configured
|
||||
"typeroots": [
|
||||
// add path to @types
|
||||
"../node_modules/@types"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue