UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

453 lines (420 loc) 15.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Triangle = void 0; var _Vector = require("./Vector3.js"); var _Vector2 = require("./Vector4.js"); const _v0 = /*@__PURE__*/new _Vector.Vector3(); const _v1 = /*@__PURE__*/new _Vector.Vector3(); const _v2 = /*@__PURE__*/new _Vector.Vector3(); const _v3 = /*@__PURE__*/new _Vector.Vector3(); const _vab = /*@__PURE__*/new _Vector.Vector3(); const _vac = /*@__PURE__*/new _Vector.Vector3(); const _vbc = /*@__PURE__*/new _Vector.Vector3(); const _vap = /*@__PURE__*/new _Vector.Vector3(); const _vbp = /*@__PURE__*/new _Vector.Vector3(); const _vcp = /*@__PURE__*/new _Vector.Vector3(); const _v40 = /*@__PURE__*/new _Vector2.Vector4(); const _v41 = /*@__PURE__*/new _Vector2.Vector4(); const _v42 = /*@__PURE__*/new _Vector2.Vector4(); /** * A geometric triangle as defined by three vectors representing its three corners. */ class Triangle { /** * Constructs a new triangle. * * @param {Vector3} [a=(0,0,0)] - The first corner of the triangle. * @param {Vector3} [b=(0,0,0)] - The second corner of the triangle. * @param {Vector3} [c=(0,0,0)] - The third corner of the triangle. */ constructor(a = new _Vector.Vector3(), b = new _Vector.Vector3(), c = new _Vector.Vector3()) { /** * The first corner of the triangle. * * @type {Vector3} */ this.a = a; /** * The second corner of the triangle. * * @type {Vector3} */ this.b = b; /** * The third corner of the triangle. * * @type {Vector3} */ this.c = c; } /** * Computes the normal vector of a triangle. * * @param {Vector3} a - The first corner of the triangle. * @param {Vector3} b - The second corner of the triangle. * @param {Vector3} c - The third corner of the triangle. * @param {Vector3} target - The target vector that is used to store the method's result. * @return {Vector3} The triangle's normal. */ 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); } /** * Computes a barycentric coordinates from the given vector. * Returns `null` if the triangle is degenerate. * * @param {Vector3} point - A point in 3D space. * @param {Vector3} a - The first corner of the triangle. * @param {Vector3} b - The second corner of the triangle. * @param {Vector3} c - The third corner of the triangle. * @param {Vector3} target - The target vector that is used to store the method's result. * @return {?Vector3} The barycentric coordinates for the given point */ static getBarycoord(point, a, b, c, target) { // based on: http://www.blackpawn.com/texts/pointinpoly/default.html _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); } /** * Returns `true` if the given point, when projected onto the plane of the * triangle, lies within the triangle. * * @param {Vector3} point - The point in 3D space to test. * @param {Vector3} a - The first corner of the triangle. * @param {Vector3} b - The second corner of the triangle. * @param {Vector3} c - The third corner of the triangle. * @return {boolean} Whether the given point, when projected onto the plane of the * triangle, lies within the triangle or not. */ 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; } /** * Computes the value barycentrically interpolated for the given point on the * triangle. Returns `null` if the triangle is degenerate. * * @param {Vector3} point - Position of interpolated point. * @param {Vector3} p1 - The first corner of the triangle. * @param {Vector3} p2 - The second corner of the triangle. * @param {Vector3} p3 - The third corner of the triangle. * @param {Vector3} v1 - Value to interpolate of first vertex. * @param {Vector3} v2 - Value to interpolate of second vertex. * @param {Vector3} v3 - Value to interpolate of third vertex. * @param {Vector3} target - The target vector that is used to store the method's result. * @return {?Vector3} The interpolated value. */ 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; } /** * Computes the value barycentrically interpolated for the given attribute and indices. * * @param {BufferAttribute} attr - The attribute to interpolate. * @param {number} i1 - Index of first vertex. * @param {number} i2 - Index of second vertex. * @param {number} i3 - Index of third vertex. * @param {Vector3} barycoord - The barycoordinate value to use to interpolate. * @param {Vector3} target - The target vector that is used to store the method's result. * @return {Vector3} The interpolated attribute value. */ 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; } /** * Returns `true` if the triangle is oriented towards the given direction. * * @param {Vector3} a - The first corner of the triangle. * @param {Vector3} b - The second corner of the triangle. * @param {Vector3} c - The third corner of the triangle. * @param {Vector3} direction - The (normalized) direction vector. * @return {boolean} Whether the triangle is oriented towards the given direction or not. */ 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; } /** * Sets the triangle's vertices by copying the given values. * * @param {Vector3} a - The first corner of the triangle. * @param {Vector3} b - The second corner of the triangle. * @param {Vector3} c - The third corner of the triangle. * @return {Triangle} A reference to this triangle. */ set(a, b, c) { this.a.copy(a); this.b.copy(b); this.c.copy(c); return this; } /** * Sets the triangle's vertices by copying the given array values. * * @param {Array<Vector3>} points - An array with 3D points. * @param {number} i0 - The array index representing the first corner of the triangle. * @param {number} i1 - The array index representing the second corner of the triangle. * @param {number} i2 - The array index representing the third corner of the triangle. * @return {Triangle} A reference to this triangle. */ setFromPointsAndIndices(points, i0, i1, i2) { this.a.copy(points[i0]); this.b.copy(points[i1]); this.c.copy(points[i2]); return this; } /** * Sets the triangle's vertices by copying the given attribute values. * * @param {BufferAttribute} attribute - A buffer attribute with 3D points data. * @param {number} i0 - The attribute index representing the first corner of the triangle. * @param {number} i1 - The attribute index representing the second corner of the triangle. * @param {number} i2 - The attribute index representing the third corner of the triangle. * @return {Triangle} A reference to this triangle. */ setFromAttributeAndIndices(attribute, i0, i1, i2) { this.a.fromBufferAttribute(attribute, i0); this.b.fromBufferAttribute(attribute, i1); this.c.fromBufferAttribute(attribute, i2); return this; } /** * Returns a new triangle with copied values from this instance. * * @return {Triangle} A clone of this instance. */ clone() { return new this.constructor().copy(this); } /** * Copies the values of the given triangle to this instance. * * @param {Triangle} triangle - The triangle to copy. * @return {Triangle} A reference to this triangle. */ copy(triangle) { this.a.copy(triangle.a); this.b.copy(triangle.b); this.c.copy(triangle.c); return this; } /** * Computes the area of the triangle. * * @return {number} The triangle's area. */ getArea() { _v0.subVectors(this.c, this.b); _v1.subVectors(this.a, this.b); return _v0.cross(_v1).length() * 0.5; } /** * Computes the midpoint of the triangle. * * @param {Vector3} target - The target vector that is used to store the method's result. * @return {Vector3} The triangle's midpoint. */ getMidpoint(target) { return target.addVectors(this.a, this.b).add(this.c).multiplyScalar(1 / 3); } /** * Computes the normal of the triangle. * * @param {Vector3} target - The target vector that is used to store the method's result. * @return {Vector3} The triangle's normal. */ getNormal(target) { return Triangle.getNormal(this.a, this.b, this.c, target); } /** * Computes a plane the triangle lies within. * * @param {Plane} target - The target vector that is used to store the method's result. * @return {Plane} The plane the triangle lies within. */ getPlane(target) { return target.setFromCoplanarPoints(this.a, this.b, this.c); } /** * Computes a barycentric coordinates from the given vector. * Returns `null` if the triangle is degenerate. * * @param {Vector3} point - A point in 3D space. * @param {Vector3} target - The target vector that is used to store the method's result. * @return {?Vector3} The barycentric coordinates for the given point */ getBarycoord(point, target) { return Triangle.getBarycoord(point, this.a, this.b, this.c, target); } /** * Computes the value barycentrically interpolated for the given point on the * triangle. Returns `null` if the triangle is degenerate. * * @param {Vector3} point - Position of interpolated point. * @param {Vector3} v1 - Value to interpolate of first vertex. * @param {Vector3} v2 - Value to interpolate of second vertex. * @param {Vector3} v3 - Value to interpolate of third vertex. * @param {Vector3} target - The target vector that is used to store the method's result. * @return {?Vector3} The interpolated value. */ getInterpolation(point, v1, v2, v3, target) { return Triangle.getInterpolation(point, this.a, this.b, this.c, v1, v2, v3, target); } /** * Returns `true` if the given point, when projected onto the plane of the * triangle, lies within the triangle. * * @param {Vector3} point - The point in 3D space to test. * @return {boolean} Whether the given point, when projected onto the plane of the * triangle, lies within the triangle or not. */ containsPoint(point) { return Triangle.containsPoint(point, this.a, this.b, this.c); } /** * Returns `true` if the triangle is oriented towards the given direction. * * @param {Vector3} direction - The (normalized) direction vector. * @return {boolean} Whether the triangle is oriented towards the given direction or not. */ isFrontFacing(direction) { return Triangle.isFrontFacing(this.a, this.b, this.c, direction); } /** * Returns `true` if this triangle intersects with the given box. * * @param {Box3} box - The box to intersect. * @return {boolean} Whether this triangle intersects with the given box or not. */ intersectsBox(box) { return box.intersectsTriangle(this); } /** * Returns the closest point on the triangle to the given point. * * @param {Vector3} p - The point to compute the closest point for. * @param {Vector3} target - The target vector that is used to store the method's result. * @return {Vector3} The closest point on the triangle. */ 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); } /** * Returns `true` if this triangle is equal with the given one. * * @param {Triangle} triangle - The triangle to test for equality. * @return {boolean} Whether this triangle is equal with the given one. */ equals(triangle) { return triangle.a.equals(this.a) && triangle.b.equals(this.b) && triangle.c.equals(this.c); } } exports.Triangle = Triangle;