350 lines
7.1 KiB
JavaScript
350 lines
7.1 KiB
JavaScript
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 };
|