Răsfoiți Sursa

A ray can now compute its minimal distance to a segment

We can give optional targets to compute the points on the ray and the other on the segment (defining the minimal distance...)
Stéphane 12 ani în urmă
părinte
comite
16328ad2cd
1 a modificat fișierele cu 60 adăugiri și 0 ștergeri
  1. 60 0
      src/math/Ray.js

+ 60 - 0
src/math/Ray.js

@@ -78,6 +78,66 @@ THREE.Ray.prototype = {
 
 	}(),
 
+	distanceSqAndPointToSegment: function( v0, v1, optionalPointOnLine, optionalPointOnSegment ) {
+		// from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistLine3Segment3.cpp
+		// It returns the min distance between the ray (actually... the line) and the segment
+		// defined by v0 and v1
+		// It can also set two optional targets :
+		// - The closest point on the ray (...line)
+		// - The closest point on the segment
+		var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 );
+		var segDir = v1.clone().sub( v0 ).normalize();
+		var segExtent = v0.distanceTo( v1 ) *0.5;
+		var diff = this.origin.clone().sub( segCenter );
+		var a01 = -this.direction.dot( segDir );
+		var b0 = diff.dot( this.direction );
+		var c = diff.lengthSq();
+		var det = Math.abs( 1 - a01 * a01 );
+		var b1, s0, s1, sqrDist, extDet;
+		if( det >= 0 ) {
+			// The line and segment are not parallel.
+			b1 = -diff.dot( segDir );
+			s1 = a01 * b0 - b1;
+			extDet = segExtent * det;
+			if( s1 >= -extDet ) {
+				if( s1 <= extDet ) {
+					// Two interior points are closest, one on the line and one
+					// on the segment.
+					var invDet = 1 / det;
+					s0 = ( a01 * b1 - b0 ) * invDet;
+					s1 *= invDet;
+					sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
+				}
+				else {
+					// The endpoint e1 of the segment and an interior point of
+					// the line are closest.
+					s1 = segExtent;
+					s0 = - ( a01 * s1 + b0 );
+					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
+				}
+			}
+			else {
+				// The end point e0 of the segment and an interior point of the
+				// line are closest.
+				s1 = - segExtent;
+				s0 = - ( a01 * s1 + b0 );
+				sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
+			}
+		}
+		else {
+			// The line and segment are parallel.  Choose the closest pair so that
+			// one point is at segment center.
+			s1 = 0;
+			s0 = - b0;
+			sqrDist = b0 * s0 + c;
+		}
+		if(optionalPointOnLine)
+			optionalPointOnLine.copy( this.direction.clone().multiplyScalar( s0 ).add( this.origin ) );
+		if(optionalPointOnSegment)
+			optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) );
+		return sqrDist;
+	},
+
 	isIntersectionSphere: function( sphere ) {
 
 		return ( this.distanceToPoint( sphere.center ) <= sphere.radius );