// Copyright (c) 2011, Chris Umbel, James Coglan // Line.Segment class - depends on Line and its dependencies. var Line = require('./line'); var Vector = require('./vector'); Line.Segment = function() {}; Line.Segment.prototype = { // Returns true iff the line segment is equal to the argument eql: function(segment) { return (this.start.eql(segment.start) && this.end.eql(segment.end)) || (this.start.eql(segment.end) && this.end.eql(segment.start)); }, // Returns a copy of the line segment dup: function() { return Line.Segment.create(this.start, this.end); }, // Returns the length of the line segment length: function() { var A = this.start.elements, B = this.end.elements; var C1 = B[0] - A[0], C2 = B[1] - A[1], C3 = B[2] - A[2]; return Math.sqrt(C1*C1 + C2*C2 + C3*C3); }, // Returns the line segment as a vector equal to its // end point relative to its endpoint toVector: function() { var A = this.start.elements, B = this.end.elements; return Vector.create([B[0] - A[0], B[1] - A[1], B[2] - A[2]]); }, // Returns the segment's midpoint as a vector midpoint: function() { var A = this.start.elements, B = this.end.elements; return Vector.create([(B[0] + A[0])/2, (B[1] + A[1])/2, (B[2] + A[2])/2]); }, // Returns the plane that bisects the segment bisectingPlane: function() { return Plane.create(this.midpoint(), this.toVector()); }, // Returns the result of translating the line by the given vector/array translate: function(vector) { var V = vector.elements || vector; var S = this.start.elements, E = this.end.elements; return Line.Segment.create( [S[0] + V[0], S[1] + V[1], S[2] + (V[2] || 0)], [E[0] + V[0], E[1] + V[1], E[2] + (V[2] || 0)] ); }, // Returns true iff the line segment is parallel to the argument. It simply forwards // the method call onto its line property. isParallelTo: function(obj) { return this.line.isParallelTo(obj); }, // Returns the distance between the argument and the line segment's closest point to the argument distanceFrom: function(obj) { var P = this.pointClosestTo(obj); return (P === null) ? null : P.distanceFrom(obj); }, // Returns true iff the given point lies on the segment contains: function(obj) { if (obj.start && obj.end) { return this.contains(obj.start) && this.contains(obj.end); } var P = (obj.elements || obj).slice(); if (P.length == 2) { P.push(0); } if (this.start.eql(P)) { return true; } var S = this.start.elements; var V = Vector.create([S[0] - P[0], S[1] - P[1], S[2] - (P[2] || 0)]); var vect = this.toVector(); return V.isAntiparallelTo(vect) && V.modulus() <= vect.modulus(); }, // Returns true iff the line segment intersects the argument intersects: function(obj) { return (this.intersectionWith(obj) !== null); }, // Returns the unique point of intersection with the argument intersectionWith: function(obj) { if (!this.line.intersects(obj)) { return null; } var P = this.line.intersectionWith(obj); return (this.contains(P) ? P : null); }, // Returns the point on the line segment closest to the given object pointClosestTo: function(obj) { if (obj.normal) { // obj is a plane var V = this.line.intersectionWith(obj); if (V === null) { return null; } return this.pointClosestTo(V); } else { // obj is a line (segment) or point var P = this.line.pointClosestTo(obj); if (P === null) { return null; } if (this.contains(P)) { return P; } return (this.line.positionOf(P) < 0 ? this.start : this.end).dup(); } }, // Set the start and end-points of the segment setPoints: function(startPoint, endPoint) { startPoint = Vector.create(startPoint).to3D(); endPoint = Vector.create(endPoint).to3D(); if (startPoint === null || endPoint === null) { return null; } this.line = Line.create(startPoint, endPoint.subtract(startPoint)); this.start = startPoint; this.end = endPoint; return this; } }; // Constructor function Line.Segment.create = function(v1, v2) { var S = new Line.Segment(); return S.setPoints(v1, v2); }; module.exports = Line.Segment;