tsmathlib
Version:
Typescript Version Math/Physics/CG Library
138 lines (115 loc) • 4.4 kB
text/typescript
/*
* @Author: Xu.Wang
* @Date: 2020-04-15 22:13:18
* @Last Modified by: Xu.Wang
* @Last Modified time: 2020-04-16 00:22:02
*/
import { Surface, SurfaceRayIntersection3 } from './surface'
import { Vector3, clampV3 } from '../math'
import { Transform } from './transform'
import { Ray } from '.'
import { BoundingBox } from './bounding_box'
import { PhysicsPlane } from './physics_plane'
export class PhysicsBox extends Surface {
private _bound: BoundingBox
constructor(
lower: Vector3 = new Vector3(),
upper: Vector3 = new Vector3(1.0, 1.0, 1.0),
transform: Transform = new Transform(),
isNormalFlipped: boolean = false
) {
super(transform, isNormalFlipped)
this._bound = new BoundingBox(lower, upper)
}
setWithBbox(bbox: BoundingBox) {
this._bound = bbox
}
bound(): BoundingBox {
return this._bound
}
closestPointLocal(otherPoint: Vector3): Vector3 {
if (this._bound.contains(otherPoint)) {
let planes = new Array<PhysicsPlane>(
new PhysicsPlane(new Vector3(1, 0, 0), this._bound.upper()),
new PhysicsPlane(new Vector3(0, 1, 0), this._bound.upper()),
new PhysicsPlane(new Vector3(0, 0, 1), this._bound.upper()),
new PhysicsPlane(new Vector3(-1, 0, 0), this._bound.lower()),
new PhysicsPlane(new Vector3(0, -1, 0), this._bound.lower()),
new PhysicsPlane(new Vector3(0, 0, -1), this._bound.lower())
)
let result = planes[0].closestPoint(otherPoint)
let distanceSquared = result.distanceSquaredTo(otherPoint)
for (let i = 1; i < 6; ++i) {
let localResult = planes[i].closestPoint(otherPoint)
let localDistanceSquared = localResult.distanceSquaredTo(otherPoint)
if (localDistanceSquared < distanceSquared) {
result = localResult
distanceSquared = localDistanceSquared
}
}
return result
} else {
return clampV3(otherPoint, this._bound.lower(), this._bound.upper())
}
}
closestNormalLocal(otherPoint: Vector3): Vector3 {
let planes = new Array<PhysicsPlane>(
new PhysicsPlane(new Vector3(1, 0, 0), this._bound.upper()),
new PhysicsPlane(new Vector3(0, 1, 0), this._bound.upper()),
new PhysicsPlane(new Vector3(0, 0, 1), this._bound.upper()),
new PhysicsPlane(new Vector3(-1, 0, 0), this._bound.lower()),
new PhysicsPlane(new Vector3(0, -1, 0), this._bound.lower()),
new PhysicsPlane(new Vector3(0, 0, -1), this._bound.lower())
)
if (this._bound.contains(otherPoint)) {
let closestNormal = planes[0].normal()
let closestPoint = planes[0].closestPoint(otherPoint)
let minDistanceSquared = closestPoint.sub(otherPoint).lengthSquared()
for (let i = 1; i < 6; ++i) {
let localClosestPoint = planes[i].closestPoint(otherPoint)
let localDistanceSquared = localClosestPoint
.sub(otherPoint)
.lengthSquared()
if (localDistanceSquared < minDistanceSquared) {
closestNormal = planes[i].normal()
minDistanceSquared = localDistanceSquared
}
}
return closestNormal
} else {
let closestPoint = clampV3(
otherPoint,
this._bound.lower(),
this._bound.upper()
)
let closestPointToInputPoint = otherPoint.sub(closestPoint)
let closestNormal = planes[0].normal()
let maxCosineAngle = closestNormal.dot(closestPointToInputPoint)
for (let i = 1; i < 6; ++i) {
let cosineAngle = planes[i].normal().dot(closestPointToInputPoint)
if (cosineAngle > maxCosineAngle) {
closestNormal = planes[i].normal()
maxCosineAngle = cosineAngle
}
}
return closestNormal
}
}
intersectsLocal(ray: Ray): boolean {
return this._bound.intersects(ray)
}
closestIntersectionLocal(ray: Ray): SurfaceRayIntersection3 {
let intersection = new SurfaceRayIntersection3()
let bbRayIntersection = this._bound.closestIntersection(ray)
intersection.isIntersecting = bbRayIntersection.isIntersecting
if (intersection.isIntersecting) {
intersection.distance = bbRayIntersection.Near
intersection.point = ray.pointAt(bbRayIntersection.Near)
intersection.normal = this.closestNormal(intersection.point)
}
return intersection
}
boundingBoxLocal(): BoundingBox {
return this._bound
}
}