UNPKG

xtorcga

Version:

Xtor Compute Geometry Algorithm Libary 计算几何算法库

340 lines (339 loc) 13.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.line = exports.Line = void 0; var Vec3_1 = require("../../math/Vec3"); var Segment_1 = require("./Segment"); var Math_1 = require("../../math/Math"); var _v1 = new Vec3_1.Vec3; ; var Line = /** @class */ (function () { function Line(origin, end) { if (origin === void 0) { origin = Vec3_1.v3(); } if (end === void 0) { end = Vec3_1.v3(); } this.origin = origin; this.end = end; this.direction = this.end .clone() .sub(this.origin) .normalize(); } Line.prototype.set = function (origin, end) { this.origin.copy(origin); this.end.copy(end); return this; }; Line.prototype.distancePoint = function (pt) { var res = pt.distanceLine(this); // res.closests?.reverse(); // res.parameters?.reverse(); return res; }; Line.prototype.distanceSegment = function (segment) { var result = { parameters: [], closests: [] }; var segCenter = segment.center; var segDirection = segment.direction; var segExtent = segment.extent * 0.5; var diff = this.origin.clone().sub(segCenter); var a01 = -this.direction.dot(segDirection); var b0 = diff.dot(this.direction); var s0, s1; if (Math.abs(a01) < 1) { // 判断是否平行 var det = 1 - a01 * a01; var extDet = segExtent * det; var b1 = -diff.dot(segDirection); s1 = a01 * b0 - b1; if (s1 >= -extDet) { if (s1 <= extDet) { // Two interior points are closest, one on the this // and one on the segment. s0 = (a01 * b1 - b0) / det; s1 /= det; } else { // The endpoint e1 of the segment and an interior // point of the this are closest. s1 = segExtent; s0 = -(a01 * s1 + b0); } } else { // The endpoint e0 of the segment and an interior point // of the this are closest. s1 = -segExtent; s0 = -(a01 * s1 + b0); } } else { // The this and segment are parallel. Choose the closest pair // so that one point is at segment origin. s1 = 0; s0 = -b0; } result.parameters[0] = s0; result.parameters[1] = s1; result.closests[0] = this.direction.clone().multiplyScalar(s0).add(this.origin); result.closests[1] = segDirection.clone().multiplyScalar(s1).add(segCenter); diff = result.closests[0].clone().sub(result.closests[1]); result.distanceSqr = diff.dot(diff); result.distance = Math.sqrt(result.distanceSqr); return result; }; //---距离------------- /** * 直线到直线的距离 * 参数与最近点顺序一致 * @param {Line} line */ Line.prototype.distanceLine = function (line) { var result = { parameters: [], closests: [] }; var diff = this.origin.clone().sub(line.origin); var a01 = -this.direction.dot(line.direction); var b0 = diff.dot(this.direction); var s0, s1; if (Math.abs(a01) < 1) { var det = 1 - a01 * a01; var b1 = -diff.dot(line.direction); s0 = (a01 * b1 - b0) / det; s1 = (a01 * b0 - b1) / det; } else { s0 = -b0; s1 = 0; } result.parameters[0] = s0; result.parameters[1] = s1; result.closests[0] = this.direction .clone() .multiplyScalar(s0) .add(this.origin); result.closests[1] = line.direction .clone() .multiplyScalar(s1) .add(line.origin); diff = result.closests[0].clone().sub(result.closests[1]); result.distanceSqr = diff.dot(diff); result.distance = Math.sqrt(result.distanceSqr); return result; }; /** * 直线与射线的距离 * @param {Ray} ray */ Line.prototype.distanceRay = function (ray) { var result = { parameters: [], closests: [] }; var diff = this.origin.clone().sub(ray.origin); var a01 = -this.direction.dot(ray.direction); var b0 = diff.dot(this.direction); var s0, s1; if (Math.abs(a01) < 1) { var b1 = -diff.dot(ray.direction); s1 = a01 * b0 - b1; if (s1 >= 0) { //在最近点在射线上,相当于直线与直线最短距离 var det = 1 - a01 * a01; s0 = (a01 * b1 - b0) / det; s1 /= det; } else { // 射线的起始点是离直线的最近点 s0 = -b0; s1 = 0; } } else { s0 = -b0; s1 = 0; } result.parameters[0] = s0; result.parameters[1] = s1; result.closests[0] = this.direction.clone().multiplyScalar(s0).add(this.origin); result.closests[1] = ray.direction.clone().multiplyScalar(s1).add(ray.origin); diff = result.closests[0].clone().sub(result.closests[1]); result.distanceSqr = diff.dot(diff); result.distance = Math.sqrt(result.distanceSqr); return result; }; /** * * @param triangle */ Line.prototype.distanceTriangle = function (triangle) { function Orthonormalize(numInputs, v, robust) { if (robust === void 0) { robust = false; } if (v && 1 <= numInputs && numInputs <= 3) { var minLength = v[0].length(); v[0].normalize(); for (var i = 1; i < numInputs; ++i) { for (var j = 0; j < i; ++j) { var dot = v[i].dot(v[j]); v[i].sub(v[j].clone().multiplyScalar(dot)); } var length = v[i].length(); v[i].normalize(); if (length < minLength) { minLength = length; } } return minLength; } return 0; } function ComputeOrthogonalComplement(numInputs, v, robust) { if (robust === void 0) { robust = false; } if (numInputs === 1) { if (Math.abs(v[0][0]) > Math.abs(v[0][1])) { v[1] = Vec3_1.v3(-v[0].z, 0, +v[0].x); } else { v[1] = Vec3_1.v3(0, +v[0].z, -v[0].y); } ; numInputs = 2; } if (numInputs == 2) { v[2] = v[0].clone().cross(v[1]); return Orthonormalize(3, v, robust); } return 0; } var result = { closests: [], parameters: [], triangleParameters: [], }; // Test if line intersects triangle. If so, the squared distance // is zero. var edge0 = triangle.p1.clone().sub(triangle.p0); var edge1 = triangle.p2.clone().sub(triangle.p0); var normal = edge0.clone().cross(edge1).normalize(); var NdD = normal.dot(this.direction); if (Math.abs(NdD) >= Math_1.delta4) { // The line and triangle are not parallel, so the line // intersects/ the plane of the triangle. var diff = this.origin.clone().sub(triangle.p0); var basis = new Array(3); // {D, U, V} basis[0] = this.direction; ComputeOrthogonalComplement(1, basis); var UdE0 = basis[1].dot(edge0); var UdE1 = basis[1].dot(edge1); var UdDiff = basis[1].dot(diff); var VdE0 = basis[2].dot(edge0); var VdE1 = basis[2].dot(edge1); var VdDiff = basis[2].dot(diff); var invDet = 1 / (UdE0 * VdE1 - UdE1 * VdE0); // Barycentric coordinates for the point of intersection. var b1 = (VdE1 * UdDiff - UdE1 * VdDiff) * invDet; var b2 = (UdE0 * VdDiff - VdE0 * UdDiff) * invDet; var b0 = 1 - b1 - b2; if (b0 >= 0 && b1 >= 0 && b2 >= 0) { // Line parameter for the point of intersection. var DdE0 = this.direction.dot(edge0); var DdE1 = this.direction.dot(edge1); var DdDiff = this.direction.dot(diff); result.lineParameter = b1 * DdE0 + b2 * DdE1 - DdDiff; // Barycentric coordinates for the point of intersection. result.triangleParameters[0] = b0; result.triangleParameters[1] = b1; result.triangleParameters[2] = b2; // The intersection point is inside or on the triangle. result.closests[0] = this.direction.clone().multiplyScalar(result.lineParameter).add(this.origin); result.closests[1] = edge0.multiplyScalar(b1).add(edge1.multiplyScalar(b2)).add(triangle.p0); result.distance = 0; result.distanceSqr = 0; return result; } } // Either (1) the line is not parallel to the triangle and the // point of intersection of the line and the plane of the triangle // is outside the triangle or (2) the line and triangle are // parallel. Regardless, the closest point on the triangle is on // an edge of the triangle. Compare the line to all three edges // of the triangle. result.distance = +Infinity; result.distanceSqr = +Infinity; for (var i0 = 2, i1 = 0; i1 < 3; i0 = i1++) { var segCenter = triangle[i0].clone().add(triangle[i1]).multiplyScalar(0.5); var segDirection = triangle[i1].clone().sub(triangle[i0]); var segExtent = 0.5 * segDirection.length(); segDirection.normalize(); var segment = new Segment_1.Segment(triangle[i0], triangle[i1]); var lsResult = this.distanceSegment(segment); if (lsResult.distanceSqr < result.distanceSqr) { result.distanceSqr = lsResult.distanceSqr; result.distance = lsResult.distance; result.lineParameter = lsResult.parameters[0]; result.triangleParameters[i0] = 0.5 * (1 - lsResult.parameters[0] / segExtent); result.triangleParameters[i1] = 1 - result.triangleParameters[i0]; result.triangleParameters[3 - i0 - i1] = 0; result.closests[0] = lsResult.closests[0]; result.closests[1] = lsResult.closests[1]; } } return result; }; Line.prototype.distancePolyline = function (polyline) { var polyl = polyline._array || polyline; var result = null; var maodian = -1; for (var i = 0; i < polyl.length - 1; i++) { var segment = new Segment_1.Segment(polyl[i], polyl[i + 1]); var oneres = this.distanceSegment(segment); if (!result || result.distance < oneres.distance) { result = oneres; } if (result.distance < Math_1.delta4) { maodian = i; break; } } return { distance: result === null || result === void 0 ? void 0 : result.distance, distanceSqr: result === null || result === void 0 ? void 0 : result.distanceSqr, parameters: result === null || result === void 0 ? void 0 : result.parameters, closests: result === null || result === void 0 ? void 0 : result.closests, segmentIndex: maodian, }; }; //---intersect-------------------------- /** * 线与平面相交 * @param plane * @param result */ Line.prototype.intersectPlane = function (plane, result) { if (!result) result = new Vec3_1.Vec3(); var direction = this.direction; var denominator = plane.normal.dot(direction); if (denominator === 0) { // line is coplanar, return origin if (this.distancePoint(this.origin).distance === 0) { return result.copy(this.origin); } // Unsure if this is the correct method to handle this case. return; } var t = -(this.origin.dot(plane.normal) - plane.w) / denominator; if (t < 0 || t > 1) { return; } return result.copy(direction).multiplyScalar(t).add(this.origin); }; return Line; }()); exports.Line = Line; function line(start, end) { return new Line(start, end); } exports.line = line;