瀏覽代碼

Rewrite Triangle.closestPointToPoint

Marshall Quander 7 年之前
父節點
當前提交
a84dcbdc6d
共有 1 個文件被更改,包括 62 次插入29 次删除
  1. 62 29
      src/math/Triangle.js

+ 62 - 29
src/math/Triangle.js

@@ -1,6 +1,4 @@
 import { Vector3 } from './Vector3.js';
-import { Line3 } from './Line3.js';
-import { Plane } from './Plane.js';
 
 /**
  * @author bhouston / http://clara.io
@@ -218,12 +216,14 @@ Object.assign( Triangle.prototype, {
 
 	closestPointToPoint: function () {
 
-		var plane = new Plane();
-		var edgeList = [ new Line3(), new Line3(), new Line3() ];
-		var projectedPoint = new Vector3();
-		var closestPoint = new Vector3();
+		var vab = new Vector3();
+		var vac = new Vector3();
+		var vbc = new Vector3();
+		var vap = new Vector3();
+		var vbp = new Vector3();
+		var vcp = new Vector3();
 
-		return function closestPointToPoint( point, target ) {
+		return function closestPointToPoint( p, target ) {
 
 			if ( target === undefined ) {
 
@@ -232,48 +232,81 @@ Object.assign( Triangle.prototype, {
 
 			}
 
-			var minDistance = Infinity;
+			var a = this.a, b = this.b, c = this.c;
+			var v, w;
 
-			// project the point onto the plane of the triangle
+			// algorithm thanks to Real-Time Collision Detection by Christer Ericson,
+			// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
+			// under the accompanying license; see chapter 5.1.5 for detailed explanation.
+			// basically, we're distinguishing which of the voronoi regions of the triangle
+			// the point lies in with the minimum amount of redundant computation.
 
-			plane.setFromCoplanarPoints( this.a, this.b, this.c );
-			plane.projectPoint( point, projectedPoint );
+			vab.subVectors( b, a );
+			vac.subVectors( c, a );
+			vap.subVectors( p, a );
+			var d1 = vab.dot( vap );
+			var d2 = vac.dot( vap );
+			if ( d1 <= 0 && d2 <= 0 ) {
 
-			// check if the projection lies within the triangle
+				// vertex region of A; barycentric coords (1, 0, 0)
+				return target.copy( a );
 
-			if ( this.containsPoint( projectedPoint ) === true ) {
+			}
+
+			vbp.subVectors( p, b );
+			var d3 = vab.dot( vbp );
+			var d4 = vac.dot( vbp );
+			if ( d3 >= 0 && d4 <= d3 ) {
 
-				// if so, this is the closest point
+				// vertex region of B; barycentric coords (0, 1, 0)
+				return target.copy( b );
 
-				target.copy( projectedPoint );
+			}
 
-			} else {
+			var vc = d1 * d4 - d3 * d2;
+			if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
 
-				// if not, the point falls outside the triangle. the target is the closest point to the triangle's edges or vertices
+				v = d1 / ( d1 - d3 );
+				// edge region of AB; barycentric coords (1-v, v, 0)
+				return target.copy( a ).addScaledVector( vab, v );
 
-				edgeList[ 0 ].set( this.a, this.b );
-				edgeList[ 1 ].set( this.b, this.c );
-				edgeList[ 2 ].set( this.c, this.a );
+			}
 
-				for ( var i = 0; i < edgeList.length; i ++ ) {
+			vcp.subVectors( p, c );
+			var d5 = vab.dot( vcp );
+			var d6 = vac.dot( vcp );
+			if ( d6 >= 0 && d5 <= d6 ) {
 
-					edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint );
+				// vertex region of C; barycentric coords (0, 0, 1)
+				return target.copy( c );
 
-					var distance = projectedPoint.distanceToSquared( closestPoint );
+			}
 
-					if ( distance < minDistance ) {
+			var vb = d5 * d2 - d1 * d6;
+			if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
 
-						minDistance = distance;
+				w = d2 / ( d2 - d6 );
+				// edge region of AC; barycentric coords (1-w, 0, w)
+				return target.copy( a ).addScaledVector( vac, w );
 
-						target.copy( closestPoint );
+			}
 
-					}
+			var va = d3 * d6 - d5 * d4;
+			if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
 
-				}
+				vbc.subVectors( c, b );
+				w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
+				// edge region of BC; barycentric coords (0, 1-w, w)
+				return target.copy( b ).addScaledVector( vbc, w ); // edge region of BC
 
 			}
 
-			return target;
+			// face region
+			var denom = 1 / ( va + vb + vc );
+			// u = va * denom
+			v = vb * denom;
+			w = vc * denom;
+			return target.copy( a ).addScaledVector( vab, v ).addScaledVector( vac, w );
 
 		};