Buckets:
ktongue/docker_container / simsite /frontend /node_modules /three-mesh-bvh /src /math /ExtendedTriangle.js
| import { Triangle, Vector3, Line3, Sphere, Plane } from 'three'; | |
| import { SeparatingAxisBounds } from './SeparatingAxisBounds.js'; | |
| import { closestPointsSegmentToSegment, sphereIntersectTriangle } from './MathUtilities.js'; | |
| const ZERO_EPSILON = 1e-15; | |
| function isNearZero( value ) { | |
| return Math.abs( value ) < ZERO_EPSILON; | |
| } | |
| export class ExtendedTriangle extends Triangle { | |
| constructor( ...args ) { | |
| super( ...args ); | |
| this.isExtendedTriangle = true; | |
| this.satAxes = new Array( 4 ).fill().map( () => new Vector3() ); | |
| this.satBounds = new Array( 4 ).fill().map( () => new SeparatingAxisBounds() ); | |
| this.points = [ this.a, this.b, this.c ]; | |
| this.sphere = new Sphere(); | |
| this.plane = new Plane(); | |
| this.needsUpdate = true; | |
| } | |
| intersectsSphere( sphere ) { | |
| return sphereIntersectTriangle( sphere, this ); | |
| } | |
| update() { | |
| const a = this.a; | |
| const b = this.b; | |
| const c = this.c; | |
| const points = this.points; | |
| const satAxes = this.satAxes; | |
| const satBounds = this.satBounds; | |
| const axis0 = satAxes[ 0 ]; | |
| const sab0 = satBounds[ 0 ]; | |
| this.getNormal( axis0 ); | |
| sab0.setFromPoints( axis0, points ); | |
| const axis1 = satAxes[ 1 ]; | |
| const sab1 = satBounds[ 1 ]; | |
| axis1.subVectors( a, b ); | |
| sab1.setFromPoints( axis1, points ); | |
| const axis2 = satAxes[ 2 ]; | |
| const sab2 = satBounds[ 2 ]; | |
| axis2.subVectors( b, c ); | |
| sab2.setFromPoints( axis2, points ); | |
| const axis3 = satAxes[ 3 ]; | |
| const sab3 = satBounds[ 3 ]; | |
| axis3.subVectors( c, a ); | |
| sab3.setFromPoints( axis3, points ); | |
| this.sphere.setFromPoints( this.points ); | |
| this.plane.setFromNormalAndCoplanarPoint( axis0, a ); | |
| this.needsUpdate = false; | |
| } | |
| } | |
| ExtendedTriangle.prototype.closestPointToSegment = ( function () { | |
| const point1 = new Vector3(); | |
| const point2 = new Vector3(); | |
| const edge = new Line3(); | |
| return function distanceToSegment( segment, target1 = null, target2 = null ) { | |
| const { start, end } = segment; | |
| const points = this.points; | |
| let distSq; | |
| let closestDistanceSq = Infinity; | |
| // check the triangle edges | |
| for ( let i = 0; i < 3; i ++ ) { | |
| const nexti = ( i + 1 ) % 3; | |
| edge.start.copy( points[ i ] ); | |
| edge.end.copy( points[ nexti ] ); | |
| closestPointsSegmentToSegment( edge, segment, point1, point2 ); | |
| distSq = point1.distanceToSquared( point2 ); | |
| if ( distSq < closestDistanceSq ) { | |
| closestDistanceSq = distSq; | |
| if ( target1 ) target1.copy( point1 ); | |
| if ( target2 ) target2.copy( point2 ); | |
| } | |
| } | |
| // check end points | |
| this.closestPointToPoint( start, point1 ); | |
| distSq = start.distanceToSquared( point1 ); | |
| if ( distSq < closestDistanceSq ) { | |
| closestDistanceSq = distSq; | |
| if ( target1 ) target1.copy( point1 ); | |
| if ( target2 ) target2.copy( start ); | |
| } | |
| this.closestPointToPoint( end, point1 ); | |
| distSq = end.distanceToSquared( point1 ); | |
| if ( distSq < closestDistanceSq ) { | |
| closestDistanceSq = distSq; | |
| if ( target1 ) target1.copy( point1 ); | |
| if ( target2 ) target2.copy( end ); | |
| } | |
| return Math.sqrt( closestDistanceSq ); | |
| }; | |
| } )(); | |
| ExtendedTriangle.prototype.intersectsTriangle = ( function () { | |
| const saTri2 = new ExtendedTriangle(); | |
| const arr1 = new Array( 3 ); | |
| const arr2 = new Array( 3 ); | |
| const cachedSatBounds = new SeparatingAxisBounds(); | |
| const cachedSatBounds2 = new SeparatingAxisBounds(); | |
| const cachedAxis = new Vector3(); | |
| const dir = new Vector3(); | |
| const dir1 = new Vector3(); | |
| const dir2 = new Vector3(); | |
| const tempDir = new Vector3(); | |
| const edge = new Line3(); | |
| const edge1 = new Line3(); | |
| const edge2 = new Line3(); | |
| const tempPoint = new Vector3(); | |
| function triIntersectPlane( tri, plane, targetEdge ) { | |
| // find the edge that intersects the other triangle plane | |
| const points = tri.points; | |
| let count = 0; | |
| let startPointIntersection = - 1; | |
| for ( let i = 0; i < 3; i ++ ) { | |
| const { start, end } = edge; | |
| start.copy( points[ i ] ); | |
| end.copy( points[ ( i + 1 ) % 3 ] ); | |
| edge.delta( dir ); | |
| const startIntersects = isNearZero( plane.distanceToPoint( start ) ); | |
| if ( isNearZero( plane.normal.dot( dir ) ) && startIntersects ) { | |
| // if the edge lies on the plane then take the line | |
| targetEdge.copy( edge ); | |
| count = 2; | |
| break; | |
| } | |
| // check if the start point is near the plane because "intersectLine" is not robust to that case | |
| const doesIntersect = plane.intersectLine( edge, tempPoint ); | |
| if ( ! doesIntersect && startIntersects ) { | |
| tempPoint.copy( start ); | |
| } | |
| // ignore the end point | |
| if ( ( doesIntersect || startIntersects ) && ! isNearZero( tempPoint.distanceTo( end ) ) ) { | |
| if ( count <= 1 ) { | |
| // assign to the start or end point and save which index was snapped to | |
| // the start point if necessary | |
| const point = count === 1 ? targetEdge.start : targetEdge.end; | |
| point.copy( tempPoint ); | |
| if ( startIntersects ) { | |
| startPointIntersection = count; | |
| } | |
| } else if ( count >= 2 ) { | |
| // if we're here that means that there must have been one point that had | |
| // snapped to the start point so replace it here | |
| const point = startPointIntersection === 1 ? targetEdge.start : targetEdge.end; | |
| point.copy( tempPoint ); | |
| count = 2; | |
| break; | |
| } | |
| count ++; | |
| if ( count === 2 && startPointIntersection === - 1 ) { | |
| break; | |
| } | |
| } | |
| } | |
| return count; | |
| } | |
| // TODO: If the triangles are coplanar and intersecting the target is nonsensical. It should at least | |
| // be a line contained by both triangles if not a different special case somehow represented in the return result. | |
| return function intersectsTriangle( other, target = null, suppressLog = false ) { | |
| if ( this.needsUpdate ) { | |
| this.update(); | |
| } | |
| if ( ! other.isExtendedTriangle ) { | |
| saTri2.copy( other ); | |
| saTri2.update(); | |
| other = saTri2; | |
| } else if ( other.needsUpdate ) { | |
| other.update(); | |
| } | |
| const plane1 = this.plane; | |
| const plane2 = other.plane; | |
| if ( Math.abs( plane1.normal.dot( plane2.normal ) ) > 1.0 - 1e-10 ) { | |
| // perform separating axis intersection test only for coplanar triangles | |
| const satBounds1 = this.satBounds; | |
| const satAxes1 = this.satAxes; | |
| arr2[ 0 ] = other.a; | |
| arr2[ 1 ] = other.b; | |
| arr2[ 2 ] = other.c; | |
| for ( let i = 0; i < 4; i ++ ) { | |
| const sb = satBounds1[ i ]; | |
| const sa = satAxes1[ i ]; | |
| cachedSatBounds.setFromPoints( sa, arr2 ); | |
| if ( sb.isSeparated( cachedSatBounds ) ) return false; | |
| } | |
| const satBounds2 = other.satBounds; | |
| const satAxes2 = other.satAxes; | |
| arr1[ 0 ] = this.a; | |
| arr1[ 1 ] = this.b; | |
| arr1[ 2 ] = this.c; | |
| for ( let i = 0; i < 4; i ++ ) { | |
| const sb = satBounds2[ i ]; | |
| const sa = satAxes2[ i ]; | |
| cachedSatBounds.setFromPoints( sa, arr1 ); | |
| if ( sb.isSeparated( cachedSatBounds ) ) return false; | |
| } | |
| // check crossed axes | |
| for ( let i = 0; i < 4; i ++ ) { | |
| const sa1 = satAxes1[ i ]; | |
| for ( let i2 = 0; i2 < 4; i2 ++ ) { | |
| const sa2 = satAxes2[ i2 ]; | |
| cachedAxis.crossVectors( sa1, sa2 ); | |
| cachedSatBounds.setFromPoints( cachedAxis, arr1 ); | |
| cachedSatBounds2.setFromPoints( cachedAxis, arr2 ); | |
| if ( cachedSatBounds.isSeparated( cachedSatBounds2 ) ) return false; | |
| } | |
| } | |
| if ( target ) { | |
| // TODO find two points that intersect on the edges and make that the result | |
| if ( ! suppressLog ) { | |
| console.warn( 'ExtendedTriangle.intersectsTriangle: Triangles are coplanar which does not support an output edge. Setting edge to 0, 0, 0.' ); | |
| } | |
| target.start.set( 0, 0, 0 ); | |
| target.end.set( 0, 0, 0 ); | |
| } | |
| return true; | |
| } else { | |
| // find the edge that intersects the other triangle plane | |
| const count1 = triIntersectPlane( this, plane2, edge1 ); | |
| if ( count1 === 1 && other.containsPoint( edge1.end ) ) { | |
| if ( target ) { | |
| target.start.copy( edge1.end ); | |
| target.end.copy( edge1.end ); | |
| } | |
| return true; | |
| } else if ( count1 !== 2 ) { | |
| return false; | |
| } | |
| // find the other triangles edge that intersects this plane | |
| const count2 = triIntersectPlane( other, plane1, edge2 ); | |
| if ( count2 === 1 && this.containsPoint( edge2.end ) ) { | |
| if ( target ) { | |
| target.start.copy( edge2.end ); | |
| target.end.copy( edge2.end ); | |
| } | |
| return true; | |
| } else if ( count2 !== 2 ) { | |
| return false; | |
| } | |
| // find swap the second edge so both lines are running the same direction | |
| edge1.delta( dir1 ); | |
| edge2.delta( dir2 ); | |
| if ( dir1.dot( dir2 ) < 0 ) { | |
| let tmp = edge2.start; | |
| edge2.start = edge2.end; | |
| edge2.end = tmp; | |
| } | |
| // check if the edges are overlapping | |
| const s1 = edge1.start.dot( dir1 ); | |
| const e1 = edge1.end.dot( dir1 ); | |
| const s2 = edge2.start.dot( dir1 ); | |
| const e2 = edge2.end.dot( dir1 ); | |
| const separated1 = e1 < s2; | |
| const separated2 = s1 < e2; | |
| if ( s1 !== e2 && s2 !== e1 && separated1 === separated2 ) { | |
| return false; | |
| } | |
| // assign the target output | |
| if ( target ) { | |
| tempDir.subVectors( edge1.start, edge2.start ); | |
| if ( tempDir.dot( dir1 ) > 0 ) { | |
| target.start.copy( edge1.start ); | |
| } else { | |
| target.start.copy( edge2.start ); | |
| } | |
| tempDir.subVectors( edge1.end, edge2.end ); | |
| if ( tempDir.dot( dir1 ) < 0 ) { | |
| target.end.copy( edge1.end ); | |
| } else { | |
| target.end.copy( edge2.end ); | |
| } | |
| } | |
| return true; | |
| } | |
| }; | |
| } )(); | |
| ExtendedTriangle.prototype.distanceToPoint = ( function () { | |
| const target = new Vector3(); | |
| return function distanceToPoint( point ) { | |
| this.closestPointToPoint( point, target ); | |
| return point.distanceTo( target ); | |
| }; | |
| } )(); | |
| ExtendedTriangle.prototype.distanceToTriangle = ( function () { | |
| const point = new Vector3(); | |
| const point2 = new Vector3(); | |
| const cornerFields = [ 'a', 'b', 'c' ]; | |
| const line1 = new Line3(); | |
| const line2 = new Line3(); | |
| return function distanceToTriangle( other, target1 = null, target2 = null ) { | |
| const lineTarget = target1 || target2 ? line1 : null; | |
| if ( this.intersectsTriangle( other, lineTarget ) ) { | |
| if ( target1 || target2 ) { | |
| if ( target1 ) lineTarget.getCenter( target1 ); | |
| if ( target2 ) lineTarget.getCenter( target2 ); | |
| } | |
| return 0; | |
| } | |
| let closestDistanceSq = Infinity; | |
| // check all point distances | |
| for ( let i = 0; i < 3; i ++ ) { | |
| let dist; | |
| const field = cornerFields[ i ]; | |
| const otherVec = other[ field ]; | |
| this.closestPointToPoint( otherVec, point ); | |
| dist = otherVec.distanceToSquared( point ); | |
| if ( dist < closestDistanceSq ) { | |
| closestDistanceSq = dist; | |
| if ( target1 ) target1.copy( point ); | |
| if ( target2 ) target2.copy( otherVec ); | |
| } | |
| const thisVec = this[ field ]; | |
| other.closestPointToPoint( thisVec, point ); | |
| dist = thisVec.distanceToSquared( point ); | |
| if ( dist < closestDistanceSq ) { | |
| closestDistanceSq = dist; | |
| if ( target1 ) target1.copy( thisVec ); | |
| if ( target2 ) target2.copy( point ); | |
| } | |
| } | |
| for ( let i = 0; i < 3; i ++ ) { | |
| const f11 = cornerFields[ i ]; | |
| const f12 = cornerFields[ ( i + 1 ) % 3 ]; | |
| line1.set( this[ f11 ], this[ f12 ] ); | |
| for ( let i2 = 0; i2 < 3; i2 ++ ) { | |
| const f21 = cornerFields[ i2 ]; | |
| const f22 = cornerFields[ ( i2 + 1 ) % 3 ]; | |
| line2.set( other[ f21 ], other[ f22 ] ); | |
| closestPointsSegmentToSegment( line1, line2, point, point2 ); | |
| const dist = point.distanceToSquared( point2 ); | |
| if ( dist < closestDistanceSq ) { | |
| closestDistanceSq = dist; | |
| if ( target1 ) target1.copy( point ); | |
| if ( target2 ) target2.copy( point2 ); | |
| } | |
| } | |
| } | |
| return Math.sqrt( closestDistanceSq ); | |
| }; | |
| } )(); | |
Xet Storage Details
- Size:
- 11.6 kB
- Xet hash:
- ddb04cd7db63494c2ee1dad5d2a0c3a56615ed692ac117d22032ffd7afc07115
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.