Browse Source

Merge remote-tracking branch 'bhouston/triangle' into dev

Mr.doob 12 years ago
parent
commit
8ac873b581

+ 0 - 0
src/math/Clock.js → src/core/Clock.js


+ 5 - 24
src/core/Raycaster.js

@@ -1,5 +1,6 @@
 /**
  * @author mrdoob / http://mrdoob.com/
+ * @author bhouston / http://exocortex.com/
  */
 
 ( function ( THREE ) {
@@ -37,26 +38,6 @@
 
 	// 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 ) {
 
 		if ( object instanceof THREE.Particle ) {
@@ -118,7 +99,7 @@
 
 				if ( material === undefined ) continue;
 				
-				facePlane.setFromNormalAndCoplanarPoint( face.normal, face.centroid );
+				facePlane.setFromNormalAndCoplanarPoint( face.normal, vertices[face.a] );
 
 				var planeDistance = localRay.distanceToPlane( facePlane );
 	
@@ -149,7 +130,7 @@
 					b = vertices[ face.b ];
 					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 ) {
 
@@ -158,8 +139,8 @@
 					c = vertices[ face.c ];
 					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 {
 

+ 10 - 7
src/math/Box2.js

@@ -116,15 +116,17 @@ THREE.Box2.prototype = {
 
 	},
 
-	center: function () {
+	center: function ( optionalTarget ) {
 
-		return new THREE.Vector2().add( this.min, this.max ).multiplyScalar( 0.5 );
+		var result = optionalTarget || new THREE.Vector2();
+		return result.add( this.min, this.max ).multiplyScalar( 0.5 );
 
 	},
 
-	size: function () {
+	size: function ( optionalTarget ) {
 
-		return new THREE.Vector2().sub( this.max, this.min );
+		var result = optionalTarget || new THREE.Vector2();
+		return result.sub( this.max, this.min );
 
 	},
 
@@ -190,7 +192,7 @@ THREE.Box2.prototype = {
 
 	},
 
-	isIntersection: function ( box ) {
+	isIntersectionBox: function ( box ) {
 
 		// using 6 splitting planes to rule out intersections.
 
@@ -205,9 +207,10 @@ THREE.Box2.prototype = {
 
 	},
 
-	clampPoint: function ( point ) {
+	clampPoint: function ( point, optionalTarget ) {
 
-		return new THREE.Vector2().copy( point ).clampSelf( this.min, this.max );
+		var result = optionalTarget || new THREE.Vector2();
+		return result.copy( point ).clampSelf( this.min, this.max );
 
 	},
 

+ 9 - 6
src/math/Box3.js

@@ -133,15 +133,17 @@ THREE.Box3.prototype = {
 
 	},
 
-	center: function () {
+	center: function ( optionalTarget ) {
 
-		return new THREE.Vector3().add( this.min, this.max ).multiplyScalar( 0.5 );
+		var result = optionalTarget || new THREE.Vector3();
+		return result.add( this.min, this.max ).multiplyScalar( 0.5 );
 
 	},
 
-	size: function () {
+	size: function ( optionalTarget ) {
 
-		return new THREE.Vector3().sub( this.max, this.min );
+		var result = optionalTarget || new THREE.Vector3();
+		return result.sub( this.max, this.min );
 
 	},
 
@@ -213,7 +215,7 @@ THREE.Box3.prototype = {
 
 	},
 
-	isIntersection: function ( box ) {
+	isIntersectionBox: function ( box ) {
 
 		// using 6 splitting planes to rule out intersections.
 
@@ -229,8 +231,9 @@ THREE.Box3.prototype = {
 
 	},
 
-	clampPoint: function ( point ) {
+	clampPoint: function ( point, optionalTarget ) {
 
+		var result = optionalTarget || new THREE.Vector3();
 		return new THREE.Vector3().copy( point ).clampSelf( this.min, this.max );
 
 	},

+ 11 - 9
src/math/Plane.js

@@ -51,8 +51,8 @@ THREE.Plane.prototype = {
 
 	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)?
 
@@ -95,21 +95,22 @@ THREE.Plane.prototype = {
 
 	},
 
-	projectPoint: function ( point ) {
+	projectPoint: function ( point, optionalTarget ) {
 
-		return this.orthoPoint( point ).subSelf( point ).negate();
+		return this.orthoPoint( point, optionalTarget ).subSelf( point ).negate();
 
 	},
 
-	orthoPoint: function ( point ) {
+	orthoPoint: function ( point, optionalTarget ) {
 
 		var perpendicularMagnitude = this.distanceToPoint( point );
 
-		return new THREE.Vector3().copy( this.normal ).multiplyScalar( perpendicularMagnitude );
+		var result = optionalTarget || new THREE.Vector3();
+		return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude );
 
 	},
 
-	intersectsLine: function ( startPoint, endPoint ) {
+	isIntersectionLine: function ( startPoint, endPoint ) {
 
 		// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
 
@@ -120,9 +121,10 @@ THREE.Plane.prototype = {
 
 	},
 
-	coplanarPoint: function () {
+	coplanarPoint: function ( optionalTarget ) {
 
-		return new THREE.Vector3().copy( this.normal ).multiplyScalar( - this.constant );
+		var result = optionalTarget || new THREE.Vector3();
+		return result.copy( this.normal ).multiplyScalar( - this.constant );
 
 	},
 

+ 9 - 12
src/math/Ray.js

@@ -34,27 +34,24 @@ THREE.Ray.prototype = {
 
 	at: function( t, optionalTarget ) {
 
-		if( optionalTarget === undefined ) {
-			optionalTarget = this.direction.clone();
-		}
-		else {
-			optionalTarget.copy( this.direction );
-		}
-		return optionalTarget.multiplyScalar( t ).addSelf( this.origin );
+		var result = optionalTarget || new THREE.Vector3();
+
+		return result.copy( this.direction ).multiplyScalar( t ).addSelf( this.origin );
 
 	},
 
 	recastSelf: function ( t ) {
 
-		this.origin = this.at( t );
+		this.origin.copy( this.at( t, THREE.Ray.__v1 ) );
 
 		return this;
 
 	},
 
-	closestPointToPoint: function ( point ) {
+	closestPointToPoint: function ( point, optionalTarget ) {
 
-		var result = point.clone().subSelf( this.origin );
+		var result = optionalTarget || new THREE.Vector3();
+		result.sub( point, this.origin );
 		var directionDistance = result.dot( this.direction );
 
 		return result.copy( this.direction ).multiplyScalar( directionDistance ).addSelf( this.origin );
@@ -121,7 +118,7 @@ THREE.Ray.prototype = {
 
 	},
 
-	intersectPlane: function ( plane ) {
+	intersectPlane: function ( plane, optionalTarget ) {
 
 		var t = this.distanceToPlane( plane );
 
@@ -130,7 +127,7 @@ THREE.Ray.prototype = {
 			return undefined;
 		}
 
-		return this.at( t );
+		return this.at( t, optionalTarget );
 
 	},
 

+ 8 - 4
src/math/Sphere.js

@@ -1,5 +1,6 @@
 /**
  * @author bhouston / http://exocortex.com
+ * @author mrdoob / http://mrdoob.com/
  */
 
 THREE.Sphere = function ( center, radius ) {
@@ -66,11 +67,12 @@ THREE.Sphere.prototype = {
 
 	},
 
-	clampPoint: function ( point ) {
+	clampPoint: function ( point, optionalTarget ) {
 
 		var deltaLengthSq = this.center.distanceToSquared( point );
 
-		var result = new THREE.Vector3().copy( point );
+		var result = optionalTarget || new THREE.Vector3();
+		result.copy( point );
 
 		if ( deltaLengthSq > ( this.radius * this.radius ) ) {
 
@@ -83,9 +85,11 @@ THREE.Sphere.prototype = {
 
 	},
 
-	bounds: function () {
+	bounds: function ( optionalTarget ) {
 
-		var box =  new THREE.Box3( this.center, this.center );
+		var box = optionalTarget || new THREE.Box3();
+
+		box.set( this.center, this.center );
 		box.expandByScalar( this.radius );
 
 		return box;

+ 168 - 0
src/math/Triangle3.js

@@ -0,0 +1,168 @@
+/**
+ * @author bhouston / http://exocortex.com
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+THREE.Triangle3 = function ( a, b, c ) {
+
+	this.a = new THREE.Vector3();
+	this.b = new THREE.Vector3();
+	this.c = new THREE.Vector3();
+
+	if( a !== undefined && b !== undefined && c !== undefined ) {
+
+		this.a.copy( a );
+		this.b.copy( b );
+		this.c.copy( c );
+
+	}
+
+};
+
+// static/instance method to calculate barycoordinates
+THREE.Triangle3.barycoordFromPoint = 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 );
+
+	var result = optionalTarget || new THREE.Vector3();
+
+	// colinear or singular triangle
+	if( denom == 0 ) {
+		// arbitrary location outside of triangle?
+		// not sure if this is the best idea, maybe should be returning undefined
+		return result.set( -2, -1, -1 );
+	}
+
+	var invDenom = 1 / denom;
+	var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
+	var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
+
+	// barycoordinates must always sum to 1
+	return result.set( 1 - u - v, v, u );
+};
+
+THREE.Triangle3.containsPoint = function ( point, a, b, c ) {
+
+	// NOTE: need to use __v3 here because __v0, __v1 and __v2 are used in barycoordFromPoint.
+	var result = THREE.Triangle3.barycoordFromPoint( point, a, b, c, THREE.Triangle3.__v3 );
+
+	return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );
+};
+
+THREE.Triangle3.prototype = {
+
+	constructor: THREE.Triangle3,
+
+	set: function ( a, b, c ) {
+
+		this.a.copy( a );
+		this.b.copy( b );
+		this.c.copy( c );
+
+		return this;
+
+	},
+
+	setFromPointsAndIndices: function ( points, i0, i1, i2 ) {
+
+		this.a.copy( points[i0] );
+		this.b.copy( points[i1] );
+		this.c.copy( points[i2] );
+
+		return this;
+
+	},
+
+	copy: function ( triangle ) {
+
+		this.a.copy( triangle.a );
+		this.b.copy( triangle.b );
+		this.c.copy( triangle.c );
+
+		return this;
+
+	},
+
+	area: function () {
+
+		THREE.Triangle3.__v0.sub( this.c, this.b );
+		THREE.Triangle3.__v1.sub( this.a, this.b );
+
+		return THREE.Triangle3.__v0.crossSelf( THREE.Triangle3.__v1 ).length() * 0.5;
+
+	},
+
+	midpoint: function ( optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Vector3();
+		return result.add( this.a, this.b ).addSelf( this.c ).multiplyScalar( 1 / 3 );
+
+	},
+
+	normal: function ( optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Vector3();
+
+		result.sub( this.c, this.b );
+		THREE.Triangle3.__v0.sub( this.a, this.b );
+		result.crossSelf( THREE.Triangle3.__v0 );
+
+		var resultLengthSq = result.lengthSq();
+		if( resultLengthSq > 0 ) {
+
+			return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );
+
+		}
+
+		return result.set( 0, 0, 0 );
+
+	},
+
+	plane: function ( optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Plane();
+
+		return result.setFromCoplanarPoints( this.a, this.b, this.c );
+
+	},
+
+	barycoordFromPoint: function ( point, optionalTarget ) {
+
+		return THREE.Triangle3.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );
+
+	},
+
+	containsPoint: function ( point ) {
+
+		return THREE.Triangle3.containsPoint( point, this.a, this.b, this.c );
+
+	},
+
+	equals: function ( triangle ) {
+
+		return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
+
+	},
+
+	clone: function () {
+
+		return new THREE.Triangle3().copy( this );
+
+	}
+
+};
+
+THREE.Triangle3.__v0 = new THREE.Vector3();
+THREE.Triangle3.__v1 = new THREE.Vector3();
+THREE.Triangle3.__v2 = new THREE.Vector3();
+THREE.Triangle3.__v3 = new THREE.Vector3();

+ 11 - 11
test/core/Box2.js

@@ -34,7 +34,7 @@ test( "copy", function() {
 test( "set", function() {
 	var a = new THREE.Box2();
 
-	a.set( zero2, one2 )
+	a.set( zero2, one2 );
 	ok( a.min.equals( zero2 ), "Passed!" );
 	ok( a.max.equals( one2 ), "Passed!" );
 });
@@ -189,23 +189,23 @@ test( "distanceToPoint", function() {
 	ok( b.distanceToPoint( new THREE.Vector2( -2, -2 ) ) == Math.sqrt( 2 ), "Passed!" );
 });
 
-test( "isIntersection", function() {
+test( "isIntersectionBox", function() {
 	var a = new THREE.Box2( zero2 );
 	var b = new THREE.Box2( zero2, 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 ) );
-	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() {

+ 11 - 11
test/core/Box3.js

@@ -34,7 +34,7 @@ test( "copy", function() {
 test( "set", function() {
 	var a = new THREE.Box3();
 
-	a.set( zero3, one3 )
+	a.set( zero3, one3 );
 	ok( a.min.equals( zero3 ), "Passed!" );
 	ok( a.max.equals( one3 ), "Passed!" );
 });
@@ -189,23 +189,23 @@ test( "distanceToPoint", function() {
 	ok( b.distanceToPoint( new THREE.Vector3( -2, -2, -2 ) ) == Math.sqrt( 3 ), "Passed!" );
 });
 
-test( "isIntersection", function() {
+test( "isIntersectionBox", function() {
 	var a = new THREE.Box3( zero3 );
 	var b = new THREE.Box3( zero3, 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 ) );
-	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() {

+ 1 - 1
test/core/Ray.js

@@ -30,7 +30,7 @@ test( "copy/equals", function() {
 test( "set", function() {
 	var a = new THREE.Ray();
 
-	a.set( one3, one3 )
+	a.set( one3, one3 );
 	ok( a.origin.equals( one3 ), "Passed!" );
 	ok( a.direction.equals( one3 ), "Passed!" );
 });

+ 1 - 1
test/core/Sphere.js

@@ -33,7 +33,7 @@ test( "set", function() {
 	ok( a.center.equals( zero3 ), "Passed!" );
 	ok( a.radius == 0, "Passed!" );
 
-	a.set( one3, 1 )
+	a.set( one3, 1 );
 	ok( a.center.equals( one3 ), "Passed!" );
 	ok( a.radius == 1, "Passed!" );
 });

+ 160 - 0
test/core/Triangle3.js

@@ -0,0 +1,160 @@
+/**
+ * @author bhouston / http://exocortex.com
+ */
+
+module( "Triangle3" );
+
+test( "constructor", function() {
+	var a = new THREE.Triangle3();
+	ok( a.a.equals( zero3 ), "Passed!" );
+	ok( a.b.equals( zero3 ), "Passed!" );
+	ok( a.c.equals( zero3 ), "Passed!" );
+
+	a = new THREE.Triangle3( one3.clone().negate(), one3, two3 );
+	ok( a.a.equals( one3.clone().negate() ), "Passed!" );
+	ok( a.b.equals( one3 ), "Passed!" );
+	ok( a.c.equals( two3 ), "Passed!" );
+});
+
+test( "copy", function() {
+	var a = new THREE.Triangle3( one3.clone().negate(), one3, two3 );
+	var b = new THREE.Triangle3().copy( a );
+	ok( b.a.equals( one3.clone().negate() ), "Passed!" );
+	ok( b.b.equals( one3 ), "Passed!" );
+	ok( b.c.equals( two3 ), "Passed!" );
+
+	// ensure that it is a true copy
+	a.a = one3;
+	a.b = zero3;
+	a.c = zero3;
+	ok( b.a.equals( one3.clone().negate() ), "Passed!" );
+	ok( b.b.equals( one3 ), "Passed!" );
+	ok( b.c.equals( two3 ), "Passed!" );
+});
+
+test( "setFromPointsAndIndices", function() {
+	var a = new THREE.Triangle3();
+
+	var points = [ one3, one3.clone().negate(), two3 ];
+	a.setFromPointsAndIndices( points, 1, 0, 2 );
+	ok( a.a.equals( one3.clone().negate() ), "Passed!" );
+	ok( a.b.equals( one3 ), "Passed!" );
+	ok( a.c.equals( two3 ), "Passed!" );
+
+});
+
+test( "set", function() {
+	var a = new THREE.Triangle3();
+
+	a.set( one3.clone().negate(), one3, two3 );
+	ok( a.a.equals( one3.clone().negate() ), "Passed!" );
+	ok( a.b.equals( one3 ), "Passed!" );
+	ok( a.c.equals( two3 ), "Passed!" );
+
+});
+
+test( "area", function() {
+	var a = new THREE.Triangle3();
+
+	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 ) );
+	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.area() == 2, "Passed!" );
+
+	// 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.area() == 0, "Passed!" );
+});
+
+test( "midpoint", function() {
+	var a = new THREE.Triangle3();
+
+	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 ) );
+	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 ) );
+	ok( a.midpoint().equals( new THREE.Vector3( 2/3, 0, 2/3 ) ), "Passed!" );
+});
+
+test( "normal", function() {
+	var a = new THREE.Triangle3();
+
+	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 ) );
+	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 ) );
+	ok( a.normal().equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" );
+});
+
+test( "plane", function() {
+	var a = new THREE.Triangle3();
+
+	// artificial normal is created in this case.
+	ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" );
+	ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" );
+	ok( a.plane().distanceToPoint( a.c ) == 0, "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 ) );
+	ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" );
+	ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" );
+	ok( a.plane().distanceToPoint( a.c ) == 0, "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 ) );
+	ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" );
+	ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" );
+	ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" );
+	ok( a.plane().normal.clone().normalize().equals( a.normal() ), "Passed!" );
+});
+
+test( "barycoordFromPoint", function() {
+	var a = new THREE.Triangle3();
+
+	var bad = new THREE.Vector3( -2, -1, -1 );
+
+	ok( a.barycoordFromPoint( a.a ).equals( bad ), "Passed!" );
+	ok( a.barycoordFromPoint( a.b ).equals( bad ), "Passed!" );
+	ok( a.barycoordFromPoint( a.c ).equals( bad ), "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.barycoordFromPoint( a.a ).equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" );
+	ok( a.barycoordFromPoint( a.b ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" );
+	ok( a.barycoordFromPoint( a.c ).equals( new THREE.Vector3( 0, 0, 1 ) ), "Passed!" );
+	ok( a.barycoordFromPoint( a.midpoint() ).distanceTo( new THREE.Vector3( 1/3, 1/3, 1/3 ) ) < 0.0001, "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.barycoordFromPoint( a.a ).equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" );
+	ok( a.barycoordFromPoint( a.b ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" );
+	ok( a.barycoordFromPoint( a.c ).equals( new THREE.Vector3( 0, 0, 1 ) ), "Passed!" );
+	ok( a.barycoordFromPoint( a.midpoint() ).distanceTo( new THREE.Vector3( 1/3, 1/3, 1/3 ) ) < 0.0001, "Passed!" );
+});
+
+test( "containsPoint", function() {
+	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.b ), "Passed!" );
+	ok( a.containsPoint( a.c ), "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 ), "Passed!" );
+	ok( a.containsPoint( a.b ), "Passed!" );
+	ok( a.containsPoint( a.c ), "Passed!" );
+	ok( a.containsPoint( a.midpoint() ), "Passed!" );
+	ok( ! a.containsPoint( new THREE.Vector3( -1, -1, -1 ) ), "Passed!" );
+});

+ 1 - 1
test/core/Vector2.js

@@ -32,7 +32,7 @@ test( "set", function() {
 	ok( a.x == 0, "Passed!" );
 	ok( a.y == 0, "Passed!" );
 
-	a.set( x, y )
+	a.set( x, y );
 	ok( a.x == x, "Passed!" );
 	ok( a.y == y, "Passed!" );
 });

+ 1 - 1
test/core/Vector3.js

@@ -38,7 +38,7 @@ test( "set", function() {
 	ok( a.y == 0, "Passed!" );
 	ok( a.z == 0, "Passed!" );
 
-	a.set( x, y, z )
+	a.set( x, y, z );
 	ok( a.x == x, "Passed!" );
 	ok( a.y == y, "Passed!" );
 	ok( a.z == z, "Passed!" );

+ 1 - 1
test/core/Vector4.js

@@ -44,7 +44,7 @@ test( "set", function() {
 	ok( a.z == 0, "Passed!" );
 	ok( a.w == 1, "Passed!" );
 
-	a.set( x, y, z, w )
+	a.set( x, y, z, w );
 	ok( a.x == x, "Passed!" );
 	ok( a.y == y, "Passed!" );
 	ok( a.z == z, "Passed!" );

+ 41 - 0
test/sources.html

@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>ThreeJS Test Suite - Using Files in /src</title>
+  <link rel="stylesheet" href="qunit/qunit-1.10.0.css">
+</head>
+<body>
+  <div id="qunit"></div>
+  <script src="qunit/qunit-1.10.0.js"></script>
+
+  <!-- add ThreeJS sources to test below -->
+
+  <script src="../src/Three.js"></script>
+  <script src="../src/math/Vector2.js"></script>
+  <script src="../src/math/Vector3.js"></script>
+  <script src="../src/math/Vector4.js"></script>
+  <script src="../src/math/Box2.js"></script>
+  <script src="../src/math/Box3.js"></script>
+  <script src="../src/math/Plane.js"></script>
+  <script src="../src/math/Ray.js"></script>
+  <script src="../src/math/Sphere.js"></script>
+  <script src="../src/math/Triangle3.js"></script>
+  <script src="../src/math/Matrix3.js"></script>
+  <script src="../src/math/Matrix4.js"></script>
+
+  <!-- add class-based unit tests below -->
+
+  <script src="core/Constants.js"></script>
+  <script src="core/Box2.js"></script>
+  <script src="core/Box3.js"></script>
+  <script src="core/Plane.js"></script>
+  <script src="core/Ray.js"></script>
+  <script src="core/Sphere.js"></script>
+  <script src="core/Triangle3.js"></script>
+  <script src="core/Vector2.js"></script>
+  <script src="core/Vector3.js"></script>
+  <script src="core/Vector4.js"></script>
+  
+</body>
+</html>

+ 30 - 0
test/three-math.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>ThreeJS Test Suite - Using build/Three-math.js</title>
+  <link rel="stylesheet" href="qunit/qunit-1.10.0.css">
+</head>
+<body>
+  <div id="qunit"></div>
+  <script src="qunit/qunit-1.10.0.js"></script>
+
+  <!-- add ThreeJS sources to test below -->
+
+  <script src="../build/Three-math.js"></script>
+
+  <!-- add class-based unit tests below -->
+
+  <script src="core/Constants.js"></script>
+  <script src="core/Box2.js"></script>
+  <script src="core/Box3.js"></script>
+  <script src="core/Plane.js"></script>
+  <script src="core/Ray.js"></script>
+  <script src="core/Sphere.js"></script>
+  <script src="core/Triangle3.js"></script>
+  <script src="core/Vector2.js"></script>
+  <script src="core/Vector3.js"></script>
+  <script src="core/Vector4.js"></script>
+  
+</body>
+</html>

+ 8 - 4
test/index.html → test/three.html

@@ -2,25 +2,29 @@
 <html>
 <head>
   <meta charset="utf-8">
-  <title>ThreeJS Test Suite</title>
+  <title>ThreeJS Test Suite - Using build/Three.js</title>
   <link rel="stylesheet" href="qunit/qunit-1.10.0.css">
 </head>
 <body>
   <div id="qunit"></div>
-  <script src="../build/three.js"></script>
   <script src="qunit/qunit-1.10.0.js"></script>
-  <script src="core/Constants.js"></script>
+
+  <!-- add ThreeJS sources to test below -->
+
+  <script src="../build/Three.js"></script>
 
   <!-- add class-based unit tests below -->
 
+  <script src="core/Constants.js"></script>
   <script src="core/Box2.js"></script>
   <script src="core/Box3.js"></script>
   <script src="core/Plane.js"></script>
+  <script src="core/Ray.js"></script>
   <script src="core/Sphere.js"></script>
+  <script src="core/Triangle3.js"></script>
   <script src="core/Vector2.js"></script>
   <script src="core/Vector3.js"></script>
   <script src="core/Vector4.js"></script>
-  <script src="core/Ray.js"></script>
   
 </body>
 </html>

+ 30 - 0
test/three.min.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>ThreeJS Test Suite - Using build/Three.min.js</title>
+  <link rel="stylesheet" href="qunit/qunit-1.10.0.css">
+</head>
+<body>
+  <div id="qunit"></div>
+  <script src="qunit/qunit-1.10.0.js"></script>
+
+  <!-- add ThreeJS sources to test below -->
+
+  <script src="../build/Three.min.js"></script>
+
+  <!-- add class-based unit tests below -->
+
+  <script src="core/Constants.js"></script>
+  <script src="core/Box2.js"></script>
+  <script src="core/Box3.js"></script>
+  <script src="core/Plane.js"></script>
+  <script src="core/Ray.js"></script>
+  <script src="core/Sphere.js"></script>
+  <script src="core/Triangle3.js"></script>
+  <script src="core/Vector2.js"></script>
+  <script src="core/Vector3.js"></script>
+  <script src="core/Vector4.js"></script>
+  
+</body>
+</html>

+ 1 - 0
utils/build_all.bat

@@ -4,3 +4,4 @@ python build.py --include canvas --minify --output ../build/three-canvas.min.js
 python build.py --include css3d --minify --output ../build/three-css3d.min.js
 python build.py --include webgl --minify --output ../build/three-webgl.min.js
 python build.py --include extras --externs externs/extras.js --minify --output ../build/three-extras.min.js
+python build.py --include math --output ../build/three-math.js

+ 1 - 0
utils/build_all.sh

@@ -6,3 +6,4 @@ python build.py --include canvas --minify --output ../build/three-canvas.min.js
 python build.py --include css3d --minify --output ../build/three-css3d.min.js
 python build.py --include webgl --minify --output ../build/three-webgl.min.js
 python build.py --include extras --externs externs/extras.js --minify --output ../build/three-extras.min.js
+python build.py --include math --output ../build/three-math.js

+ 1 - 0
utils/includes/canvas.json

@@ -13,6 +13,7 @@
 	"../src/math/Frustum.js",
 	"../src/math/Rectangle.js",
 	"../src/math/Math.js",
+	"../src/math/Triangle3.js",
 	"../src/math/Quaternion.js",
 	"../src/math/Vertex.js",
 	"../src/math/UV.js",

+ 2 - 1
utils/includes/common.json

@@ -1,6 +1,5 @@
 [
 	"../src/Three.js",
-	"../src/math/Clock.js",
 	"../src/math/Color.js",
 	"../src/math/Vector2.js",
 	"../src/math/Vector3.js",
@@ -17,8 +16,10 @@
 	"../src/math/Math.js",
 	"../src/math/Quaternion.js",
 	"../src/math/Spline.js",
+	"../src/math/Triangle3.js",
 	"../src/math/Vertex.js",
 	"../src/math/UV.js",
+	"../src/core/Clock.js",
 	"../src/core/EventTarget.js",
 	"../src/core/Raycaster.js",
 	"../src/core/Object3D.js",

+ 1 - 0
utils/includes/css3d.json

@@ -10,6 +10,7 @@
 	"../src/math/Box2.js",
 	"../src/math/Box3.js",
 	"../src/math/Sphere.js",
+	"../src/math/Triangle3.js",
 	"../src/math/Plane.js",
 	"../src/core/EventTarget.js",
 	"../src/core/Raycaster.js",

+ 20 - 0
utils/includes/math.json

@@ -0,0 +1,20 @@
+[
+	"../src/Three.js",
+	"../src/math/Color.js",
+	"../src/math/Vector2.js",
+	"../src/math/Vector3.js",
+	"../src/math/Vector4.js",
+	"../src/math/Box2.js",
+	"../src/math/Box3.js",
+	"../src/math/Matrix3.js",
+	"../src/math/Matrix4.js",
+	"../src/math/Ray.js",
+	"../src/math/Frustum.js",
+	"../src/math/Plane.js",
+	"../src/math/Rectangle.js",
+	"../src/math/Sphere.js",
+	"../src/math/Math.js",
+	"../src/math/Quaternion.js",
+	"../src/math/Spline.js",
+	"../src/math/Triangle3.js"
+]

+ 2 - 1
utils/includes/webgl.json

@@ -1,6 +1,5 @@
 [
 	"../src/Three.js",
-	"../src/math/Clock.js",
 	"../src/math/Color.js",
 	"../src/math/Vector2.js",
 	"../src/math/Vector3.js",
@@ -16,8 +15,10 @@
 	"../src/math/Spline.js",
 	"../src/math/Box2.js",
 	"../src/math/Box3.js",
+	"../src/math/Triangle3.js",
 	"../src/math/Sphere.js",
 	"../src/math/Plane.js",
+	"../src/core/Clock.js",
 	"../src/core/EventTarget.js",
 	"../src/core/Raycaster.js",
 	"../src/core/Object3D.js",