import { BoundingBox } from "./BoundingBox" ; import { BoundingFrustum } from "./BoundingFrustum" ; import { BoundingSphere } from "./BoundingSphere" ; import { ContainmentType } from "./enums/ContainmentType" ; import { PlaneIntersectionType } from "./enums/PlaneIntersectionType" ; import { MathUtil } from "./MathUtil" ; import { Plane } from "./Plane" ; import { Ray } from "./Ray" ; import { Vector3 } from "./Vector3" ; /**
 * Contains static methods to help in determining intersections, containment, etc.
 */ export class CollisionUtil { private static _tempVec30 : Vector3 = new Vector3 ( ) ; private static _tempVec31 : Vector3 = new Vector3 ( ) ; param plane param point returns static distancePlaneAndPoint ( plane , point ) { return Vector3 . dot ( plane . normal , point ) + plane . distance ; } param plane param point returns static intersectsPlaneAndPoint ( plane , point ) { const distance = CollisionUtil . distancePlaneAndPoint ( plane , point ) ; if ( distance > 0 ) { return PlaneIntersectionType . Front ; } if ( distance < 0 ) { return PlaneIntersectionType . Back ; } return PlaneIntersectionType . Intersecting ; } param plane param box returns static intersectsPlaneAndBox ( plane , box ) { const { min , max } = box ; const { normal } = plane ; const front = CollisionUtil . _tempVec30 ; const back = CollisionUtil . _tempVec31 ; if ( normal . x >= 0 ) { front . x = max . x ; back . x = min . x ; } else { front . x = min . x ; back . x = max . x ; } if ( normal . y >= 0 ) { front . y = max . y ; back . y = min . y ; } else { front . y = min . y ; back . y = max . y ; } if ( normal . z >= 0 ) { front . z = max . z ; back . z = min . z ; } else { front . z = min . z ; back . z = max . z ; } if ( CollisionUtil . distancePlaneAndPoint ( plane , front ) < 0 ) { return PlaneIntersectionType . Back ; } if ( CollisionUtil . distancePlaneAndPoint ( plane , back ) > 0 ) { return PlaneIntersectionType . Front ; } return PlaneIntersectionType . Intersecting ; } param plane param sphere returns static intersectsPlaneAndSphere ( plane , sphere ) { const { center , radius } = sphere ; const distance = CollisionUtil . distancePlaneAndPoint ( plane , center ) ; if ( distance > radius ) { return PlaneIntersectionType . Front ; } if ( distance < - radius ) { return PlaneIntersectionType . Back ; } return PlaneIntersectionType . Intersecting ; } param ray param plane returns static intersectsRayAndPlane ( ray , plane ) { const { normal } = plane ; const { zeroTolerance } = MathUtil ; const dir = Vector3 . dot ( normal , ray . direction ) ; if ( Math . abs ( dir ) < zeroTolerance ) { return - 1 ; } const position = Vector3 . dot ( normal , ray . origin ) ; let distance = ( - plane . distance - position ) / dir ; if ( distance < 0 ) { if ( distance < - zeroTolerance ) { return - 1 ; } distance = 0 ; } return distance ; } param ray param box returns static intersectsRayAndBox ( ray , box ) { const { zeroTolerance } = MathUtil ; const { origin , direction } = ray ; const { min , max } = box ; const dirX = direction . x ; const dirY = direction . y ; const dirZ = direction . z ; const oriX = origin . x ; const oriY = origin . y ; const oriZ = origin . z ; let distance = 0 ; let tmax = Number . MAX_VALUE ; if ( Math . abs ( dirX ) < zeroTolerance ) { if ( oriX < min . x || oriX > max . x ) { return - 1 ; } } else { const inverse = 1.0 / dirX ; let t1 = ( min . x - oriX ) * inverse ; let t2 = ( max . x - oriX ) * inverse ; if ( t1 > t2 ) { const temp = t1 ; t1 = t2 ; t2 = temp ; } distance = Math . max ( t1 , distance ) ; tmax = Math . min ( t2 , tmax ) ; if ( distance > tmax ) { return - 1 ; } } if ( Math . abs ( dirY ) < zeroTolerance ) { if ( oriY < min . y || oriY > max . y ) { return - 1 ; } } else { const inverse = 1.0 / dirY ; let t1 = ( min . y - oriY ) * inverse ; let t2 = ( max . y - oriY ) * inverse ; if ( t1 > t2 ) { const temp = t1 ; t1 = t2 ; t2 = temp ; } distance = Math . max ( t1 , distance ) ; tmax = Math . min ( t2 , tmax ) ; if ( distance > tmax ) { return - 1 ; } } if ( Math . abs ( dirZ ) < zeroTolerance ) { if ( oriZ < min . z || oriZ > max . z ) { return - 1 ; } } else { const inverse = 1.0 / dirZ ; let t1 = ( min . z - oriZ ) * inverse ; let t2 = ( max . z - oriZ ) * inverse ; if ( t1 > t2 ) { const temp = t1 ; t1 = t2 ; t2 = temp ; } distance = Math . max ( t1 , distance ) ; tmax = Math . min ( t2 , tmax ) ; if ( distance > tmax ) { return - 1 ; } } return distance ; } param ray param sphere returns static intersectsRayAndSphere ( ray , sphere ) { const { origin , direction } = ray ; const { center , radius } = sphere ; const m = CollisionUtil . _tempVec30 ; Vector3 . subtract ( origin , center , m ) ; const b = Vector3 . dot ( m , direction ) ; const c = Vector3 . dot ( m , m ) - radius * radius ; if ( b > 0 && c > 0 ) { return - 1 ; } let discriminant = b * b - c ; if ( discriminant < 0 ) { return - 1 ; } let distance = - b - Math . sqrt ( discriminant ) ; if ( distance < 0 ) { distance = 0 ; } return distance ; } param boxA param boxB returns static intersectsBoxAndBox ( boxA , boxB ) { if ( boxA . min . x > boxB . max . x || boxB . min . x > boxA . max . x ) { return false ; } if ( boxA . min . y > boxB . max . y || boxB . min . y > boxA . max . y ) { return false ; } return ! ( boxA . min . z > boxB . max . z || boxB . min . z > boxA . max . z ) ; } param sphereA param sphereB returns static intersectsSphereAndSphere ( sphereA , sphereB ) { const radiisum = sphereA . radius + sphereB . radius ; return Vector3 . distanceSquared ( sphereA . center , sphereB . center ) < radiisum * radiisum ; } param sphere param box returns static intersectsSphereAndBox ( sphere , box ) { const center = sphere . center ; const max = box . max ; const min = box . min ; const closestPoint = CollisionUtil . _tempVec30 ; closestPoint . setValue ( Math . max ( min . x , Math . min ( center . x , max . x ) ) , Math . max ( min . y , Math . min ( center . y , max . y ) ) , Math . max ( min . z , Math . min ( center . z , max . z ) ) ) ; const distance = Vector3 . distanceSquared ( center , closestPoint ) ; return distance <= sphere . radius * sphere . radius ; } param frustum param box returns static intersectsFrustumAndBox ( frustum , box ) { const { min , max } = box ; const back = CollisionUtil . _tempVec30 ; for ( let i = 0 ; i < 6 ; ++ i ) { const plane = frustum . getPlane ( i ) ; const normal = plane . normal ; back . x = normal . x >= 0 ? min . x : max . x ; back . y = normal . y >= 0 ? min . y : max . y ; back . z = normal . z >= 0 ? min . z : max . z ; if ( Vector3 . dot ( plane . normal , back ) > - plane . distance ) { return false ; } } return true ; } param frustum param box returns static frustumContainsBox ( frustum , box ) { const { min , max } = box ; const front = CollisionUtil . _tempVec30 ; const back = CollisionUtil . _tempVec31 ; let result = ContainmentType . Contains ; for ( let i = 0 ; i < 6 ; ++ i ) { const plane = frustum . getPlane ( i ) ; const normal = plane . normal ; if ( normal . x >= 0 ) { front . x = max . x ; back . x = min . x ; } else { front . x = min . x ; back . x = max . x ; } if ( normal . y >= 0 ) { front . y = max . y ; back . y = min . y ; } else { front . y = min . y ; back . y = max . y ; } if ( normal . z >= 0 ) { front . z = max . z ; back . z = min . z ; } else { front . z = min . z ; back . z = max . z ; } if ( CollisionUtil . intersectsPlaneAndPoint ( plane , back ) === PlaneIntersectionType . Front ) { return ContainmentType . Disjoint ; } if ( CollisionUtil . intersectsPlaneAndPoint ( plane , front ) === PlaneIntersectionType . Front ) { result = ContainmentType . Intersects ; } } return result ; } param frustum param sphere returns static frustumContainsSphere ( frustum , sphere ) { let result = ContainmentType . Contains ; for ( let i = 0 ; i < 6 ; ++ i ) { const plane = frustum . getPlane ( i ) ; const intersectionType = CollisionUtil . intersectsPlaneAndSphere ( plane , sphere ) ; if ( intersectionType === PlaneIntersectionType . Front ) { return ContainmentType . Disjoint ; } else if ( intersectionType === PlaneIntersectionType . Intersecting ) { result = ContainmentType . Intersects ; break ; } } return result ; } }