127 lines
4.2 KiB
JavaScript
127 lines
4.2 KiB
JavaScript
// 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;
|