在 3D 中找到从点到截锥的最短向量

Posted

技术标签:

【中文标题】在 3D 中找到从点到截锥的最短向量【英文标题】:Finding the shortest vector from a point to a truncated cone in 3D 【发布时间】:2021-09-07 11:08:07 【问题描述】:

我试图了解计算点和 3D 截锥之间的最短向量的某种实现。最初的想法在this paper中介绍。

因此,如果我们有两个球形物体:物体 A 的半径为 rA,位置 pA 和速度 vA,物体 B 的半径为 rB,位置 pB 和速度 vB,那么我们可以用更简单的方式表示,计算相对位置和相对速度,假设物体 A 是一个点,物体 B 的半径是 rA + rB。

在 2D 中,这看起来像是从图 (a) 到图 (b) 的转换,其中 tau 只是一个标量因子: 一个

3D 图形很相似,但不是圆形,而是球体。

现在,如果相对速度矢量位于灰色的截锥中,我们应该找到相对速度V变化最小的矢量u来移动它到圆锥的圆周如下图所示(注意:P为相对位置):

这有两种情况:

    如果相对速度低于截止圆的中心(低于蓝色虚线)。在这种情况下,u 将位于截止圆(较小的圆)上。

    第二种情况,我不明白是怎么计算出来的,是相对速度在小圆(球体)的中心以上时,在这种情况下u会投影在圆锥的切线。 PV 向量表示的平面与大球体的交点是一个u 所在的圆。

        const Vector3 relativePosition = other->position_ - position_;
        const Vector3 relativeVelocity = velocity_ - other->velocity_;
        const float distSq = absSq(relativePosition);
        const float combinedRadius = radius_ + other->radius_;
        const float combinedRadiusSq = sqr(combinedRadius);
    
        Plane plane;
        Vector3 u;
    
        if (distSq > combinedRadiusSq) 
            /* No collision. */
            const Vector3 w = relativeVelocity - tau * relativePosition;
            /* Vector from cutoff center to relative velocity. */
            const float wLengthSq = absSq(w);
    
            const float dotProduct = w * relativePosition;
    
            if (dotProduct < 0.0f && sqr(dotProduct) > combinedRadiusSq * wLengthSq) 
                /* Project on cut-off circle. */
                const float wLength = std::sqrt(wLengthSq);
                const Vector3 unitW = w / wLength;
    
                plane.normal = unitW;
                u = (combinedRadius * tau - wLength) * unitW;
            
            else 
                **/* Project on cone. I Don't understand this! */
    
    
                const float a = distSq;
                const float b = relativePosition * relativeVelocity;
                const float c = absSq(relativeVelocity) - absSq(cross(relativePosition, relativeVelocity)) / (distSq - combinedRadiusSq);
                const float t = (b + std::sqrt(sqr(b) - a * c)) / a;
                const Vector3 ww = relativeVelocity - t * relativePosition;
                const float wwLength = abs(ww);
                const Vector3 unitWW = ww / wwLength;
                plane.normal = unitWW;
                u = (combinedRadius * t - wwLength) * unitWW;**
            
        
    

我知道最终我们需要找到 t(如代码中所示)来缩放 P。但是,我不明白这里如何使用叉积以及我们试图求解的二次方程代表什么。

这个功能可以在here找到。

【问题讨论】:

点积通常在 3D 中用于测试对齐。我相信1 = colinear0 = perpendicular-1 is colinear 在另一个方向。叉积会在 90 度角处找到反射光线的法线。 【参考方案1】:

…虽然我不明白collision avoidance模型是如何工作的,但似乎可以通过考虑围绕轴的一些角度来获得相关方程。

顺便说一句,它看起来像一个纯数学问题,不适合 SO。如果您想问这种问题,Mathematics Stack Exchange 可能会更好。

附录:另一种方法

为了让问题/答案更加醒目,我想考虑另一种编码方法的可能性。由于我们在实际程序中可以毫不犹豫地使用很多数学函数(例如asin()sqrt()),因此也可以利用数学函数和vector algebra来计算没有quadratic equation的交叉点,如下所示。

/* Project on cone. */
const float sin_phi = combinedRadius / std::sqrt(distSq);
const float cos_phi = std::cos(std::asin(sin_phi));

Vector3 E_axial = normalize(relativePosition);
Vector3 E_inplane = normalize(cross(cross(relativePosition, relativeVelocity), E_axial));

Vector3 E_dir = E_axial * cos_phi + E_inplane * sin_phi;

// Based on math: (s * E_dir - relativeVelocity) * E_dir = 0
const float s = relativeVelocity * E_dir;

u = s * E_dir - relativeVelocity;
plane.normal = -normalize(u);

【讨论】:

感谢您的回答。您能否详细说明检查 w 是否应该投影在圆锥或截止圆上的 if 语句?我的意思是: if (dotProduct combinedRadiusSq * wLengthSq) 我理解 dotProduct 部分。但是,我不明白第二个条件背后的几何形状。 截断边界如图中虚线所示。考虑条件w 点在截止锥之外。 dotProduct = sqrt(wLengthSq) * |P| * cos(psi)|P| * cos(pi/2 - phi) = combinedRadius 然后 cos(psi)^2 &gt; cos(pi/2 - phi)^2

以上是关于在 3D 中找到从点到截锥的最短向量的主要内容,如果未能解决你的问题,请参考以下文章

图结构练习——BFS——从起始点到目标点的最短步数(邻接表+BFS)

通过 3D 向量拟合线并找到与平面的交点

Dijkstra算法(求一点到任意一点的最短距离)

lio_sam之点到空间直线空间平面的法向量

给定 3D 旋转矩阵和 3D 方向向量求角度差

点到平面的距离公式