球形扇形的边界框(圆锥-球面相交)

时间:2020-11-04 20:37:46

标签: algorithm geometry intersection bounding-box

给出一个球形段(其半径,方向和角度),如何以最简单的方式计算其与轴对齐的边界框?

请注意,我对任意定向的线段感兴趣,而框必须是轴向对齐的。紧密的边界框很容易计算。

这个问题可以简化为球形帽的边界框,但是我也找不到相应的算法。

Spherical segment

2 个答案:

答案 0 :(得分:3)

为简单起见,假设我们平移并缩放坐标系,以使中心位于(0,...,0),半径为1。设 u 为端点的端点。分段(使“ u ”²= 1)并使弧度角为θ。蓝色扇区是所有 v 点,使得‖ v ‖²≤1和 u · v ≥‖< strong> u ‖‖ v ‖cosθ=‖ v ‖cosθ。要在 d 维度中找到与轴对齐的边界框,我们需要找到2 d 个矢量 v ,这些矢量会最小化/最大化每个单独的坐标,即,给定向量 e ,使得+ e 或- e 属于轴向基准(例如 e =(0,−1,0,...,0))我们要最大化 e · v ,但要受 v

maximize e·v
subject to
‖v‖² ≤ 1
u·v ≥ ‖v‖ cos θ

我们首先观察到在不丧失一般性的情况下,“ v ” = 0或“ v ” = 1,因为目标是线性的,而其他点位于a上这些的凸组合。让我们集中讨论后一种情况。

maximize e·v
subject to
‖v‖² = 1
u·v ≥ cos θ

第二,存在一个最佳解决方案,该解决方案位于 e u 所跨越的空间中。给定任何最佳解,我们可以将正交投影带入该空间而无需增加其范数或使用 e u 更改点积,因此投影也是可行且最佳的

因此,通过让 v e u ,用系数α和β重写问题。

maximize e·(αe + βu)
subject to
‖αe + βu‖² = 1
u·(αe + βu) ≥ cos θ

让我们扩展产品并使用“ e ”²=“ u ”²= 1的事实。

maximize α + β(e·u)
subject to
α² + 2αβ(e·u) + β² = 1
α(e·u) + β ≥ cos θ

现在我们有一个案例分析。忽略线性约束,目标最多为1,因此解α= 1和β= 0(即 v = e )是最佳的。仅当 e · u ≥cosθ时,该解决方案才可行。

如果该解决方案不可行,则线性约束必须严格:α( e · u )+β= cosθ,或β= cosθ-α ( e · u )。然后我们可以代入,求解所得二次方程式,并采用得分更高的解决方案(除非它们均得分为负,否则边界为0)。

答案 1 :(得分:1)

按照David的回答,我实现了似乎运行良好的算法:

Box ComputeSphericalSegmentBoundingBox( const Vec3& u, const float angle )
{
    const float cosAngle = cosf( angle ); // cos θ

    const auto solveAxis = [&] ( const Vec3& e )
    {
        const float eu = Vec3::Dot( e, u ); // e·u
        if ( eu >= cosAngle )
        {
            return 1.0f;
        }

        // solve for a² + 2a(cosθ - a(e·u))(e·u) + (cosθ - a(e·u))² = 1
        const float det = ( cosAngle * cosAngle - 1.0f ) / ( eu * eu - 1.0f );
        if ( det >= 0.0f )
        {
            const float a = sqrtf( det );

            // maximize x = a + b(e·u)
            const float x0 = ( cosAngle - a * eu ) * eu + a;
            const float x1 = ( cosAngle + a * eu ) * eu - a;
            return Clamp( max( x0, x1 ), 0.0f, 1.0f );
        }

        return 0.0f;
    };

    Vec3 boxMin
    {
        min(0.0f, -solveAxis( Vec3(-1,0,0) ) ),
        min(0.0f, -solveAxis( Vec3(0,-1,0) ) ),
        min(0.0f, -solveAxis( Vec3(0,0,-1) ) )
    };

    Vec3 boxMax
    {
        max(0.0f, solveAxis( Vec3(1,0,0) ) ),
        max(0.0f, solveAxis( Vec3(0,1,0) ) ),
        max(0.0f, solveAxis( Vec3(0,0,1) ) )
    };

    return { boxMin, boxMax };
}