UNPKG

support

Version:

A toolkit for node.js

235 lines (190 loc) 6.13 kB
var _ = require('underscore'); var util = require('util'); var fs = require('fs'); var path = require('path'); /* ***************** CLOSURE ************* */ function Line2point(p1, p2) { this._p1 = p1; this._p2 = p2; } function Rect(from_pt, to_pt) { this._p1 = from_pt; this._p2 = to_pt; } Rect.prototype = { contains:function (pt) { return (pt.x >= this._p1.x) && (pt.y >= this._p1.y) && (pt.x <= this._p2.x) && (pt.y <= this._p2.y); } } Line2point.prototype = { _slope:null, slope:function () { if (!this._slope) { if (this._p1.x == this._p2.x) { this._slope = Infinity; } else { this._slope = this.ydist() / this.xdist(); } } return this._slope; }, _xdist:null, _ydist:null, ydist:function () { if (null === this._ydist) { this._ydist = this._p2.y - this._p1.y; } return this._ydist; }, xdist:function () { if (null === this._xdist) { this._xdist = this._p2.x - this._p1.x; } return this._xdist; }, _c:function () { var A = this.ydist(); var B = -this.xdist(); return this._p1.x * A + this._p1.y * B; }, eq:function (line) { return (line.xdist() == this.xdist()) && (line.ydist() == this.ydist()) && (line._c() == this._c()); }, _parallel:{x:null, y:null, error:'parallel'}, _identical:{x:null, y:null, error:'identical'}, cross:function (line) { var A1 = this.ydist(); var A2 = line.ydist(); var B1 = -this.xdist(); var B2 = -line.xdist(); var C1 = this._c(); var C2 = line._c(); if (line.slope() == this.slope()) { if (this.eq(line)) { return this._identical; } else { return this._parallel; } } else if (this.slope() == Infinity) { return line.point_at_x(this.p1.x); } else if (line.slope() == Infinity) { return this.point_at_x(line.p1.x); } else { var det = A1 * B2 - A2 * B1; if (det == 0) { return this._parallel; } else { var x = (B2 * C1 - B1 * C2) / det; var y = (A1 * C2 - A2 * C1) / det; return {x:x, y:y, between:this.between({x:x, y:y}) && line.between({x:x, y:y})}; } } }, _rect:null, rect:function () { if (this._rect === null) { var min = {x:Math.min(this._p1.x, this._p2.x), y:Math.min(this._p1.y, this._p2.y)}; var max = {x:Math.max(this._p1.x, this._p2.x), y:Math.max(this._p1.y, this._p2.y)}; this._rect = new Rect(min, max); } return this._rect; }, // note - this method DOES NOT check whether the point is on the line! // it only validtaes that the point is inside the rect that contains these two points. between:function (point) { return this.rect().contains(point) } } /* ***************** MODULE *********** */ module.exports = { Line2Point:Line2point, Rect:Rect, dist:function (p1, p2) { var xd = p2.x - p1.x; var yd = p2.y - p1.y; return Math.sqrt((xd * xd) + (yd * yd)); }, unit_vector:function (origin, destination) { var distance = module.exports.dist(origin, destination); var scale = 1 / distance; var vector = module.exports.sub_points(destination, origin); return module.exports.scaled_vector(vector, scale); }, add_points:function (p1, p2) { return { x:p1.x + p2.x, y:p1.y + p2.y }; }, /** * subtracts SECOND from FIRST * @param p1 * @param p2 * @return {Object} */ sub_points:function (p1, p2) { return { x:p1.x - p2.x, y:p1.y - p2.y }; }, peq:function (p1, p2) { return (p1.x == p2.x && p1.y == p2.y); }, scaled_vector:function (vector, scale, origin) { if (isNaN(scale)) { throw new Error('scaled_vector: isNaN ' + util.inspect(scale)); } var out = { x:vector.x * scale, y:vector.y * scale }; if (origin) { return module.exports.add_points(out, origin); } else { return out; } }, segments:function (p_start, p_end, seg_len) { //console.log('segments %s to %s - seg len %s', util.inspect(p_start), util.inspect(p_end), seg_len); var p_dist = module.exports.dist(p_start, p_end); var points = [_.clone(p_start)]; var vector = module.exports.unit_vector(p_start, p_end); // console.log('unit vector: ' + util.inspect(vector)); var scale = 1; do { var dist = seg_len * scale; points.push(module.exports.scaled_vector(vector, dist, p_start)); ++scale; } while (dist < p_dist) return points; }, ppv: function(n){ return Math.round(n * 100)/100; }, pp: function(p){ return util.format('(%s, %s)', module.exports.ppv(p.x), module.exports.ppv(p.y)); }, ppl: function(pl){ return '[' + _.map(pl, module.exports.pp).join(', ') + ']'; }, segments_approx:function (p_start, p_end, seg_len) { var dist = this.dist(p_start, p_end); var divs = Math.ceil(dist/seg_len); console.log('segments %s long from %s to %s: %s divs for %s dist', seg_len, this.pp(p_start), this.pp(p_end), divs, dist); if (divs <= 1){ console.log('... short cutting for low divs') return [p_start, p_end]; } var points = []; for (var i = 0; i <= divs; ++i){ var x = (p_start.x * i + p_end.x * (divs - i)) / divs; var y = (p_start.y * i + p_end.y * (divs - i)) / divs; points.push({x: x, y: y}); } return points; } }