UNPKG

@xtor/cga.js

Version:

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

285 lines (265 loc) 9.46 kB
import { Vec3 } from '../../math/Vec3'; import { Segment } from './Segment'; import { DistanceResult } from '../../alg/result'; import { Triangle } from './Triangle'; import { Line } from './Line'; import { Rectangle } from './Rectangle'; export class Ray { origin: Vec3; direction: Vec3; constructor(origin: Vec3, direction: Vec3) { this.origin = origin; this.direction = direction.normalize(); } /** * 射线到射线的距离 * @param {Ray} ray */ distanceRay(ray: Ray): DistanceResult { var result: DistanceResult = { parameters: [], closests: [], }; 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.distanceSqr = diff.dot(diff); result.distance = Math.sqrt(result.distanceSqr); return result; } /** * 射线到线段的距离 * @param segment */ distanceSegment(segment: Segment): DistanceResult { const result: DistanceResult = { parameters: [], closests: [] }; // segment.GetCenteredForm(segCenter, segDirection, segExtent); 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) { // 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.distanceSqr = diff.dot(diff); result.distance = Math.sqrt(result.distanceSqr); return result; } distanceTriangle(triangle: Triangle): DistanceResult { const result: DistanceResult = { parameters: [], closests: [], triangleParameters: [], }; 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.distanceSqr = ltResult.distanceSqr; result.rayParameter = ltResult.lineParameter; result.triangleParameters![0] = ltResult.triangleParameters![0]; result.triangleParameters![1] = ltResult.triangleParameters![1]; result.triangleParameters![2] = ltResult.triangleParameters![2]; result.closests![0] = ltResult.closests![0]; result.closests![1] = ltResult.closests![1]; } else { var ptResult = this.origin.clone().distanceTriangle(triangle); result.distance = ptResult.distance; result.distanceSqr = ptResult.distanceSqr; result.rayParameter = 0; result.triangleParameters![0] = ptResult.triangleParameters![0]; result.triangleParameters![1] = ptResult.triangleParameters![1]; result.triangleParameters![2] = ptResult.triangleParameters![2]; result.closests![0] = this.origin; result.closests![1] = ptResult.closests![1]; } return result; } distancePloyline(): DistanceResult { const result = {}; return result; } }