diff options
Diffstat (limited to 'assets/javascripts/math/vec2.js')
| -rw-r--r-- | assets/javascripts/math/vec2.js | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/assets/javascripts/math/vec2.js b/assets/javascripts/math/vec2.js new file mode 100644 index 0000000..3e1f463 --- /dev/null +++ b/assets/javascripts/math/vec2.js @@ -0,0 +1,237 @@ + +(function(){ + var point + if ('window' in this) { + point = window.point + } + else { + point = require('./point') + FRONT = 0x1, BACK = 0x2, LEFT = 0x4, RIGHT = 0x8, FLOOR = 0x10, CEILING = 0x20 + TOP = CEILING, BOTTOM = FLOOR + function sidesToString(sides){ + var s = "" + if (sides & FRONT) s += "front " + if (sides & BACK) s += "back " + if (sides & LEFT) s += "left " + if (sides & RIGHT) s += "right " + if (sides & TOP) s += "top " + if (sides & BOTTOM) s += "bottom " + return s + } + } + + var vec2 = function (x0,y0,x1,y1){ + if (x0 instanceof point) { + this.x = x0 + this.y = y0 + } + else if (x1 === undefined) { + this.x = new point(x0,x0) + this.y = new point(y0,y0) + } + else { + this.x = new point(x0,x1) + this.y = new point(y0,y1) + } + this.translation = new point(0,0) + this.sides = FRONT | BACK | LEFT | RIGHT + } + vec2.prototype.clone = function(){ + return new vec2( this.x.clone(), this.y.clone() ) + } + vec2.prototype.assign = function(r) { + this.x.assign(r.x) + this.y.assign(r.y) + return this + } + vec2.prototype.center = function(){ + return new point(this.x.midpoint(), this.y.midpoint()) + } + vec2.prototype.area = function(){ + return this.x.length() * this.y.length() + } + vec2.prototype.magnitude = function(){ + return dist(this.x.a, this.y.a, this.x.b, this.y.b) + } + vec2.prototype.maxDimension = function(){ + return abs(this.width) > abs(this.height) ? this.width : this.height + } + + vec2.prototype.mul = function(n){ + this.x.mul(n) + this.y.mul(n) + return this + } + vec2.prototype.div = function(n){ + this.x.div(n) + this.y.div(n) + return this + } + + vec2.prototype.translate = function(translation){ + var translation = translation || this.translation + this.x.abs().add(translation.a) + this.y.abs().add(translation.b) + this.translation.a = this.translation.b = 0 + return this + } + vec2.prototype.resize = function(translation, sides){ + var translation = translation || this.translation + sides = sides || translation.sides + + if (sides & LEFT) { + this.x.a += translation.a + } + if (sides & RIGHT) { + this.x.b += translation.a + } + if (sides & FRONT) { + this.y.a += translation.b + } + if (sides & BACK) { + this.y.b += translation.b + } + this.translation.a = this.translation.b = 0 + } + vec2.prototype.contains = function(x,y){ + return this.x.contains(x) && this.y.contains(y) + } + vec2.prototype.contains_point = function(p){ + return this.x.contains(p.x) && this.y.contains(p.y) + } + vec2.prototype.containsDisc = function(x,y,r){ + return this.x.containsDisc(x,r) && this.y.containsDisc(y,r) + } + vec2.prototype.overlaps = function(rect){ + return this.x.overlaps(rect.x) && this.y.overlaps(rect.y) + } + vec2.prototype.intersects = function(r){ + var corner_intersect = (this.x.b === r.x.a && this.y.b === r.y.a) + return this.x.intersects(r.x) && this.y.intersects(r.y) && ! corner_intersect + } + vec2.prototype.adjacent = function(r){ + return this.x.adjacent(r.x) && this.y.adjacent(r.y) + } + vec2.prototype.eq = function(r){ + return this.x.eq(r.x) && this.y.eq(r.y) + } + vec2.prototype.fits = function(v){ + return this.x.length() >= v.a && this.y.length() >= v.b + } + vec2.prototype.zero = function(){ + this.a.zero() + this.b.zero() + } + vec2.prototype.nearEdge = function (x, y, r) { + var edges = 0 + if (x < this.x.a+r) { + edges |= LEFT + } + else if (x > this.x.b-r) { + edges |= RIGHT + } + if (y < this.y.a+r) { + edges |= FRONT + } + else if (y > this.y.b-r) { + edges |= BACK + } + return edges + } + vec2.prototype.width = function(){ return this.x.length() } + vec2.prototype.height = function(){ return this.y.length() } + vec2.prototype.delta = function(){ return new point( this.x.magnitude(), this.y.magnitude() ) } + vec2.prototype.expand = function(rect){ + this.x.a = Math.min( this.x.a, rect.x.a ) + this.x.b = Math.max( this.x.b, rect.x.b ) + this.y.a = Math.min( this.y.a, rect.y.a ) + this.y.b = Math.max( this.y.b, rect.y.b ) + return this + } + vec2.prototype.square = function(){ + var width = this.x.length() + var height = this.y.length() + var diff + if (width < height) { + diff = (height - width) / 2 + this.x.a -= diff + this.x.b += diff + } + else { + diff = (width - height) / 2 + this.y.a -= diff + this.y.b += diff + } + return this + } + vec2.prototype.toString = function(){ + var sides = sidesToString(this.sides) + var s = "[" + this.x.toString() + " " + this.y.toString() + "] " + sides + return s + } + vec2.prototype.exactString = function(){ + var sides = sidesToString(this.sides) + var s = "[" + this.x.exactString() + " " + this.y.exactString() + "] " + sides + return s + } + + vec2.prototype.serialize = function(){ + return { x: this.x.serialize(), y: this.y.serialize() } + } + vec2.prototype.quantize = function(n){ + this.x.quantize(n) + this.y.quantize(n) + return this + } + vec2.prototype.split = function(r){ + var rz = this + var splits = [] + var sides = this.sides + + // bisect (or trisect) two overlapping rectangles + var x_intervals = this.x.split( r.x, LEFT, RIGHT ) + var y_intervals = this.y.split( r.y, FRONT, BACK ) + + // generate rectangular regions by crossing the two sets of vectors + x_intervals.forEach(function(x, i){ + y_intervals.forEach(function(y, i){ + var rn = new vec2(x[0], y[0]) + rn.id = rz.id + rn.sides = ((x[1] | y[1]) & sides) + rn.focused = rz.focused + splits.push(rn) + + // cull extra walls from overlapping regions + if (r.x.contains(rn.x.a) && r.x.contains(rn.x.b)) { + if (rz.y.a == rn.y.a && r.y.containsCenter(rn.y.a)) { // top edges + rn.sides &= ~ FRONT + } + if (rz.y.b == rn.y.b && r.y.containsCenter(rn.y.b)) { // bottom edges + rn.sides &= ~ BACK + } + } + + if (r.y.contains(rn.y.a) && r.y.contains(rn.y.b)) { + if (rz.x.a == rn.x.a && r.x.containsCenter(rn.x.a)) { // left edges + rn.sides &= ~ LEFT + } + + if (rz.x.b == rn.x.b && r.x.containsCenter(rn.x.b) ) { // right edges + rn.sides &= ~ RIGHT + } + } + + }) + }) + + return splits + } + + if ('window' in this) { + window.vec2 = vec2 + } + else { + module.exports = vec2 + } + +})() |
