Browse Source

All unit tests pass now for Box2, Box3 and Triangle3. Fix bug in Plane.js caught in Triangle3 unit tests. Replace Raycaster.pointInFace3 with Triangle3.containsPoint, no loss of FPS in examples.

Ben Houston 12 years ago
parent
commit
14ad378826
7 changed files with 100 additions and 92 deletions
  1. 3 23
      src/core/Raycaster.js
  2. 1 1
      src/math/Box3.js
  3. 2 2
      src/math/Plane.js
  4. 50 23
      src/math/Triangle3.js
  5. 9 9
      test/core/Box2.js
  6. 9 9
      test/core/Box3.js
  7. 26 25
      test/core/Triangle3.js

+ 3 - 23
src/core/Raycaster.js

@@ -37,26 +37,6 @@
 
 
 	// http://www.blackpawn.com/texts/pointinpoly/default.html
 	// http://www.blackpawn.com/texts/pointinpoly/default.html
 
 
-	var pointInFace3 = function ( p, a, b, c ) {
-
-		v0.sub( c, a );
-		v1.sub( b, a );
-		v2.sub( p, a );
-
-		var dot00 = v0.dot( v0 );
-		var dot01 = v0.dot( v1 );
-		var dot02 = v0.dot( v2 );
-		var dot11 = v1.dot( v1 );
-		var dot12 = v1.dot( v2 );
-
-		var invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 );
-		var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
-		var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
-
-		return ( u >= 0 ) && ( v >= 0 ) && ( u + v < 1 );
-
-	};
-
 	var intersectObject = function ( object, raycaster, intersects ) {
 	var intersectObject = function ( object, raycaster, intersects ) {
 
 
 		if ( object instanceof THREE.Particle ) {
 		if ( object instanceof THREE.Particle ) {
@@ -149,7 +129,7 @@
 					b = vertices[ face.b ];
 					b = vertices[ face.b ];
 					c = vertices[ face.c ];
 					c = vertices[ face.c ];
 
 
-					if ( ! pointInFace3( intersectPoint, a, b, c ) ) continue;
+					if ( ! THREE.Triangle3.containsPoint( intersectPoint, a, b, c ) ) continue;
 
 
 				} else if ( face instanceof THREE.Face4 ) {
 				} else if ( face instanceof THREE.Face4 ) {
 
 
@@ -158,8 +138,8 @@
 					c = vertices[ face.c ];
 					c = vertices[ face.c ];
 					d = vertices[ face.d ];
 					d = vertices[ face.d ];
 
 
-					if ( ( ! pointInFace3( intersectPoint, a, b, d ) ) &&
-						 ( ! pointInFace3( intersectPoint, b, c, d ) ) ) continue;
+					if ( ( ! THREE.Triangle3.containsPoint( intersectPoint, a, b, d ) ) &&
+						 ( ! THREE.Triangle3.containsPoint( intersectPoint, b, c, d ) ) ) continue;
 
 
 				} else {
 				} else {
 
 

+ 1 - 1
src/math/Box3.js

@@ -140,7 +140,7 @@ THREE.Box3.prototype = {
 
 
 	},
 	},
 
 
-	size: function () {
+	size: function ( optionalTarget ) {
 
 
 		var result = optionalTarget || new THREE.Vector3();
 		var result = optionalTarget || new THREE.Vector3();
 		return result.sub( this.max, this.min );
 		return result.sub( this.max, this.min );

+ 2 - 2
src/math/Plane.js

@@ -51,8 +51,8 @@ THREE.Plane.prototype = {
 
 
 	setFromCoplanarPoints: function ( a, b, c ) {
 	setFromCoplanarPoints: function ( a, b, c ) {
 
 
-		var normal = THREE.Plane.__v1.sub( b, a ).cross(
-					 THREE.Plane.__v2.sub( c, a ) );
+		var normal = THREE.Plane.__v1.sub( c, b ).crossSelf(
+					 THREE.Plane.__v2.sub( a, b ) );
 
 
 		// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
 		// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
 
 

+ 50 - 23
src/math/Triangle3.js

@@ -18,6 +18,42 @@ THREE.Triangle3 = function ( a, b, c ) {
 
 
 };
 };
 
 
+// static/instance method to calculate barycoordinates
+THREE.Triangle3.barycoordinate = function ( point, a, b, c, optionalTarget ) {
+
+	THREE.Triangle3.__v0.sub( c, a );
+	THREE.Triangle3.__v1.sub( b, a );
+	THREE.Triangle3.__v2.sub( point, a );
+
+	var dot00 = THREE.Triangle3.__v0.dot( THREE.Triangle3.__v0 );
+	var dot01 = THREE.Triangle3.__v0.dot( THREE.Triangle3.__v1 );
+	var dot02 = THREE.Triangle3.__v0.dot( THREE.Triangle3.__v2 );
+	var dot11 = THREE.Triangle3.__v1.dot( THREE.Triangle3.__v1 );
+	var dot12 = THREE.Triangle3.__v1.dot( THREE.Triangle3.__v2 );
+
+	var denom = ( dot00 * dot11 - dot01 * dot01 );
+
+	// colinear or singular triangle
+	if( denom == 0 ) {
+		return false;
+	}
+
+	var invDenom = 1 / denom;
+	var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
+	var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
+
+	var result = optionalTarget || new THREE.Vector3();
+
+	return result.set( u, v, 1 - u - v );
+}
+
+THREE.Triangle3.containsPoint = function ( point, a, b, c ) {
+
+	var result = THREE.Triangle3.barycoordinate( point, a, b, c, THREE.Triangle3.__v3 );
+
+	return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );
+}
+
 THREE.Triangle3.prototype = {
 THREE.Triangle3.prototype = {
 
 
 	constructor: THREE.Triangle3,
 	constructor: THREE.Triangle3,
@@ -54,17 +90,17 @@ THREE.Triangle3.prototype = {
 
 
 	area: function () {
 	area: function () {
 
 
-		__v0.sub( this.c, this.b );
-		__v1.sub( this.a, this.b );
+		THREE.Triangle3.__v0.sub( this.c, this.b );
+		THREE.Triangle3.__v1.sub( this.a, this.b );
 
 
-		return __v0.cross( __v1 ).length() * 0.5;
+		return THREE.Triangle3.__v0.crossSelf( THREE.Triangle3.__v1 ).length() * 0.5;
 
 
 	},
 	},
 
 
 	midpoint: function ( optionalTarget ) {
 	midpoint: function ( optionalTarget ) {
 
 
 		var result = optionalTarget || new THREE.Vector3();
 		var result = optionalTarget || new THREE.Vector3();
-		return result.add( this.a, this.b ).addSelf( this.b ).multiplyScalar( 1 / 3 );
+		return result.add( this.a, this.b ).addSelf( this.c ).multiplyScalar( 1 / 3 );
 
 
 	},
 	},
 
 
@@ -73,19 +109,17 @@ THREE.Triangle3.prototype = {
 		var result = optionalTarget || new THREE.Vector3();
 		var result = optionalTarget || new THREE.Vector3();
 
 
 		result.sub( this.c, this.b );
 		result.sub( this.c, this.b );
-		__v0.sub( this.a, this.b );
-		result.cross( __v0 );
+		THREE.Triangle3.__v0.sub( this.a, this.b );
+		result.crossSelf( THREE.Triangle3.__v0 );
 
 
 		var resultLengthSq = result.lengthSq();
 		var resultLengthSq = result.lengthSq();
 		if( resultLengthSq > 0 ) {
 		if( resultLengthSq > 0 ) {
 
 
-			return result.multiplyScalar( 1 / resultLengthSq );
+			return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );
 
 
 		}
 		}
 
 
-		// It is usually best to return a non-zero normal, even if it is made up, to avoid
-		// special case code to handle zero-length normals.
-		return result.set( 1, 0, 0 );
+		return result.set( 0, 0, 0 );
 
 
 	},
 	},
 
 
@@ -97,23 +131,15 @@ THREE.Triangle3.prototype = {
 
 
 	},
 	},
 
 
-	containsPoint: function ( point ) {
+	barycoordinate: function ( point, optionalTarget ) {
 
 
-		__v0.sub( c, a );
-		__v1.sub( b, a );
-		__v2.sub( point, a );
+		return THREE.Triangle3.barycoordinate( point, this.a, this.b, this.c, optionalTarget );
 
 
-		var dot00 = __v0.dot( __v0 );
-		var dot01 = __v0.dot( __v1 );
-		var dot02 = __v0.dot( __v2 );
-		var dot11 = __v1.dot( __v1 );
-		var dot12 = __v1.dot( __v2 );
+	},
 
 
-		var invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 );
-		var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
-		var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
+	containsPoint: function ( point ) {
 
 
-		return ( u >= 0 ) && ( v >= 0 ) && ( u + v < 1 );
+		return THREE.Triangle3.containsPoint( point, this.a, this.b, this.c );
 
 
 	},
 	},
 
 
@@ -134,3 +160,4 @@ THREE.Triangle3.prototype = {
 THREE.Triangle3.__v0 = new THREE.Vector3();
 THREE.Triangle3.__v0 = new THREE.Vector3();
 THREE.Triangle3.__v1 = new THREE.Vector3();
 THREE.Triangle3.__v1 = new THREE.Vector3();
 THREE.Triangle3.__v2 = new THREE.Vector3();
 THREE.Triangle3.__v2 = new THREE.Vector3();
+THREE.Triangle3.__v3 = new THREE.Vector3();

+ 9 - 9
test/core/Box2.js

@@ -194,18 +194,18 @@ test( "isIntersectionBox", function() {
 	var b = new THREE.Box2( zero2, one2 );
 	var b = new THREE.Box2( zero2, one2 );
 	var c = new THREE.Box2( one2.clone().negate(), one2 );
 	var c = new THREE.Box2( one2.clone().negate(), one2 );
 
 
-	ok( a.isIntersection( a ), "Passed!" );
-	ok( a.isIntersection( b ), "Passed!" );
-	ok( a.isIntersection( c ), "Passed!" );
+	ok( a.isIntersectionBox( a ), "Passed!" );
+	ok( a.isIntersectionBox( b ), "Passed!" );
+	ok( a.isIntersectionBox( c ), "Passed!" );
 
 
-	ok( b.isIntersection( a ), "Passed!" );
-	ok( c.isIntersection( a ), "Passed!" );
-	ok( b.isIntersection( c ), "Passed!" );
+	ok( b.isIntersectionBox( a ), "Passed!" );
+	ok( c.isIntersectionBox( a ), "Passed!" );
+	ok( b.isIntersectionBox( c ), "Passed!" );
 
 
 	b.translate( new THREE.Vector2( 2, 2 ) );
 	b.translate( new THREE.Vector2( 2, 2 ) );
-	ok( ! a.isIntersection( b ), "Passed!" );
-	ok( ! b.isIntersection( a ), "Passed!" );
-	ok( ! b.isIntersection( c ), "Passed!" );
+	ok( ! a.isIntersectionBox( b ), "Passed!" );
+	ok( ! b.isIntersectionBox( a ), "Passed!" );
+	ok( ! b.isIntersectionBox( c ), "Passed!" );
 });
 });
 
 
 test( "intersect", function() {
 test( "intersect", function() {

+ 9 - 9
test/core/Box3.js

@@ -194,18 +194,18 @@ test( "isIntersectionBox", function() {
 	var b = new THREE.Box3( zero3, one3 );
 	var b = new THREE.Box3( zero3, one3 );
 	var c = new THREE.Box3( one3.clone().negate(), one3 );
 	var c = new THREE.Box3( one3.clone().negate(), one3 );
 
 
-	ok( a.isIntersection( a ), "Passed!" );
-	ok( a.isIntersection( b ), "Passed!" );
-	ok( a.isIntersection( c ), "Passed!" );
+	ok( a.isIntersectionBox( a ), "Passed!" );
+	ok( a.isIntersectionBox( b ), "Passed!" );
+	ok( a.isIntersectionBox( c ), "Passed!" );
 
 
-	ok( b.isIntersection( a ), "Passed!" );
-	ok( c.isIntersection( a ), "Passed!" );
-	ok( b.isIntersection( c ), "Passed!" );
+	ok( b.isIntersectionBox( a ), "Passed!" );
+	ok( c.isIntersectionBox( a ), "Passed!" );
+	ok( b.isIntersectionBox( c ), "Passed!" );
 
 
 	b.translate( new THREE.Vector3( 2, 2, 2 ) );
 	b.translate( new THREE.Vector3( 2, 2, 2 ) );
-	ok( ! a.isIntersection( b ), "Passed!" );
-	ok( ! b.isIntersection( a ), "Passed!" );
-	ok( ! b.isIntersection( c ), "Passed!" );
+	ok( ! a.isIntersectionBox( b ), "Passed!" );
+	ok( ! b.isIntersectionBox( a ), "Passed!" );
+	ok( ! b.isIntersectionBox( c ), "Passed!" );
 });
 });
 
 
 test( "intersect", function() {
 test( "intersect", function() {

+ 26 - 25
test/core/Triangle3.js

@@ -47,15 +47,15 @@ test( "area", function() {
 
 
 	ok( a.area() == 0, "Passed!" );
 	ok( a.area() == 0, "Passed!" );
 
 
-	a = new THREE.Triangle3( new THREE.Vector3( 0, 0, 0, ), new THREE.Vector3( 1, 0, 0, ), new THREE.Vector3( 0, 1, 0, ) );
+	a = new THREE.Triangle3( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) );
 	ok( a.area() == 0.5, "Passed!" );
 	ok( a.area() == 0.5, "Passed!" );
 
 
-	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0, ), new THREE.Vector3( 0, 0, 0, ), new THREE.Vector3( 0, 0, 2, ) );
-	ok( a.empty() == 2, "Passed!" );
+	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) );
+	ok( a.area() == 2, "Passed!" );
 
 
 	// colinear triangle.
 	// colinear triangle.
-	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0, ), new THREE.Vector3( 0, 0, 0, ), new THREE.Vector3( 3, 0, 0, ) );
-	ok( a.empty() == 0, "Passed!" );
+	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 3, 0, 0 ) );
+	ok( a.area() == 0, "Passed!" );
 });
 });
 
 
 test( "midpoint", function() {
 test( "midpoint", function() {
@@ -63,23 +63,22 @@ test( "midpoint", function() {
 
 
 	ok( a.midpoint().equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" );
 	ok( a.midpoint().equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" );
 
 
-	a = new THREE.Triangle3( new THREE.Vector3( 0, 0, 0, ), new THREE.Vector3( 1, 0, 0, ), new THREE.Vector3( 0, 1, 0, ) );
+	a = new THREE.Triangle3( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) );
 	ok( a.midpoint().equals( new THREE.Vector3( 1/3, 1/3, 0 ) ), "Passed!" );
 	ok( a.midpoint().equals( new THREE.Vector3( 1/3, 1/3, 0 ) ), "Passed!" );
 
 
-	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0, ), new THREE.Vector3( 0, 0, 0, ), new THREE.Vector3( 0, 0, 2, ) );
+	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) );
 	ok( a.midpoint().equals( new THREE.Vector3( 2/3, 0, 2/3 ) ), "Passed!" );
 	ok( a.midpoint().equals( new THREE.Vector3( 2/3, 0, 2/3 ) ), "Passed!" );
 });
 });
 
 
 test( "normal", function() {
 test( "normal", function() {
 	var a = new THREE.Triangle3();
 	var a = new THREE.Triangle3();
 
 
-	// artificial normal is created in this case.
-	ok( a.normal().equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" );
+	ok( a.normal().equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" );
 
 
-	a = new THREE.Triangle3( new THREE.Vector3( 0, 0, 0, ), new THREE.Vector3( 1, 0, 0, ), new THREE.Vector3( 0, 1, 0, ) );
+	a = new THREE.Triangle3( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) );
 	ok( a.normal().equals( new THREE.Vector3( 0, 0, 1 ) ), "Passed!" );
 	ok( a.normal().equals( new THREE.Vector3( 0, 0, 1 ) ), "Passed!" );
 
 
-	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0, ), new THREE.Vector3( 0, 0, 0, ), new THREE.Vector3( 0, 0, 2, ) );
+	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) );
 	ok( a.normal().equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" );
 	ok( a.normal().equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" );
 });
 });
 
 
@@ -90,37 +89,39 @@ test( "plane", function() {
 	ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" );
-	ok( a.plane().equal( a.normal() ), "Passed!" );
+	ok( a.plane().normal.equals( a.normal() ), "Passed!" );
 
 
-	a = new THREE.Triangle3( new THREE.Vector3( 0, 0, 0, ), new THREE.Vector3( 1, 0, 0, ), new THREE.Vector3( 0, 1, 0, ) );
+	a = new THREE.Triangle3( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) );
 	ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" );
-	ok( a.plane().equal( a.normal() ), "Passed!" );
+	ok( a.plane().normal.equals( a.normal() ), "Passed!" );
 
 
-	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0, ), new THREE.Vector3( 0, 0, 0, ), new THREE.Vector3( 0, 0, 2, ) );
+	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) );
 	ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" );
 	ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" );
-	ok( a.plane().equal( a.normal() ), "Passed!" );
+	ok( a.plane().normal.clone().normalize().equals( a.normal() ), "Passed!" );
 });
 });
 
 
 test( "containsPoint", function() {
 test( "containsPoint", function() {
 	var a = new THREE.Triangle3();
 	var a = new THREE.Triangle3();
 
 
+	ok( ! a.containsPoint( a.a ), "Passed!" );
+	ok( ! a.containsPoint( a.b ), "Passed!" );
+	ok( ! a.containsPoint( a.c ), "Passed!" );
+
+	a = new THREE.Triangle3( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) );
 	ok( a.containsPoint( a.a ), "Passed!" );
 	ok( a.containsPoint( a.a ), "Passed!" );
 	ok( a.containsPoint( a.b ), "Passed!" );
 	ok( a.containsPoint( a.b ), "Passed!" );
 	ok( a.containsPoint( a.c ), "Passed!" );
 	ok( a.containsPoint( a.c ), "Passed!" );
-
-	a = new THREE.Triangle3( new THREE.Vector3( 0, 0, 0, ), new THREE.Vector3( 1, 0, 0, ), new THREE.Vector3( 0, 1, 0, ) );
-	ok( a.containsPoint( a.a ) == 0, "Passed!" );
-	ok( a.containsPoint( a.b ) == 0, "Passed!" );
-	ok( a.containsPoint( a.c ) == 0, "Passed!" );
 	ok( a.containsPoint( a.midpoint() ), "Passed!" );
 	ok( a.containsPoint( a.midpoint() ), "Passed!" );
+	ok( ! a.containsPoint( new THREE.Vector3( -1, -1, -1 ) ), "Passed!" );
 
 
-	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0, ), new THREE.Vector3( 0, 0, 0, ), new THREE.Vector3( 0, 0, 2, ) );
-	ok( a.containsPoint( a.a ) == 0, "Passed!" );
-	ok( a.containsPoint( a.b ) == 0, "Passed!" );
-	ok( a.containsPoint( a.c ) == 0, "Passed!" );
+	a = new THREE.Triangle3( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) );
+	ok( a.containsPoint( a.a ), "Passed!" );
+	ok( a.containsPoint( a.b ), "Passed!" );
+	ok( a.containsPoint( a.c ), "Passed!" );
 	ok( a.containsPoint( a.midpoint() ), "Passed!" );
 	ok( a.containsPoint( a.midpoint() ), "Passed!" );
+	ok( ! a.containsPoint( new THREE.Vector3( -1, -1, -1 ) ), "Passed!" );
 });
 });