initial commit
This commit is contained in:
244
lib/math/Box2.js
Normal file
244
lib/math/Box2.js
Normal file
@ -0,0 +1,244 @@
|
||||
import { Vector2 } from './Vector2.js';
|
||||
|
||||
/**
|
||||
* @author bhouston / http://clara.io
|
||||
*/
|
||||
|
||||
function Box2( min, max ) {
|
||||
|
||||
this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity );
|
||||
this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity );
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Box2.prototype, {
|
||||
|
||||
set: function ( min, max ) {
|
||||
|
||||
this.min.copy( min );
|
||||
this.max.copy( max );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromPoints: function ( points ) {
|
||||
|
||||
this.makeEmpty();
|
||||
|
||||
for ( var i = 0, il = points.length; i < il; i ++ ) {
|
||||
|
||||
this.expandByPoint( points[ i ] );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromCenterAndSize: function () {
|
||||
|
||||
var v1 = new Vector2();
|
||||
|
||||
return function setFromCenterAndSize( center, size ) {
|
||||
|
||||
var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
|
||||
this.min.copy( center ).sub( halfSize );
|
||||
this.max.copy( center ).add( halfSize );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( box ) {
|
||||
|
||||
this.min.copy( box.min );
|
||||
this.max.copy( box.max );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
makeEmpty: function () {
|
||||
|
||||
this.min.x = this.min.y = + Infinity;
|
||||
this.max.x = this.max.y = - Infinity;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
isEmpty: function () {
|
||||
|
||||
// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
|
||||
|
||||
return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
|
||||
|
||||
},
|
||||
|
||||
getCenter: function ( target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Box2: .getCenter() target is now required' );
|
||||
target = new Vector2();
|
||||
|
||||
}
|
||||
|
||||
return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
|
||||
|
||||
},
|
||||
|
||||
getSize: function ( target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Box2: .getSize() target is now required' );
|
||||
target = new Vector2();
|
||||
|
||||
}
|
||||
|
||||
return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min );
|
||||
|
||||
},
|
||||
|
||||
expandByPoint: function ( point ) {
|
||||
|
||||
this.min.min( point );
|
||||
this.max.max( point );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
expandByVector: function ( vector ) {
|
||||
|
||||
this.min.sub( vector );
|
||||
this.max.add( vector );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
expandByScalar: function ( scalar ) {
|
||||
|
||||
this.min.addScalar( - scalar );
|
||||
this.max.addScalar( scalar );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
containsPoint: function ( point ) {
|
||||
|
||||
return point.x < this.min.x || point.x > this.max.x ||
|
||||
point.y < this.min.y || point.y > this.max.y ? false : true;
|
||||
|
||||
},
|
||||
|
||||
containsBox: function ( box ) {
|
||||
|
||||
return this.min.x <= box.min.x && box.max.x <= this.max.x &&
|
||||
this.min.y <= box.min.y && box.max.y <= this.max.y;
|
||||
|
||||
},
|
||||
|
||||
getParameter: function ( point, target ) {
|
||||
|
||||
// This can potentially have a divide by zero if the box
|
||||
// has a size dimension of 0.
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Box2: .getParameter() target is now required' );
|
||||
target = new Vector2();
|
||||
|
||||
}
|
||||
|
||||
return target.set(
|
||||
( point.x - this.min.x ) / ( this.max.x - this.min.x ),
|
||||
( point.y - this.min.y ) / ( this.max.y - this.min.y )
|
||||
);
|
||||
|
||||
},
|
||||
|
||||
intersectsBox: function ( box ) {
|
||||
|
||||
// using 4 splitting planes to rule out intersections
|
||||
|
||||
return box.max.x < this.min.x || box.min.x > this.max.x ||
|
||||
box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
|
||||
|
||||
},
|
||||
|
||||
clampPoint: function ( point, target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Box2: .clampPoint() target is now required' );
|
||||
target = new Vector2();
|
||||
|
||||
}
|
||||
|
||||
return target.copy( point ).clamp( this.min, this.max );
|
||||
|
||||
},
|
||||
|
||||
distanceToPoint: function () {
|
||||
|
||||
var v1 = new Vector2();
|
||||
|
||||
return function distanceToPoint( point ) {
|
||||
|
||||
var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
|
||||
return clampedPoint.sub( point ).length();
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
intersect: function ( box ) {
|
||||
|
||||
this.min.max( box.min );
|
||||
this.max.min( box.max );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
union: function ( box ) {
|
||||
|
||||
this.min.min( box.min );
|
||||
this.max.max( box.max );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
translate: function ( offset ) {
|
||||
|
||||
this.min.add( offset );
|
||||
this.max.add( offset );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
equals: function ( box ) {
|
||||
|
||||
return box.min.equals( this.min ) && box.max.equals( this.max );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Box2 };
|
616
lib/math/Box3.js
Normal file
616
lib/math/Box3.js
Normal file
@ -0,0 +1,616 @@
|
||||
import { Vector3 } from './Vector3.js';
|
||||
import { Sphere } from './Sphere.js';
|
||||
|
||||
/**
|
||||
* @author bhouston / http://clara.io
|
||||
* @author WestLangley / http://github.com/WestLangley
|
||||
*/
|
||||
|
||||
function Box3( min, max ) {
|
||||
|
||||
this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
|
||||
this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Box3.prototype, {
|
||||
|
||||
isBox3: true,
|
||||
|
||||
set: function ( min, max ) {
|
||||
|
||||
this.min.copy( min );
|
||||
this.max.copy( max );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromArray: function ( array ) {
|
||||
|
||||
var minX = + Infinity;
|
||||
var minY = + Infinity;
|
||||
var minZ = + Infinity;
|
||||
|
||||
var maxX = - Infinity;
|
||||
var maxY = - Infinity;
|
||||
var maxZ = - Infinity;
|
||||
|
||||
for ( var i = 0, l = array.length; i < l; i += 3 ) {
|
||||
|
||||
var x = array[ i ];
|
||||
var y = array[ i + 1 ];
|
||||
var z = array[ i + 2 ];
|
||||
|
||||
if ( x < minX ) minX = x;
|
||||
if ( y < minY ) minY = y;
|
||||
if ( z < minZ ) minZ = z;
|
||||
|
||||
if ( x > maxX ) maxX = x;
|
||||
if ( y > maxY ) maxY = y;
|
||||
if ( z > maxZ ) maxZ = z;
|
||||
|
||||
}
|
||||
|
||||
this.min.set( minX, minY, minZ );
|
||||
this.max.set( maxX, maxY, maxZ );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromBufferAttribute: function ( attribute ) {
|
||||
|
||||
var minX = + Infinity;
|
||||
var minY = + Infinity;
|
||||
var minZ = + Infinity;
|
||||
|
||||
var maxX = - Infinity;
|
||||
var maxY = - Infinity;
|
||||
var maxZ = - Infinity;
|
||||
|
||||
for ( var i = 0, l = attribute.count; i < l; i ++ ) {
|
||||
|
||||
var x = attribute.getX( i );
|
||||
var y = attribute.getY( i );
|
||||
var z = attribute.getZ( i );
|
||||
|
||||
if ( x < minX ) minX = x;
|
||||
if ( y < minY ) minY = y;
|
||||
if ( z < minZ ) minZ = z;
|
||||
|
||||
if ( x > maxX ) maxX = x;
|
||||
if ( y > maxY ) maxY = y;
|
||||
if ( z > maxZ ) maxZ = z;
|
||||
|
||||
}
|
||||
|
||||
this.min.set( minX, minY, minZ );
|
||||
this.max.set( maxX, maxY, maxZ );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromPoints: function ( points ) {
|
||||
|
||||
this.makeEmpty();
|
||||
|
||||
for ( var i = 0, il = points.length; i < il; i ++ ) {
|
||||
|
||||
this.expandByPoint( points[ i ] );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromCenterAndSize: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function setFromCenterAndSize( center, size ) {
|
||||
|
||||
var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
|
||||
|
||||
this.min.copy( center ).sub( halfSize );
|
||||
this.max.copy( center ).add( halfSize );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
setFromObject: function ( object ) {
|
||||
|
||||
this.makeEmpty();
|
||||
|
||||
return this.expandByObject( object );
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( box ) {
|
||||
|
||||
this.min.copy( box.min );
|
||||
this.max.copy( box.max );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
makeEmpty: function () {
|
||||
|
||||
this.min.x = this.min.y = this.min.z = + Infinity;
|
||||
this.max.x = this.max.y = this.max.z = - Infinity;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
isEmpty: function () {
|
||||
|
||||
// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
|
||||
|
||||
return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
|
||||
|
||||
},
|
||||
|
||||
getCenter: function ( target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Box3: .getCenter() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
|
||||
|
||||
},
|
||||
|
||||
getSize: function ( target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Box3: .getSize() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );
|
||||
|
||||
},
|
||||
|
||||
expandByPoint: function ( point ) {
|
||||
|
||||
this.min.min( point );
|
||||
this.max.max( point );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
expandByVector: function ( vector ) {
|
||||
|
||||
this.min.sub( vector );
|
||||
this.max.add( vector );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
expandByScalar: function ( scalar ) {
|
||||
|
||||
this.min.addScalar( - scalar );
|
||||
this.max.addScalar( scalar );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
expandByObject: function () {
|
||||
|
||||
// Computes the world-axis-aligned bounding box of an object (including its children),
|
||||
// accounting for both the object's, and children's, world transforms
|
||||
|
||||
var scope, i, l;
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
function traverse( node ) {
|
||||
|
||||
var geometry = node.geometry;
|
||||
|
||||
if ( geometry !== undefined ) {
|
||||
|
||||
if ( geometry.isGeometry ) {
|
||||
|
||||
var vertices = geometry.vertices;
|
||||
|
||||
for ( i = 0, l = vertices.length; i < l; i ++ ) {
|
||||
|
||||
v1.copy( vertices[ i ] );
|
||||
v1.applyMatrix4( node.matrixWorld );
|
||||
|
||||
scope.expandByPoint( v1 );
|
||||
|
||||
}
|
||||
|
||||
} else if ( geometry.isBufferGeometry ) {
|
||||
|
||||
var attribute = geometry.attributes.position;
|
||||
|
||||
if ( attribute !== undefined ) {
|
||||
|
||||
for ( i = 0, l = attribute.count; i < l; i ++ ) {
|
||||
|
||||
v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld );
|
||||
|
||||
scope.expandByPoint( v1 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return function expandByObject( object ) {
|
||||
|
||||
scope = this;
|
||||
|
||||
object.updateMatrixWorld( true );
|
||||
|
||||
object.traverse( traverse );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
containsPoint: function ( point ) {
|
||||
|
||||
return point.x < this.min.x || point.x > this.max.x ||
|
||||
point.y < this.min.y || point.y > this.max.y ||
|
||||
point.z < this.min.z || point.z > this.max.z ? false : true;
|
||||
|
||||
},
|
||||
|
||||
containsBox: function ( box ) {
|
||||
|
||||
return this.min.x <= box.min.x && box.max.x <= this.max.x &&
|
||||
this.min.y <= box.min.y && box.max.y <= this.max.y &&
|
||||
this.min.z <= box.min.z && box.max.z <= this.max.z;
|
||||
|
||||
},
|
||||
|
||||
getParameter: function ( point, target ) {
|
||||
|
||||
// This can potentially have a divide by zero if the box
|
||||
// has a size dimension of 0.
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Box3: .getParameter() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return target.set(
|
||||
( point.x - this.min.x ) / ( this.max.x - this.min.x ),
|
||||
( point.y - this.min.y ) / ( this.max.y - this.min.y ),
|
||||
( point.z - this.min.z ) / ( this.max.z - this.min.z )
|
||||
);
|
||||
|
||||
},
|
||||
|
||||
intersectsBox: function ( box ) {
|
||||
|
||||
// using 6 splitting planes to rule out intersections.
|
||||
return box.max.x < this.min.x || box.min.x > this.max.x ||
|
||||
box.max.y < this.min.y || box.min.y > this.max.y ||
|
||||
box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
|
||||
|
||||
},
|
||||
|
||||
intersectsSphere: ( function () {
|
||||
|
||||
var closestPoint = new Vector3();
|
||||
|
||||
return function intersectsSphere( sphere ) {
|
||||
|
||||
// Find the point on the AABB closest to the sphere center.
|
||||
this.clampPoint( sphere.center, closestPoint );
|
||||
|
||||
// If that point is inside the sphere, the AABB and sphere intersect.
|
||||
return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
|
||||
|
||||
};
|
||||
|
||||
} )(),
|
||||
|
||||
intersectsPlane: function ( plane ) {
|
||||
|
||||
// We compute the minimum and maximum dot product values. If those values
|
||||
// are on the same side (back or front) of the plane, then there is no intersection.
|
||||
|
||||
var min, max;
|
||||
|
||||
if ( plane.normal.x > 0 ) {
|
||||
|
||||
min = plane.normal.x * this.min.x;
|
||||
max = plane.normal.x * this.max.x;
|
||||
|
||||
} else {
|
||||
|
||||
min = plane.normal.x * this.max.x;
|
||||
max = plane.normal.x * this.min.x;
|
||||
|
||||
}
|
||||
|
||||
if ( plane.normal.y > 0 ) {
|
||||
|
||||
min += plane.normal.y * this.min.y;
|
||||
max += plane.normal.y * this.max.y;
|
||||
|
||||
} else {
|
||||
|
||||
min += plane.normal.y * this.max.y;
|
||||
max += plane.normal.y * this.min.y;
|
||||
|
||||
}
|
||||
|
||||
if ( plane.normal.z > 0 ) {
|
||||
|
||||
min += plane.normal.z * this.min.z;
|
||||
max += plane.normal.z * this.max.z;
|
||||
|
||||
} else {
|
||||
|
||||
min += plane.normal.z * this.max.z;
|
||||
max += plane.normal.z * this.min.z;
|
||||
|
||||
}
|
||||
|
||||
return ( min <= - plane.constant && max >= - plane.constant );
|
||||
|
||||
},
|
||||
|
||||
intersectsTriangle: ( function () {
|
||||
|
||||
// triangle centered vertices
|
||||
var v0 = new Vector3();
|
||||
var v1 = new Vector3();
|
||||
var v2 = new Vector3();
|
||||
|
||||
// triangle edge vectors
|
||||
var f0 = new Vector3();
|
||||
var f1 = new Vector3();
|
||||
var f2 = new Vector3();
|
||||
|
||||
var testAxis = new Vector3();
|
||||
|
||||
var center = new Vector3();
|
||||
var extents = new Vector3();
|
||||
|
||||
var triangleNormal = new Vector3();
|
||||
|
||||
function satForAxes( axes ) {
|
||||
|
||||
var i, j;
|
||||
|
||||
for ( i = 0, j = axes.length - 3; i <= j; i += 3 ) {
|
||||
|
||||
testAxis.fromArray( axes, i );
|
||||
// project the aabb onto the seperating axis
|
||||
var r = extents.x * Math.abs( testAxis.x ) + extents.y * Math.abs( testAxis.y ) + extents.z * Math.abs( testAxis.z );
|
||||
// project all 3 vertices of the triangle onto the seperating axis
|
||||
var p0 = v0.dot( testAxis );
|
||||
var p1 = v1.dot( testAxis );
|
||||
var p2 = v2.dot( testAxis );
|
||||
// actual test, basically see if either of the most extreme of the triangle points intersects r
|
||||
if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
|
||||
|
||||
// points of the projected triangle are outside the projected half-length of the aabb
|
||||
// the axis is seperating and we can exit
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return function intersectsTriangle( triangle ) {
|
||||
|
||||
if ( this.isEmpty() ) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// compute box center and extents
|
||||
this.getCenter( center );
|
||||
extents.subVectors( this.max, center );
|
||||
|
||||
// translate triangle to aabb origin
|
||||
v0.subVectors( triangle.a, center );
|
||||
v1.subVectors( triangle.b, center );
|
||||
v2.subVectors( triangle.c, center );
|
||||
|
||||
// compute edge vectors for triangle
|
||||
f0.subVectors( v1, v0 );
|
||||
f1.subVectors( v2, v1 );
|
||||
f2.subVectors( v0, v2 );
|
||||
|
||||
// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
|
||||
// make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
|
||||
// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
|
||||
var axes = [
|
||||
0, - f0.z, f0.y, 0, - f1.z, f1.y, 0, - f2.z, f2.y,
|
||||
f0.z, 0, - f0.x, f1.z, 0, - f1.x, f2.z, 0, - f2.x,
|
||||
- f0.y, f0.x, 0, - f1.y, f1.x, 0, - f2.y, f2.x, 0
|
||||
];
|
||||
if ( ! satForAxes( axes ) ) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// test 3 face normals from the aabb
|
||||
axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
|
||||
if ( ! satForAxes( axes ) ) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// finally testing the face normal of the triangle
|
||||
// use already existing triangle edge vectors here
|
||||
triangleNormal.crossVectors( f0, f1 );
|
||||
axes = [ triangleNormal.x, triangleNormal.y, triangleNormal.z ];
|
||||
return satForAxes( axes );
|
||||
|
||||
};
|
||||
|
||||
} )(),
|
||||
|
||||
clampPoint: function ( point, target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Box3: .clampPoint() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return target.copy( point ).clamp( this.min, this.max );
|
||||
|
||||
},
|
||||
|
||||
distanceToPoint: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function distanceToPoint( point ) {
|
||||
|
||||
var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
|
||||
return clampedPoint.sub( point ).length();
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
getBoundingSphere: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function getBoundingSphere( target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Box3: .getBoundingSphere() target is now required' );
|
||||
target = new Sphere();
|
||||
|
||||
}
|
||||
|
||||
this.getCenter( target.center );
|
||||
|
||||
target.radius = this.getSize( v1 ).length() * 0.5;
|
||||
|
||||
return target;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
intersect: function ( box ) {
|
||||
|
||||
this.min.max( box.min );
|
||||
this.max.min( box.max );
|
||||
|
||||
// ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
|
||||
if ( this.isEmpty() ) this.makeEmpty();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
union: function ( box ) {
|
||||
|
||||
this.min.min( box.min );
|
||||
this.max.max( box.max );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
applyMatrix4: function () {
|
||||
|
||||
var points = [
|
||||
new Vector3(),
|
||||
new Vector3(),
|
||||
new Vector3(),
|
||||
new Vector3(),
|
||||
new Vector3(),
|
||||
new Vector3(),
|
||||
new Vector3(),
|
||||
new Vector3()
|
||||
];
|
||||
|
||||
return function applyMatrix4( matrix ) {
|
||||
|
||||
// transform of empty box is an empty box.
|
||||
if ( this.isEmpty() ) return this;
|
||||
|
||||
// NOTE: I am using a binary pattern to specify all 2^3 combinations below
|
||||
points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
|
||||
points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
|
||||
points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
|
||||
points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
|
||||
points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
|
||||
points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
|
||||
points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
|
||||
points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
|
||||
|
||||
this.setFromPoints( points );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
translate: function ( offset ) {
|
||||
|
||||
this.min.add( offset );
|
||||
this.max.add( offset );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
equals: function ( box ) {
|
||||
|
||||
return box.min.equals( this.min ) && box.max.equals( this.max );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Box3 };
|
606
lib/math/Color.js
Normal file
606
lib/math/Color.js
Normal file
@ -0,0 +1,606 @@
|
||||
import { _Math } from './Math.js';
|
||||
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
|
||||
'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
|
||||
'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
|
||||
'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
|
||||
'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
|
||||
'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
|
||||
'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
|
||||
'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
|
||||
'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
|
||||
'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
|
||||
'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
|
||||
'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
|
||||
'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
|
||||
'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
|
||||
'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
|
||||
'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
|
||||
'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
|
||||
'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
|
||||
'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
|
||||
'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
|
||||
'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
|
||||
'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
|
||||
'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
|
||||
'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
|
||||
|
||||
function Color( r, g, b ) {
|
||||
|
||||
if ( g === undefined && b === undefined ) {
|
||||
|
||||
// r is THREE.Color, hex or string
|
||||
return this.set( r );
|
||||
|
||||
}
|
||||
|
||||
return this.setRGB( r, g, b );
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Color.prototype, {
|
||||
|
||||
isColor: true,
|
||||
|
||||
r: 1, g: 1, b: 1,
|
||||
|
||||
set: function ( value ) {
|
||||
|
||||
if ( value && value.isColor ) {
|
||||
|
||||
this.copy( value );
|
||||
|
||||
} else if ( typeof value === 'number' ) {
|
||||
|
||||
this.setHex( value );
|
||||
|
||||
} else if ( typeof value === 'string' ) {
|
||||
|
||||
this.setStyle( value );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setScalar: function ( scalar ) {
|
||||
|
||||
this.r = scalar;
|
||||
this.g = scalar;
|
||||
this.b = scalar;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setHex: function ( hex ) {
|
||||
|
||||
hex = Math.floor( hex );
|
||||
|
||||
this.r = ( hex >> 16 & 255 ) / 255;
|
||||
this.g = ( hex >> 8 & 255 ) / 255;
|
||||
this.b = ( hex & 255 ) / 255;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setRGB: function ( r, g, b ) {
|
||||
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setHSL: function () {
|
||||
|
||||
function hue2rgb( p, q, t ) {
|
||||
|
||||
if ( t < 0 ) t += 1;
|
||||
if ( t > 1 ) t -= 1;
|
||||
if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
|
||||
if ( t < 1 / 2 ) return q;
|
||||
if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
return function setHSL( h, s, l ) {
|
||||
|
||||
// h,s,l ranges are in 0.0 - 1.0
|
||||
h = _Math.euclideanModulo( h, 1 );
|
||||
s = _Math.clamp( s, 0, 1 );
|
||||
l = _Math.clamp( l, 0, 1 );
|
||||
|
||||
if ( s === 0 ) {
|
||||
|
||||
this.r = this.g = this.b = l;
|
||||
|
||||
} else {
|
||||
|
||||
var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
|
||||
var q = ( 2 * l ) - p;
|
||||
|
||||
this.r = hue2rgb( q, p, h + 1 / 3 );
|
||||
this.g = hue2rgb( q, p, h );
|
||||
this.b = hue2rgb( q, p, h - 1 / 3 );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
setStyle: function ( style ) {
|
||||
|
||||
function handleAlpha( string ) {
|
||||
|
||||
if ( string === undefined ) return;
|
||||
|
||||
if ( parseFloat( string ) < 1 ) {
|
||||
|
||||
console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
var m;
|
||||
|
||||
if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) {
|
||||
|
||||
// rgb / hsl
|
||||
|
||||
var color;
|
||||
var name = m[ 1 ];
|
||||
var components = m[ 2 ];
|
||||
|
||||
switch ( name ) {
|
||||
|
||||
case 'rgb':
|
||||
case 'rgba':
|
||||
|
||||
if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
|
||||
|
||||
// rgb(255,0,0) rgba(255,0,0,0.5)
|
||||
this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
|
||||
this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
|
||||
this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
|
||||
|
||||
handleAlpha( color[ 5 ] );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
|
||||
|
||||
// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
|
||||
this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
|
||||
this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
|
||||
this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
|
||||
|
||||
handleAlpha( color[ 5 ] );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'hsl':
|
||||
case 'hsla':
|
||||
|
||||
if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
|
||||
|
||||
// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
|
||||
var h = parseFloat( color[ 1 ] ) / 360;
|
||||
var s = parseInt( color[ 2 ], 10 ) / 100;
|
||||
var l = parseInt( color[ 3 ], 10 ) / 100;
|
||||
|
||||
handleAlpha( color[ 5 ] );
|
||||
|
||||
return this.setHSL( h, s, l );
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) {
|
||||
|
||||
// hex color
|
||||
|
||||
var hex = m[ 1 ];
|
||||
var size = hex.length;
|
||||
|
||||
if ( size === 3 ) {
|
||||
|
||||
// #ff0
|
||||
this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
|
||||
this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
|
||||
this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
|
||||
|
||||
return this;
|
||||
|
||||
} else if ( size === 6 ) {
|
||||
|
||||
// #ff0000
|
||||
this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
|
||||
this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
|
||||
this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( style && style.length > 0 ) {
|
||||
|
||||
// color keywords
|
||||
var hex = ColorKeywords[ style ];
|
||||
|
||||
if ( hex !== undefined ) {
|
||||
|
||||
// red
|
||||
this.setHex( hex );
|
||||
|
||||
} else {
|
||||
|
||||
// unknown color
|
||||
console.warn( 'THREE.Color: Unknown color ' + style );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor( this.r, this.g, this.b );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( color ) {
|
||||
|
||||
this.r = color.r;
|
||||
this.g = color.g;
|
||||
this.b = color.b;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
copyGammaToLinear: function ( color, gammaFactor ) {
|
||||
|
||||
if ( gammaFactor === undefined ) gammaFactor = 2.0;
|
||||
|
||||
this.r = Math.pow( color.r, gammaFactor );
|
||||
this.g = Math.pow( color.g, gammaFactor );
|
||||
this.b = Math.pow( color.b, gammaFactor );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
copyLinearToGamma: function ( color, gammaFactor ) {
|
||||
|
||||
if ( gammaFactor === undefined ) gammaFactor = 2.0;
|
||||
|
||||
var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
|
||||
|
||||
this.r = Math.pow( color.r, safeInverse );
|
||||
this.g = Math.pow( color.g, safeInverse );
|
||||
this.b = Math.pow( color.b, safeInverse );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
convertGammaToLinear: function ( gammaFactor ) {
|
||||
|
||||
this.copyGammaToLinear( this, gammaFactor );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
convertLinearToGamma: function ( gammaFactor ) {
|
||||
|
||||
this.copyLinearToGamma( this, gammaFactor );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
copySRGBToLinear: function () {
|
||||
|
||||
function SRGBToLinear( c ) {
|
||||
|
||||
return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
|
||||
|
||||
}
|
||||
|
||||
return function copySRGBToLinear( color ) {
|
||||
|
||||
this.r = SRGBToLinear( color.r );
|
||||
this.g = SRGBToLinear( color.g );
|
||||
this.b = SRGBToLinear( color.b );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
copyLinearToSRGB: function () {
|
||||
|
||||
function LinearToSRGB( c ) {
|
||||
|
||||
return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
|
||||
|
||||
}
|
||||
|
||||
return function copyLinearToSRGB( color ) {
|
||||
|
||||
this.r = LinearToSRGB( color.r );
|
||||
this.g = LinearToSRGB( color.g );
|
||||
this.b = LinearToSRGB( color.b );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
convertSRGBToLinear: function () {
|
||||
|
||||
this.copySRGBToLinear( this );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
convertLinearToSRGB: function () {
|
||||
|
||||
this.copyLinearToSRGB( this );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
getHex: function () {
|
||||
|
||||
return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
|
||||
|
||||
},
|
||||
|
||||
getHexString: function () {
|
||||
|
||||
return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
|
||||
|
||||
},
|
||||
|
||||
getHSL: function ( target ) {
|
||||
|
||||
// h,s,l ranges are in 0.0 - 1.0
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Color: .getHSL() target is now required' );
|
||||
target = { h: 0, s: 0, l: 0 };
|
||||
|
||||
}
|
||||
|
||||
var r = this.r, g = this.g, b = this.b;
|
||||
|
||||
var max = Math.max( r, g, b );
|
||||
var min = Math.min( r, g, b );
|
||||
|
||||
var hue, saturation;
|
||||
var lightness = ( min + max ) / 2.0;
|
||||
|
||||
if ( min === max ) {
|
||||
|
||||
hue = 0;
|
||||
saturation = 0;
|
||||
|
||||
} else {
|
||||
|
||||
var delta = max - min;
|
||||
|
||||
saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
|
||||
|
||||
switch ( max ) {
|
||||
|
||||
case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
|
||||
case g: hue = ( b - r ) / delta + 2; break;
|
||||
case b: hue = ( r - g ) / delta + 4; break;
|
||||
|
||||
}
|
||||
|
||||
hue /= 6;
|
||||
|
||||
}
|
||||
|
||||
target.h = hue;
|
||||
target.s = saturation;
|
||||
target.l = lightness;
|
||||
|
||||
return target;
|
||||
|
||||
},
|
||||
|
||||
getStyle: function () {
|
||||
|
||||
return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
|
||||
|
||||
},
|
||||
|
||||
offsetHSL: function () {
|
||||
|
||||
var hsl = {};
|
||||
|
||||
return function ( h, s, l ) {
|
||||
|
||||
this.getHSL( hsl );
|
||||
|
||||
hsl.h += h; hsl.s += s; hsl.l += l;
|
||||
|
||||
this.setHSL( hsl.h, hsl.s, hsl.l );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
add: function ( color ) {
|
||||
|
||||
this.r += color.r;
|
||||
this.g += color.g;
|
||||
this.b += color.b;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
addColors: function ( color1, color2 ) {
|
||||
|
||||
this.r = color1.r + color2.r;
|
||||
this.g = color1.g + color2.g;
|
||||
this.b = color1.b + color2.b;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
addScalar: function ( s ) {
|
||||
|
||||
this.r += s;
|
||||
this.g += s;
|
||||
this.b += s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
sub: function ( color ) {
|
||||
|
||||
this.r = Math.max( 0, this.r - color.r );
|
||||
this.g = Math.max( 0, this.g - color.g );
|
||||
this.b = Math.max( 0, this.b - color.b );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
multiply: function ( color ) {
|
||||
|
||||
this.r *= color.r;
|
||||
this.g *= color.g;
|
||||
this.b *= color.b;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
multiplyScalar: function ( s ) {
|
||||
|
||||
this.r *= s;
|
||||
this.g *= s;
|
||||
this.b *= s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
lerp: function ( color, alpha ) {
|
||||
|
||||
this.r += ( color.r - this.r ) * alpha;
|
||||
this.g += ( color.g - this.g ) * alpha;
|
||||
this.b += ( color.b - this.b ) * alpha;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
lerpHSL: function () {
|
||||
|
||||
var hslA = { h: 0, s: 0, l: 0 };
|
||||
var hslB = { h: 0, s: 0, l: 0 };
|
||||
|
||||
return function lerpHSL( color, alpha ) {
|
||||
|
||||
this.getHSL( hslA );
|
||||
color.getHSL( hslB );
|
||||
|
||||
var h = _Math.lerp( hslA.h, hslB.h, alpha );
|
||||
var s = _Math.lerp( hslA.s, hslB.s, alpha );
|
||||
var l = _Math.lerp( hslA.l, hslB.l, alpha );
|
||||
|
||||
this.setHSL( h, s, l );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
equals: function ( c ) {
|
||||
|
||||
return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
|
||||
|
||||
},
|
||||
|
||||
fromArray: function ( array, offset ) {
|
||||
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
this.r = array[ offset ];
|
||||
this.g = array[ offset + 1 ];
|
||||
this.b = array[ offset + 2 ];
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
toArray: function ( array, offset ) {
|
||||
|
||||
if ( array === undefined ) array = [];
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
array[ offset ] = this.r;
|
||||
array[ offset + 1 ] = this.g;
|
||||
array[ offset + 2 ] = this.b;
|
||||
|
||||
return array;
|
||||
|
||||
},
|
||||
|
||||
toJSON: function () {
|
||||
|
||||
return this.getHex();
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Color };
|
65
lib/math/Cylindrical.js
Normal file
65
lib/math/Cylindrical.js
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @author Mugen87 / https://github.com/Mugen87
|
||||
*
|
||||
* Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
|
||||
*
|
||||
*/
|
||||
|
||||
function Cylindrical( radius, theta, y ) {
|
||||
|
||||
this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane
|
||||
this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
|
||||
this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Cylindrical.prototype, {
|
||||
|
||||
set: function ( radius, theta, y ) {
|
||||
|
||||
this.radius = radius;
|
||||
this.theta = theta;
|
||||
this.y = y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( other ) {
|
||||
|
||||
this.radius = other.radius;
|
||||
this.theta = other.theta;
|
||||
this.y = other.y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromVector3: function ( v ) {
|
||||
|
||||
return this.setFromCartesianCoords( v.x, v.y, v.z );
|
||||
|
||||
},
|
||||
|
||||
setFromCartesianCoords: function ( x, y, z ) {
|
||||
|
||||
this.radius = Math.sqrt( x * x + z * z );
|
||||
this.theta = Math.atan2( x, z );
|
||||
this.y = y;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Cylindrical };
|
352
lib/math/Euler.js
Normal file
352
lib/math/Euler.js
Normal file
@ -0,0 +1,352 @@
|
||||
import { Quaternion } from './Quaternion.js';
|
||||
import { Vector3 } from './Vector3.js';
|
||||
import { Matrix4 } from './Matrix4.js';
|
||||
import { _Math } from './Math.js';
|
||||
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
* @author WestLangley / http://github.com/WestLangley
|
||||
* @author bhouston / http://clara.io
|
||||
*/
|
||||
|
||||
function Euler( x, y, z, order ) {
|
||||
|
||||
this._x = x || 0;
|
||||
this._y = y || 0;
|
||||
this._z = z || 0;
|
||||
this._order = order || Euler.DefaultOrder;
|
||||
|
||||
}
|
||||
|
||||
Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
|
||||
|
||||
Euler.DefaultOrder = 'XYZ';
|
||||
|
||||
Object.defineProperties( Euler.prototype, {
|
||||
|
||||
x: {
|
||||
|
||||
get: function () {
|
||||
|
||||
return this._x;
|
||||
|
||||
},
|
||||
|
||||
set: function ( value ) {
|
||||
|
||||
this._x = value;
|
||||
this.onChangeCallback();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
y: {
|
||||
|
||||
get: function () {
|
||||
|
||||
return this._y;
|
||||
|
||||
},
|
||||
|
||||
set: function ( value ) {
|
||||
|
||||
this._y = value;
|
||||
this.onChangeCallback();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
z: {
|
||||
|
||||
get: function () {
|
||||
|
||||
return this._z;
|
||||
|
||||
},
|
||||
|
||||
set: function ( value ) {
|
||||
|
||||
this._z = value;
|
||||
this.onChangeCallback();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
order: {
|
||||
|
||||
get: function () {
|
||||
|
||||
return this._order;
|
||||
|
||||
},
|
||||
|
||||
set: function ( value ) {
|
||||
|
||||
this._order = value;
|
||||
this.onChangeCallback();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
Object.assign( Euler.prototype, {
|
||||
|
||||
isEuler: true,
|
||||
|
||||
set: function ( x, y, z, order ) {
|
||||
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._z = z;
|
||||
this._order = order || this._order;
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor( this._x, this._y, this._z, this._order );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( euler ) {
|
||||
|
||||
this._x = euler._x;
|
||||
this._y = euler._y;
|
||||
this._z = euler._z;
|
||||
this._order = euler._order;
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromRotationMatrix: function ( m, order, update ) {
|
||||
|
||||
var clamp = _Math.clamp;
|
||||
|
||||
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
|
||||
|
||||
var te = m.elements;
|
||||
var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
|
||||
var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
|
||||
var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
|
||||
|
||||
order = order || this._order;
|
||||
|
||||
if ( order === 'XYZ' ) {
|
||||
|
||||
this._y = Math.asin( clamp( m13, - 1, 1 ) );
|
||||
|
||||
if ( Math.abs( m13 ) < 0.99999 ) {
|
||||
|
||||
this._x = Math.atan2( - m23, m33 );
|
||||
this._z = Math.atan2( - m12, m11 );
|
||||
|
||||
} else {
|
||||
|
||||
this._x = Math.atan2( m32, m22 );
|
||||
this._z = 0;
|
||||
|
||||
}
|
||||
|
||||
} else if ( order === 'YXZ' ) {
|
||||
|
||||
this._x = Math.asin( - clamp( m23, - 1, 1 ) );
|
||||
|
||||
if ( Math.abs( m23 ) < 0.99999 ) {
|
||||
|
||||
this._y = Math.atan2( m13, m33 );
|
||||
this._z = Math.atan2( m21, m22 );
|
||||
|
||||
} else {
|
||||
|
||||
this._y = Math.atan2( - m31, m11 );
|
||||
this._z = 0;
|
||||
|
||||
}
|
||||
|
||||
} else if ( order === 'ZXY' ) {
|
||||
|
||||
this._x = Math.asin( clamp( m32, - 1, 1 ) );
|
||||
|
||||
if ( Math.abs( m32 ) < 0.99999 ) {
|
||||
|
||||
this._y = Math.atan2( - m31, m33 );
|
||||
this._z = Math.atan2( - m12, m22 );
|
||||
|
||||
} else {
|
||||
|
||||
this._y = 0;
|
||||
this._z = Math.atan2( m21, m11 );
|
||||
|
||||
}
|
||||
|
||||
} else if ( order === 'ZYX' ) {
|
||||
|
||||
this._y = Math.asin( - clamp( m31, - 1, 1 ) );
|
||||
|
||||
if ( Math.abs( m31 ) < 0.99999 ) {
|
||||
|
||||
this._x = Math.atan2( m32, m33 );
|
||||
this._z = Math.atan2( m21, m11 );
|
||||
|
||||
} else {
|
||||
|
||||
this._x = 0;
|
||||
this._z = Math.atan2( - m12, m22 );
|
||||
|
||||
}
|
||||
|
||||
} else if ( order === 'YZX' ) {
|
||||
|
||||
this._z = Math.asin( clamp( m21, - 1, 1 ) );
|
||||
|
||||
if ( Math.abs( m21 ) < 0.99999 ) {
|
||||
|
||||
this._x = Math.atan2( - m23, m22 );
|
||||
this._y = Math.atan2( - m31, m11 );
|
||||
|
||||
} else {
|
||||
|
||||
this._x = 0;
|
||||
this._y = Math.atan2( m13, m33 );
|
||||
|
||||
}
|
||||
|
||||
} else if ( order === 'XZY' ) {
|
||||
|
||||
this._z = Math.asin( - clamp( m12, - 1, 1 ) );
|
||||
|
||||
if ( Math.abs( m12 ) < 0.99999 ) {
|
||||
|
||||
this._x = Math.atan2( m32, m22 );
|
||||
this._y = Math.atan2( m13, m11 );
|
||||
|
||||
} else {
|
||||
|
||||
this._x = Math.atan2( - m23, m33 );
|
||||
this._y = 0;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order );
|
||||
|
||||
}
|
||||
|
||||
this._order = order;
|
||||
|
||||
if ( update !== false ) this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromQuaternion: function () {
|
||||
|
||||
var matrix = new Matrix4();
|
||||
|
||||
return function setFromQuaternion( q, order, update ) {
|
||||
|
||||
matrix.makeRotationFromQuaternion( q );
|
||||
|
||||
return this.setFromRotationMatrix( matrix, order, update );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
setFromVector3: function ( v, order ) {
|
||||
|
||||
return this.set( v.x, v.y, v.z, order || this._order );
|
||||
|
||||
},
|
||||
|
||||
reorder: function () {
|
||||
|
||||
// WARNING: this discards revolution information -bhouston
|
||||
|
||||
var q = new Quaternion();
|
||||
|
||||
return function reorder( newOrder ) {
|
||||
|
||||
q.setFromEuler( this );
|
||||
|
||||
return this.setFromQuaternion( q, newOrder );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
equals: function ( euler ) {
|
||||
|
||||
return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
|
||||
|
||||
},
|
||||
|
||||
fromArray: function ( array ) {
|
||||
|
||||
this._x = array[ 0 ];
|
||||
this._y = array[ 1 ];
|
||||
this._z = array[ 2 ];
|
||||
if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
toArray: function ( array, offset ) {
|
||||
|
||||
if ( array === undefined ) array = [];
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
array[ offset ] = this._x;
|
||||
array[ offset + 1 ] = this._y;
|
||||
array[ offset + 2 ] = this._z;
|
||||
array[ offset + 3 ] = this._order;
|
||||
|
||||
return array;
|
||||
|
||||
},
|
||||
|
||||
toVector3: function ( optionalResult ) {
|
||||
|
||||
if ( optionalResult ) {
|
||||
|
||||
return optionalResult.set( this._x, this._y, this._z );
|
||||
|
||||
} else {
|
||||
|
||||
return new Vector3( this._x, this._y, this._z );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
onChange: function ( callback ) {
|
||||
|
||||
this.onChangeCallback = callback;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
onChangeCallback: function () {}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Euler };
|
194
lib/math/Frustum.js
Normal file
194
lib/math/Frustum.js
Normal file
@ -0,0 +1,194 @@
|
||||
import { Vector3 } from './Vector3.js';
|
||||
import { Sphere } from './Sphere.js';
|
||||
import { Plane } from './Plane.js';
|
||||
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author bhouston / http://clara.io
|
||||
*/
|
||||
|
||||
function Frustum( p0, p1, p2, p3, p4, p5 ) {
|
||||
|
||||
this.planes = [
|
||||
|
||||
( p0 !== undefined ) ? p0 : new Plane(),
|
||||
( p1 !== undefined ) ? p1 : new Plane(),
|
||||
( p2 !== undefined ) ? p2 : new Plane(),
|
||||
( p3 !== undefined ) ? p3 : new Plane(),
|
||||
( p4 !== undefined ) ? p4 : new Plane(),
|
||||
( p5 !== undefined ) ? p5 : new Plane()
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Frustum.prototype, {
|
||||
|
||||
set: function ( p0, p1, p2, p3, p4, p5 ) {
|
||||
|
||||
var planes = this.planes;
|
||||
|
||||
planes[ 0 ].copy( p0 );
|
||||
planes[ 1 ].copy( p1 );
|
||||
planes[ 2 ].copy( p2 );
|
||||
planes[ 3 ].copy( p3 );
|
||||
planes[ 4 ].copy( p4 );
|
||||
planes[ 5 ].copy( p5 );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( frustum ) {
|
||||
|
||||
var planes = this.planes;
|
||||
|
||||
for ( var i = 0; i < 6; i ++ ) {
|
||||
|
||||
planes[ i ].copy( frustum.planes[ i ] );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromMatrix: function ( m ) {
|
||||
|
||||
var planes = this.planes;
|
||||
var me = m.elements;
|
||||
var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
|
||||
var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
|
||||
var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
|
||||
var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
|
||||
|
||||
planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
|
||||
planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
|
||||
planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
|
||||
planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
|
||||
planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
|
||||
planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
intersectsObject: function () {
|
||||
|
||||
var sphere = new Sphere();
|
||||
|
||||
return function intersectsObject( object ) {
|
||||
|
||||
var geometry = object.geometry;
|
||||
|
||||
if ( geometry.boundingSphere === null )
|
||||
geometry.computeBoundingSphere();
|
||||
|
||||
sphere.copy( geometry.boundingSphere )
|
||||
.applyMatrix4( object.matrixWorld );
|
||||
|
||||
return this.intersectsSphere( sphere );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
intersectsSprite: function () {
|
||||
|
||||
var sphere = new Sphere();
|
||||
|
||||
return function intersectsSprite( sprite ) {
|
||||
|
||||
sphere.center.set( 0, 0, 0 );
|
||||
sphere.radius = 0.7071067811865476;
|
||||
sphere.applyMatrix4( sprite.matrixWorld );
|
||||
|
||||
return this.intersectsSphere( sphere );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
intersectsSphere: function ( sphere ) {
|
||||
|
||||
var planes = this.planes;
|
||||
var center = sphere.center;
|
||||
var negRadius = - sphere.radius;
|
||||
|
||||
for ( var i = 0; i < 6; i ++ ) {
|
||||
|
||||
var distance = planes[ i ].distanceToPoint( center );
|
||||
|
||||
if ( distance < negRadius ) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
},
|
||||
|
||||
intersectsBox: function () {
|
||||
|
||||
var p = new Vector3();
|
||||
|
||||
return function intersectsBox( box ) {
|
||||
|
||||
var planes = this.planes;
|
||||
|
||||
for ( var i = 0; i < 6; i ++ ) {
|
||||
|
||||
var plane = planes[ i ];
|
||||
|
||||
// corner at max distance
|
||||
|
||||
p.x = plane.normal.x > 0 ? box.max.x : box.min.x;
|
||||
p.y = plane.normal.y > 0 ? box.max.y : box.min.y;
|
||||
p.z = plane.normal.z > 0 ? box.max.z : box.min.z;
|
||||
|
||||
if ( plane.distanceToPoint( p ) < 0 ) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
containsPoint: function ( point ) {
|
||||
|
||||
var planes = this.planes;
|
||||
|
||||
for ( var i = 0; i < 6; i ++ ) {
|
||||
|
||||
if ( planes[ i ].distanceToPoint( point ) < 0 ) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Frustum };
|
259
lib/math/Interpolant.js
Normal file
259
lib/math/Interpolant.js
Normal file
@ -0,0 +1,259 @@
|
||||
/**
|
||||
* Abstract base class of interpolants over parametric samples.
|
||||
*
|
||||
* The parameter domain is one dimensional, typically the time or a path
|
||||
* along a curve defined by the data.
|
||||
*
|
||||
* The sample values can have any dimensionality and derived classes may
|
||||
* apply special interpretations to the data.
|
||||
*
|
||||
* This class provides the interval seek in a Template Method, deferring
|
||||
* the actual interpolation to derived classes.
|
||||
*
|
||||
* Time complexity is O(1) for linear access crossing at most two points
|
||||
* and O(log N) for random access, where N is the number of positions.
|
||||
*
|
||||
* References:
|
||||
*
|
||||
* http://www.oodesign.com/template-method-pattern.html
|
||||
*
|
||||
* @author tschw
|
||||
*/
|
||||
|
||||
function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
|
||||
|
||||
this.parameterPositions = parameterPositions;
|
||||
this._cachedIndex = 0;
|
||||
|
||||
this.resultBuffer = resultBuffer !== undefined ?
|
||||
resultBuffer : new sampleValues.constructor( sampleSize );
|
||||
this.sampleValues = sampleValues;
|
||||
this.valueSize = sampleSize;
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Interpolant.prototype, {
|
||||
|
||||
evaluate: function ( t ) {
|
||||
|
||||
var pp = this.parameterPositions,
|
||||
i1 = this._cachedIndex,
|
||||
|
||||
t1 = pp[ i1 ],
|
||||
t0 = pp[ i1 - 1 ];
|
||||
|
||||
validate_interval: {
|
||||
|
||||
seek: {
|
||||
|
||||
var right;
|
||||
|
||||
linear_scan: {
|
||||
|
||||
//- See http://jsperf.com/comparison-to-undefined/3
|
||||
//- slower code:
|
||||
//-
|
||||
//- if ( t >= t1 || t1 === undefined ) {
|
||||
forward_scan: if ( ! ( t < t1 ) ) {
|
||||
|
||||
for ( var giveUpAt = i1 + 2; ; ) {
|
||||
|
||||
if ( t1 === undefined ) {
|
||||
|
||||
if ( t < t0 ) break forward_scan;
|
||||
|
||||
// after end
|
||||
|
||||
i1 = pp.length;
|
||||
this._cachedIndex = i1;
|
||||
return this.afterEnd_( i1 - 1, t, t0 );
|
||||
|
||||
}
|
||||
|
||||
if ( i1 === giveUpAt ) break; // this loop
|
||||
|
||||
t0 = t1;
|
||||
t1 = pp[ ++ i1 ];
|
||||
|
||||
if ( t < t1 ) {
|
||||
|
||||
// we have arrived at the sought interval
|
||||
break seek;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// prepare binary search on the right side of the index
|
||||
right = pp.length;
|
||||
break linear_scan;
|
||||
|
||||
}
|
||||
|
||||
//- slower code:
|
||||
//- if ( t < t0 || t0 === undefined ) {
|
||||
if ( ! ( t >= t0 ) ) {
|
||||
|
||||
// looping?
|
||||
|
||||
var t1global = pp[ 1 ];
|
||||
|
||||
if ( t < t1global ) {
|
||||
|
||||
i1 = 2; // + 1, using the scan for the details
|
||||
t0 = t1global;
|
||||
|
||||
}
|
||||
|
||||
// linear reverse scan
|
||||
|
||||
for ( var giveUpAt = i1 - 2; ; ) {
|
||||
|
||||
if ( t0 === undefined ) {
|
||||
|
||||
// before start
|
||||
|
||||
this._cachedIndex = 0;
|
||||
return this.beforeStart_( 0, t, t1 );
|
||||
|
||||
}
|
||||
|
||||
if ( i1 === giveUpAt ) break; // this loop
|
||||
|
||||
t1 = t0;
|
||||
t0 = pp[ -- i1 - 1 ];
|
||||
|
||||
if ( t >= t0 ) {
|
||||
|
||||
// we have arrived at the sought interval
|
||||
break seek;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// prepare binary search on the left side of the index
|
||||
right = i1;
|
||||
i1 = 0;
|
||||
break linear_scan;
|
||||
|
||||
}
|
||||
|
||||
// the interval is valid
|
||||
|
||||
break validate_interval;
|
||||
|
||||
} // linear scan
|
||||
|
||||
// binary search
|
||||
|
||||
while ( i1 < right ) {
|
||||
|
||||
var mid = ( i1 + right ) >>> 1;
|
||||
|
||||
if ( t < pp[ mid ] ) {
|
||||
|
||||
right = mid;
|
||||
|
||||
} else {
|
||||
|
||||
i1 = mid + 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
t1 = pp[ i1 ];
|
||||
t0 = pp[ i1 - 1 ];
|
||||
|
||||
// check boundary cases, again
|
||||
|
||||
if ( t0 === undefined ) {
|
||||
|
||||
this._cachedIndex = 0;
|
||||
return this.beforeStart_( 0, t, t1 );
|
||||
|
||||
}
|
||||
|
||||
if ( t1 === undefined ) {
|
||||
|
||||
i1 = pp.length;
|
||||
this._cachedIndex = i1;
|
||||
return this.afterEnd_( i1 - 1, t0, t );
|
||||
|
||||
}
|
||||
|
||||
} // seek
|
||||
|
||||
this._cachedIndex = i1;
|
||||
|
||||
this.intervalChanged_( i1, t0, t1 );
|
||||
|
||||
} // validate_interval
|
||||
|
||||
return this.interpolate_( i1, t0, t, t1 );
|
||||
|
||||
},
|
||||
|
||||
settings: null, // optional, subclass-specific settings structure
|
||||
// Note: The indirection allows central control of many interpolants.
|
||||
|
||||
// --- Protected interface
|
||||
|
||||
DefaultSettings_: {},
|
||||
|
||||
getSettings_: function () {
|
||||
|
||||
return this.settings || this.DefaultSettings_;
|
||||
|
||||
},
|
||||
|
||||
copySampleValue_: function ( index ) {
|
||||
|
||||
// copies a sample value to the result buffer
|
||||
|
||||
var result = this.resultBuffer,
|
||||
values = this.sampleValues,
|
||||
stride = this.valueSize,
|
||||
offset = index * stride;
|
||||
|
||||
for ( var i = 0; i !== stride; ++ i ) {
|
||||
|
||||
result[ i ] = values[ offset + i ];
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
},
|
||||
|
||||
// Template methods for derived classes:
|
||||
|
||||
interpolate_: function ( /* i1, t0, t, t1 */ ) {
|
||||
|
||||
throw new Error( 'call to abstract method' );
|
||||
// implementations shall return this.resultBuffer
|
||||
|
||||
},
|
||||
|
||||
intervalChanged_: function ( /* i1, t0, t1 */ ) {
|
||||
|
||||
// empty
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
//!\ DECLARE ALIAS AFTER assign prototype !
|
||||
Object.assign( Interpolant.prototype, {
|
||||
|
||||
//( 0, t, t0 ), returns this.resultBuffer
|
||||
beforeStart_: Interpolant.prototype.copySampleValue_,
|
||||
|
||||
//( N-1, tN-1, t ), returns this.resultBuffer
|
||||
afterEnd_: Interpolant.prototype.copySampleValue_,
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Interpolant };
|
152
lib/math/Line3.js
Normal file
152
lib/math/Line3.js
Normal file
@ -0,0 +1,152 @@
|
||||
import { Vector3 } from './Vector3.js';
|
||||
import { _Math } from './Math.js';
|
||||
|
||||
/**
|
||||
* @author bhouston / http://clara.io
|
||||
*/
|
||||
|
||||
function Line3( start, end ) {
|
||||
|
||||
this.start = ( start !== undefined ) ? start : new Vector3();
|
||||
this.end = ( end !== undefined ) ? end : new Vector3();
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Line3.prototype, {
|
||||
|
||||
set: function ( start, end ) {
|
||||
|
||||
this.start.copy( start );
|
||||
this.end.copy( end );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( line ) {
|
||||
|
||||
this.start.copy( line.start );
|
||||
this.end.copy( line.end );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
getCenter: function ( target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Line3: .getCenter() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
|
||||
|
||||
},
|
||||
|
||||
delta: function ( target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Line3: .delta() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return target.subVectors( this.end, this.start );
|
||||
|
||||
},
|
||||
|
||||
distanceSq: function () {
|
||||
|
||||
return this.start.distanceToSquared( this.end );
|
||||
|
||||
},
|
||||
|
||||
distance: function () {
|
||||
|
||||
return this.start.distanceTo( this.end );
|
||||
|
||||
},
|
||||
|
||||
at: function ( t, target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Line3: .at() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return this.delta( target ).multiplyScalar( t ).add( this.start );
|
||||
|
||||
},
|
||||
|
||||
closestPointToPointParameter: function () {
|
||||
|
||||
var startP = new Vector3();
|
||||
var startEnd = new Vector3();
|
||||
|
||||
return function closestPointToPointParameter( point, clampToLine ) {
|
||||
|
||||
startP.subVectors( point, this.start );
|
||||
startEnd.subVectors( this.end, this.start );
|
||||
|
||||
var startEnd2 = startEnd.dot( startEnd );
|
||||
var startEnd_startP = startEnd.dot( startP );
|
||||
|
||||
var t = startEnd_startP / startEnd2;
|
||||
|
||||
if ( clampToLine ) {
|
||||
|
||||
t = _Math.clamp( t, 0, 1 );
|
||||
|
||||
}
|
||||
|
||||
return t;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
closestPointToPoint: function ( point, clampToLine, target ) {
|
||||
|
||||
var t = this.closestPointToPointParameter( point, clampToLine );
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Line3: .closestPointToPoint() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return this.delta( target ).multiplyScalar( t ).add( this.start );
|
||||
|
||||
},
|
||||
|
||||
applyMatrix4: function ( matrix ) {
|
||||
|
||||
this.start.applyMatrix4( matrix );
|
||||
this.end.applyMatrix4( matrix );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
equals: function ( line ) {
|
||||
|
||||
return line.start.equals( this.start ) && line.end.equals( this.end );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Line3 };
|
153
lib/math/Math.js
Normal file
153
lib/math/Math.js
Normal file
@ -0,0 +1,153 @@
|
||||
/**
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
var _Math = {
|
||||
|
||||
DEG2RAD: Math.PI / 180,
|
||||
RAD2DEG: 180 / Math.PI,
|
||||
|
||||
generateUUID: ( function () {
|
||||
|
||||
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
|
||||
|
||||
var lut = [];
|
||||
|
||||
for ( var i = 0; i < 256; i ++ ) {
|
||||
|
||||
lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 );
|
||||
|
||||
}
|
||||
|
||||
return function generateUUID() {
|
||||
|
||||
var d0 = Math.random() * 0xffffffff | 0;
|
||||
var d1 = Math.random() * 0xffffffff | 0;
|
||||
var d2 = Math.random() * 0xffffffff | 0;
|
||||
var d3 = Math.random() * 0xffffffff | 0;
|
||||
var uuid = lut[ d0 & 0xff ] + lut[ d0 >> 8 & 0xff ] + lut[ d0 >> 16 & 0xff ] + lut[ d0 >> 24 & 0xff ] + '-' +
|
||||
lut[ d1 & 0xff ] + lut[ d1 >> 8 & 0xff ] + '-' + lut[ d1 >> 16 & 0x0f | 0x40 ] + lut[ d1 >> 24 & 0xff ] + '-' +
|
||||
lut[ d2 & 0x3f | 0x80 ] + lut[ d2 >> 8 & 0xff ] + '-' + lut[ d2 >> 16 & 0xff ] + lut[ d2 >> 24 & 0xff ] +
|
||||
lut[ d3 & 0xff ] + lut[ d3 >> 8 & 0xff ] + lut[ d3 >> 16 & 0xff ] + lut[ d3 >> 24 & 0xff ];
|
||||
|
||||
// .toUpperCase() here flattens concatenated strings to save heap memory space.
|
||||
return uuid.toUpperCase();
|
||||
|
||||
};
|
||||
|
||||
} )(),
|
||||
|
||||
clamp: function ( value, min, max ) {
|
||||
|
||||
return Math.max( min, Math.min( max, value ) );
|
||||
|
||||
},
|
||||
|
||||
// compute euclidian modulo of m % n
|
||||
// https://en.wikipedia.org/wiki/Modulo_operation
|
||||
|
||||
euclideanModulo: function ( n, m ) {
|
||||
|
||||
return ( ( n % m ) + m ) % m;
|
||||
|
||||
},
|
||||
|
||||
// Linear mapping from range <a1, a2> to range <b1, b2>
|
||||
|
||||
mapLinear: function ( x, a1, a2, b1, b2 ) {
|
||||
|
||||
return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
|
||||
|
||||
},
|
||||
|
||||
// https://en.wikipedia.org/wiki/Linear_interpolation
|
||||
|
||||
lerp: function ( x, y, t ) {
|
||||
|
||||
return ( 1 - t ) * x + t * y;
|
||||
|
||||
},
|
||||
|
||||
// http://en.wikipedia.org/wiki/Smoothstep
|
||||
|
||||
smoothstep: function ( x, min, max ) {
|
||||
|
||||
if ( x <= min ) return 0;
|
||||
if ( x >= max ) return 1;
|
||||
|
||||
x = ( x - min ) / ( max - min );
|
||||
|
||||
return x * x * ( 3 - 2 * x );
|
||||
|
||||
},
|
||||
|
||||
smootherstep: function ( x, min, max ) {
|
||||
|
||||
if ( x <= min ) return 0;
|
||||
if ( x >= max ) return 1;
|
||||
|
||||
x = ( x - min ) / ( max - min );
|
||||
|
||||
return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
|
||||
|
||||
},
|
||||
|
||||
// Random integer from <low, high> interval
|
||||
|
||||
randInt: function ( low, high ) {
|
||||
|
||||
return low + Math.floor( Math.random() * ( high - low + 1 ) );
|
||||
|
||||
},
|
||||
|
||||
// Random float from <low, high> interval
|
||||
|
||||
randFloat: function ( low, high ) {
|
||||
|
||||
return low + Math.random() * ( high - low );
|
||||
|
||||
},
|
||||
|
||||
// Random float from <-range/2, range/2> interval
|
||||
|
||||
randFloatSpread: function ( range ) {
|
||||
|
||||
return range * ( 0.5 - Math.random() );
|
||||
|
||||
},
|
||||
|
||||
degToRad: function ( degrees ) {
|
||||
|
||||
return degrees * _Math.DEG2RAD;
|
||||
|
||||
},
|
||||
|
||||
radToDeg: function ( radians ) {
|
||||
|
||||
return radians * _Math.RAD2DEG;
|
||||
|
||||
},
|
||||
|
||||
isPowerOfTwo: function ( value ) {
|
||||
|
||||
return ( value & ( value - 1 ) ) === 0 && value !== 0;
|
||||
|
||||
},
|
||||
|
||||
ceilPowerOfTwo: function ( value ) {
|
||||
|
||||
return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
|
||||
|
||||
},
|
||||
|
||||
floorPowerOfTwo: function ( value ) {
|
||||
|
||||
return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
export { _Math };
|
388
lib/math/Matrix3.js
Normal file
388
lib/math/Matrix3.js
Normal file
@ -0,0 +1,388 @@
|
||||
import { Vector3 } from './Vector3.js';
|
||||
|
||||
/**
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author WestLangley / http://github.com/WestLangley
|
||||
* @author bhouston / http://clara.io
|
||||
* @author tschw
|
||||
*/
|
||||
|
||||
function Matrix3() {
|
||||
|
||||
this.elements = [
|
||||
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1
|
||||
|
||||
];
|
||||
|
||||
if ( arguments.length > 0 ) {
|
||||
|
||||
console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Matrix3.prototype, {
|
||||
|
||||
isMatrix3: true,
|
||||
|
||||
set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
|
||||
te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
|
||||
te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
identity: function () {
|
||||
|
||||
this.set(
|
||||
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1
|
||||
|
||||
);
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().fromArray( this.elements );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( m ) {
|
||||
|
||||
var te = this.elements;
|
||||
var me = m.elements;
|
||||
|
||||
te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
|
||||
te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
|
||||
te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromMatrix4: function ( m ) {
|
||||
|
||||
var me = m.elements;
|
||||
|
||||
this.set(
|
||||
|
||||
me[ 0 ], me[ 4 ], me[ 8 ],
|
||||
me[ 1 ], me[ 5 ], me[ 9 ],
|
||||
me[ 2 ], me[ 6 ], me[ 10 ]
|
||||
|
||||
);
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
applyToBufferAttribute: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function applyToBufferAttribute( attribute ) {
|
||||
|
||||
for ( var i = 0, l = attribute.count; i < l; i ++ ) {
|
||||
|
||||
v1.x = attribute.getX( i );
|
||||
v1.y = attribute.getY( i );
|
||||
v1.z = attribute.getZ( i );
|
||||
|
||||
v1.applyMatrix3( this );
|
||||
|
||||
attribute.setXYZ( i, v1.x, v1.y, v1.z );
|
||||
|
||||
}
|
||||
|
||||
return attribute;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
multiply: function ( m ) {
|
||||
|
||||
return this.multiplyMatrices( this, m );
|
||||
|
||||
},
|
||||
|
||||
premultiply: function ( m ) {
|
||||
|
||||
return this.multiplyMatrices( m, this );
|
||||
|
||||
},
|
||||
|
||||
multiplyMatrices: function ( a, b ) {
|
||||
|
||||
var ae = a.elements;
|
||||
var be = b.elements;
|
||||
var te = this.elements;
|
||||
|
||||
var a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
|
||||
var a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
|
||||
var a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
|
||||
|
||||
var b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
|
||||
var b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
|
||||
var b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
|
||||
|
||||
te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
|
||||
te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
|
||||
te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
|
||||
|
||||
te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
|
||||
te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
|
||||
te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
|
||||
|
||||
te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
|
||||
te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
|
||||
te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
multiplyScalar: function ( s ) {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
|
||||
te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
|
||||
te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
determinant: function () {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
|
||||
d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
|
||||
g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
|
||||
|
||||
return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
|
||||
|
||||
},
|
||||
|
||||
getInverse: function ( matrix, throwOnDegenerate ) {
|
||||
|
||||
if ( matrix && matrix.isMatrix4 ) {
|
||||
|
||||
console.error( "THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument." );
|
||||
|
||||
}
|
||||
|
||||
var me = matrix.elements,
|
||||
te = this.elements,
|
||||
|
||||
n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ],
|
||||
n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ],
|
||||
n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ],
|
||||
|
||||
t11 = n33 * n22 - n32 * n23,
|
||||
t12 = n32 * n13 - n33 * n12,
|
||||
t13 = n23 * n12 - n22 * n13,
|
||||
|
||||
det = n11 * t11 + n21 * t12 + n31 * t13;
|
||||
|
||||
if ( det === 0 ) {
|
||||
|
||||
var msg = "THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";
|
||||
|
||||
if ( throwOnDegenerate === true ) {
|
||||
|
||||
throw new Error( msg );
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( msg );
|
||||
|
||||
}
|
||||
|
||||
return this.identity();
|
||||
|
||||
}
|
||||
|
||||
var detInv = 1 / det;
|
||||
|
||||
te[ 0 ] = t11 * detInv;
|
||||
te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
|
||||
te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
|
||||
|
||||
te[ 3 ] = t12 * detInv;
|
||||
te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
|
||||
te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
|
||||
|
||||
te[ 6 ] = t13 * detInv;
|
||||
te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
|
||||
te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
transpose: function () {
|
||||
|
||||
var tmp, m = this.elements;
|
||||
|
||||
tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
|
||||
tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
|
||||
tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
getNormalMatrix: function ( matrix4 ) {
|
||||
|
||||
return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();
|
||||
|
||||
},
|
||||
|
||||
transposeIntoArray: function ( r ) {
|
||||
|
||||
var m = this.elements;
|
||||
|
||||
r[ 0 ] = m[ 0 ];
|
||||
r[ 1 ] = m[ 3 ];
|
||||
r[ 2 ] = m[ 6 ];
|
||||
r[ 3 ] = m[ 1 ];
|
||||
r[ 4 ] = m[ 4 ];
|
||||
r[ 5 ] = m[ 7 ];
|
||||
r[ 6 ] = m[ 2 ];
|
||||
r[ 7 ] = m[ 5 ];
|
||||
r[ 8 ] = m[ 8 ];
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setUvTransform: function ( tx, ty, sx, sy, rotation, cx, cy ) {
|
||||
|
||||
var c = Math.cos( rotation );
|
||||
var s = Math.sin( rotation );
|
||||
|
||||
this.set(
|
||||
sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
|
||||
- sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
|
||||
0, 0, 1
|
||||
);
|
||||
|
||||
},
|
||||
|
||||
scale: function ( sx, sy ) {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx;
|
||||
te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
rotate: function ( theta ) {
|
||||
|
||||
var c = Math.cos( theta );
|
||||
var s = Math.sin( theta );
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
var a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ];
|
||||
var a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ];
|
||||
|
||||
te[ 0 ] = c * a11 + s * a21;
|
||||
te[ 3 ] = c * a12 + s * a22;
|
||||
te[ 6 ] = c * a13 + s * a23;
|
||||
|
||||
te[ 1 ] = - s * a11 + c * a21;
|
||||
te[ 4 ] = - s * a12 + c * a22;
|
||||
te[ 7 ] = - s * a13 + c * a23;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
translate: function ( tx, ty ) {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
te[ 0 ] += tx * te[ 2 ]; te[ 3 ] += tx * te[ 5 ]; te[ 6 ] += tx * te[ 8 ];
|
||||
te[ 1 ] += ty * te[ 2 ]; te[ 4 ] += ty * te[ 5 ]; te[ 7 ] += ty * te[ 8 ];
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
equals: function ( matrix ) {
|
||||
|
||||
var te = this.elements;
|
||||
var me = matrix.elements;
|
||||
|
||||
for ( var i = 0; i < 9; i ++ ) {
|
||||
|
||||
if ( te[ i ] !== me[ i ] ) return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
},
|
||||
|
||||
fromArray: function ( array, offset ) {
|
||||
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
for ( var i = 0; i < 9; i ++ ) {
|
||||
|
||||
this.elements[ i ] = array[ i + offset ];
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
toArray: function ( array, offset ) {
|
||||
|
||||
if ( array === undefined ) array = [];
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
array[ offset ] = te[ 0 ];
|
||||
array[ offset + 1 ] = te[ 1 ];
|
||||
array[ offset + 2 ] = te[ 2 ];
|
||||
|
||||
array[ offset + 3 ] = te[ 3 ];
|
||||
array[ offset + 4 ] = te[ 4 ];
|
||||
array[ offset + 5 ] = te[ 5 ];
|
||||
|
||||
array[ offset + 6 ] = te[ 6 ];
|
||||
array[ offset + 7 ] = te[ 7 ];
|
||||
array[ offset + 8 ] = te[ 8 ];
|
||||
|
||||
return array;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Matrix3 };
|
938
lib/math/Matrix4.js
Normal file
938
lib/math/Matrix4.js
Normal file
@ -0,0 +1,938 @@
|
||||
import { Vector3 } from './Vector3.js';
|
||||
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
* @author supereggbert / http://www.paulbrunt.co.uk/
|
||||
* @author philogb / http://blog.thejit.org/
|
||||
* @author jordi_ros / http://plattsoft.com
|
||||
* @author D1plo1d / http://github.com/D1plo1d
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author mikael emtinger / http://gomo.se/
|
||||
* @author timknip / http://www.floorplanner.com/
|
||||
* @author bhouston / http://clara.io
|
||||
* @author WestLangley / http://github.com/WestLangley
|
||||
*/
|
||||
|
||||
function Matrix4() {
|
||||
|
||||
this.elements = [
|
||||
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
|
||||
];
|
||||
|
||||
if ( arguments.length > 0 ) {
|
||||
|
||||
console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Matrix4.prototype, {
|
||||
|
||||
isMatrix4: true,
|
||||
|
||||
set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
|
||||
te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
|
||||
te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
|
||||
te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
identity: function () {
|
||||
|
||||
this.set(
|
||||
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
|
||||
);
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new Matrix4().fromArray( this.elements );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( m ) {
|
||||
|
||||
var te = this.elements;
|
||||
var me = m.elements;
|
||||
|
||||
te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
|
||||
te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
|
||||
te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
|
||||
te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
copyPosition: function ( m ) {
|
||||
|
||||
var te = this.elements, me = m.elements;
|
||||
|
||||
te[ 12 ] = me[ 12 ];
|
||||
te[ 13 ] = me[ 13 ];
|
||||
te[ 14 ] = me[ 14 ];
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
extractBasis: function ( xAxis, yAxis, zAxis ) {
|
||||
|
||||
xAxis.setFromMatrixColumn( this, 0 );
|
||||
yAxis.setFromMatrixColumn( this, 1 );
|
||||
zAxis.setFromMatrixColumn( this, 2 );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
makeBasis: function ( xAxis, yAxis, zAxis ) {
|
||||
|
||||
this.set(
|
||||
xAxis.x, yAxis.x, zAxis.x, 0,
|
||||
xAxis.y, yAxis.y, zAxis.y, 0,
|
||||
xAxis.z, yAxis.z, zAxis.z, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
extractRotation: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function extractRotation( m ) {
|
||||
|
||||
// this method does not support reflection matrices
|
||||
|
||||
var te = this.elements;
|
||||
var me = m.elements;
|
||||
|
||||
var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();
|
||||
var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();
|
||||
var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length();
|
||||
|
||||
te[ 0 ] = me[ 0 ] * scaleX;
|
||||
te[ 1 ] = me[ 1 ] * scaleX;
|
||||
te[ 2 ] = me[ 2 ] * scaleX;
|
||||
te[ 3 ] = 0;
|
||||
|
||||
te[ 4 ] = me[ 4 ] * scaleY;
|
||||
te[ 5 ] = me[ 5 ] * scaleY;
|
||||
te[ 6 ] = me[ 6 ] * scaleY;
|
||||
te[ 7 ] = 0;
|
||||
|
||||
te[ 8 ] = me[ 8 ] * scaleZ;
|
||||
te[ 9 ] = me[ 9 ] * scaleZ;
|
||||
te[ 10 ] = me[ 10 ] * scaleZ;
|
||||
te[ 11 ] = 0;
|
||||
|
||||
te[ 12 ] = 0;
|
||||
te[ 13 ] = 0;
|
||||
te[ 14 ] = 0;
|
||||
te[ 15 ] = 1;
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
makeRotationFromEuler: function ( euler ) {
|
||||
|
||||
if ( ! ( euler && euler.isEuler ) ) {
|
||||
|
||||
console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
|
||||
|
||||
}
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
var x = euler.x, y = euler.y, z = euler.z;
|
||||
var a = Math.cos( x ), b = Math.sin( x );
|
||||
var c = Math.cos( y ), d = Math.sin( y );
|
||||
var e = Math.cos( z ), f = Math.sin( z );
|
||||
|
||||
if ( euler.order === 'XYZ' ) {
|
||||
|
||||
var ae = a * e, af = a * f, be = b * e, bf = b * f;
|
||||
|
||||
te[ 0 ] = c * e;
|
||||
te[ 4 ] = - c * f;
|
||||
te[ 8 ] = d;
|
||||
|
||||
te[ 1 ] = af + be * d;
|
||||
te[ 5 ] = ae - bf * d;
|
||||
te[ 9 ] = - b * c;
|
||||
|
||||
te[ 2 ] = bf - ae * d;
|
||||
te[ 6 ] = be + af * d;
|
||||
te[ 10 ] = a * c;
|
||||
|
||||
} else if ( euler.order === 'YXZ' ) {
|
||||
|
||||
var ce = c * e, cf = c * f, de = d * e, df = d * f;
|
||||
|
||||
te[ 0 ] = ce + df * b;
|
||||
te[ 4 ] = de * b - cf;
|
||||
te[ 8 ] = a * d;
|
||||
|
||||
te[ 1 ] = a * f;
|
||||
te[ 5 ] = a * e;
|
||||
te[ 9 ] = - b;
|
||||
|
||||
te[ 2 ] = cf * b - de;
|
||||
te[ 6 ] = df + ce * b;
|
||||
te[ 10 ] = a * c;
|
||||
|
||||
} else if ( euler.order === 'ZXY' ) {
|
||||
|
||||
var ce = c * e, cf = c * f, de = d * e, df = d * f;
|
||||
|
||||
te[ 0 ] = ce - df * b;
|
||||
te[ 4 ] = - a * f;
|
||||
te[ 8 ] = de + cf * b;
|
||||
|
||||
te[ 1 ] = cf + de * b;
|
||||
te[ 5 ] = a * e;
|
||||
te[ 9 ] = df - ce * b;
|
||||
|
||||
te[ 2 ] = - a * d;
|
||||
te[ 6 ] = b;
|
||||
te[ 10 ] = a * c;
|
||||
|
||||
} else if ( euler.order === 'ZYX' ) {
|
||||
|
||||
var ae = a * e, af = a * f, be = b * e, bf = b * f;
|
||||
|
||||
te[ 0 ] = c * e;
|
||||
te[ 4 ] = be * d - af;
|
||||
te[ 8 ] = ae * d + bf;
|
||||
|
||||
te[ 1 ] = c * f;
|
||||
te[ 5 ] = bf * d + ae;
|
||||
te[ 9 ] = af * d - be;
|
||||
|
||||
te[ 2 ] = - d;
|
||||
te[ 6 ] = b * c;
|
||||
te[ 10 ] = a * c;
|
||||
|
||||
} else if ( euler.order === 'YZX' ) {
|
||||
|
||||
var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
|
||||
|
||||
te[ 0 ] = c * e;
|
||||
te[ 4 ] = bd - ac * f;
|
||||
te[ 8 ] = bc * f + ad;
|
||||
|
||||
te[ 1 ] = f;
|
||||
te[ 5 ] = a * e;
|
||||
te[ 9 ] = - b * e;
|
||||
|
||||
te[ 2 ] = - d * e;
|
||||
te[ 6 ] = ad * f + bc;
|
||||
te[ 10 ] = ac - bd * f;
|
||||
|
||||
} else if ( euler.order === 'XZY' ) {
|
||||
|
||||
var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
|
||||
|
||||
te[ 0 ] = c * e;
|
||||
te[ 4 ] = - f;
|
||||
te[ 8 ] = d * e;
|
||||
|
||||
te[ 1 ] = ac * f + bd;
|
||||
te[ 5 ] = a * e;
|
||||
te[ 9 ] = ad * f - bc;
|
||||
|
||||
te[ 2 ] = bc * f - ad;
|
||||
te[ 6 ] = b * e;
|
||||
te[ 10 ] = bd * f + ac;
|
||||
|
||||
}
|
||||
|
||||
// bottom row
|
||||
te[ 3 ] = 0;
|
||||
te[ 7 ] = 0;
|
||||
te[ 11 ] = 0;
|
||||
|
||||
// last column
|
||||
te[ 12 ] = 0;
|
||||
te[ 13 ] = 0;
|
||||
te[ 14 ] = 0;
|
||||
te[ 15 ] = 1;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
makeRotationFromQuaternion: function () {
|
||||
|
||||
var zero = new Vector3( 0, 0, 0 );
|
||||
var one = new Vector3( 1, 1, 1 );
|
||||
|
||||
return function makeRotationFromQuaternion( q ) {
|
||||
|
||||
return this.compose( zero, q, one );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
lookAt: function () {
|
||||
|
||||
var x = new Vector3();
|
||||
var y = new Vector3();
|
||||
var z = new Vector3();
|
||||
|
||||
return function lookAt( eye, target, up ) {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
z.subVectors( eye, target );
|
||||
|
||||
if ( z.lengthSq() === 0 ) {
|
||||
|
||||
// eye and target are in the same position
|
||||
|
||||
z.z = 1;
|
||||
|
||||
}
|
||||
|
||||
z.normalize();
|
||||
x.crossVectors( up, z );
|
||||
|
||||
if ( x.lengthSq() === 0 ) {
|
||||
|
||||
// up and z are parallel
|
||||
|
||||
if ( Math.abs( up.z ) === 1 ) {
|
||||
|
||||
z.x += 0.0001;
|
||||
|
||||
} else {
|
||||
|
||||
z.z += 0.0001;
|
||||
|
||||
}
|
||||
|
||||
z.normalize();
|
||||
x.crossVectors( up, z );
|
||||
|
||||
}
|
||||
|
||||
x.normalize();
|
||||
y.crossVectors( z, x );
|
||||
|
||||
te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
|
||||
te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
|
||||
te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
multiply: function ( m, n ) {
|
||||
|
||||
if ( n !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
|
||||
return this.multiplyMatrices( m, n );
|
||||
|
||||
}
|
||||
|
||||
return this.multiplyMatrices( this, m );
|
||||
|
||||
},
|
||||
|
||||
premultiply: function ( m ) {
|
||||
|
||||
return this.multiplyMatrices( m, this );
|
||||
|
||||
},
|
||||
|
||||
multiplyMatrices: function ( a, b ) {
|
||||
|
||||
var ae = a.elements;
|
||||
var be = b.elements;
|
||||
var te = this.elements;
|
||||
|
||||
var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
|
||||
var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
|
||||
var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
|
||||
var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
|
||||
|
||||
var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
|
||||
var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
|
||||
var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
|
||||
var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
|
||||
|
||||
te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
|
||||
te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
|
||||
te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
|
||||
te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
|
||||
|
||||
te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
|
||||
te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
|
||||
te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
|
||||
te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
|
||||
|
||||
te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
|
||||
te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
|
||||
te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
|
||||
te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
|
||||
|
||||
te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
|
||||
te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
|
||||
te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
|
||||
te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
multiplyScalar: function ( s ) {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
|
||||
te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
|
||||
te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
|
||||
te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
applyToBufferAttribute: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function applyToBufferAttribute( attribute ) {
|
||||
|
||||
for ( var i = 0, l = attribute.count; i < l; i ++ ) {
|
||||
|
||||
v1.x = attribute.getX( i );
|
||||
v1.y = attribute.getY( i );
|
||||
v1.z = attribute.getZ( i );
|
||||
|
||||
v1.applyMatrix4( this );
|
||||
|
||||
attribute.setXYZ( i, v1.x, v1.y, v1.z );
|
||||
|
||||
}
|
||||
|
||||
return attribute;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
determinant: function () {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
|
||||
var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
|
||||
var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
|
||||
var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
|
||||
|
||||
//TODO: make this more efficient
|
||||
//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
|
||||
|
||||
return (
|
||||
n41 * (
|
||||
+ n14 * n23 * n32
|
||||
- n13 * n24 * n32
|
||||
- n14 * n22 * n33
|
||||
+ n12 * n24 * n33
|
||||
+ n13 * n22 * n34
|
||||
- n12 * n23 * n34
|
||||
) +
|
||||
n42 * (
|
||||
+ n11 * n23 * n34
|
||||
- n11 * n24 * n33
|
||||
+ n14 * n21 * n33
|
||||
- n13 * n21 * n34
|
||||
+ n13 * n24 * n31
|
||||
- n14 * n23 * n31
|
||||
) +
|
||||
n43 * (
|
||||
+ n11 * n24 * n32
|
||||
- n11 * n22 * n34
|
||||
- n14 * n21 * n32
|
||||
+ n12 * n21 * n34
|
||||
+ n14 * n22 * n31
|
||||
- n12 * n24 * n31
|
||||
) +
|
||||
n44 * (
|
||||
- n13 * n22 * n31
|
||||
- n11 * n23 * n32
|
||||
+ n11 * n22 * n33
|
||||
+ n13 * n21 * n32
|
||||
- n12 * n21 * n33
|
||||
+ n12 * n23 * n31
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
},
|
||||
|
||||
transpose: function () {
|
||||
|
||||
var te = this.elements;
|
||||
var tmp;
|
||||
|
||||
tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
|
||||
tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
|
||||
tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
|
||||
|
||||
tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
|
||||
tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
|
||||
tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setPosition: function ( v ) {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
te[ 12 ] = v.x;
|
||||
te[ 13 ] = v.y;
|
||||
te[ 14 ] = v.z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
getInverse: function ( m, throwOnDegenerate ) {
|
||||
|
||||
// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
|
||||
var te = this.elements,
|
||||
me = m.elements,
|
||||
|
||||
n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ],
|
||||
n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ],
|
||||
n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ],
|
||||
n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ],
|
||||
|
||||
t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
|
||||
t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
|
||||
t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
|
||||
t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
|
||||
|
||||
var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
|
||||
|
||||
if ( det === 0 ) {
|
||||
|
||||
var msg = "THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0";
|
||||
|
||||
if ( throwOnDegenerate === true ) {
|
||||
|
||||
throw new Error( msg );
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( msg );
|
||||
|
||||
}
|
||||
|
||||
return this.identity();
|
||||
|
||||
}
|
||||
|
||||
var detInv = 1 / det;
|
||||
|
||||
te[ 0 ] = t11 * detInv;
|
||||
te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
|
||||
te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
|
||||
te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
|
||||
|
||||
te[ 4 ] = t12 * detInv;
|
||||
te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
|
||||
te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
|
||||
te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
|
||||
|
||||
te[ 8 ] = t13 * detInv;
|
||||
te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
|
||||
te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
|
||||
te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
|
||||
|
||||
te[ 12 ] = t14 * detInv;
|
||||
te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
|
||||
te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
|
||||
te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
scale: function ( v ) {
|
||||
|
||||
var te = this.elements;
|
||||
var x = v.x, y = v.y, z = v.z;
|
||||
|
||||
te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
|
||||
te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
|
||||
te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
|
||||
te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
getMaxScaleOnAxis: function () {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
|
||||
var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
|
||||
var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
|
||||
|
||||
return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
|
||||
|
||||
},
|
||||
|
||||
makeTranslation: function ( x, y, z ) {
|
||||
|
||||
this.set(
|
||||
|
||||
1, 0, 0, x,
|
||||
0, 1, 0, y,
|
||||
0, 0, 1, z,
|
||||
0, 0, 0, 1
|
||||
|
||||
);
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
makeRotationX: function ( theta ) {
|
||||
|
||||
var c = Math.cos( theta ), s = Math.sin( theta );
|
||||
|
||||
this.set(
|
||||
|
||||
1, 0, 0, 0,
|
||||
0, c, - s, 0,
|
||||
0, s, c, 0,
|
||||
0, 0, 0, 1
|
||||
|
||||
);
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
makeRotationY: function ( theta ) {
|
||||
|
||||
var c = Math.cos( theta ), s = Math.sin( theta );
|
||||
|
||||
this.set(
|
||||
|
||||
c, 0, s, 0,
|
||||
0, 1, 0, 0,
|
||||
- s, 0, c, 0,
|
||||
0, 0, 0, 1
|
||||
|
||||
);
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
makeRotationZ: function ( theta ) {
|
||||
|
||||
var c = Math.cos( theta ), s = Math.sin( theta );
|
||||
|
||||
this.set(
|
||||
|
||||
c, - s, 0, 0,
|
||||
s, c, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
|
||||
);
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
makeRotationAxis: function ( axis, angle ) {
|
||||
|
||||
// Based on http://www.gamedev.net/reference/articles/article1199.asp
|
||||
|
||||
var c = Math.cos( angle );
|
||||
var s = Math.sin( angle );
|
||||
var t = 1 - c;
|
||||
var x = axis.x, y = axis.y, z = axis.z;
|
||||
var tx = t * x, ty = t * y;
|
||||
|
||||
this.set(
|
||||
|
||||
tx * x + c, tx * y - s * z, tx * z + s * y, 0,
|
||||
tx * y + s * z, ty * y + c, ty * z - s * x, 0,
|
||||
tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
|
||||
0, 0, 0, 1
|
||||
|
||||
);
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
makeScale: function ( x, y, z ) {
|
||||
|
||||
this.set(
|
||||
|
||||
x, 0, 0, 0,
|
||||
0, y, 0, 0,
|
||||
0, 0, z, 0,
|
||||
0, 0, 0, 1
|
||||
|
||||
);
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
makeShear: function ( x, y, z ) {
|
||||
|
||||
this.set(
|
||||
|
||||
1, y, z, 0,
|
||||
x, 1, z, 0,
|
||||
x, y, 1, 0,
|
||||
0, 0, 0, 1
|
||||
|
||||
);
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
compose: function ( position, quaternion, scale ) {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
var x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
|
||||
var x2 = x + x, y2 = y + y, z2 = z + z;
|
||||
var xx = x * x2, xy = x * y2, xz = x * z2;
|
||||
var yy = y * y2, yz = y * z2, zz = z * z2;
|
||||
var wx = w * x2, wy = w * y2, wz = w * z2;
|
||||
|
||||
var sx = scale.x, sy = scale.y, sz = scale.z;
|
||||
|
||||
te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
|
||||
te[ 1 ] = ( xy + wz ) * sx;
|
||||
te[ 2 ] = ( xz - wy ) * sx;
|
||||
te[ 3 ] = 0;
|
||||
|
||||
te[ 4 ] = ( xy - wz ) * sy;
|
||||
te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
|
||||
te[ 6 ] = ( yz + wx ) * sy;
|
||||
te[ 7 ] = 0;
|
||||
|
||||
te[ 8 ] = ( xz + wy ) * sz;
|
||||
te[ 9 ] = ( yz - wx ) * sz;
|
||||
te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
|
||||
te[ 11 ] = 0;
|
||||
|
||||
te[ 12 ] = position.x;
|
||||
te[ 13 ] = position.y;
|
||||
te[ 14 ] = position.z;
|
||||
te[ 15 ] = 1;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
decompose: function () {
|
||||
|
||||
var vector = new Vector3();
|
||||
var matrix = new Matrix4();
|
||||
|
||||
return function decompose( position, quaternion, scale ) {
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
|
||||
var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
|
||||
var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
|
||||
|
||||
// if determine is negative, we need to invert one scale
|
||||
var det = this.determinant();
|
||||
if ( det < 0 ) sx = - sx;
|
||||
|
||||
position.x = te[ 12 ];
|
||||
position.y = te[ 13 ];
|
||||
position.z = te[ 14 ];
|
||||
|
||||
// scale the rotation part
|
||||
matrix.copy( this );
|
||||
|
||||
var invSX = 1 / sx;
|
||||
var invSY = 1 / sy;
|
||||
var invSZ = 1 / sz;
|
||||
|
||||
matrix.elements[ 0 ] *= invSX;
|
||||
matrix.elements[ 1 ] *= invSX;
|
||||
matrix.elements[ 2 ] *= invSX;
|
||||
|
||||
matrix.elements[ 4 ] *= invSY;
|
||||
matrix.elements[ 5 ] *= invSY;
|
||||
matrix.elements[ 6 ] *= invSY;
|
||||
|
||||
matrix.elements[ 8 ] *= invSZ;
|
||||
matrix.elements[ 9 ] *= invSZ;
|
||||
matrix.elements[ 10 ] *= invSZ;
|
||||
|
||||
quaternion.setFromRotationMatrix( matrix );
|
||||
|
||||
scale.x = sx;
|
||||
scale.y = sy;
|
||||
scale.z = sz;
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
makePerspective: function ( left, right, top, bottom, near, far ) {
|
||||
|
||||
if ( far === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
|
||||
|
||||
}
|
||||
|
||||
var te = this.elements;
|
||||
var x = 2 * near / ( right - left );
|
||||
var y = 2 * near / ( top - bottom );
|
||||
|
||||
var a = ( right + left ) / ( right - left );
|
||||
var b = ( top + bottom ) / ( top - bottom );
|
||||
var c = - ( far + near ) / ( far - near );
|
||||
var d = - 2 * far * near / ( far - near );
|
||||
|
||||
te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0;
|
||||
te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0;
|
||||
te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d;
|
||||
te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
makeOrthographic: function ( left, right, top, bottom, near, far ) {
|
||||
|
||||
var te = this.elements;
|
||||
var w = 1.0 / ( right - left );
|
||||
var h = 1.0 / ( top - bottom );
|
||||
var p = 1.0 / ( far - near );
|
||||
|
||||
var x = ( right + left ) * w;
|
||||
var y = ( top + bottom ) * h;
|
||||
var z = ( far + near ) * p;
|
||||
|
||||
te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
|
||||
te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y;
|
||||
te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z;
|
||||
te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
equals: function ( matrix ) {
|
||||
|
||||
var te = this.elements;
|
||||
var me = matrix.elements;
|
||||
|
||||
for ( var i = 0; i < 16; i ++ ) {
|
||||
|
||||
if ( te[ i ] !== me[ i ] ) return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
},
|
||||
|
||||
fromArray: function ( array, offset ) {
|
||||
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
for ( var i = 0; i < 16; i ++ ) {
|
||||
|
||||
this.elements[ i ] = array[ i + offset ];
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
toArray: function ( array, offset ) {
|
||||
|
||||
if ( array === undefined ) array = [];
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
var te = this.elements;
|
||||
|
||||
array[ offset ] = te[ 0 ];
|
||||
array[ offset + 1 ] = te[ 1 ];
|
||||
array[ offset + 2 ] = te[ 2 ];
|
||||
array[ offset + 3 ] = te[ 3 ];
|
||||
|
||||
array[ offset + 4 ] = te[ 4 ];
|
||||
array[ offset + 5 ] = te[ 5 ];
|
||||
array[ offset + 6 ] = te[ 6 ];
|
||||
array[ offset + 7 ] = te[ 7 ];
|
||||
|
||||
array[ offset + 8 ] = te[ 8 ];
|
||||
array[ offset + 9 ] = te[ 9 ];
|
||||
array[ offset + 10 ] = te[ 10 ];
|
||||
array[ offset + 11 ] = te[ 11 ];
|
||||
|
||||
array[ offset + 12 ] = te[ 12 ];
|
||||
array[ offset + 13 ] = te[ 13 ];
|
||||
array[ offset + 14 ] = te[ 14 ];
|
||||
array[ offset + 15 ] = te[ 15 ];
|
||||
|
||||
return array;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Matrix4 };
|
245
lib/math/Plane.js
Normal file
245
lib/math/Plane.js
Normal file
@ -0,0 +1,245 @@
|
||||
import { Matrix3 } from './Matrix3.js';
|
||||
import { Vector3 } from './Vector3.js';
|
||||
|
||||
/**
|
||||
* @author bhouston / http://clara.io
|
||||
*/
|
||||
|
||||
function Plane( normal, constant ) {
|
||||
|
||||
// normal is assumed to be normalized
|
||||
|
||||
this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );
|
||||
this.constant = ( constant !== undefined ) ? constant : 0;
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Plane.prototype, {
|
||||
|
||||
set: function ( normal, constant ) {
|
||||
|
||||
this.normal.copy( normal );
|
||||
this.constant = constant;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setComponents: function ( x, y, z, w ) {
|
||||
|
||||
this.normal.set( x, y, z );
|
||||
this.constant = w;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromNormalAndCoplanarPoint: function ( normal, point ) {
|
||||
|
||||
this.normal.copy( normal );
|
||||
this.constant = - point.dot( this.normal );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromCoplanarPoints: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
var v2 = new Vector3();
|
||||
|
||||
return function setFromCoplanarPoints( a, b, c ) {
|
||||
|
||||
var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize();
|
||||
|
||||
// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
|
||||
|
||||
this.setFromNormalAndCoplanarPoint( normal, a );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( plane ) {
|
||||
|
||||
this.normal.copy( plane.normal );
|
||||
this.constant = plane.constant;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
normalize: function () {
|
||||
|
||||
// Note: will lead to a divide by zero if the plane is invalid.
|
||||
|
||||
var inverseNormalLength = 1.0 / this.normal.length();
|
||||
this.normal.multiplyScalar( inverseNormalLength );
|
||||
this.constant *= inverseNormalLength;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
negate: function () {
|
||||
|
||||
this.constant *= - 1;
|
||||
this.normal.negate();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
distanceToPoint: function ( point ) {
|
||||
|
||||
return this.normal.dot( point ) + this.constant;
|
||||
|
||||
},
|
||||
|
||||
distanceToSphere: function ( sphere ) {
|
||||
|
||||
return this.distanceToPoint( sphere.center ) - sphere.radius;
|
||||
|
||||
},
|
||||
|
||||
projectPoint: function ( point, target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Plane: .projectPoint() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point );
|
||||
|
||||
},
|
||||
|
||||
intersectLine: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function intersectLine( line, target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Plane: .intersectLine() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
var direction = line.delta( v1 );
|
||||
|
||||
var denominator = this.normal.dot( direction );
|
||||
|
||||
if ( denominator === 0 ) {
|
||||
|
||||
// line is coplanar, return origin
|
||||
if ( this.distanceToPoint( line.start ) === 0 ) {
|
||||
|
||||
return target.copy( line.start );
|
||||
|
||||
}
|
||||
|
||||
// Unsure if this is the correct method to handle this case.
|
||||
return undefined;
|
||||
|
||||
}
|
||||
|
||||
var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
|
||||
|
||||
if ( t < 0 || t > 1 ) {
|
||||
|
||||
return undefined;
|
||||
|
||||
}
|
||||
|
||||
return target.copy( direction ).multiplyScalar( t ).add( line.start );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
intersectsLine: function ( line ) {
|
||||
|
||||
// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
|
||||
|
||||
var startSign = this.distanceToPoint( line.start );
|
||||
var endSign = this.distanceToPoint( line.end );
|
||||
|
||||
return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
|
||||
|
||||
},
|
||||
|
||||
intersectsBox: function ( box ) {
|
||||
|
||||
return box.intersectsPlane( this );
|
||||
|
||||
},
|
||||
|
||||
intersectsSphere: function ( sphere ) {
|
||||
|
||||
return sphere.intersectsPlane( this );
|
||||
|
||||
},
|
||||
|
||||
coplanarPoint: function ( target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Plane: .coplanarPoint() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return target.copy( this.normal ).multiplyScalar( - this.constant );
|
||||
|
||||
},
|
||||
|
||||
applyMatrix4: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
var m1 = new Matrix3();
|
||||
|
||||
return function applyMatrix4( matrix, optionalNormalMatrix ) {
|
||||
|
||||
var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );
|
||||
|
||||
var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix );
|
||||
|
||||
var normal = this.normal.applyMatrix3( normalMatrix ).normalize();
|
||||
|
||||
this.constant = - referencePoint.dot( normal );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
translate: function ( offset ) {
|
||||
|
||||
this.constant -= offset.dot( this.normal );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
equals: function ( plane ) {
|
||||
|
||||
return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Plane };
|
637
lib/math/Quaternion.js
Normal file
637
lib/math/Quaternion.js
Normal file
@ -0,0 +1,637 @@
|
||||
/**
|
||||
* @author mikael emtinger / http://gomo.se/
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author WestLangley / http://github.com/WestLangley
|
||||
* @author bhouston / http://clara.io
|
||||
*/
|
||||
|
||||
import { _Math } from './Math.js';
|
||||
import { Vector3 } from './Vector3.js';
|
||||
|
||||
function Quaternion( x, y, z, w ) {
|
||||
|
||||
this._x = x || 0;
|
||||
this._y = y || 0;
|
||||
this._z = z || 0;
|
||||
this._w = ( w !== undefined ) ? w : 1;
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Quaternion, {
|
||||
|
||||
slerp: function ( qa, qb, qm, t ) {
|
||||
|
||||
return qm.copy( qa ).slerp( qb, t );
|
||||
|
||||
},
|
||||
|
||||
slerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
|
||||
|
||||
// fuzz-free, array-based Quaternion SLERP operation
|
||||
|
||||
var x0 = src0[ srcOffset0 + 0 ],
|
||||
y0 = src0[ srcOffset0 + 1 ],
|
||||
z0 = src0[ srcOffset0 + 2 ],
|
||||
w0 = src0[ srcOffset0 + 3 ],
|
||||
|
||||
x1 = src1[ srcOffset1 + 0 ],
|
||||
y1 = src1[ srcOffset1 + 1 ],
|
||||
z1 = src1[ srcOffset1 + 2 ],
|
||||
w1 = src1[ srcOffset1 + 3 ];
|
||||
|
||||
if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
|
||||
|
||||
var s = 1 - t,
|
||||
|
||||
cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
|
||||
|
||||
dir = ( cos >= 0 ? 1 : - 1 ),
|
||||
sqrSin = 1 - cos * cos;
|
||||
|
||||
// Skip the Slerp for tiny steps to avoid numeric problems:
|
||||
if ( sqrSin > Number.EPSILON ) {
|
||||
|
||||
var sin = Math.sqrt( sqrSin ),
|
||||
len = Math.atan2( sin, cos * dir );
|
||||
|
||||
s = Math.sin( s * len ) / sin;
|
||||
t = Math.sin( t * len ) / sin;
|
||||
|
||||
}
|
||||
|
||||
var tDir = t * dir;
|
||||
|
||||
x0 = x0 * s + x1 * tDir;
|
||||
y0 = y0 * s + y1 * tDir;
|
||||
z0 = z0 * s + z1 * tDir;
|
||||
w0 = w0 * s + w1 * tDir;
|
||||
|
||||
// Normalize in case we just did a lerp:
|
||||
if ( s === 1 - t ) {
|
||||
|
||||
var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
|
||||
|
||||
x0 *= f;
|
||||
y0 *= f;
|
||||
z0 *= f;
|
||||
w0 *= f;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dst[ dstOffset ] = x0;
|
||||
dst[ dstOffset + 1 ] = y0;
|
||||
dst[ dstOffset + 2 ] = z0;
|
||||
dst[ dstOffset + 3 ] = w0;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
Object.defineProperties( Quaternion.prototype, {
|
||||
|
||||
x: {
|
||||
|
||||
get: function () {
|
||||
|
||||
return this._x;
|
||||
|
||||
},
|
||||
|
||||
set: function ( value ) {
|
||||
|
||||
this._x = value;
|
||||
this.onChangeCallback();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
y: {
|
||||
|
||||
get: function () {
|
||||
|
||||
return this._y;
|
||||
|
||||
},
|
||||
|
||||
set: function ( value ) {
|
||||
|
||||
this._y = value;
|
||||
this.onChangeCallback();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
z: {
|
||||
|
||||
get: function () {
|
||||
|
||||
return this._z;
|
||||
|
||||
},
|
||||
|
||||
set: function ( value ) {
|
||||
|
||||
this._z = value;
|
||||
this.onChangeCallback();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
w: {
|
||||
|
||||
get: function () {
|
||||
|
||||
return this._w;
|
||||
|
||||
},
|
||||
|
||||
set: function ( value ) {
|
||||
|
||||
this._w = value;
|
||||
this.onChangeCallback();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
Object.assign( Quaternion.prototype, {
|
||||
|
||||
isQuaternion: true,
|
||||
|
||||
set: function ( x, y, z, w ) {
|
||||
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._z = z;
|
||||
this._w = w;
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor( this._x, this._y, this._z, this._w );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( quaternion ) {
|
||||
|
||||
this._x = quaternion.x;
|
||||
this._y = quaternion.y;
|
||||
this._z = quaternion.z;
|
||||
this._w = quaternion.w;
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromEuler: function ( euler, update ) {
|
||||
|
||||
if ( ! ( euler && euler.isEuler ) ) {
|
||||
|
||||
throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
|
||||
|
||||
}
|
||||
|
||||
var x = euler._x, y = euler._y, z = euler._z, order = euler.order;
|
||||
|
||||
// http://www.mathworks.com/matlabcentral/fileexchange/
|
||||
// 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
|
||||
// content/SpinCalc.m
|
||||
|
||||
var cos = Math.cos;
|
||||
var sin = Math.sin;
|
||||
|
||||
var c1 = cos( x / 2 );
|
||||
var c2 = cos( y / 2 );
|
||||
var c3 = cos( z / 2 );
|
||||
|
||||
var s1 = sin( x / 2 );
|
||||
var s2 = sin( y / 2 );
|
||||
var s3 = sin( z / 2 );
|
||||
|
||||
if ( order === 'XYZ' ) {
|
||||
|
||||
this._x = s1 * c2 * c3 + c1 * s2 * s3;
|
||||
this._y = c1 * s2 * c3 - s1 * c2 * s3;
|
||||
this._z = c1 * c2 * s3 + s1 * s2 * c3;
|
||||
this._w = c1 * c2 * c3 - s1 * s2 * s3;
|
||||
|
||||
} else if ( order === 'YXZ' ) {
|
||||
|
||||
this._x = s1 * c2 * c3 + c1 * s2 * s3;
|
||||
this._y = c1 * s2 * c3 - s1 * c2 * s3;
|
||||
this._z = c1 * c2 * s3 - s1 * s2 * c3;
|
||||
this._w = c1 * c2 * c3 + s1 * s2 * s3;
|
||||
|
||||
} else if ( order === 'ZXY' ) {
|
||||
|
||||
this._x = s1 * c2 * c3 - c1 * s2 * s3;
|
||||
this._y = c1 * s2 * c3 + s1 * c2 * s3;
|
||||
this._z = c1 * c2 * s3 + s1 * s2 * c3;
|
||||
this._w = c1 * c2 * c3 - s1 * s2 * s3;
|
||||
|
||||
} else if ( order === 'ZYX' ) {
|
||||
|
||||
this._x = s1 * c2 * c3 - c1 * s2 * s3;
|
||||
this._y = c1 * s2 * c3 + s1 * c2 * s3;
|
||||
this._z = c1 * c2 * s3 - s1 * s2 * c3;
|
||||
this._w = c1 * c2 * c3 + s1 * s2 * s3;
|
||||
|
||||
} else if ( order === 'YZX' ) {
|
||||
|
||||
this._x = s1 * c2 * c3 + c1 * s2 * s3;
|
||||
this._y = c1 * s2 * c3 + s1 * c2 * s3;
|
||||
this._z = c1 * c2 * s3 - s1 * s2 * c3;
|
||||
this._w = c1 * c2 * c3 - s1 * s2 * s3;
|
||||
|
||||
} else if ( order === 'XZY' ) {
|
||||
|
||||
this._x = s1 * c2 * c3 - c1 * s2 * s3;
|
||||
this._y = c1 * s2 * c3 - s1 * c2 * s3;
|
||||
this._z = c1 * c2 * s3 + s1 * s2 * c3;
|
||||
this._w = c1 * c2 * c3 + s1 * s2 * s3;
|
||||
|
||||
}
|
||||
|
||||
if ( update !== false ) this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromAxisAngle: function ( axis, angle ) {
|
||||
|
||||
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
|
||||
|
||||
// assumes axis is normalized
|
||||
|
||||
var halfAngle = angle / 2, s = Math.sin( halfAngle );
|
||||
|
||||
this._x = axis.x * s;
|
||||
this._y = axis.y * s;
|
||||
this._z = axis.z * s;
|
||||
this._w = Math.cos( halfAngle );
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromRotationMatrix: function ( m ) {
|
||||
|
||||
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
|
||||
|
||||
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
|
||||
|
||||
var te = m.elements,
|
||||
|
||||
m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
|
||||
m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
|
||||
m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
|
||||
|
||||
trace = m11 + m22 + m33,
|
||||
s;
|
||||
|
||||
if ( trace > 0 ) {
|
||||
|
||||
s = 0.5 / Math.sqrt( trace + 1.0 );
|
||||
|
||||
this._w = 0.25 / s;
|
||||
this._x = ( m32 - m23 ) * s;
|
||||
this._y = ( m13 - m31 ) * s;
|
||||
this._z = ( m21 - m12 ) * s;
|
||||
|
||||
} else if ( m11 > m22 && m11 > m33 ) {
|
||||
|
||||
s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
|
||||
|
||||
this._w = ( m32 - m23 ) / s;
|
||||
this._x = 0.25 * s;
|
||||
this._y = ( m12 + m21 ) / s;
|
||||
this._z = ( m13 + m31 ) / s;
|
||||
|
||||
} else if ( m22 > m33 ) {
|
||||
|
||||
s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
|
||||
|
||||
this._w = ( m13 - m31 ) / s;
|
||||
this._x = ( m12 + m21 ) / s;
|
||||
this._y = 0.25 * s;
|
||||
this._z = ( m23 + m32 ) / s;
|
||||
|
||||
} else {
|
||||
|
||||
s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
|
||||
|
||||
this._w = ( m21 - m12 ) / s;
|
||||
this._x = ( m13 + m31 ) / s;
|
||||
this._y = ( m23 + m32 ) / s;
|
||||
this._z = 0.25 * s;
|
||||
|
||||
}
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromUnitVectors: function () {
|
||||
|
||||
// assumes direction vectors vFrom and vTo are normalized
|
||||
|
||||
var v1 = new Vector3();
|
||||
var r;
|
||||
|
||||
var EPS = 0.000001;
|
||||
|
||||
return function setFromUnitVectors( vFrom, vTo ) {
|
||||
|
||||
if ( v1 === undefined ) v1 = new Vector3();
|
||||
|
||||
r = vFrom.dot( vTo ) + 1;
|
||||
|
||||
if ( r < EPS ) {
|
||||
|
||||
r = 0;
|
||||
|
||||
if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
|
||||
|
||||
v1.set( - vFrom.y, vFrom.x, 0 );
|
||||
|
||||
} else {
|
||||
|
||||
v1.set( 0, - vFrom.z, vFrom.y );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
v1.crossVectors( vFrom, vTo );
|
||||
|
||||
}
|
||||
|
||||
this._x = v1.x;
|
||||
this._y = v1.y;
|
||||
this._z = v1.z;
|
||||
this._w = r;
|
||||
|
||||
return this.normalize();
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
angleTo: function ( q ) {
|
||||
|
||||
return 2 * Math.acos( Math.abs( _Math.clamp( this.dot( q ), - 1, 1 ) ) );
|
||||
|
||||
},
|
||||
|
||||
rotateTowards: function ( q, step ) {
|
||||
|
||||
var angle = this.angleTo( q );
|
||||
|
||||
if ( angle === 0 ) return this;
|
||||
|
||||
var t = Math.min( 1, step / angle );
|
||||
|
||||
this.slerp( q, t );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
inverse: function () {
|
||||
|
||||
// quaternion is assumed to have unit length
|
||||
|
||||
return this.conjugate();
|
||||
|
||||
},
|
||||
|
||||
conjugate: function () {
|
||||
|
||||
this._x *= - 1;
|
||||
this._y *= - 1;
|
||||
this._z *= - 1;
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
dot: function ( v ) {
|
||||
|
||||
return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
|
||||
|
||||
},
|
||||
|
||||
lengthSq: function () {
|
||||
|
||||
return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
|
||||
|
||||
},
|
||||
|
||||
length: function () {
|
||||
|
||||
return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
|
||||
|
||||
},
|
||||
|
||||
normalize: function () {
|
||||
|
||||
var l = this.length();
|
||||
|
||||
if ( l === 0 ) {
|
||||
|
||||
this._x = 0;
|
||||
this._y = 0;
|
||||
this._z = 0;
|
||||
this._w = 1;
|
||||
|
||||
} else {
|
||||
|
||||
l = 1 / l;
|
||||
|
||||
this._x = this._x * l;
|
||||
this._y = this._y * l;
|
||||
this._z = this._z * l;
|
||||
this._w = this._w * l;
|
||||
|
||||
}
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
multiply: function ( q, p ) {
|
||||
|
||||
if ( p !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
|
||||
return this.multiplyQuaternions( q, p );
|
||||
|
||||
}
|
||||
|
||||
return this.multiplyQuaternions( this, q );
|
||||
|
||||
},
|
||||
|
||||
premultiply: function ( q ) {
|
||||
|
||||
return this.multiplyQuaternions( q, this );
|
||||
|
||||
},
|
||||
|
||||
multiplyQuaternions: function ( a, b ) {
|
||||
|
||||
// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
|
||||
|
||||
var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
|
||||
var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
|
||||
|
||||
this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
|
||||
this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
|
||||
this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
|
||||
this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
slerp: function ( qb, t ) {
|
||||
|
||||
if ( t === 0 ) return this;
|
||||
if ( t === 1 ) return this.copy( qb );
|
||||
|
||||
var x = this._x, y = this._y, z = this._z, w = this._w;
|
||||
|
||||
// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
|
||||
|
||||
var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
|
||||
|
||||
if ( cosHalfTheta < 0 ) {
|
||||
|
||||
this._w = - qb._w;
|
||||
this._x = - qb._x;
|
||||
this._y = - qb._y;
|
||||
this._z = - qb._z;
|
||||
|
||||
cosHalfTheta = - cosHalfTheta;
|
||||
|
||||
} else {
|
||||
|
||||
this.copy( qb );
|
||||
|
||||
}
|
||||
|
||||
if ( cosHalfTheta >= 1.0 ) {
|
||||
|
||||
this._w = w;
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._z = z;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
var sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
|
||||
|
||||
if ( sqrSinHalfTheta <= Number.EPSILON ) {
|
||||
|
||||
var s = 1 - t;
|
||||
this._w = s * w + t * this._w;
|
||||
this._x = s * x + t * this._x;
|
||||
this._y = s * y + t * this._y;
|
||||
this._z = s * z + t * this._z;
|
||||
|
||||
return this.normalize();
|
||||
|
||||
}
|
||||
|
||||
var sinHalfTheta = Math.sqrt( sqrSinHalfTheta );
|
||||
var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
|
||||
var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
|
||||
ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
|
||||
|
||||
this._w = ( w * ratioA + this._w * ratioB );
|
||||
this._x = ( x * ratioA + this._x * ratioB );
|
||||
this._y = ( y * ratioA + this._y * ratioB );
|
||||
this._z = ( z * ratioA + this._z * ratioB );
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
equals: function ( quaternion ) {
|
||||
|
||||
return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
|
||||
|
||||
},
|
||||
|
||||
fromArray: function ( array, offset ) {
|
||||
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
this._x = array[ offset ];
|
||||
this._y = array[ offset + 1 ];
|
||||
this._z = array[ offset + 2 ];
|
||||
this._w = array[ offset + 3 ];
|
||||
|
||||
this.onChangeCallback();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
toArray: function ( array, offset ) {
|
||||
|
||||
if ( array === undefined ) array = [];
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
array[ offset ] = this._x;
|
||||
array[ offset + 1 ] = this._y;
|
||||
array[ offset + 2 ] = this._z;
|
||||
array[ offset + 3 ] = this._w;
|
||||
|
||||
return array;
|
||||
|
||||
},
|
||||
|
||||
onChange: function ( callback ) {
|
||||
|
||||
this.onChangeCallback = callback;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
onChangeCallback: function () {}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Quaternion };
|
546
lib/math/Ray.js
Normal file
546
lib/math/Ray.js
Normal file
@ -0,0 +1,546 @@
|
||||
import { Vector3 } from './Vector3.js';
|
||||
|
||||
/**
|
||||
* @author bhouston / http://clara.io
|
||||
*/
|
||||
|
||||
function Ray( origin, direction ) {
|
||||
|
||||
this.origin = ( origin !== undefined ) ? origin : new Vector3();
|
||||
this.direction = ( direction !== undefined ) ? direction : new Vector3();
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Ray.prototype, {
|
||||
|
||||
set: function ( origin, direction ) {
|
||||
|
||||
this.origin.copy( origin );
|
||||
this.direction.copy( direction );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( ray ) {
|
||||
|
||||
this.origin.copy( ray.origin );
|
||||
this.direction.copy( ray.direction );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
at: function ( t, target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Ray: .at() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return target.copy( this.direction ).multiplyScalar( t ).add( this.origin );
|
||||
|
||||
},
|
||||
|
||||
lookAt: function ( v ) {
|
||||
|
||||
this.direction.copy( v ).sub( this.origin ).normalize();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
recast: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function recast( t ) {
|
||||
|
||||
this.origin.copy( this.at( t, v1 ) );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
closestPointToPoint: function ( point, target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Ray: .closestPointToPoint() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
target.subVectors( point, this.origin );
|
||||
|
||||
var directionDistance = target.dot( this.direction );
|
||||
|
||||
if ( directionDistance < 0 ) {
|
||||
|
||||
return target.copy( this.origin );
|
||||
|
||||
}
|
||||
|
||||
return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
|
||||
|
||||
},
|
||||
|
||||
distanceToPoint: function ( point ) {
|
||||
|
||||
return Math.sqrt( this.distanceSqToPoint( point ) );
|
||||
|
||||
},
|
||||
|
||||
distanceSqToPoint: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function distanceSqToPoint( point ) {
|
||||
|
||||
var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
|
||||
|
||||
// point behind the ray
|
||||
|
||||
if ( directionDistance < 0 ) {
|
||||
|
||||
return this.origin.distanceToSquared( point );
|
||||
|
||||
}
|
||||
|
||||
v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
|
||||
|
||||
return v1.distanceToSquared( point );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
distanceSqToSegment: function () {
|
||||
|
||||
var segCenter = new Vector3();
|
||||
var segDir = new Vector3();
|
||||
var diff = new Vector3();
|
||||
|
||||
return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
|
||||
|
||||
// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
|
||||
// It returns the min distance between the ray and the segment
|
||||
// defined by v0 and v1
|
||||
// It can also set two optional targets :
|
||||
// - The closest point on the ray
|
||||
// - The closest point on the segment
|
||||
|
||||
segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
|
||||
segDir.copy( v1 ).sub( v0 ).normalize();
|
||||
diff.copy( this.origin ).sub( segCenter );
|
||||
|
||||
var segExtent = v0.distanceTo( v1 ) * 0.5;
|
||||
var a01 = - this.direction.dot( segDir );
|
||||
var b0 = diff.dot( this.direction );
|
||||
var b1 = - diff.dot( segDir );
|
||||
var c = diff.lengthSq();
|
||||
var det = Math.abs( 1 - a01 * a01 );
|
||||
var s0, s1, sqrDist, extDet;
|
||||
|
||||
if ( det > 0 ) {
|
||||
|
||||
// The ray and segment are not parallel.
|
||||
|
||||
s0 = a01 * b1 - b0;
|
||||
s1 = a01 * b0 - b1;
|
||||
extDet = segExtent * det;
|
||||
|
||||
if ( s0 >= 0 ) {
|
||||
|
||||
if ( s1 >= - extDet ) {
|
||||
|
||||
if ( s1 <= extDet ) {
|
||||
|
||||
// region 0
|
||||
// Minimum at interior points of ray and segment.
|
||||
|
||||
var invDet = 1 / det;
|
||||
s0 *= invDet;
|
||||
s1 *= invDet;
|
||||
sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
|
||||
|
||||
} else {
|
||||
|
||||
// region 1
|
||||
|
||||
s1 = segExtent;
|
||||
s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
|
||||
sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// region 5
|
||||
|
||||
s1 = - segExtent;
|
||||
s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
|
||||
sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ( s1 <= - extDet ) {
|
||||
|
||||
// region 4
|
||||
|
||||
s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
|
||||
s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
|
||||
sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
|
||||
|
||||
} else if ( s1 <= extDet ) {
|
||||
|
||||
// region 3
|
||||
|
||||
s0 = 0;
|
||||
s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
|
||||
sqrDist = s1 * ( s1 + 2 * b1 ) + c;
|
||||
|
||||
} else {
|
||||
|
||||
// region 2
|
||||
|
||||
s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
|
||||
s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
|
||||
sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Ray and segment are parallel.
|
||||
|
||||
s1 = ( a01 > 0 ) ? - segExtent : segExtent;
|
||||
s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
|
||||
sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
|
||||
|
||||
}
|
||||
|
||||
if ( optionalPointOnRay ) {
|
||||
|
||||
optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
|
||||
|
||||
}
|
||||
|
||||
if ( optionalPointOnSegment ) {
|
||||
|
||||
optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter );
|
||||
|
||||
}
|
||||
|
||||
return sqrDist;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
intersectSphere: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function intersectSphere( sphere, target ) {
|
||||
|
||||
v1.subVectors( sphere.center, this.origin );
|
||||
var tca = v1.dot( this.direction );
|
||||
var d2 = v1.dot( v1 ) - tca * tca;
|
||||
var radius2 = sphere.radius * sphere.radius;
|
||||
|
||||
if ( d2 > radius2 ) return null;
|
||||
|
||||
var thc = Math.sqrt( radius2 - d2 );
|
||||
|
||||
// t0 = first intersect point - entrance on front of sphere
|
||||
var t0 = tca - thc;
|
||||
|
||||
// t1 = second intersect point - exit point on back of sphere
|
||||
var t1 = tca + thc;
|
||||
|
||||
// test to see if both t0 and t1 are behind the ray - if so, return null
|
||||
if ( t0 < 0 && t1 < 0 ) return null;
|
||||
|
||||
// test to see if t0 is behind the ray:
|
||||
// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
|
||||
// in order to always return an intersect point that is in front of the ray.
|
||||
if ( t0 < 0 ) return this.at( t1, target );
|
||||
|
||||
// else t0 is in front of the ray, so return the first collision point scaled by t0
|
||||
return this.at( t0, target );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
intersectsSphere: function ( sphere ) {
|
||||
|
||||
return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );
|
||||
|
||||
},
|
||||
|
||||
distanceToPlane: function ( plane ) {
|
||||
|
||||
var denominator = plane.normal.dot( this.direction );
|
||||
|
||||
if ( denominator === 0 ) {
|
||||
|
||||
// line is coplanar, return origin
|
||||
if ( plane.distanceToPoint( this.origin ) === 0 ) {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
// Null is preferable to undefined since undefined means.... it is undefined
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
|
||||
|
||||
// Return if the ray never intersects the plane
|
||||
|
||||
return t >= 0 ? t : null;
|
||||
|
||||
},
|
||||
|
||||
intersectPlane: function ( plane, target ) {
|
||||
|
||||
var t = this.distanceToPlane( plane );
|
||||
|
||||
if ( t === null ) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
return this.at( t, target );
|
||||
|
||||
},
|
||||
|
||||
intersectsPlane: function ( plane ) {
|
||||
|
||||
// check if the ray lies on the plane first
|
||||
|
||||
var distToPoint = plane.distanceToPoint( this.origin );
|
||||
|
||||
if ( distToPoint === 0 ) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
var denominator = plane.normal.dot( this.direction );
|
||||
|
||||
if ( denominator * distToPoint < 0 ) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// ray origin is behind the plane (and is pointing behind it)
|
||||
|
||||
return false;
|
||||
|
||||
},
|
||||
|
||||
intersectBox: function ( box, target ) {
|
||||
|
||||
var tmin, tmax, tymin, tymax, tzmin, tzmax;
|
||||
|
||||
var invdirx = 1 / this.direction.x,
|
||||
invdiry = 1 / this.direction.y,
|
||||
invdirz = 1 / this.direction.z;
|
||||
|
||||
var origin = this.origin;
|
||||
|
||||
if ( invdirx >= 0 ) {
|
||||
|
||||
tmin = ( box.min.x - origin.x ) * invdirx;
|
||||
tmax = ( box.max.x - origin.x ) * invdirx;
|
||||
|
||||
} else {
|
||||
|
||||
tmin = ( box.max.x - origin.x ) * invdirx;
|
||||
tmax = ( box.min.x - origin.x ) * invdirx;
|
||||
|
||||
}
|
||||
|
||||
if ( invdiry >= 0 ) {
|
||||
|
||||
tymin = ( box.min.y - origin.y ) * invdiry;
|
||||
tymax = ( box.max.y - origin.y ) * invdiry;
|
||||
|
||||
} else {
|
||||
|
||||
tymin = ( box.max.y - origin.y ) * invdiry;
|
||||
tymax = ( box.min.y - origin.y ) * invdiry;
|
||||
|
||||
}
|
||||
|
||||
if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
|
||||
|
||||
// These lines also handle the case where tmin or tmax is NaN
|
||||
// (result of 0 * Infinity). x !== x returns true if x is NaN
|
||||
|
||||
if ( tymin > tmin || tmin !== tmin ) tmin = tymin;
|
||||
|
||||
if ( tymax < tmax || tmax !== tmax ) tmax = tymax;
|
||||
|
||||
if ( invdirz >= 0 ) {
|
||||
|
||||
tzmin = ( box.min.z - origin.z ) * invdirz;
|
||||
tzmax = ( box.max.z - origin.z ) * invdirz;
|
||||
|
||||
} else {
|
||||
|
||||
tzmin = ( box.max.z - origin.z ) * invdirz;
|
||||
tzmax = ( box.min.z - origin.z ) * invdirz;
|
||||
|
||||
}
|
||||
|
||||
if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
|
||||
|
||||
if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
|
||||
|
||||
if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
|
||||
|
||||
//return point closest to the ray (positive side)
|
||||
|
||||
if ( tmax < 0 ) return null;
|
||||
|
||||
return this.at( tmin >= 0 ? tmin : tmax, target );
|
||||
|
||||
},
|
||||
|
||||
intersectsBox: ( function () {
|
||||
|
||||
var v = new Vector3();
|
||||
|
||||
return function intersectsBox( box ) {
|
||||
|
||||
return this.intersectBox( box, v ) !== null;
|
||||
|
||||
};
|
||||
|
||||
} )(),
|
||||
|
||||
intersectTriangle: function () {
|
||||
|
||||
// Compute the offset origin, edges, and normal.
|
||||
var diff = new Vector3();
|
||||
var edge1 = new Vector3();
|
||||
var edge2 = new Vector3();
|
||||
var normal = new Vector3();
|
||||
|
||||
return function intersectTriangle( a, b, c, backfaceCulling, target ) {
|
||||
|
||||
// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
|
||||
|
||||
edge1.subVectors( b, a );
|
||||
edge2.subVectors( c, a );
|
||||
normal.crossVectors( edge1, edge2 );
|
||||
|
||||
// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
|
||||
// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
|
||||
// |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
|
||||
// |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
|
||||
// |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
|
||||
var DdN = this.direction.dot( normal );
|
||||
var sign;
|
||||
|
||||
if ( DdN > 0 ) {
|
||||
|
||||
if ( backfaceCulling ) return null;
|
||||
sign = 1;
|
||||
|
||||
} else if ( DdN < 0 ) {
|
||||
|
||||
sign = - 1;
|
||||
DdN = - DdN;
|
||||
|
||||
} else {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
diff.subVectors( this.origin, a );
|
||||
var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );
|
||||
|
||||
// b1 < 0, no intersection
|
||||
if ( DdQxE2 < 0 ) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );
|
||||
|
||||
// b2 < 0, no intersection
|
||||
if ( DdE1xQ < 0 ) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
// b1+b2 > 1, no intersection
|
||||
if ( DdQxE2 + DdE1xQ > DdN ) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
// Line intersects triangle, check if ray does.
|
||||
var QdN = - sign * diff.dot( normal );
|
||||
|
||||
// t < 0, no intersection
|
||||
if ( QdN < 0 ) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
// Ray intersects triangle.
|
||||
return this.at( QdN / DdN, target );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
applyMatrix4: function ( matrix4 ) {
|
||||
|
||||
this.origin.applyMatrix4( matrix4 );
|
||||
this.direction.transformDirection( matrix4 );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
equals: function ( ray ) {
|
||||
|
||||
return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Ray };
|
180
lib/math/Sphere.js
Normal file
180
lib/math/Sphere.js
Normal file
@ -0,0 +1,180 @@
|
||||
import { Box3 } from './Box3.js';
|
||||
import { Vector3 } from './Vector3.js';
|
||||
|
||||
/**
|
||||
* @author bhouston / http://clara.io
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
function Sphere( center, radius ) {
|
||||
|
||||
this.center = ( center !== undefined ) ? center : new Vector3();
|
||||
this.radius = ( radius !== undefined ) ? radius : 0;
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Sphere.prototype, {
|
||||
|
||||
set: function ( center, radius ) {
|
||||
|
||||
this.center.copy( center );
|
||||
this.radius = radius;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromPoints: function () {
|
||||
|
||||
var box = new Box3();
|
||||
|
||||
return function setFromPoints( points, optionalCenter ) {
|
||||
|
||||
var center = this.center;
|
||||
|
||||
if ( optionalCenter !== undefined ) {
|
||||
|
||||
center.copy( optionalCenter );
|
||||
|
||||
} else {
|
||||
|
||||
box.setFromPoints( points ).getCenter( center );
|
||||
|
||||
}
|
||||
|
||||
var maxRadiusSq = 0;
|
||||
|
||||
for ( var i = 0, il = points.length; i < il; i ++ ) {
|
||||
|
||||
maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
|
||||
|
||||
}
|
||||
|
||||
this.radius = Math.sqrt( maxRadiusSq );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( sphere ) {
|
||||
|
||||
this.center.copy( sphere.center );
|
||||
this.radius = sphere.radius;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
empty: function () {
|
||||
|
||||
return ( this.radius <= 0 );
|
||||
|
||||
},
|
||||
|
||||
containsPoint: function ( point ) {
|
||||
|
||||
return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
|
||||
|
||||
},
|
||||
|
||||
distanceToPoint: function ( point ) {
|
||||
|
||||
return ( point.distanceTo( this.center ) - this.radius );
|
||||
|
||||
},
|
||||
|
||||
intersectsSphere: function ( sphere ) {
|
||||
|
||||
var radiusSum = this.radius + sphere.radius;
|
||||
|
||||
return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
|
||||
|
||||
},
|
||||
|
||||
intersectsBox: function ( box ) {
|
||||
|
||||
return box.intersectsSphere( this );
|
||||
|
||||
},
|
||||
|
||||
intersectsPlane: function ( plane ) {
|
||||
|
||||
return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
|
||||
|
||||
},
|
||||
|
||||
clampPoint: function ( point, target ) {
|
||||
|
||||
var deltaLengthSq = this.center.distanceToSquared( point );
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Sphere: .clampPoint() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
target.copy( point );
|
||||
|
||||
if ( deltaLengthSq > ( this.radius * this.radius ) ) {
|
||||
|
||||
target.sub( this.center ).normalize();
|
||||
target.multiplyScalar( this.radius ).add( this.center );
|
||||
|
||||
}
|
||||
|
||||
return target;
|
||||
|
||||
},
|
||||
|
||||
getBoundingBox: function ( target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Sphere: .getBoundingBox() target is now required' );
|
||||
target = new Box3();
|
||||
|
||||
}
|
||||
|
||||
target.set( this.center, this.center );
|
||||
target.expandByScalar( this.radius );
|
||||
|
||||
return target;
|
||||
|
||||
},
|
||||
|
||||
applyMatrix4: function ( matrix ) {
|
||||
|
||||
this.center.applyMatrix4( matrix );
|
||||
this.radius = this.radius * matrix.getMaxScaleOnAxis();
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
translate: function ( offset ) {
|
||||
|
||||
this.center.add( offset );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
equals: function ( sphere ) {
|
||||
|
||||
return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Sphere };
|
90
lib/math/Spherical.js
Normal file
90
lib/math/Spherical.js
Normal file
@ -0,0 +1,90 @@
|
||||
import { _Math } from './Math.js';
|
||||
|
||||
/**
|
||||
* @author bhouston / http://clara.io
|
||||
* @author WestLangley / http://github.com/WestLangley
|
||||
*
|
||||
* Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
|
||||
*
|
||||
* The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up.
|
||||
* The azimuthal angle (theta) is measured from the positive z-axiz.
|
||||
*/
|
||||
|
||||
function Spherical( radius, phi, theta ) {
|
||||
|
||||
this.radius = ( radius !== undefined ) ? radius : 1.0;
|
||||
this.phi = ( phi !== undefined ) ? phi : 0; // polar angle
|
||||
this.theta = ( theta !== undefined ) ? theta : 0; // azimuthal angle
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Spherical.prototype, {
|
||||
|
||||
set: function ( radius, phi, theta ) {
|
||||
|
||||
this.radius = radius;
|
||||
this.phi = phi;
|
||||
this.theta = theta;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( other ) {
|
||||
|
||||
this.radius = other.radius;
|
||||
this.phi = other.phi;
|
||||
this.theta = other.theta;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
// restrict phi to be betwee EPS and PI-EPS
|
||||
makeSafe: function () {
|
||||
|
||||
var EPS = 0.000001;
|
||||
this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromVector3: function ( v ) {
|
||||
|
||||
return this.setFromCartesianCoords( v.x, v.y, v.z );
|
||||
|
||||
},
|
||||
|
||||
setFromCartesianCoords: function ( x, y, z ) {
|
||||
|
||||
this.radius = Math.sqrt( x * x + y * y + z * z );
|
||||
|
||||
if ( this.radius === 0 ) {
|
||||
|
||||
this.theta = 0;
|
||||
this.phi = 0;
|
||||
|
||||
} else {
|
||||
|
||||
this.theta = Math.atan2( x, z );
|
||||
this.phi = Math.acos( _Math.clamp( y / this.radius, - 1, 1 ) );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Spherical };
|
349
lib/math/Triangle.js
Normal file
349
lib/math/Triangle.js
Normal file
@ -0,0 +1,349 @@
|
||||
import { Vector3 } from './Vector3.js';
|
||||
|
||||
/**
|
||||
* @author bhouston / http://clara.io
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
function Triangle( a, b, c ) {
|
||||
|
||||
this.a = ( a !== undefined ) ? a : new Vector3();
|
||||
this.b = ( b !== undefined ) ? b : new Vector3();
|
||||
this.c = ( c !== undefined ) ? c : new Vector3();
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Triangle, {
|
||||
|
||||
getNormal: function () {
|
||||
|
||||
var v0 = new Vector3();
|
||||
|
||||
return function getNormal( a, b, c, target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Triangle: .getNormal() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
target.subVectors( c, b );
|
||||
v0.subVectors( a, b );
|
||||
target.cross( v0 );
|
||||
|
||||
var targetLengthSq = target.lengthSq();
|
||||
if ( targetLengthSq > 0 ) {
|
||||
|
||||
return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
|
||||
|
||||
}
|
||||
|
||||
return target.set( 0, 0, 0 );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
// static/instance method to calculate barycentric coordinates
|
||||
// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
|
||||
getBarycoord: function () {
|
||||
|
||||
var v0 = new Vector3();
|
||||
var v1 = new Vector3();
|
||||
var v2 = new Vector3();
|
||||
|
||||
return function getBarycoord( point, a, b, c, target ) {
|
||||
|
||||
v0.subVectors( c, a );
|
||||
v1.subVectors( b, a );
|
||||
v2.subVectors( 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 denom = ( dot00 * dot11 - dot01 * dot01 );
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Triangle: .getBarycoord() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
// collinear 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 target.set( - 2, - 1, - 1 );
|
||||
|
||||
}
|
||||
|
||||
var invDenom = 1 / denom;
|
||||
var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
|
||||
var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
|
||||
|
||||
// barycentric coordinates must always sum to 1
|
||||
return target.set( 1 - u - v, v, u );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
containsPoint: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function containsPoint( point, a, b, c ) {
|
||||
|
||||
Triangle.getBarycoord( point, a, b, c, v1 );
|
||||
|
||||
return ( v1.x >= 0 ) && ( v1.y >= 0 ) && ( ( v1.x + v1.y ) <= 1 );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
getUV: function () {
|
||||
|
||||
var barycoord = new Vector3();
|
||||
|
||||
return function getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) {
|
||||
|
||||
this.getBarycoord( point, p1, p2, p3, barycoord );
|
||||
|
||||
target.set( 0, 0 );
|
||||
target.addScaledVector( uv1, barycoord.x );
|
||||
target.addScaledVector( uv2, barycoord.y );
|
||||
target.addScaledVector( uv3, barycoord.z );
|
||||
|
||||
return target;
|
||||
|
||||
};
|
||||
|
||||
}()
|
||||
|
||||
} );
|
||||
|
||||
Object.assign( Triangle.prototype, {
|
||||
|
||||
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;
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor().copy( this );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( triangle ) {
|
||||
|
||||
this.a.copy( triangle.a );
|
||||
this.b.copy( triangle.b );
|
||||
this.c.copy( triangle.c );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
getArea: function () {
|
||||
|
||||
var v0 = new Vector3();
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function getArea() {
|
||||
|
||||
v0.subVectors( this.c, this.b );
|
||||
v1.subVectors( this.a, this.b );
|
||||
|
||||
return v0.cross( v1 ).length() * 0.5;
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
getMidpoint: function ( target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Triangle: .getMidpoint() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
|
||||
|
||||
},
|
||||
|
||||
getNormal: function ( target ) {
|
||||
|
||||
return Triangle.getNormal( this.a, this.b, this.c, target );
|
||||
|
||||
},
|
||||
|
||||
getPlane: function ( target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Triangle: .getPlane() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
return target.setFromCoplanarPoints( this.a, this.b, this.c );
|
||||
|
||||
},
|
||||
|
||||
getBarycoord: function ( point, target ) {
|
||||
|
||||
return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
|
||||
|
||||
},
|
||||
|
||||
containsPoint: function ( point ) {
|
||||
|
||||
return Triangle.containsPoint( point, this.a, this.b, this.c );
|
||||
|
||||
},
|
||||
|
||||
getUV: function ( point, uv1, uv2, uv3, result ) {
|
||||
|
||||
return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, result );
|
||||
|
||||
},
|
||||
|
||||
intersectsBox: function ( box ) {
|
||||
|
||||
return box.intersectsTriangle( this );
|
||||
|
||||
},
|
||||
|
||||
closestPointToPoint: function () {
|
||||
|
||||
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( p, target ) {
|
||||
|
||||
if ( target === undefined ) {
|
||||
|
||||
console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' );
|
||||
target = new Vector3();
|
||||
|
||||
}
|
||||
|
||||
var a = this.a, b = this.b, c = this.c;
|
||||
var v, w;
|
||||
|
||||
// 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.
|
||||
|
||||
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 ) {
|
||||
|
||||
// vertex region of A; barycentric coords (1, 0, 0)
|
||||
return target.copy( a );
|
||||
|
||||
}
|
||||
|
||||
vbp.subVectors( p, b );
|
||||
var d3 = vab.dot( vbp );
|
||||
var d4 = vac.dot( vbp );
|
||||
if ( d3 >= 0 && d4 <= d3 ) {
|
||||
|
||||
// vertex region of B; barycentric coords (0, 1, 0)
|
||||
return target.copy( b );
|
||||
|
||||
}
|
||||
|
||||
var vc = d1 * d4 - d3 * d2;
|
||||
if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
|
||||
|
||||
v = d1 / ( d1 - d3 );
|
||||
// edge region of AB; barycentric coords (1-v, v, 0)
|
||||
return target.copy( a ).addScaledVector( vab, v );
|
||||
|
||||
}
|
||||
|
||||
vcp.subVectors( p, c );
|
||||
var d5 = vab.dot( vcp );
|
||||
var d6 = vac.dot( vcp );
|
||||
if ( d6 >= 0 && d5 <= d6 ) {
|
||||
|
||||
// vertex region of C; barycentric coords (0, 0, 1)
|
||||
return target.copy( c );
|
||||
|
||||
}
|
||||
|
||||
var vb = d5 * d2 - d1 * d6;
|
||||
if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
|
||||
|
||||
w = d2 / ( d2 - d6 );
|
||||
// edge region of AC; barycentric coords (1-w, 0, w)
|
||||
return target.copy( a ).addScaledVector( vac, w );
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
// 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 );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
equals: function ( triangle ) {
|
||||
|
||||
return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Triangle };
|
499
lib/math/Vector2.js
Normal file
499
lib/math/Vector2.js
Normal file
@ -0,0 +1,499 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
* @author philogb / http://blog.thejit.org/
|
||||
* @author egraether / http://egraether.com/
|
||||
* @author zz85 / http://www.lab4games.net/zz85/blog
|
||||
*/
|
||||
|
||||
function Vector2( x, y ) {
|
||||
|
||||
this.x = x || 0;
|
||||
this.y = y || 0;
|
||||
|
||||
}
|
||||
|
||||
Object.defineProperties( Vector2.prototype, {
|
||||
|
||||
"width": {
|
||||
|
||||
get: function () {
|
||||
|
||||
return this.x;
|
||||
|
||||
},
|
||||
|
||||
set: function ( value ) {
|
||||
|
||||
this.x = value;
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
"height": {
|
||||
|
||||
get: function () {
|
||||
|
||||
return this.y;
|
||||
|
||||
},
|
||||
|
||||
set: function ( value ) {
|
||||
|
||||
this.y = value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
Object.assign( Vector2.prototype, {
|
||||
|
||||
isVector2: true,
|
||||
|
||||
set: function ( x, y ) {
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setScalar: function ( scalar ) {
|
||||
|
||||
this.x = scalar;
|
||||
this.y = scalar;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setX: function ( x ) {
|
||||
|
||||
this.x = x;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setY: function ( y ) {
|
||||
|
||||
this.y = y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setComponent: function ( index, value ) {
|
||||
|
||||
switch ( index ) {
|
||||
|
||||
case 0: this.x = value; break;
|
||||
case 1: this.y = value; break;
|
||||
default: throw new Error( 'index is out of range: ' + index );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
getComponent: function ( index ) {
|
||||
|
||||
switch ( index ) {
|
||||
|
||||
case 0: return this.x;
|
||||
case 1: return this.y;
|
||||
default: throw new Error( 'index is out of range: ' + index );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor( this.x, this.y );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( v ) {
|
||||
|
||||
this.x = v.x;
|
||||
this.y = v.y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
add: function ( v, w ) {
|
||||
|
||||
if ( w !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
|
||||
return this.addVectors( v, w );
|
||||
|
||||
}
|
||||
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
addScalar: function ( s ) {
|
||||
|
||||
this.x += s;
|
||||
this.y += s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
addVectors: function ( a, b ) {
|
||||
|
||||
this.x = a.x + b.x;
|
||||
this.y = a.y + b.y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
addScaledVector: function ( v, s ) {
|
||||
|
||||
this.x += v.x * s;
|
||||
this.y += v.y * s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
sub: function ( v, w ) {
|
||||
|
||||
if ( w !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
|
||||
return this.subVectors( v, w );
|
||||
|
||||
}
|
||||
|
||||
this.x -= v.x;
|
||||
this.y -= v.y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
subScalar: function ( s ) {
|
||||
|
||||
this.x -= s;
|
||||
this.y -= s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
subVectors: function ( a, b ) {
|
||||
|
||||
this.x = a.x - b.x;
|
||||
this.y = a.y - b.y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
multiply: function ( v ) {
|
||||
|
||||
this.x *= v.x;
|
||||
this.y *= v.y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
multiplyScalar: function ( scalar ) {
|
||||
|
||||
this.x *= scalar;
|
||||
this.y *= scalar;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
divide: function ( v ) {
|
||||
|
||||
this.x /= v.x;
|
||||
this.y /= v.y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
divideScalar: function ( scalar ) {
|
||||
|
||||
return this.multiplyScalar( 1 / scalar );
|
||||
|
||||
},
|
||||
|
||||
applyMatrix3: function ( m ) {
|
||||
|
||||
var x = this.x, y = this.y;
|
||||
var e = m.elements;
|
||||
|
||||
this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
|
||||
this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
min: function ( v ) {
|
||||
|
||||
this.x = Math.min( this.x, v.x );
|
||||
this.y = Math.min( this.y, v.y );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
max: function ( v ) {
|
||||
|
||||
this.x = Math.max( this.x, v.x );
|
||||
this.y = Math.max( this.y, v.y );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clamp: function ( min, max ) {
|
||||
|
||||
// assumes min < max, componentwise
|
||||
|
||||
this.x = Math.max( min.x, Math.min( max.x, this.x ) );
|
||||
this.y = Math.max( min.y, Math.min( max.y, this.y ) );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clampScalar: function () {
|
||||
|
||||
var min = new Vector2();
|
||||
var max = new Vector2();
|
||||
|
||||
return function clampScalar( minVal, maxVal ) {
|
||||
|
||||
min.set( minVal, minVal );
|
||||
max.set( maxVal, maxVal );
|
||||
|
||||
return this.clamp( min, max );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
clampLength: function ( min, max ) {
|
||||
|
||||
var length = this.length();
|
||||
|
||||
return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
|
||||
|
||||
},
|
||||
|
||||
floor: function () {
|
||||
|
||||
this.x = Math.floor( this.x );
|
||||
this.y = Math.floor( this.y );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
ceil: function () {
|
||||
|
||||
this.x = Math.ceil( this.x );
|
||||
this.y = Math.ceil( this.y );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
round: function () {
|
||||
|
||||
this.x = Math.round( this.x );
|
||||
this.y = Math.round( this.y );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
roundToZero: function () {
|
||||
|
||||
this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
|
||||
this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
negate: function () {
|
||||
|
||||
this.x = - this.x;
|
||||
this.y = - this.y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
dot: function ( v ) {
|
||||
|
||||
return this.x * v.x + this.y * v.y;
|
||||
|
||||
},
|
||||
|
||||
cross: function ( v ) {
|
||||
|
||||
return this.x * v.y - this.y * v.x;
|
||||
|
||||
},
|
||||
|
||||
lengthSq: function () {
|
||||
|
||||
return this.x * this.x + this.y * this.y;
|
||||
|
||||
},
|
||||
|
||||
length: function () {
|
||||
|
||||
return Math.sqrt( this.x * this.x + this.y * this.y );
|
||||
|
||||
},
|
||||
|
||||
manhattanLength: function () {
|
||||
|
||||
return Math.abs( this.x ) + Math.abs( this.y );
|
||||
|
||||
},
|
||||
|
||||
normalize: function () {
|
||||
|
||||
return this.divideScalar( this.length() || 1 );
|
||||
|
||||
},
|
||||
|
||||
angle: function () {
|
||||
|
||||
// computes the angle in radians with respect to the positive x-axis
|
||||
|
||||
var angle = Math.atan2( this.y, this.x );
|
||||
|
||||
if ( angle < 0 ) angle += 2 * Math.PI;
|
||||
|
||||
return angle;
|
||||
|
||||
},
|
||||
|
||||
distanceTo: function ( v ) {
|
||||
|
||||
return Math.sqrt( this.distanceToSquared( v ) );
|
||||
|
||||
},
|
||||
|
||||
distanceToSquared: function ( v ) {
|
||||
|
||||
var dx = this.x - v.x, dy = this.y - v.y;
|
||||
return dx * dx + dy * dy;
|
||||
|
||||
},
|
||||
|
||||
manhattanDistanceTo: function ( v ) {
|
||||
|
||||
return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
|
||||
|
||||
},
|
||||
|
||||
setLength: function ( length ) {
|
||||
|
||||
return this.normalize().multiplyScalar( length );
|
||||
|
||||
},
|
||||
|
||||
lerp: function ( v, alpha ) {
|
||||
|
||||
this.x += ( v.x - this.x ) * alpha;
|
||||
this.y += ( v.y - this.y ) * alpha;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
lerpVectors: function ( v1, v2, alpha ) {
|
||||
|
||||
return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
|
||||
|
||||
},
|
||||
|
||||
equals: function ( v ) {
|
||||
|
||||
return ( ( v.x === this.x ) && ( v.y === this.y ) );
|
||||
|
||||
},
|
||||
|
||||
fromArray: function ( array, offset ) {
|
||||
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
this.x = array[ offset ];
|
||||
this.y = array[ offset + 1 ];
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
toArray: function ( array, offset ) {
|
||||
|
||||
if ( array === undefined ) array = [];
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
array[ offset ] = this.x;
|
||||
array[ offset + 1 ] = this.y;
|
||||
|
||||
return array;
|
||||
|
||||
},
|
||||
|
||||
fromBufferAttribute: function ( attribute, index, offset ) {
|
||||
|
||||
if ( offset !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );
|
||||
|
||||
}
|
||||
|
||||
this.x = attribute.getX( index );
|
||||
this.y = attribute.getY( index );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
rotateAround: function ( center, angle ) {
|
||||
|
||||
var c = Math.cos( angle ), s = Math.sin( angle );
|
||||
|
||||
var x = this.x - center.x;
|
||||
var y = this.y - center.y;
|
||||
|
||||
this.x = x * c - y * s + center.x;
|
||||
this.y = x * s + y * c + center.y;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Vector2 };
|
734
lib/math/Vector3.js
Normal file
734
lib/math/Vector3.js
Normal file
@ -0,0 +1,734 @@
|
||||
import { _Math } from './Math.js';
|
||||
import { Matrix4 } from './Matrix4.js';
|
||||
import { Quaternion } from './Quaternion.js';
|
||||
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
* @author kile / http://kile.stravaganza.org/
|
||||
* @author philogb / http://blog.thejit.org/
|
||||
* @author mikael emtinger / http://gomo.se/
|
||||
* @author egraether / http://egraether.com/
|
||||
* @author WestLangley / http://github.com/WestLangley
|
||||
*/
|
||||
|
||||
function Vector3( x, y, z ) {
|
||||
|
||||
this.x = x || 0;
|
||||
this.y = y || 0;
|
||||
this.z = z || 0;
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Vector3.prototype, {
|
||||
|
||||
isVector3: true,
|
||||
|
||||
set: function ( x, y, z ) {
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setScalar: function ( scalar ) {
|
||||
|
||||
this.x = scalar;
|
||||
this.y = scalar;
|
||||
this.z = scalar;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setX: function ( x ) {
|
||||
|
||||
this.x = x;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setY: function ( y ) {
|
||||
|
||||
this.y = y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setZ: function ( z ) {
|
||||
|
||||
this.z = z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setComponent: function ( index, value ) {
|
||||
|
||||
switch ( index ) {
|
||||
|
||||
case 0: this.x = value; break;
|
||||
case 1: this.y = value; break;
|
||||
case 2: this.z = value; break;
|
||||
default: throw new Error( 'index is out of range: ' + index );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
getComponent: function ( index ) {
|
||||
|
||||
switch ( index ) {
|
||||
|
||||
case 0: return this.x;
|
||||
case 1: return this.y;
|
||||
case 2: return this.z;
|
||||
default: throw new Error( 'index is out of range: ' + index );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor( this.x, this.y, this.z );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( v ) {
|
||||
|
||||
this.x = v.x;
|
||||
this.y = v.y;
|
||||
this.z = v.z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
add: function ( v, w ) {
|
||||
|
||||
if ( w !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
|
||||
return this.addVectors( v, w );
|
||||
|
||||
}
|
||||
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
this.z += v.z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
addScalar: function ( s ) {
|
||||
|
||||
this.x += s;
|
||||
this.y += s;
|
||||
this.z += s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
addVectors: function ( a, b ) {
|
||||
|
||||
this.x = a.x + b.x;
|
||||
this.y = a.y + b.y;
|
||||
this.z = a.z + b.z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
addScaledVector: function ( v, s ) {
|
||||
|
||||
this.x += v.x * s;
|
||||
this.y += v.y * s;
|
||||
this.z += v.z * s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
sub: function ( v, w ) {
|
||||
|
||||
if ( w !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
|
||||
return this.subVectors( v, w );
|
||||
|
||||
}
|
||||
|
||||
this.x -= v.x;
|
||||
this.y -= v.y;
|
||||
this.z -= v.z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
subScalar: function ( s ) {
|
||||
|
||||
this.x -= s;
|
||||
this.y -= s;
|
||||
this.z -= s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
subVectors: function ( a, b ) {
|
||||
|
||||
this.x = a.x - b.x;
|
||||
this.y = a.y - b.y;
|
||||
this.z = a.z - b.z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
multiply: function ( v, w ) {
|
||||
|
||||
if ( w !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
|
||||
return this.multiplyVectors( v, w );
|
||||
|
||||
}
|
||||
|
||||
this.x *= v.x;
|
||||
this.y *= v.y;
|
||||
this.z *= v.z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
multiplyScalar: function ( scalar ) {
|
||||
|
||||
this.x *= scalar;
|
||||
this.y *= scalar;
|
||||
this.z *= scalar;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
multiplyVectors: function ( a, b ) {
|
||||
|
||||
this.x = a.x * b.x;
|
||||
this.y = a.y * b.y;
|
||||
this.z = a.z * b.z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
applyEuler: function () {
|
||||
|
||||
var quaternion = new Quaternion();
|
||||
|
||||
return function applyEuler( euler ) {
|
||||
|
||||
if ( ! ( euler && euler.isEuler ) ) {
|
||||
|
||||
console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
|
||||
|
||||
}
|
||||
|
||||
return this.applyQuaternion( quaternion.setFromEuler( euler ) );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
applyAxisAngle: function () {
|
||||
|
||||
var quaternion = new Quaternion();
|
||||
|
||||
return function applyAxisAngle( axis, angle ) {
|
||||
|
||||
return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
applyMatrix3: function ( m ) {
|
||||
|
||||
var x = this.x, y = this.y, z = this.z;
|
||||
var e = m.elements;
|
||||
|
||||
this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
|
||||
this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
|
||||
this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
applyMatrix4: function ( m ) {
|
||||
|
||||
var x = this.x, y = this.y, z = this.z;
|
||||
var e = m.elements;
|
||||
|
||||
var w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
|
||||
|
||||
this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
|
||||
this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
|
||||
this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
applyQuaternion: function ( q ) {
|
||||
|
||||
var x = this.x, y = this.y, z = this.z;
|
||||
var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
|
||||
|
||||
// calculate quat * vector
|
||||
|
||||
var ix = qw * x + qy * z - qz * y;
|
||||
var iy = qw * y + qz * x - qx * z;
|
||||
var iz = qw * z + qx * y - qy * x;
|
||||
var iw = - qx * x - qy * y - qz * z;
|
||||
|
||||
// calculate result * inverse quat
|
||||
|
||||
this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
|
||||
this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
|
||||
this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
project: function ( camera ) {
|
||||
|
||||
return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
|
||||
|
||||
},
|
||||
|
||||
unproject: function () {
|
||||
|
||||
var matrix = new Matrix4();
|
||||
|
||||
return function unproject( camera ) {
|
||||
|
||||
return this.applyMatrix4( matrix.getInverse( camera.projectionMatrix ) ).applyMatrix4( camera.matrixWorld );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
transformDirection: function ( m ) {
|
||||
|
||||
// input: THREE.Matrix4 affine matrix
|
||||
// vector interpreted as a direction
|
||||
|
||||
var x = this.x, y = this.y, z = this.z;
|
||||
var e = m.elements;
|
||||
|
||||
this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
|
||||
this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
|
||||
this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
|
||||
|
||||
return this.normalize();
|
||||
|
||||
},
|
||||
|
||||
divide: function ( v ) {
|
||||
|
||||
this.x /= v.x;
|
||||
this.y /= v.y;
|
||||
this.z /= v.z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
divideScalar: function ( scalar ) {
|
||||
|
||||
return this.multiplyScalar( 1 / scalar );
|
||||
|
||||
},
|
||||
|
||||
min: function ( v ) {
|
||||
|
||||
this.x = Math.min( this.x, v.x );
|
||||
this.y = Math.min( this.y, v.y );
|
||||
this.z = Math.min( this.z, v.z );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
max: function ( v ) {
|
||||
|
||||
this.x = Math.max( this.x, v.x );
|
||||
this.y = Math.max( this.y, v.y );
|
||||
this.z = Math.max( this.z, v.z );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clamp: function ( min, max ) {
|
||||
|
||||
// assumes min < max, componentwise
|
||||
|
||||
this.x = Math.max( min.x, Math.min( max.x, this.x ) );
|
||||
this.y = Math.max( min.y, Math.min( max.y, this.y ) );
|
||||
this.z = Math.max( min.z, Math.min( max.z, this.z ) );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clampScalar: function () {
|
||||
|
||||
var min = new Vector3();
|
||||
var max = new Vector3();
|
||||
|
||||
return function clampScalar( minVal, maxVal ) {
|
||||
|
||||
min.set( minVal, minVal, minVal );
|
||||
max.set( maxVal, maxVal, maxVal );
|
||||
|
||||
return this.clamp( min, max );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
clampLength: function ( min, max ) {
|
||||
|
||||
var length = this.length();
|
||||
|
||||
return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
|
||||
|
||||
},
|
||||
|
||||
floor: function () {
|
||||
|
||||
this.x = Math.floor( this.x );
|
||||
this.y = Math.floor( this.y );
|
||||
this.z = Math.floor( this.z );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
ceil: function () {
|
||||
|
||||
this.x = Math.ceil( this.x );
|
||||
this.y = Math.ceil( this.y );
|
||||
this.z = Math.ceil( this.z );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
round: function () {
|
||||
|
||||
this.x = Math.round( this.x );
|
||||
this.y = Math.round( this.y );
|
||||
this.z = Math.round( this.z );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
roundToZero: function () {
|
||||
|
||||
this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
|
||||
this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
|
||||
this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
negate: function () {
|
||||
|
||||
this.x = - this.x;
|
||||
this.y = - this.y;
|
||||
this.z = - this.z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
dot: function ( v ) {
|
||||
|
||||
return this.x * v.x + this.y * v.y + this.z * v.z;
|
||||
|
||||
},
|
||||
|
||||
// TODO lengthSquared?
|
||||
|
||||
lengthSq: function () {
|
||||
|
||||
return this.x * this.x + this.y * this.y + this.z * this.z;
|
||||
|
||||
},
|
||||
|
||||
length: function () {
|
||||
|
||||
return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
|
||||
|
||||
},
|
||||
|
||||
manhattanLength: function () {
|
||||
|
||||
return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
|
||||
|
||||
},
|
||||
|
||||
normalize: function () {
|
||||
|
||||
return this.divideScalar( this.length() || 1 );
|
||||
|
||||
},
|
||||
|
||||
setLength: function ( length ) {
|
||||
|
||||
return this.normalize().multiplyScalar( length );
|
||||
|
||||
},
|
||||
|
||||
lerp: function ( v, alpha ) {
|
||||
|
||||
this.x += ( v.x - this.x ) * alpha;
|
||||
this.y += ( v.y - this.y ) * alpha;
|
||||
this.z += ( v.z - this.z ) * alpha;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
lerpVectors: function ( v1, v2, alpha ) {
|
||||
|
||||
return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
|
||||
|
||||
},
|
||||
|
||||
cross: function ( v, w ) {
|
||||
|
||||
if ( w !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
|
||||
return this.crossVectors( v, w );
|
||||
|
||||
}
|
||||
|
||||
return this.crossVectors( this, v );
|
||||
|
||||
},
|
||||
|
||||
crossVectors: function ( a, b ) {
|
||||
|
||||
var ax = a.x, ay = a.y, az = a.z;
|
||||
var bx = b.x, by = b.y, bz = b.z;
|
||||
|
||||
this.x = ay * bz - az * by;
|
||||
this.y = az * bx - ax * bz;
|
||||
this.z = ax * by - ay * bx;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
projectOnVector: function ( vector ) {
|
||||
|
||||
var scalar = vector.dot( this ) / vector.lengthSq();
|
||||
|
||||
return this.copy( vector ).multiplyScalar( scalar );
|
||||
|
||||
},
|
||||
|
||||
projectOnPlane: function () {
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function projectOnPlane( planeNormal ) {
|
||||
|
||||
v1.copy( this ).projectOnVector( planeNormal );
|
||||
|
||||
return this.sub( v1 );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
reflect: function () {
|
||||
|
||||
// reflect incident vector off plane orthogonal to normal
|
||||
// normal is assumed to have unit length
|
||||
|
||||
var v1 = new Vector3();
|
||||
|
||||
return function reflect( normal ) {
|
||||
|
||||
return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
angleTo: function ( v ) {
|
||||
|
||||
var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) );
|
||||
|
||||
// clamp, to handle numerical problems
|
||||
|
||||
return Math.acos( _Math.clamp( theta, - 1, 1 ) );
|
||||
|
||||
},
|
||||
|
||||
distanceTo: function ( v ) {
|
||||
|
||||
return Math.sqrt( this.distanceToSquared( v ) );
|
||||
|
||||
},
|
||||
|
||||
distanceToSquared: function ( v ) {
|
||||
|
||||
var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
|
||||
|
||||
return dx * dx + dy * dy + dz * dz;
|
||||
|
||||
},
|
||||
|
||||
manhattanDistanceTo: function ( v ) {
|
||||
|
||||
return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
|
||||
|
||||
},
|
||||
|
||||
setFromSpherical: function ( s ) {
|
||||
|
||||
return this.setFromSphericalCoords( s.radius, s.phi, s.theta );
|
||||
|
||||
},
|
||||
|
||||
setFromSphericalCoords: function ( radius, phi, theta ) {
|
||||
|
||||
var sinPhiRadius = Math.sin( phi ) * radius;
|
||||
|
||||
this.x = sinPhiRadius * Math.sin( theta );
|
||||
this.y = Math.cos( phi ) * radius;
|
||||
this.z = sinPhiRadius * Math.cos( theta );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromCylindrical: function ( c ) {
|
||||
|
||||
return this.setFromCylindricalCoords( c.radius, c.theta, c.y );
|
||||
|
||||
},
|
||||
|
||||
setFromCylindricalCoords: function ( radius, theta, y ) {
|
||||
|
||||
this.x = radius * Math.sin( theta );
|
||||
this.y = y;
|
||||
this.z = radius * Math.cos( theta );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromMatrixPosition: function ( m ) {
|
||||
|
||||
var e = m.elements;
|
||||
|
||||
this.x = e[ 12 ];
|
||||
this.y = e[ 13 ];
|
||||
this.z = e[ 14 ];
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromMatrixScale: function ( m ) {
|
||||
|
||||
var sx = this.setFromMatrixColumn( m, 0 ).length();
|
||||
var sy = this.setFromMatrixColumn( m, 1 ).length();
|
||||
var sz = this.setFromMatrixColumn( m, 2 ).length();
|
||||
|
||||
this.x = sx;
|
||||
this.y = sy;
|
||||
this.z = sz;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setFromMatrixColumn: function ( m, index ) {
|
||||
|
||||
return this.fromArray( m.elements, index * 4 );
|
||||
|
||||
},
|
||||
|
||||
equals: function ( v ) {
|
||||
|
||||
return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
|
||||
|
||||
},
|
||||
|
||||
fromArray: function ( array, offset ) {
|
||||
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
this.x = array[ offset ];
|
||||
this.y = array[ offset + 1 ];
|
||||
this.z = array[ offset + 2 ];
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
toArray: function ( array, offset ) {
|
||||
|
||||
if ( array === undefined ) array = [];
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
array[ offset ] = this.x;
|
||||
array[ offset + 1 ] = this.y;
|
||||
array[ offset + 2 ] = this.z;
|
||||
|
||||
return array;
|
||||
|
||||
},
|
||||
|
||||
fromBufferAttribute: function ( attribute, index, offset ) {
|
||||
|
||||
if ( offset !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );
|
||||
|
||||
}
|
||||
|
||||
this.x = attribute.getX( index );
|
||||
this.y = attribute.getY( index );
|
||||
this.z = attribute.getZ( index );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Vector3 };
|
629
lib/math/Vector4.js
Normal file
629
lib/math/Vector4.js
Normal file
@ -0,0 +1,629 @@
|
||||
/**
|
||||
* @author supereggbert / http://www.paulbrunt.co.uk/
|
||||
* @author philogb / http://blog.thejit.org/
|
||||
* @author mikael emtinger / http://gomo.se/
|
||||
* @author egraether / http://egraether.com/
|
||||
* @author WestLangley / http://github.com/WestLangley
|
||||
*/
|
||||
|
||||
function Vector4( x, y, z, w ) {
|
||||
|
||||
this.x = x || 0;
|
||||
this.y = y || 0;
|
||||
this.z = z || 0;
|
||||
this.w = ( w !== undefined ) ? w : 1;
|
||||
|
||||
}
|
||||
|
||||
Object.assign( Vector4.prototype, {
|
||||
|
||||
isVector4: true,
|
||||
|
||||
set: function ( x, y, z, w ) {
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setScalar: function ( scalar ) {
|
||||
|
||||
this.x = scalar;
|
||||
this.y = scalar;
|
||||
this.z = scalar;
|
||||
this.w = scalar;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setX: function ( x ) {
|
||||
|
||||
this.x = x;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setY: function ( y ) {
|
||||
|
||||
this.y = y;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setZ: function ( z ) {
|
||||
|
||||
this.z = z;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setW: function ( w ) {
|
||||
|
||||
this.w = w;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setComponent: function ( index, value ) {
|
||||
|
||||
switch ( index ) {
|
||||
|
||||
case 0: this.x = value; break;
|
||||
case 1: this.y = value; break;
|
||||
case 2: this.z = value; break;
|
||||
case 3: this.w = value; break;
|
||||
default: throw new Error( 'index is out of range: ' + index );
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
getComponent: function ( index ) {
|
||||
|
||||
switch ( index ) {
|
||||
|
||||
case 0: return this.x;
|
||||
case 1: return this.y;
|
||||
case 2: return this.z;
|
||||
case 3: return this.w;
|
||||
default: throw new Error( 'index is out of range: ' + index );
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
|
||||
return new this.constructor( this.x, this.y, this.z, this.w );
|
||||
|
||||
},
|
||||
|
||||
copy: function ( v ) {
|
||||
|
||||
this.x = v.x;
|
||||
this.y = v.y;
|
||||
this.z = v.z;
|
||||
this.w = ( v.w !== undefined ) ? v.w : 1;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
add: function ( v, w ) {
|
||||
|
||||
if ( w !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
|
||||
return this.addVectors( v, w );
|
||||
|
||||
}
|
||||
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
this.z += v.z;
|
||||
this.w += v.w;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
addScalar: function ( s ) {
|
||||
|
||||
this.x += s;
|
||||
this.y += s;
|
||||
this.z += s;
|
||||
this.w += s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
addVectors: 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;
|
||||
|
||||
},
|
||||
|
||||
addScaledVector: function ( v, s ) {
|
||||
|
||||
this.x += v.x * s;
|
||||
this.y += v.y * s;
|
||||
this.z += v.z * s;
|
||||
this.w += v.w * s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
sub: function ( v, w ) {
|
||||
|
||||
if ( w !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
|
||||
return this.subVectors( v, w );
|
||||
|
||||
}
|
||||
|
||||
this.x -= v.x;
|
||||
this.y -= v.y;
|
||||
this.z -= v.z;
|
||||
this.w -= v.w;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
subScalar: function ( s ) {
|
||||
|
||||
this.x -= s;
|
||||
this.y -= s;
|
||||
this.z -= s;
|
||||
this.w -= s;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
subVectors: 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;
|
||||
|
||||
},
|
||||
|
||||
multiplyScalar: function ( scalar ) {
|
||||
|
||||
this.x *= scalar;
|
||||
this.y *= scalar;
|
||||
this.z *= scalar;
|
||||
this.w *= scalar;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
applyMatrix4: function ( m ) {
|
||||
|
||||
var x = this.x, y = this.y, z = this.z, w = this.w;
|
||||
var e = m.elements;
|
||||
|
||||
this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
|
||||
this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
|
||||
this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
|
||||
this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
divideScalar: function ( scalar ) {
|
||||
|
||||
return this.multiplyScalar( 1 / scalar );
|
||||
|
||||
},
|
||||
|
||||
setAxisAngleFromQuaternion: function ( q ) {
|
||||
|
||||
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
|
||||
|
||||
// q is assumed to be normalized
|
||||
|
||||
this.w = 2 * Math.acos( q.w );
|
||||
|
||||
var s = Math.sqrt( 1 - q.w * q.w );
|
||||
|
||||
if ( s < 0.0001 ) {
|
||||
|
||||
this.x = 1;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
|
||||
} else {
|
||||
|
||||
this.x = q.x / s;
|
||||
this.y = q.y / s;
|
||||
this.z = q.z / s;
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setAxisAngleFromRotationMatrix: function ( m ) {
|
||||
|
||||
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
|
||||
|
||||
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
|
||||
|
||||
var angle, x, y, z, // variables for result
|
||||
epsilon = 0.01, // margin to allow for rounding errors
|
||||
epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees
|
||||
|
||||
te = m.elements,
|
||||
|
||||
m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
|
||||
m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
|
||||
m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
|
||||
|
||||
if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
|
||||
( Math.abs( m13 - m31 ) < epsilon ) &&
|
||||
( Math.abs( m23 - m32 ) < epsilon ) ) {
|
||||
|
||||
// singularity found
|
||||
// first check for identity matrix which must have +1 for all terms
|
||||
// in leading diagonal and zero in other terms
|
||||
|
||||
if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
|
||||
( Math.abs( m13 + m31 ) < epsilon2 ) &&
|
||||
( Math.abs( m23 + m32 ) < epsilon2 ) &&
|
||||
( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
|
||||
|
||||
// this singularity is identity matrix so angle = 0
|
||||
|
||||
this.set( 1, 0, 0, 0 );
|
||||
|
||||
return this; // zero angle, arbitrary axis
|
||||
|
||||
}
|
||||
|
||||
// otherwise this singularity is angle = 180
|
||||
|
||||
angle = Math.PI;
|
||||
|
||||
var xx = ( m11 + 1 ) / 2;
|
||||
var yy = ( m22 + 1 ) / 2;
|
||||
var zz = ( m33 + 1 ) / 2;
|
||||
var xy = ( m12 + m21 ) / 4;
|
||||
var xz = ( m13 + m31 ) / 4;
|
||||
var yz = ( m23 + m32 ) / 4;
|
||||
|
||||
if ( ( xx > yy ) && ( xx > zz ) ) {
|
||||
|
||||
// m11 is the largest diagonal term
|
||||
|
||||
if ( xx < epsilon ) {
|
||||
|
||||
x = 0;
|
||||
y = 0.707106781;
|
||||
z = 0.707106781;
|
||||
|
||||
} else {
|
||||
|
||||
x = Math.sqrt( xx );
|
||||
y = xy / x;
|
||||
z = xz / x;
|
||||
|
||||
}
|
||||
|
||||
} else if ( yy > zz ) {
|
||||
|
||||
// m22 is the largest diagonal term
|
||||
|
||||
if ( yy < epsilon ) {
|
||||
|
||||
x = 0.707106781;
|
||||
y = 0;
|
||||
z = 0.707106781;
|
||||
|
||||
} else {
|
||||
|
||||
y = Math.sqrt( yy );
|
||||
x = xy / y;
|
||||
z = yz / y;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// m33 is the largest diagonal term so base result on this
|
||||
|
||||
if ( zz < epsilon ) {
|
||||
|
||||
x = 0.707106781;
|
||||
y = 0.707106781;
|
||||
z = 0;
|
||||
|
||||
} else {
|
||||
|
||||
z = Math.sqrt( zz );
|
||||
x = xz / z;
|
||||
y = yz / z;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.set( x, y, z, angle );
|
||||
|
||||
return this; // return 180 deg rotation
|
||||
|
||||
}
|
||||
|
||||
// as we have reached here there are no singularities so we can handle normally
|
||||
|
||||
var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
|
||||
( m13 - m31 ) * ( m13 - m31 ) +
|
||||
( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
|
||||
|
||||
if ( Math.abs( s ) < 0.001 ) s = 1;
|
||||
|
||||
// prevent divide by zero, should not happen if matrix is orthogonal and should be
|
||||
// caught by singularity test above, but I've left it in just in case
|
||||
|
||||
this.x = ( m32 - m23 ) / s;
|
||||
this.y = ( m13 - m31 ) / s;
|
||||
this.z = ( m21 - m12 ) / s;
|
||||
this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
min: function ( v ) {
|
||||
|
||||
this.x = Math.min( this.x, v.x );
|
||||
this.y = Math.min( this.y, v.y );
|
||||
this.z = Math.min( this.z, v.z );
|
||||
this.w = Math.min( this.w, v.w );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
max: function ( v ) {
|
||||
|
||||
this.x = Math.max( this.x, v.x );
|
||||
this.y = Math.max( this.y, v.y );
|
||||
this.z = Math.max( this.z, v.z );
|
||||
this.w = Math.max( this.w, v.w );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clamp: function ( min, max ) {
|
||||
|
||||
// assumes min < max, componentwise
|
||||
|
||||
this.x = Math.max( min.x, Math.min( max.x, this.x ) );
|
||||
this.y = Math.max( min.y, Math.min( max.y, this.y ) );
|
||||
this.z = Math.max( min.z, Math.min( max.z, this.z ) );
|
||||
this.w = Math.max( min.w, Math.min( max.w, this.w ) );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
clampScalar: function () {
|
||||
|
||||
var min, max;
|
||||
|
||||
return function clampScalar( minVal, maxVal ) {
|
||||
|
||||
if ( min === undefined ) {
|
||||
|
||||
min = new Vector4();
|
||||
max = new Vector4();
|
||||
|
||||
}
|
||||
|
||||
min.set( minVal, minVal, minVal, minVal );
|
||||
max.set( maxVal, maxVal, maxVal, maxVal );
|
||||
|
||||
return this.clamp( min, max );
|
||||
|
||||
};
|
||||
|
||||
}(),
|
||||
|
||||
clampLength: function ( min, max ) {
|
||||
|
||||
var length = this.length();
|
||||
|
||||
return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
|
||||
|
||||
},
|
||||
|
||||
floor: function () {
|
||||
|
||||
this.x = Math.floor( this.x );
|
||||
this.y = Math.floor( this.y );
|
||||
this.z = Math.floor( this.z );
|
||||
this.w = Math.floor( this.w );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
ceil: function () {
|
||||
|
||||
this.x = Math.ceil( this.x );
|
||||
this.y = Math.ceil( this.y );
|
||||
this.z = Math.ceil( this.z );
|
||||
this.w = Math.ceil( this.w );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
round: function () {
|
||||
|
||||
this.x = Math.round( this.x );
|
||||
this.y = Math.round( this.y );
|
||||
this.z = Math.round( this.z );
|
||||
this.w = Math.round( this.w );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
roundToZero: function () {
|
||||
|
||||
this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
|
||||
this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
|
||||
this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
|
||||
this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
negate: function () {
|
||||
|
||||
this.x = - this.x;
|
||||
this.y = - this.y;
|
||||
this.z = - this.z;
|
||||
this.w = - this.w;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
dot: function ( v ) {
|
||||
|
||||
return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
|
||||
|
||||
},
|
||||
|
||||
lengthSq: function () {
|
||||
|
||||
return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
|
||||
|
||||
},
|
||||
|
||||
length: function () {
|
||||
|
||||
return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
|
||||
|
||||
},
|
||||
|
||||
manhattanLength: function () {
|
||||
|
||||
return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
|
||||
|
||||
},
|
||||
|
||||
normalize: function () {
|
||||
|
||||
return this.divideScalar( this.length() || 1 );
|
||||
|
||||
},
|
||||
|
||||
setLength: function ( length ) {
|
||||
|
||||
return this.normalize().multiplyScalar( length );
|
||||
|
||||
},
|
||||
|
||||
lerp: function ( v, alpha ) {
|
||||
|
||||
this.x += ( v.x - this.x ) * alpha;
|
||||
this.y += ( v.y - this.y ) * alpha;
|
||||
this.z += ( v.z - this.z ) * alpha;
|
||||
this.w += ( v.w - this.w ) * alpha;
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
lerpVectors: function ( v1, v2, alpha ) {
|
||||
|
||||
return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
|
||||
|
||||
},
|
||||
|
||||
equals: function ( v ) {
|
||||
|
||||
return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
|
||||
|
||||
},
|
||||
|
||||
fromArray: function ( array, offset ) {
|
||||
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
this.x = array[ offset ];
|
||||
this.y = array[ offset + 1 ];
|
||||
this.z = array[ offset + 2 ];
|
||||
this.w = array[ offset + 3 ];
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
toArray: function ( array, offset ) {
|
||||
|
||||
if ( array === undefined ) array = [];
|
||||
if ( offset === undefined ) offset = 0;
|
||||
|
||||
array[ offset ] = this.x;
|
||||
array[ offset + 1 ] = this.y;
|
||||
array[ offset + 2 ] = this.z;
|
||||
array[ offset + 3 ] = this.w;
|
||||
|
||||
return array;
|
||||
|
||||
},
|
||||
|
||||
fromBufferAttribute: function ( attribute, index, offset ) {
|
||||
|
||||
if ( offset !== undefined ) {
|
||||
|
||||
console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );
|
||||
|
||||
}
|
||||
|
||||
this.x = attribute.getX( index );
|
||||
this.y = attribute.getY( index );
|
||||
this.z = attribute.getZ( index );
|
||||
this.w = attribute.getW( index );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { Vector4 };
|
156
lib/math/interpolants/CubicInterpolant.js
Normal file
156
lib/math/interpolants/CubicInterpolant.js
Normal file
@ -0,0 +1,156 @@
|
||||
import { ZeroCurvatureEnding } from '../../constants.js';
|
||||
import { Interpolant } from '../Interpolant.js';
|
||||
import { WrapAroundEnding, ZeroSlopeEnding } from '../../constants.js';
|
||||
|
||||
/**
|
||||
* Fast and simple cubic spline interpolant.
|
||||
*
|
||||
* It was derived from a Hermitian construction setting the first derivative
|
||||
* at each sample position to the linear slope between neighboring positions
|
||||
* over their parameter interval.
|
||||
*
|
||||
* @author tschw
|
||||
*/
|
||||
|
||||
function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
|
||||
|
||||
Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
|
||||
|
||||
this._weightPrev = - 0;
|
||||
this._offsetPrev = - 0;
|
||||
this._weightNext = - 0;
|
||||
this._offsetNext = - 0;
|
||||
|
||||
}
|
||||
|
||||
CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
|
||||
|
||||
constructor: CubicInterpolant,
|
||||
|
||||
DefaultSettings_: {
|
||||
|
||||
endingStart: ZeroCurvatureEnding,
|
||||
endingEnd: ZeroCurvatureEnding
|
||||
|
||||
},
|
||||
|
||||
intervalChanged_: function ( i1, t0, t1 ) {
|
||||
|
||||
var pp = this.parameterPositions,
|
||||
iPrev = i1 - 2,
|
||||
iNext = i1 + 1,
|
||||
|
||||
tPrev = pp[ iPrev ],
|
||||
tNext = pp[ iNext ];
|
||||
|
||||
if ( tPrev === undefined ) {
|
||||
|
||||
switch ( this.getSettings_().endingStart ) {
|
||||
|
||||
case ZeroSlopeEnding:
|
||||
|
||||
// f'(t0) = 0
|
||||
iPrev = i1;
|
||||
tPrev = 2 * t0 - t1;
|
||||
|
||||
break;
|
||||
|
||||
case WrapAroundEnding:
|
||||
|
||||
// use the other end of the curve
|
||||
iPrev = pp.length - 2;
|
||||
tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
|
||||
|
||||
break;
|
||||
|
||||
default: // ZeroCurvatureEnding
|
||||
|
||||
// f''(t0) = 0 a.k.a. Natural Spline
|
||||
iPrev = i1;
|
||||
tPrev = t1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( tNext === undefined ) {
|
||||
|
||||
switch ( this.getSettings_().endingEnd ) {
|
||||
|
||||
case ZeroSlopeEnding:
|
||||
|
||||
// f'(tN) = 0
|
||||
iNext = i1;
|
||||
tNext = 2 * t1 - t0;
|
||||
|
||||
break;
|
||||
|
||||
case WrapAroundEnding:
|
||||
|
||||
// use the other end of the curve
|
||||
iNext = 1;
|
||||
tNext = t1 + pp[ 1 ] - pp[ 0 ];
|
||||
|
||||
break;
|
||||
|
||||
default: // ZeroCurvatureEnding
|
||||
|
||||
// f''(tN) = 0, a.k.a. Natural Spline
|
||||
iNext = i1 - 1;
|
||||
tNext = t0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var halfDt = ( t1 - t0 ) * 0.5,
|
||||
stride = this.valueSize;
|
||||
|
||||
this._weightPrev = halfDt / ( t0 - tPrev );
|
||||
this._weightNext = halfDt / ( tNext - t1 );
|
||||
this._offsetPrev = iPrev * stride;
|
||||
this._offsetNext = iNext * stride;
|
||||
|
||||
},
|
||||
|
||||
interpolate_: function ( i1, t0, t, t1 ) {
|
||||
|
||||
var result = this.resultBuffer,
|
||||
values = this.sampleValues,
|
||||
stride = this.valueSize,
|
||||
|
||||
o1 = i1 * stride, o0 = o1 - stride,
|
||||
oP = this._offsetPrev, oN = this._offsetNext,
|
||||
wP = this._weightPrev, wN = this._weightNext,
|
||||
|
||||
p = ( t - t0 ) / ( t1 - t0 ),
|
||||
pp = p * p,
|
||||
ppp = pp * p;
|
||||
|
||||
// evaluate polynomials
|
||||
|
||||
var sP = - wP * ppp + 2 * wP * pp - wP * p;
|
||||
var s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;
|
||||
var s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
|
||||
var sN = wN * ppp - wN * pp;
|
||||
|
||||
// combine data linearly
|
||||
|
||||
for ( var i = 0; i !== stride; ++ i ) {
|
||||
|
||||
result[ i ] =
|
||||
sP * values[ oP + i ] +
|
||||
s0 * values[ o0 + i ] +
|
||||
s1 * values[ o1 + i ] +
|
||||
sN * values[ oN + i ];
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { CubicInterpolant };
|
30
lib/math/interpolants/DiscreteInterpolant.js
Normal file
30
lib/math/interpolants/DiscreteInterpolant.js
Normal file
@ -0,0 +1,30 @@
|
||||
import { Interpolant } from '../Interpolant.js';
|
||||
|
||||
/**
|
||||
*
|
||||
* Interpolant that evaluates to the sample value at the position preceeding
|
||||
* the parameter.
|
||||
*
|
||||
* @author tschw
|
||||
*/
|
||||
|
||||
function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
|
||||
|
||||
Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
|
||||
|
||||
}
|
||||
|
||||
DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
|
||||
|
||||
constructor: DiscreteInterpolant,
|
||||
|
||||
interpolate_: function ( i1 /*, t0, t, t1 */ ) {
|
||||
|
||||
return this.copySampleValue_( i1 - 1 );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { DiscreteInterpolant };
|
44
lib/math/interpolants/LinearInterpolant.js
Normal file
44
lib/math/interpolants/LinearInterpolant.js
Normal file
@ -0,0 +1,44 @@
|
||||
import { Interpolant } from '../Interpolant.js';
|
||||
|
||||
/**
|
||||
* @author tschw
|
||||
*/
|
||||
|
||||
function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
|
||||
|
||||
Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
|
||||
|
||||
}
|
||||
|
||||
LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
|
||||
|
||||
constructor: LinearInterpolant,
|
||||
|
||||
interpolate_: function ( i1, t0, t, t1 ) {
|
||||
|
||||
var result = this.resultBuffer,
|
||||
values = this.sampleValues,
|
||||
stride = this.valueSize,
|
||||
|
||||
offset1 = i1 * stride,
|
||||
offset0 = offset1 - stride,
|
||||
|
||||
weight1 = ( t - t0 ) / ( t1 - t0 ),
|
||||
weight0 = 1 - weight1;
|
||||
|
||||
for ( var i = 0; i !== stride; ++ i ) {
|
||||
|
||||
result[ i ] =
|
||||
values[ offset0 + i ] * weight0 +
|
||||
values[ offset1 + i ] * weight1;
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { LinearInterpolant };
|
43
lib/math/interpolants/QuaternionLinearInterpolant.js
Normal file
43
lib/math/interpolants/QuaternionLinearInterpolant.js
Normal file
@ -0,0 +1,43 @@
|
||||
import { Interpolant } from '../Interpolant.js';
|
||||
import { Quaternion } from '../Quaternion.js';
|
||||
|
||||
/**
|
||||
* Spherical linear unit quaternion interpolant.
|
||||
*
|
||||
* @author tschw
|
||||
*/
|
||||
|
||||
function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
|
||||
|
||||
Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
|
||||
|
||||
}
|
||||
|
||||
QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
|
||||
|
||||
constructor: QuaternionLinearInterpolant,
|
||||
|
||||
interpolate_: function ( i1, t0, t, t1 ) {
|
||||
|
||||
var result = this.resultBuffer,
|
||||
values = this.sampleValues,
|
||||
stride = this.valueSize,
|
||||
|
||||
offset = i1 * stride,
|
||||
|
||||
alpha = ( t - t0 ) / ( t1 - t0 );
|
||||
|
||||
for ( var end = offset + stride; offset !== end; offset += 4 ) {
|
||||
|
||||
Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { QuaternionLinearInterpolant };
|
Reference in New Issue
Block a user