Browse Source

add Triangle3, add optionalTargets to Box2,Box3,Plane,Sphere,Ray where possible to reduce GC load, add Triangle3 unit tests.

Ben Houston 12 years ago
parent
commit
c5d38e8993

+ 10 - 7
src/math/Box2.js

@@ -115,15 +115,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 );
 
 	},
 
@@ -189,7 +191,7 @@ THREE.Box2.prototype = {
 
 	},
 
-	isIntersection: function ( box ) {
+	isIntersectionBox: function ( box ) {
 
 		// using 6 splitting planes to rule out intersections.
 
@@ -204,9 +206,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 );
 
 	},
 

+ 8 - 5
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 () {
 
-		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 );
 
 	},

+ 9 - 7
src/math/Plane.js

@@ -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 );
 
 	},
 

+ 5 - 4
src/math/Ray.js

@@ -52,9 +52,10 @@ THREE.Ray.prototype = {
 
 	},
 
-	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 +122,7 @@ THREE.Ray.prototype = {
 
 	},
 
-	intersectPlane: function ( plane ) {
+	intersectPlane: function ( plane, optionalTarget ) {
 
 		var t = this.distanceToPlane( plane );
 
@@ -130,7 +131,7 @@ THREE.Ray.prototype = {
 			return undefined;
 		}
 
-		return this.at( t );
+		return this.at( t, optionalTarget );
 
 	},
 

+ 7 - 4
src/math/Sphere.js

@@ -77,11 +77,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 ) ) {
 
@@ -94,9 +95,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;

+ 136 - 0
src/math/Triangle3.js

@@ -0,0 +1,136 @@
+/**
+ * @author bhouston / http://exocortex.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 );
+
+	}
+
+};
+
+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;
+
+	},
+
+	setPointsAndIndices: 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 () {
+
+		__v0.sub( this.c, this.b );
+		__v1.sub( this.a, this.b );
+
+		return __v0.cross( __v1 ).length() * 0.5;
+
+	},
+
+	midpoint: function ( optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Vector3();
+		return result.add( this.a, this.b ).addSelf( this.b ).multiplyScalar( 1 / 3 );
+
+	},
+
+	normal: function ( optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Vector3();
+
+		result.sub( this.c, this.b );
+		__v0.sub( this.a, this.b );
+		result.cross( __v0 );
+
+		var resultLengthSq = result.lengthSq();
+		if( resultLengthSq > 0 ) {
+
+			return result.multiplyScalar( 1 / 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 );
+
+	},
+
+	plane: function ( optionalTarget ) {
+
+		var result = optionalTarget || new THREE.Plane();
+
+		return result.setFromCoplanarPoints( this.a, this.b, this.c );
+
+	},
+
+	containsPoint: function ( point ) {
+
+		__v0.sub( c, a );
+		__v1.sub( b, a );
+		__v2.sub( point, 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 );
+
+	},
+
+	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();

+ 2 - 2
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,7 +189,7 @@ 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 );

+ 2 - 2
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,7 +189,7 @@ 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 );

+ 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!" );
 });

+ 126 - 0
test/core/Triangle3.js

@@ -0,0 +1,126 @@
+/**
+ * @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( "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.empty() == 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.empty() == 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();
+
+	// artificial normal is created in this case.
+	ok( a.normal().equals( new THREE.Vector3( 1, 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().equal( 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().equal( 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().equal( a.normal() ), "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 ) == 0, "Passed!" );
+	ok( a.containsPoint( a.b ) == 0, "Passed!" );
+	ok( a.containsPoint( a.c ) == 0, "Passed!" );
+	ok( a.containsPoint( a.midpoint() ), "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!" );
+	ok( a.containsPoint( a.midpoint() ), "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!" );

+ 2 - 1
test/index.html

@@ -16,11 +16,12 @@
   <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>

+ 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",

+ 1 - 0
utils/includes/common.json

@@ -17,6 +17,7 @@
 	"../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/EventTarget.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",

+ 1 - 0
utils/includes/webgl.json

@@ -16,6 +16,7 @@
 	"../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/EventTarget.js",