-
-
Notifications
You must be signed in to change notification settings - Fork 36k
Line3: Add method for computing closest squared distance between line segments. #31384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ts covering corner cases
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
Real-Time Collision Detection by Christer Ericson is a really good source for these kind of algorithms. I've used the book in other projects extensively^^. I had a go on this myself and ported the source function almost 1:1 which makes it way easier to stick to the reference and thus improves maintainance. The idea is to have just a single function that returns the squared distance and optionally the closest points on both line segments. Clamping is always done since I think something else does not really make sense in context of line segments. Would this work for you as well? const _d1 = /*@__PURE__*/ new Vector3();
const _d2 = /*@__PURE__*/ new Vector3();
const _r = /*@__PURE__*/ new Vector3();
const _c1 = /*@__PURE__*/ new Vector3();
const _c2 = /*@__PURE__*/ new Vector3();
/**
* Returns the closest squared distance between this line segment and the given one.
*
* @param {Line3} line - The line segment to compute the closest squared distance to.
* @param {?Vector3} c1 - The closest point on this line segment.
* @param {?Vector3} c2 - The closest point on the given line segment.
* @return {number} The squared distance between this line segment and the given one.
*/
distanceSqToLine3( line, c1 = _c1, c2 = _c2 ) {
// from Real-Time Collision Detection by Christer Ericson, chapter 5.1.9
// Computes closest points C1 and C2 of S1(s)=P1+s*(Q1-P1) and
// S2(t)=P2+t*(Q2-P2), returning s and t. Function result is squared
// distance between between S1(s) and S2(t)
const EPSILON = 1e-8 * 1e-8; // must be squared since we compare squared length
let s, t;
const p1 = this.start;
const p2 = line.start;
const q1 = this.end;
const q2 = line.end;
_d1.subVectors( q1, p1 ); // Direction vector of segment S1
_d2.subVectors( q2, p2 ); // Direction vector of segment S2
_r.subVectors( p1, p2 );
const a = _d1.dot( _d1 ); // Squared length of segment S1, always nonnegative
const e = _d2.dot( _d2 ); // Squared length of segment S2, always nonnegative
const f = _d2.dot( _r );
// Check if either or both segments degenerate into points
if ( a <= EPSILON && e <= EPSILON ) {
// Both segments degenerate into points
c1.copy( p1 );
c2.copy( p2 );
c1.sub( c2 );
return c1.dot( c1 );
}
if ( a <= EPSILON ) {
// First segment degenerates into a point
s = 0;
t = f / e; // s = 0 => t = (b*s + f) / e = f / e
t = clamp( t, 0, 1 );
} else {
const c = _d1.dot( _r );
if ( e <= EPSILON ) {
// Second segment degenerates into a point
t = 0;
s = clamp( - c / a, 0, 1 ); // t = 0 => s = (b*t - c) / a = -c / a
} else {
// The general nondegenerate case starts here
const b = _d1.dot( _d2 );
const denom = a * e - b * b; // Always nonnegative
// If segments not parallel, compute closest point on L1 to L2 and
// clamp to segment S1. Else pick arbitrary s (here 0)
if ( denom !== 0 ) {
s = clamp( ( b * f - c * e ) / denom, 0, 1 );
} else {
s = 0;
}
// Compute point on L2 closest to S1(s) using
// t = Dot((P1 + D1*s) - P2,D2) / Dot(D2,D2) = (b*s + f) / e
t = ( b * s + f ) / e;
// If t in [0,1] done. Else clamp t, recompute s for the new value
// of t using s = Dot((P2 + D2*t) - P1,D1) / Dot(D1,D1)= (t*b - c) / a
// and clamp s to [0, 1]
if ( t < 0 ) {
t = 0.;
s = clamp( - c / a, 0, 1 );
} else if ( t > 1 ) {
t = 1;
s = clamp( ( b - c ) / a, 0, 1 );
}
}
}
c1.copy( p1 ).add( _d1.multiplyScalar( s ) );
c2.copy( p2 ).add( _d2.multiplyScalar( t ) );
c1.sub( c2 );
return c1.dot( c1 );
} |
Agreed, that looks great.
Not clamping in that context would mean finding distance between lines. Similar to Distance between lines could be another function but I thought that would make the api a bit inconsistent, that's all. I will be happy if your code merges as is. |
Fixed #31368
Description
Adds function to find distance between two Line3-s:
closestDistanceToLine
. I wanted to create granularity in the API as it is with distance to point. HenceshortestSegmentToLine
andshortestSegmentToLineParameters
which return shortest segment and shortest segment point's parameters.Also adds helper function
distanceToPoint
on Line3 to more easily get distance to point.