summaryrefslogtreecommitdiff
path: root/public/assets/javascripts/rectangles/models/surface.js
diff options
context:
space:
mode:
authorJules Laplace <jules@okfoc.us>2014-08-22 19:41:37 -0400
committerJules Laplace <jules@okfoc.us>2014-08-22 19:41:37 -0400
commit2235c34e498499b8141e835998b962067583a0ce (patch)
tree22406e6484a7cccc1c72fb47cc4e5848f57ee2c4 /public/assets/javascripts/rectangles/models/surface.js
parented5751766079a62ce596dcc0abc1a211b5b633dc (diff)
parent4ef340497ef24bb2ecacb2c9c4106c24515c874f (diff)
merge
Diffstat (limited to 'public/assets/javascripts/rectangles/models/surface.js')
-rw-r--r--public/assets/javascripts/rectangles/models/surface.js281
1 files changed, 281 insertions, 0 deletions
diff --git a/public/assets/javascripts/rectangles/models/surface.js b/public/assets/javascripts/rectangles/models/surface.js
new file mode 100644
index 0000000..53977c8
--- /dev/null
+++ b/public/assets/javascripts/rectangles/models/surface.js
@@ -0,0 +1,281 @@
+(function(){
+
+ var vec2, Rect
+ if ('window' in this) {
+ vec2 = window.vec2
+ Rect = window.Rect
+ }
+ else {
+ vec2 = require('./vec2')
+ Rect = require('./rect')
+ }
+
+ var Surface = function (face){
+ this.bounds = new Rect (new vec2(0, 0), new vec2(0, 0))
+ this.faces = []
+ if (face) {
+ this.add(face)
+ }
+ }
+ Surface.prototype.add = function(rect){
+ if (this.faces.length == 0) {
+ this.bounds.x.a = rect.x.a
+ this.bounds.x.b = rect.x.a
+ this.bounds.y.a = rect.y.a
+ this.bounds.y.b = rect.y.a
+ }
+ this.bounds.x.b += rect.width()
+ this.bounds.y.a = Math.min(this.bounds.y.a, rect.y.a)
+ this.bounds.y.b = Math.max(this.bounds.y.b, rect.y.b)
+ this.faces.push(rect)
+ }
+ Surface.prototype.fits_scale = function(v, scale){
+ v = v.clone().mul(scale)
+ return this.fits(v)
+ }
+ Surface.prototype.fits = function(v){
+ var faces = this.faces
+ var scratch
+ if (this.bounds.x.b < v.a || this.bounds.y.b < v.b) {
+ return null
+ }
+ for (var i = 0; i < faces.length; i++) {
+ if (faces[i].fits(v)) {
+ return faces[i]
+ }
+ }
+ scratch = new Rect (0,0,0,0)
+ for (var i = 0; i < faces.length; i++) {
+ if (faces[i].y.length() < v.b) {
+ continue
+ }
+ scratch.x.a = faces[i].x.a
+ scratch.x.b = faces[i].x.b
+ scratch.y.a = faces[i].y.a
+ scratch.y.b = faces[i].y.b
+ SEARCH: for (var j = i+1; j < faces.length; j++) {
+ if (faces[j].y.a > scratch.y.a) {
+ scratch.y.a = faces[j].y.a
+ }
+ if (faces[j].y.b < scratch.y.b) {
+ scratch.y.b = faces[j].y.b
+ }
+ if (scratch.y.b <= scratch.y.a || scratch.y.length() < v.b) {
+ break SEARCH
+ }
+ scratch.x.b = faces[j].x.b
+ if (scratch.fits(v)) {
+ return scratch
+ }
+ }
+ }
+ return null
+ }
+
+ function center_for (dimension, position, delta) {
+ var center = new vec2( position.a + dimension.a/2, position.b + dimension.b/2 )
+ if (delta) {
+ center.a += delta.a
+ center.b += delta.b
+ }
+ return center
+ }
+
+ Surface.prototype.clamp_delta = function (bounds, dimension, position, delta) {
+ var left_edge = position.a + delta.a - bounds.x.a
+ if (left_edge < 0) {
+ delta.a -= left_edge
+ }
+
+ var right_edge = position.a + dimension.a + delta.a - bounds.x.b
+ if (right_edge > 0) {
+ delta.a -= right_edge
+ }
+ var bottom_edge = position.b + delta.b - bounds.y.a
+ if (bottom_edge < 0) {
+ delta.b -= bottom_edge
+ }
+
+ var top_edge = position.b + dimension.b + delta.b - bounds.y.b
+ if (top_edge > 0) {
+ delta.b -= top_edge
+ }
+
+ return delta
+ }
+
+ Surface.prototype.translate = function (old_bounds, dimension, position, delta) {
+ this.clamp_delta( this.bounds, dimension, position, delta )
+
+ var new_delta = delta.clone()
+ if (this.clamp_delta(old_bounds, dimension, position, new_delta).eq(delta)) {
+ return old_bounds
+ }
+
+// var left_index = this.index_for_x( position.a + delta.a, 0 )
+// var center_index = this.index_for_x( position.a + dimension.a/2 + delta.a, left_index )
+// var right_index = this.index_for_x( position.a + dimension.a + delta.a, center_index )
+// var new_bounds = this.bounds_at_index_with_dimensions(center_index, dimension)
+//
+// this.clamp_delta(new_bounds, dimension, position, delta)
+//
+// return new_bounds
+
+ var left_side = this.index_for_x( position.a + delta.a, 0 )
+ var right_side = this.index_for_x( position.a + dimension.a + delta.a, left_side )
+
+ var bounds = this.faces[left_side].clone()
+ var intersection
+
+ for (var i = Math.min(left_side+1, right_side); i <= right_side; i++) {
+ intersection = bounds.y.intersection(this.faces[i].y)
+ if (intersection.length() < dimension.b) {
+ bounds = null
+ break
+ }
+ bounds.y.assign(intersection)
+ bounds.x.b = this.faces[i].x.b
+ }
+ if (! bounds || bounds.width() < dimension.a || bounds.height() < dimension.b ||
+ bounds.y.a > position.b + delta.b || bounds.y.b < position.b + dimension.b + delta.b) {
+ bounds = old_bounds
+ }
+
+ this.clamp_delta(bounds, dimension, position, delta)
+ return bounds
+ }
+
+ Surface.prototype.index_for_x = function(x, min_i){
+ min_i = min_i || 0
+ for (var i = min_i; i < this.faces.length; i++) {
+ if (this.faces[i].x.contains(x)) {
+ return i
+ }
+ }
+ return -1
+ }
+
+ Surface.prototype.bounds_at_index_with_dimensions = function(index, dimensions){
+ var faces = this.faces
+ if (index == -1) index = this.faces.length-1
+
+ var bounds, intersection
+ var width = dimensions.a
+ var height = dimensions.b
+
+ for (var i = index; i >= 0; i--) {
+ var face = faces[i]
+ if (face.y.length() < height) {
+ if (bounds) break
+ else continue
+ }
+ if (! bounds) {
+ bounds = face.clone()
+ bounds.last = i
+ }
+ else if (bounds.width() < width) {
+ intersection = bounds.y.intersection(face.y)
+ if (intersection.length() < height) {
+ // not totally sure if we can clobber the bounds here since this would prevent
+ // us from looking rightwise later
+ break
+ }
+ else {
+ bounds.y.a = intersection.a
+ bounds.y.b = intersection.b
+ bounds.x.a = face.x.a
+ bounds.first = i
+ continue
+ }
+ }
+ else {
+ if (face.y.a > bounds.y.a) break
+ if (face.y.b < bounds.y.b) break
+ }
+ bounds.x.a = face.x.a
+ bounds.first = i
+ }
+
+ for (var i = bounds ? bounds.last+1 : index+1; i < faces.length; i++) {
+ var face = faces[i]
+ if (face.y.length() < height) {
+ if (bounds) break
+ else continue
+ }
+ if (! bounds) {
+ bounds = face.clone()
+ bounds.first = i
+ }
+ else if (bounds.width() < width) {
+ intersection = bounds.y.intersection(face.y)
+ if (intersection.length() < height) {
+ // here, since the element is tall enough, we can clobber the bounds completely
+ bounds.y.a = face.y.a
+ bounds.y.b = face.y.b
+ bounds.x.a = face.x.a
+ bounds.x.b = face.x.b
+ bounds.first = bounds.last = i
+ continue
+ }
+ else {
+ bounds.y.a = intersection.a
+ bounds.y.b = intersection.b
+ bounds.x.b = face.x.b
+ bounds.last = i
+ continue
+ }
+ }
+ if (face.y.a > bounds.y.a) break
+ if (face.y.b < bounds.y.b) break
+ bounds.x.b = face.x.b
+ bounds.last = i
+ }
+
+ if (! bounds) {
+ // console.log('no bounds')
+ return false
+ }
+ else if (bounds.width() < width) {
+ // console.log('too narrow')
+ return false
+ }
+ return bounds
+ }
+
+ Surface.prototype.bounds_at_index = function(index){
+ var faces = this.faces
+ if (index == -1) index = this.faces.length-1
+
+ var bounds = faces[index].clone()
+ var height = faces[index].height()
+ bounds.first = bounds.last = index
+
+ for (var i = index-1; i >= 0; i--) {
+ var face = faces[i]
+ if (face.y.length() < height) break
+ if (face.y.a > bounds.y.a) break
+ if (face.y.b < bounds.y.b) break
+
+ bounds.x.a = face.x.a
+ bounds.first = i
+ }
+
+ for (var i = index+1; i < faces.length; i++) {
+ var face = faces[i]
+ if (face.y.length() < height) break
+ if (face.y.a > bounds.y.a) break
+ if (face.y.b < bounds.y.b) break
+
+ bounds.x.b = face.x.b
+ bounds.last = i
+ }
+ return bounds
+ }
+
+ if ('window' in this) {
+ window.Surface = Surface
+ }
+ else {
+ module.exports = Surface
+ }
+})()