UNPKG

@xtor/cga.js

Version:

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

333 lines (309 loc) 7.85 kB
import { Line } from "./Line"; import { Point } from "./Point"; class Ray { constructor(origin, direction) { this.origin = origin; this.direction = direction.normalize(); } /** * 射线到射线的距离 * @param {Ray} ray */ distanceRay(ray) { var result = { parameters: [], closests: [], sqrDistance: 0, distance: 0 }; var diff = this.origin.clone().sub(ray.origin); var a01 = - this.direction.dot(ray.direction); var b0 = diff.dot(this.direction), b1; var s0, s1; if (Math.abs(a01) < 1) { // 射线不平行 b1 = - diff.dot(ray.direction); s0 = a01 * b1 - b0; s1 = a01 * b0 - b1; if (s0 >= 0) { if (s1 >= 0) // region 0 (interior) { // Minimum at two interior points of rays. var det = 1 - a01 * a01; s0 /= det; s1 /= det; } else // region 3 (side) { s1 = 0; if (b0 >= 0) { s0 = 0; } else { s0 = -b0; } } } else { if (s1 >= 0) // region 1 (side) { s0 = 0; if (b1 >= 0) { s1 = 0; } else { s1 = -b1; } } else // region 2 (corner) { if (b0 < 0) { s0 = -b0; s1 = 0; } else { s0 = 0; if (b1 >= 0) { s1 = 0; } else { s1 = -b1; } } } } } else { // Rays are parallel. if (a01 > 0) { // Opposite direction vectors. s1 = 0; if (b0 >= 0) { s0 = 0; } else { s0 = -b0; } } else { // Same direction vectors. if (b0 >= 0) { b1 = - diff.dot(ray.direction); s0 = 0; s1 = -b1; } 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.sqrDistance = diff.dot(diff); result.distance = Math.sqrt(result.sqrDistance); return result; } /** * 射线与线段的距离 * @param {Segment} segment */ distanceSegment(segment) { const result = { parameters: [], closests: [], sqrDistance: 0, distance: 0 }; // segment.GetCenteredForm(segCenter, segDirection, segExtent); var segCenter = segment.center; var segDirection = segment.direction; var segExtent = segment.len * 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) { // The ray and segment are not parallel. var det = 1 - a01 * a01; var extDet = segExtent * det; var b1 = - diff.dot(segDirection); s0 = a01 * b1 - b0; s1 = a01 * b0 - b1; if (s0 >= 0) { if (s1 >= -extDet) { if (s1 <= extDet) // region 0 { // Minimum at interior points of ray and segment. s0 /= det; s1 /= det; } else // region 1 { s1 = segExtent; s0 = Math.max(-(a01 * s1 + b0), 0); } } else // region 5 { s1 = -segExtent; s0 = Math.max(-(a01 * s1 + b0), 0); } } else { if (s1 <= -extDet) // region 4 { s0 = -(-a01 * segExtent + b0); if (s0 > 0) { s1 = -segExtent; } else { s0 = 0; s1 = -b1; if (s1 < -segExtent) { s1 = -segExtent; } else if (s1 > segExtent) { s1 = segExtent; } } } else if (s1 <= extDet) // region 3 { s0 = 0; s1 = -b1; if (s1 < -segExtent) { s1 = -segExtent; } else if (s1 > segExtent) { s1 = segExtent; } } else // region 2 { s0 = -(a01 * segExtent + b0); if (s0 > 0) { s1 = segExtent; } else { s0 = 0; s1 = -b1; if (s1 < -segExtent) { s1 = -segExtent; } else if (s1 > segExtent) { s1 = segExtent; } } } } } else { // Ray and segment are parallel. if (a01 > 0) { // Opposite direction vectors. s1 = -segExtent; } else { // Same direction vectors. s1 = segExtent; } s0 = Math.max(-(a01 * s1 + b0), 0); } 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.sqrDistance = diff.dot(diff); result.distance = Math.sqrt(result.sqrDistance); return result; } distanceTriangle(triangle) { const result = { parameters: [], closests: [], triangleParameter: [], sqrDistance: 0, distance: 0 }; var line = new Line(this.origin, this.origin.clone().add(this.direction)); // DCPQuery < Real, Line3 < Real >, Triangle3 < Real >> ltQuery; var ltResult = line.distanceTriangle(triangle); if (ltResult.lineParameter >= 0) { //最近点在直线前半部分部分,涉嫌方向 result.distance = ltResult.distance; result.sqrDistance = ltResult.sqrDistance; result.rayParameter = ltResult.lineParameter; result.triangleParameter[0] = ltResult.triangleParameter[0]; result.triangleParameter[1] = ltResult.triangleParameter[1]; result.triangleParameter[2] = ltResult.triangleParameter[2]; result.closests[0] = ltResult.closests[0]; result.closests[1] = ltResult.closests[1]; } else { var ptResult = new Point().copy(this.origin).distanceTriangle(triangle); result.distance = ptResult.distance; result.sqrDistance = ptResult.sqrDistance; result.rayParameter = 0; result.triangleParameter[0] = ptResult.parameter[0]; result.triangleParameter[1] = ptResult.parameter[1]; result.triangleParameter[2] = ptResult.parameter[2]; result.closests[0] = this.origin; result.closests[1] = ptResult.closest; } return result; } /** * 直线到直线的距离 * @param {Ray} ray */ distanceLine(line) { } } function fromTwoPoint(orgin, point) { return new Ray(orgin, point.sub(orgin)); } function ray(orgin, direction) { return new Ray(orgin, direction); } export { Ray, ray, fromTwoPoint };