UNPKG

@turbox3d/math

Version:

Large-scale graphics application math library

223 lines 7.74 kB
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck"; import _createClass from "@babel/runtime/helpers/esm/createClass"; import { Vector3 } from './Vector3'; var _vector = new Vector3(); var _segCenter = new Vector3(); var _segDir = new Vector3(); var _diff = new Vector3(); var Ray = /*#__PURE__*/function () { function Ray(origin, direction) { _classCallCheck(this, Ray); this.origin = origin !== undefined ? origin : new Vector3(); this.direction = direction !== undefined ? direction : new Vector3(0, 0, -1); } return _createClass(Ray, [{ key: "set", value: function set(origin, direction) { this.origin.copy(origin); this.direction.copy(direction); return this; } }, { key: "clone", value: function clone() { return new Ray().copy(this); } }, { key: "copy", value: function copy(ray) { this.origin.copy(ray.origin); this.direction.copy(ray.direction); return this; } }, { key: "at", value: function at(t, target) { return target.copy(this.direction).multiplyScalar(t).add(this.origin); } }, { key: "lookAt", value: function lookAt(v) { this.direction.copy(v).sub(this.origin).normalize(); return this; } }, { key: "recast", value: function recast(t) { this.origin.copy(this.at(t, _vector)); return this; } }, { key: "closestPointToPoint", value: function closestPointToPoint(point, target) { target.subVectors(point, this.origin); var directionDistance = target.dot(this.direction); if (directionDistance < 0) { return target.copy(this.origin); } return target.copy(this.direction).multiplyScalar(directionDistance).add(this.origin); } }, { key: "distanceToPoint", value: function distanceToPoint(point) { return Math.sqrt(this.distanceSqToPoint(point)); } }, { key: "distanceSqToPoint", value: function distanceSqToPoint(point) { var directionDistance = _vector.subVectors(point, this.origin).dot(this.direction); // point behind the ray if (directionDistance < 0) { return this.origin.distanceToSquared(point); } _vector.copy(this.direction).multiplyScalar(directionDistance).add(this.origin); return _vector.distanceToSquared(point); } }, { key: "distanceSqToSegment", value: function distanceSqToSegment(v0, v1, optionalPointOnRay, optionalPointOnSegment) { // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h // It returns the min distance between the ray and the segment // defined by v0 and v1 // It can also set two optional targets : // - The closest point on the ray // - The closest point on the segment _segCenter.copy(v0).add(v1).multiplyScalar(0.5); _segDir.copy(v1).sub(v0).normalize(); _diff.copy(this.origin).sub(_segCenter); var segExtent = v0.distanceTo(v1) * 0.5; var a01 = -this.direction.dot(_segDir); var b0 = _diff.dot(this.direction); var b1 = -_diff.dot(_segDir); var c = _diff.lengthSq; var det = Math.abs(1 - a01 * a01); var s0; var s1; var sqrDist; var extDet; if (det > 0) { // The ray and segment are not parallel. s0 = a01 * b1 - b0; s1 = a01 * b0 - b1; extDet = segExtent * det; if (s0 >= 0) { if (s1 >= -extDet) { if (s1 <= extDet) { // region 0 // Minimum at interior points of ray and segment. var invDet = 1 / det; s0 *= invDet; s1 *= invDet; sqrDist = s0 * (s0 + a01 * s1 + 2 * b0) + s1 * (a01 * s0 + s1 + 2 * b1) + c; } else { // region 1 s1 = segExtent; s0 = Math.max(0, -(a01 * s1 + b0)); sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c; } } else { // region 5 s1 = -segExtent; s0 = Math.max(0, -(a01 * s1 + b0)); sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c; } } else if (s1 <= -extDet) { // region 4 s0 = Math.max(0, -(-a01 * segExtent + b0)); s1 = s0 > 0 ? -segExtent : Math.min(Math.max(-segExtent, -b1), segExtent); sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c; } else if (s1 <= extDet) { // region 3 s0 = 0; s1 = Math.min(Math.max(-segExtent, -b1), segExtent); sqrDist = s1 * (s1 + 2 * b1) + c; } else { // region 2 s0 = Math.max(0, -(a01 * segExtent + b0)); s1 = s0 > 0 ? segExtent : Math.min(Math.max(-segExtent, -b1), segExtent); sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c; } } else { // Ray and segment are parallel. s1 = a01 > 0 ? -segExtent : segExtent; s0 = Math.max(0, -(a01 * s1 + b0)); sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c; } if (optionalPointOnRay) { optionalPointOnRay.copy(this.direction).multiplyScalar(s0).add(this.origin); } if (optionalPointOnSegment) { optionalPointOnSegment.copy(_segDir).multiplyScalar(s1).add(_segCenter); } return sqrDist; } }, { key: "intersectBox", value: function intersectBox(box, target) { var tmin; var tmax; var tymin; var tymax; var tzmin; var tzmax; var invdirx = 1 / this.direction.x; var invdiry = 1 / this.direction.y; var invdirz = 1 / this.direction.z; var origin = this.origin; if (invdirx >= 0) { tmin = (box.min.x - origin.x) * invdirx; tmax = (box.max.x - origin.x) * invdirx; } else { tmin = (box.max.x - origin.x) * invdirx; tmax = (box.min.x - origin.x) * invdirx; } if (invdiry >= 0) { tymin = (box.min.y - origin.y) * invdiry; tymax = (box.max.y - origin.y) * invdiry; } else { tymin = (box.max.y - origin.y) * invdiry; tymax = (box.min.y - origin.y) * invdiry; } if (tmin > tymax || tymin > tmax) return null; // These lines also handle the case where tmin or tmax is NaN // (result of 0 * Infinity). x !== x returns true if x is NaN // eslint-disable-next-line no-self-compare if (tymin > tmin || tmin !== tmin) tmin = tymin; // eslint-disable-next-line no-self-compare if (tymax < tmax || tmax !== tmax) tmax = tymax; if (invdirz >= 0) { tzmin = (box.min.z - origin.z) * invdirz; tzmax = (box.max.z - origin.z) * invdirz; } else { tzmin = (box.max.z - origin.z) * invdirz; tzmax = (box.min.z - origin.z) * invdirz; } if (tmin > tzmax || tzmin > tmax) return null; // eslint-disable-next-line no-self-compare if (tzmin > tmin || tmin !== tmin) tmin = tzmin; // eslint-disable-next-line no-self-compare if (tzmax < tmax || tmax !== tmax) tmax = tzmax; // return point closest to the ray (positive side) if (tmax < 0) return null; return this.at(tmin >= 0 ? tmin : tmax, target); } }, { key: "intersectsBox", value: function intersectsBox(box) { return this.intersectBox(box, _vector) !== null; } }, { key: "applyMatrix4", value: function applyMatrix4(matrix4) { this.origin.applyMatrix4(matrix4); this.direction.transformDirection(matrix4); return this; } }, { key: "equals", value: function equals(ray) { return ray.origin.equals(this.origin) && ray.direction.equals(this.direction); } }]); }(); export { Ray };