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
|
HAML=/usr/bin/haml
|
||||||
COFFEE = coffee
|
COFFEE = coffee
|
||||||
|
TSC=tsc
|
||||||
LESSCSS=lessc
|
LESSCSS=lessc
|
||||||
SED=sed
|
SED=sed
|
||||||
COMPILER=uglifyjs
|
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
|
all: index.html style.css js/magnets.js js/sat.js js/wordlist.js
|
||||||
|
|
||||||
js/magnets.js: src/magnets.coffee
|
js/magnets.js: src/magnets.coffee
|
||||||
$(COFFEE) --compile --lint --output js/ $<
|
$(COFFEE) --compile --output js/ $<
|
||||||
|
|
||||||
js/wordlist.js: src/wordlist.coffee
|
js/wordlist.js: src/wordlist.coffee
|
||||||
$(COFFEE) --compile --lint --bare --output js/ $<
|
$(COFFEE) --compile --no-header --bare --output js/ $<
|
||||||
$(SED) -i -e '$$ s/;$$//' $@
|
$(SED) -i -e '$$ s/;$$//' $@
|
||||||
|
|
||||||
js/sat.js: src/sat.coffee
|
js/sat.js: src/sat.ts
|
||||||
$(COFFEE) --compile --lint --output js/ $<
|
$(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
|
style.css: src/style.less
|
||||||
$(LESSCSS) $< $@
|
$(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