Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/flo-bit/shapecraft. flo-bit.dev/shapecraft
Something went wrong. Try again.
7.1 kB · 335 lines
JavaScript
at commit 049ef598
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336import { Vector3 } from './Vector3.js';import { Vector4 } from './Vector4.js';
const _v0 = /*@__PURE__*/ new Vector3();const _v1 = /*@__PURE__*/ new Vector3();const _v2 = /*@__PURE__*/ new Vector3();const _v3 = /*@__PURE__*/ new Vector3();
const _vab = /*@__PURE__*/ new Vector3();const _vac = /*@__PURE__*/ new Vector3();const _vbc = /*@__PURE__*/ new Vector3();const _vap = /*@__PURE__*/ new Vector3();const _vbp = /*@__PURE__*/ new Vector3();const _vcp = /*@__PURE__*/ new Vector3();
const _v40 = /*@__PURE__*/ new Vector4();const _v41 = /*@__PURE__*/ new Vector4();const _v42 = /*@__PURE__*/ new Vector4();
class Triangle {
constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) {
this.a = a; this.b = b; this.c = c;
}
static getNormal( a, b, c, target ) {
target.subVectors( c, b ); _v0.subVectors( a, b ); target.cross( _v0 );
const 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 static getBarycoord( point, a, b, c, target ) {
_v0.subVectors( c, a ); _v1.subVectors( b, a ); _v2.subVectors( point, a );
const dot00 = _v0.dot( _v0 ); const dot01 = _v0.dot( _v1 ); const dot02 = _v0.dot( _v2 ); const dot11 = _v1.dot( _v1 ); const dot12 = _v1.dot( _v2 );
const denom = ( dot00 * dot11 - dot01 * dot01 );
// collinear or singular triangle if ( denom === 0 ) {
target.set( 0, 0, 0 ); return null;
}
const invDenom = 1 / denom; const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
// barycentric coordinates must always sum to 1 return target.set( 1 - u - v, v, u );
}
static containsPoint( point, a, b, c ) {
// if the triangle is degenerate then we can't contain a point if ( this.getBarycoord( point, a, b, c, _v3 ) === null ) {
return false;
}
return ( _v3.x >= 0 ) && ( _v3.y >= 0 ) && ( ( _v3.x + _v3.y ) <= 1 );
}
static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) {
if ( this.getBarycoord( point, p1, p2, p3, _v3 ) === null ) {
target.x = 0; target.y = 0; if ( 'z' in target ) target.z = 0; if ( 'w' in target ) target.w = 0; return null;
}
target.setScalar( 0 ); target.addScaledVector( v1, _v3.x ); target.addScaledVector( v2, _v3.y ); target.addScaledVector( v3, _v3.z );
return target;
}
static getInterpolatedAttribute( attr, i1, i2, i3, barycoord, target ) {
_v40.setScalar( 0 ); _v41.setScalar( 0 ); _v42.setScalar( 0 );
_v40.fromBufferAttribute( attr, i1 ); _v41.fromBufferAttribute( attr, i2 ); _v42.fromBufferAttribute( attr, i3 );
target.setScalar( 0 ); target.addScaledVector( _v40, barycoord.x ); target.addScaledVector( _v41, barycoord.y ); target.addScaledVector( _v42, barycoord.z );
return target;
}
static isFrontFacing( a, b, c, direction ) {
_v0.subVectors( c, b ); _v1.subVectors( a, b );
// strictly front facing return ( _v0.cross( _v1 ).dot( direction ) < 0 ) ? true : false;
}
set( a, b, c ) {
this.a.copy( a ); this.b.copy( b ); this.c.copy( c );
return this;
}
setFromPointsAndIndices( points, i0, i1, i2 ) {
this.a.copy( points[ i0 ] ); this.b.copy( points[ i1 ] ); this.c.copy( points[ i2 ] );
return this;
}
setFromAttributeAndIndices( attribute, i0, i1, i2 ) {
this.a.fromBufferAttribute( attribute, i0 ); this.b.fromBufferAttribute( attribute, i1 ); this.c.fromBufferAttribute( attribute, i2 );
return this;
}
clone() {
return new this.constructor().copy( this );
}
copy( triangle ) {
this.a.copy( triangle.a ); this.b.copy( triangle.b ); this.c.copy( triangle.c );
return this;
}
getArea() {
_v0.subVectors( this.c, this.b ); _v1.subVectors( this.a, this.b );
return _v0.cross( _v1 ).length() * 0.5;
}
getMidpoint( target ) {
return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
}
getNormal( target ) {
return Triangle.getNormal( this.a, this.b, this.c, target );
}
getPlane( target ) {
return target.setFromCoplanarPoints( this.a, this.b, this.c );
}
getBarycoord( point, target ) {
return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
}
getInterpolation( point, v1, v2, v3, target ) {
return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target );
}
containsPoint( point ) {
return Triangle.containsPoint( point, this.a, this.b, this.c );
}
isFrontFacing( direction ) {
return Triangle.isFrontFacing( this.a, this.b, this.c, direction );
}
intersectsBox( box ) {
return box.intersectsTriangle( this );
}
closestPointToPoint( p, target ) {
const a = this.a, b = this.b, c = this.c; let 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 ); const d1 = _vab.dot( _vap ); const 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 ); const d3 = _vab.dot( _vbp ); const d4 = _vac.dot( _vbp ); if ( d3 >= 0 && d4 <= d3 ) {
// vertex region of B; barycentric coords (0, 1, 0) return target.copy( b );
}
const 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 ); const d5 = _vab.dot( _vcp ); const d6 = _vac.dot( _vcp ); if ( d6 >= 0 && d5 <= d6 ) {
// vertex region of C; barycentric coords (0, 0, 1) return target.copy( c );
}
const 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 );
}
const 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 const 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( triangle ) {
return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
}
}
export { Triangle };