summaryrefslogtreecommitdiff
path: root/assets/javascripts/math/vec2.js
diff options
context:
space:
mode:
Diffstat (limited to 'assets/javascripts/math/vec2.js')
-rw-r--r--assets/javascripts/math/vec2.js237
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
+ }
+
+})()