提交 835d6b13 编写于 作者: B Ben Houston

initial quaternion unit tests, add Quaterion.toEuler (untested for now.)

上级 a32ee687
......@@ -174,6 +174,28 @@ THREE.Quaternion.prototype = {
},
add: function ( a, b ) {
this.x = a.x + b.x;
this.y = a.y + b.y;
this.z = a.z + b.z;
this.w = a.w + b.w;
return this;
},
addSelf: function ( v ) {
this.x += v.x;
this.y += v.y;
this.z += v.z;
this.w += v.w;
return this;
},
inverse: function () {
this.conjugate().normalize();
......@@ -277,6 +299,55 @@ THREE.Quaternion.prototype = {
},
toEuler: function ( order, optionalTarget ) {
var result = optionalTarget || new THREE.Vector3();
var qx = this.x,
qy = this.y,
qz = this.z,
qw = this.w;
var sqx = qx*qx,
sqy = qy*qy,
sqz = qz*qz,
sqw = qw*qw;
if ( order === undefined || order === 'XYZ' ) {
var test = qw*qy - qx*qz;
if (test > 0.4999) {
result.x = 0;
result.y = 90;
result.z = -2 * Math.atan2(qx, qw);
} else if (test < -0.4999) {
result.x = 0;
result.y = -90;
result.z = 2 * Math.atan2(qx, qw);
} else {
result.x = Math.atan2(2 * (qw*qx + qy*qz), sqw - sqx - sqy + sqz);
result.y = Math.asin(2 * (qw*qy - qx*qz));
result.z = Math.atan2(2 * (qx*qy + qw*qz), sqw + sqx - sqy - sqz);
}
}
else {
// TODO: support more Euler orders.
throw new Error( "Euler order not supported: " + order );
}
return result;
},
slerpSelf: function ( qb, t ) {
var x = this.x, y = this.y, z = this.z, w = this.w;
......@@ -337,6 +408,12 @@ THREE.Quaternion.prototype = {
},
equals: function ( v ) {
return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
},
clone: function () {
return new THREE.Quaternion( this.x, this.y, this.z, this.w );
......@@ -347,58 +424,6 @@ THREE.Quaternion.prototype = {
THREE.Quaternion.slerp = function ( qa, qb, qm, t ) {
// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
var cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;
if ( cosHalfTheta < 0 ) {
qm.w = -qb.w;
qm.x = -qb.x;
qm.y = -qb.y;
qm.z = -qb.z;
cosHalfTheta = -cosHalfTheta;
} else {
qm.copy( qb );
}
if ( Math.abs( cosHalfTheta ) >= 1.0 ) {
qm.w = qa.w;
qm.x = qa.x;
qm.y = qa.y;
qm.z = qa.z;
return qm;
}
var halfTheta = Math.acos( cosHalfTheta );
var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
if ( Math.abs( sinHalfTheta ) < 0.001 ) {
qm.w = 0.5 * ( qa.w + qm.w );
qm.x = 0.5 * ( qa.x + qm.x );
qm.y = 0.5 * ( qa.y + qm.y );
qm.z = 0.5 * ( qa.z + qm.z );
return qm;
}
var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta;
var ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
qm.w = ( qa.w * ratioA + qm.w * ratioB );
qm.x = ( qa.x * ratioA + qm.x * ratioB );
qm.y = ( qa.y * ratioA + qm.y * ratioB );
qm.z = ( qa.z * ratioA + qm.z * ratioB );
return qm;
return qm.copy( qa ).slerpSelf( qb, t );
}
/**
* @author bhouston / http://exocortex.com
*/
module( "Quaternion" );
test( "constructor", function() {
var a = new THREE.Quaternion();
ok( a.x == 0, "Passed!" );
ok( a.y == 0, "Passed!" );
ok( a.z == 0, "Passed!" );
ok( a.w == 1, "Passed!" );
a = new THREE.Quaternion( x, y, z, w );
ok( a.x === x, "Passed!" );
ok( a.y === y, "Passed!" );
ok( a.z === z, "Passed!" );
ok( a.w === w, "Passed!" );
});
test( "copy", function() {
var a = new THREE.Quaternion( x, y, z, w );
var b = new THREE.Quaternion().copy( a );
ok( b.x == x, "Passed!" );
ok( b.y == y, "Passed!" );
ok( b.z == z, "Passed!" );
ok( b.w == w, "Passed!" );
// ensure that it is a true copy
a.x = 0;
a.y = -1;
a.z = 0;
a.w = -1;
ok( b.x == x, "Passed!" );
ok( b.y == y, "Passed!" );
});
test( "set", function() {
var a = new THREE.Quaternion();
ok( a.x == 0, "Passed!" );
ok( a.y == 0, "Passed!" );
ok( a.z == 0, "Passed!" );
ok( a.w == 1, "Passed!" );
a.set( x, y, z, w );
ok( a.x == x, "Passed!" );
ok( a.y == y, "Passed!" );
ok( a.z === z, "Passed!" );
ok( a.w === w, "Passed!" );
});
test( "setFromAxisAngle", function() {
// TODO: find cases to validate.
ok( true, "Passed!" );
var zero = new THREE.Quaternion();
var a = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), 0 );
ok( a.equals( zero ), "Passed!" );
a = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), 0 );
ok( a.equals( zero ), "Passed!" );
a = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 0, 0, 1 ), 0 );
ok( a.equals( zero ), "Passed!" );
var b1 = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), Math.PI );
ok( ! a.equals( b1 ), "Passed!" );
var b2 = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), -Math.PI );
ok( ! a.equals( b2 ), "Passed!" );
b1.multiplySelf( b2 );
ok( a.equals( b1 ), "Passed!" );
});
test( "setFromRotationMatrix", function() {
// TODO: find cases to validate.
ok( true, "Passed!" );
});
test( "fromEuler/toEuler", function() {
// TODO: find cases to validate.
ok( true, "Passed!" );
});
test( "add", function() {
var a = new THREE.Quaternion( x, y, z, w );
var b = new THREE.Quaternion( -x, -y, -z, -w );
a.addSelf( b );
ok( a.x == 0, "Passed!" );
ok( a.y == 0, "Passed!" );
ok( a.z == 0, "Passed!" );
ok( a.w == 0, "Passed!" );
var c = new THREE.Quaternion().add( b, b );
ok( c.x == -2*x, "Passed!" );
ok( c.y == -2*y, "Passed!" );
ok( c.z == -2*z, "Passed!" );
ok( c.w == -2*w, "Passed!" );
});
test( "normalize/length", function() {
var a = new THREE.Quaternion( x, y, z, w );
var b = new THREE.Quaternion( -x, -y, -z, -w );
ok( a.length() != 1, "Passed!");
a.normalize();
ok( a.length() == 1, "Passed!");
a.set( 0, 0, 0, 0 );
ok( a.length() == 0, "Passed!");
a.normalize();
ok( a.length() == 1, "Passed!");
});
test( "inverse/conjugate", function() {
var a = new THREE.Quaternion( x, y, z, w );
// TODO: add better validation here.
var b = a.clone().conjugate();
ok( a.x == -b.x, "Passed!" );
ok( a.y == -b.y, "Passed!" );
ok( a.z == -b.z, "Passed!" );
ok( a.w == b.w, "Passed!" );
});
test( "multiply/multiplySelf", function() {
// TODO: find cases to validate.
ok( true, "Passed!" );
});
test( "multiplyVector3", function() {
// TODO: find cases to validate.
ok( true, "Passed!" );
});
test( "slerpSelf/slerp", function() {
// TODO: find cases to validate.
ok( true, "Passed!" );
});
test( "equals", function() {
var a = new THREE.Quaternion( x, y, z, w );
var b = new THREE.Quaternion( -x, -y, -z, -w );
ok( a.x != b.x, "Passed!" );
ok( a.y != b.y, "Passed!" );
ok( ! a.equals( b ), "Passed!" );
ok( ! b.equals( a ), "Passed!" );
a.copy( b );
ok( a.x == b.x, "Passed!" );
ok( a.y == b.y, "Passed!" );
ok( a.equals( b ), "Passed!" );
ok( b.equals( a ), "Passed!" );
});
......@@ -23,7 +23,8 @@
<script src="../src/math/Triangle.js"></script>
<script src="../src/math/Matrix3.js"></script>
<script src="../src/math/Matrix4.js"></script>
<script src="../src/math/Quaternion.js"></script>
<!-- add class-based unit tests below -->
<script src="math/Constants.js"></script>
......@@ -36,6 +37,7 @@
<script src="math/Vector2.js"></script>
<script src="math/Vector3.js"></script>
<script src="math/Vector4.js"></script>
<script src="math/Quaternion.js"></script>
</body>
</html>
\ No newline at end of file
......@@ -25,6 +25,7 @@
<script src="math/Vector2.js"></script>
<script src="math/Vector3.js"></script>
<script src="math/Vector4.js"></script>
<script src="math/Quaternion.js"></script>
</body>
</html>
......@@ -25,6 +25,7 @@
<script src="math/Vector2.js"></script>
<script src="math/Vector3.js"></script>
<script src="math/Vector4.js"></script>
<script src="math/Quaternion.js"></script>
</body>
</html>
......@@ -25,6 +25,7 @@
<script src="math/Vector2.js"></script>
<script src="math/Vector3.js"></script>
<script src="math/Vector4.js"></script>
<script src="math/Quaternion.js"></script>
</body>
</html>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册