Spaces:
Running
Running
| import { Vector3 } from './Vector3.js'; | |
| const _v0 = /*@__PURE__*/ new Vector3(); | |
| const _v1 = /*@__PURE__*/ new Vector3(); | |
| const _v2 = /*@__PURE__*/ new Vector3(); | |
| const _v3 = /*@__PURE__*/ new Vector3(); | |
| const _vab = /*@__PURE__*/ new Vector3(); | |
| const _vac = /*@__PURE__*/ new Vector3(); | |
| const _vbc = /*@__PURE__*/ new Vector3(); | |
| const _vap = /*@__PURE__*/ new Vector3(); | |
| const _vbp = /*@__PURE__*/ new Vector3(); | |
| const _vcp = /*@__PURE__*/ new Vector3(); | |
| class Triangle { | |
| constructor(a = new Vector3(), b = new Vector3(), c = new Vector3()) { | |
| this.a = a; | |
| this.b = b; | |
| this.c = c; | |
| } | |
| 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); | |
| } | |
| // static/instance method to calculate barycentric coordinates | |
| // based on: http://www.blackpawn.com/texts/pointinpoly/default.html | |
| static getBarycoord(point, a, b, c, target) { | |
| _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) { | |
| // arbitrary location outside of triangle? | |
| // not sure if this is the best idea, maybe should be returning undefined | |
| return target.set(-2, -1, -1); | |
| } | |
| 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); | |
| } | |
| static containsPoint(point, a, b, c) { | |
| this.getBarycoord(point, a, b, c, _v3); | |
| return _v3.x >= 0 && _v3.y >= 0 && _v3.x + _v3.y <= 1; | |
| } | |
| static getUV(point, p1, p2, p3, uv1, uv2, uv3, target) { | |
| this.getBarycoord(point, p1, p2, p3, _v3); | |
| target.set(0, 0); | |
| target.addScaledVector(uv1, _v3.x); | |
| target.addScaledVector(uv2, _v3.y); | |
| target.addScaledVector(uv3, _v3.z); | |
| return target; | |
| } | |
| 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; | |
| } | |
| set(a, b, c) { | |
| this.a.copy(a); | |
| this.b.copy(b); | |
| this.c.copy(c); | |
| return this; | |
| } | |
| setFromPointsAndIndices(points, i0, i1, i2) { | |
| this.a.copy(points[i0]); | |
| this.b.copy(points[i1]); | |
| this.c.copy(points[i2]); | |
| return this; | |
| } | |
| setFromAttributeAndIndices(attribute, i0, i1, i2) { | |
| this.a.fromBufferAttribute(attribute, i0); | |
| this.b.fromBufferAttribute(attribute, i1); | |
| this.c.fromBufferAttribute(attribute, i2); | |
| return this; | |
| } | |
| clone() { | |
| return new this.constructor().copy(this); | |
| } | |
| copy(triangle) { | |
| this.a.copy(triangle.a); | |
| this.b.copy(triangle.b); | |
| this.c.copy(triangle.c); | |
| return this; | |
| } | |
| getArea() { | |
| _v0.subVectors(this.c, this.b); | |
| _v1.subVectors(this.a, this.b); | |
| return _v0.cross(_v1).length() * 0.5; | |
| } | |
| getMidpoint(target) { | |
| return target | |
| .addVectors(this.a, this.b) | |
| .add(this.c) | |
| .multiplyScalar(1 / 3); | |
| } | |
| getNormal(target) { | |
| return Triangle.getNormal(this.a, this.b, this.c, target); | |
| } | |
| getPlane(target) { | |
| return target.setFromCoplanarPoints(this.a, this.b, this.c); | |
| } | |
| getBarycoord(point, target) { | |
| return Triangle.getBarycoord(point, this.a, this.b, this.c, target); | |
| } | |
| getUV(point, uv1, uv2, uv3, target) { | |
| return Triangle.getUV(point, this.a, this.b, this.c, uv1, uv2, uv3, target); | |
| } | |
| containsPoint(point) { | |
| return Triangle.containsPoint(point, this.a, this.b, this.c); | |
| } | |
| isFrontFacing(direction) { | |
| return Triangle.isFrontFacing(this.a, this.b, this.c, direction); | |
| } | |
| intersectsBox(box) { | |
| return box.intersectsTriangle(this); | |
| } | |
| 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); | |
| } | |
| equals(triangle) { | |
| return triangle.a.equals(this.a) && triangle.b.equals(this.b) && triangle.c.equals(this.c); | |
| } | |
| } | |
| export { Triangle }; | |