diff options
Diffstat (limited to 'public/assets/javascripts/rectangles/engine/shapes/polyline.js')
| -rw-r--r-- | public/assets/javascripts/rectangles/engine/shapes/polyline.js | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/public/assets/javascripts/rectangles/engine/shapes/polyline.js b/public/assets/javascripts/rectangles/engine/shapes/polyline.js new file mode 100644 index 0000000..b2cd92f --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/shapes/polyline.js @@ -0,0 +1,212 @@ +// A Polyline is a set of points inputted by the user using the V2 editor to trace a blueprint. +// Additionally, it manages a set of MX objects which correspond to the walls in 3D. +// In this way, it attempts to bridge the 2D (canvas, imperative) and 3D (css, declarative) views. + +if (! ('window' in this) ) { + var Fiber = require("../../../vendor/bower_components/fiber/src/fiber.js") + var vec2 = require("../../models/vec2") +} + +var Polyline = Fiber.extend(function(base){ + var exports = {} + exports.init = function(){ + this.points = [] + this.mx_points = [] + this.closed = false + } + exports.type = function(){ + return "polyline" + } + exports.instantiate = function(){ + return new Polyline + } + exports.add = function(p){ + this.points.push( p ) + this.mx_points.push( new MX.Point(p) ) + } + exports.firstPoint = function(){ + return this.points[0] + } + exports.lastPoint = function(){ + return this.points[this.points.length-1] + } + exports.canCloseWith = function(p){ + return (this.points.length > 2 && this.points[0].distanceTo( p ) < 10/map.zoom) + } + exports.getHeadAtIndex = function(index){ + if (index == 0) { return null } + if (index == this.points.length-1) { return this.clone() } + var head = this.instantiate() + head.points = this.points.slice(0, index+1) + return head + } + exports.getTailAtIndex = function(index){ + if (index == this.points.length-1) { return null } + if (index == 0) { return this.clone() } + var tail = this.instantiate() + tail.points = this.points.slice(index, this.points.length) + return tail + } + exports.clone = function(){ + var clone = this.instantiate() + clone.points = this.points.concat() + } + exports.getSegment = function(segment){ + var seg = [ + this.points[segment.head], + this.points[segment.tail], + ] + if (segment.head == 0) { + seg.push( this.lastPoint() ) + } + else if (segment.tail == this.points.length-1) { + seg.push( this.firstPoint() ) + } + return seg + } + exports.cloneSegment = function(segment){ + return this.getSegment(segment).map(function(point){ return point.clone() }) + } + exports.translateSegment = function(src, dest, dx, dy){ + dest[0].a = src[0].a + dx + dest[0].b = src[0].b + dy + dest[1].a = src[1].a + dx + dest[1].b = src[1].b + dy + if (src.length == 3) { + dest[2].a = src[2].a + dx + dest[2].b = src[2].b + dy + } + } + exports.hasPointNear = function(p){ + var point + for (var i = 0; i < this.points.length; i++){ + point = this.points[i] + if (point.distanceTo( p ) < 10/map.zoom) { + return point + } + } + return null + } + exports.hasEndPointNear = function(p){ + if (this.closed || ! this.points.length) return null + if (this.firstPoint().distanceTo( p ) < 10/map.zoom) { + return this.firstPoint() + } + if (this.lastPoint().distanceTo( p ) < 10/map.zoom) { + return this.lastPoint() + } + return null + } + exports.hasSegmentNear = function(p, min_dist){ + var p1, p2, d1, d2, sum, rat + var dx, dy, new_x, new_y, x, y, closest_distance = min_dist || Infinity + var closest_i = -1 + var points = this.points + var p1, p2 = points[0] + for (var i = 1; i < points.length; i++) { + p1 = p2 + p2 = points[i] + d1 = p2.a - p1.a + d2 = p2.b - p1.b + sum = d1*d1 + d2*d2 + rat = ((p.a - p1.a) * d1 + (p.b - p1.b) * d2) / sum + rat = rat < 0 ? 0 : rat < 1 ? rat : 1 + new_x = p1.a + rat * d1 + new_y = p1.b + rat * d2 + dx = new_x - p.a + dy = new_y - p.b + sum2 = sqrt(dx*dx+dy*dy) + if (sum2 < closest_distance) { + x = new_x + y = new_y + closest_distance = sum2 + closest_i = i + } + } + if (closest_i == -1) return null + return { + x: x, + y: y, + distance: closest_distance, + head: closest_i-1, + tail: closest_i, + } + } + exports.draw = function(ctx, fillStyle, strokeStyle){ + var points = this.points + if (! points.length) return + if (points.length == 1) { + ctx.fillStyle = "#f80" + map.draw.dot_at(this.points[0].a, points[0].b, 5) + } + if (points.length > 1) { + ctx.fillStyle = fillStyle + ctx.strokeStyle = strokeStyle + ctx.lineWidth = 2 / map.zoom + ctx.beginPath() + ctx.moveTo(points[0].a, points[0].b) + points.forEach(function(point, i){ + i && ctx.lineTo(point.a, point.b) + }) + strokeStyle && ctx.stroke() + if (! map.ui.placing || this.closed) { + fillStyle && ctx.fill() + } + } + } + exports.draw_line = function (ctx, p){ + var last = this.points[this.points.length-1] + ctx.strokeStyle = "#f80" + ctx.lineWidth = 2 / map.zoom + ctx.beginPath() + ctx.moveTo(last.a, last.b) + ctx.lineTo(p.a, p.b) + ctx.stroke() + } + exports.close = function(){ + this.points[this.points.length] = this.points[0] + this.closed = true + } + exports.build = function(){ + this.mx_points && this.mx_points.forEach(function(mx){ scene.remove(mx) }) + this.mx = new MX.Polyline(this) + } + exports.rebuild = function(){ + this.mx.rebuild() + } + exports.getSegments = function(){ + if (this.points.length == 1) { + return [] + } + var segments = [] + for (var i = 1; i < this.points.length; i++) { + segments.push( [ this.points[i-1], this.points[i] ] ) + } + return segments + } + exports.serialize = function(){ + return { + type: this.type(), + closed: this.closed, + points: this.points.map(function(point){ return [point.a, point.b] }), + } + } + exports.deserialize = function(data){ + this.closed = data.closed || false + this.points = (data.points || data).map(function(point){ return new vec2(point[0], point[1]) }) + } + exports.reset = function(){ + this.mx_points.forEach(function(mx){ scene.remove(mx) }) + this.mx_points.length = 0 + this.points.length = 0 + } + exports.destroy = function(){ + this.reset() + this.mx && this.mx.destroy() + } + return exports +}) + +if (! ('window' in this) ) { + module.exports = Polyline +} |
