为什么此代码会以某些角度返回框错误一侧的交点?

发布于 2024-10-19 05:17:12 字数 2422 浏览 1 评论 0原文

在某些角度,这将显示错误一侧的交叉点(应该在前面时向后,或者在应该正确时向左)。

怎么了?

inline bool GetIntersection(f32 fDst1, f32 fDst2, 
        vector3df P1,  vector3df P2,  vector3df &Hit) {
    if ( (fDst1 * fDst2) >= 0.0f) 
        return 0;

    if ( fDst1 == fDst2) 
        return 0; 

    Hit = P1 + (P2-P1) * ( -fDst1/(fDst2-fDst1) );

    return 1;
}

inline bool InBox(vector3df Hit, vector3df B1, vector3df B2, const int AXis) {
    if ( AXis==1 && Hit.Z > B1.Z && 
        Hit.Z < B2.Z && Hit.Y > B1.Y && Hit.Y < B2.Y) 
    return 1;

    if ( AXis==2 && Hit.Z > B1.Z && 
        Hit.Z < B2.Z && Hit.X > B1.X && Hit.X < B2.X) 
    return 1;

    if ( AXis==3 && Hit.X > B1.X && Hit.X < B2.X &&
         Hit.Y > B1.Y && Hit.Y < B2.Y) 

    return 1;
return 0;
}

// returns true if line (L1, L2) intersects with the boX (B1, B2)
// returns intersection point in Hit
bool CheckLineBox( vector3df B1, vector3df B2, 
        vector3df L1, vector3df L2, vector3df &Hit) {
    if (L2.X < B1.X && L1.X < B1.X) return false;
    if (L2.X > B2.X && L1.X > B2.X) return false;
    if (L2.Y < B1.Y && L1.Y < B1.Y) return false;
    if (L2.Y > B2.Y && L1.Y > B2.Y) return false;
    if (L2.Z < B1.Z && L1.Z < B1.Z) return false;
    if (L2.Z > B2.Z && L1.Z > B2.Z) return false;
    if (L1.X > B1.X && L1.X < B2.X &&
            L1.Y > B1.Y && L1.Y < B2.Y &&
            L1.Z > B1.Z && L1.Z < B2.Z) {
        Hit = L1; 
        return true;
    }

    if ((GetIntersection( L1.X-B1.X, L2.X-B1.X, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 1)) || 
        (GetIntersection( L1.Y-B1.Y, L2.Y-B1.Y, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 2))  || 
        (GetIntersection( L1.Z-B1.Z, L2.Z-B1.Z, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 3)) || 
        (GetIntersection( L1.X-B2.X, L2.X-B2.X, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 1)) || 
        (GetIntersection( L1.Y-B2.Y, L2.Y-B2.Y, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 2)) || 
        (GetIntersection( L1.Z-B2.Z, L2.Z-B2.Z, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 3)))
        return true;

    return false;
}

At some angles this will show an intersection on the wrong side (back when it should be front OR left when it should be right).

What is wrong?

inline bool GetIntersection(f32 fDst1, f32 fDst2, 
        vector3df P1,  vector3df P2,  vector3df &Hit) {
    if ( (fDst1 * fDst2) >= 0.0f) 
        return 0;

    if ( fDst1 == fDst2) 
        return 0; 

    Hit = P1 + (P2-P1) * ( -fDst1/(fDst2-fDst1) );

    return 1;
}

inline bool InBox(vector3df Hit, vector3df B1, vector3df B2, const int AXis) {
    if ( AXis==1 && Hit.Z > B1.Z && 
        Hit.Z < B2.Z && Hit.Y > B1.Y && Hit.Y < B2.Y) 
    return 1;

    if ( AXis==2 && Hit.Z > B1.Z && 
        Hit.Z < B2.Z && Hit.X > B1.X && Hit.X < B2.X) 
    return 1;

    if ( AXis==3 && Hit.X > B1.X && Hit.X < B2.X &&
         Hit.Y > B1.Y && Hit.Y < B2.Y) 

    return 1;
return 0;
}

// returns true if line (L1, L2) intersects with the boX (B1, B2)
// returns intersection point in Hit
bool CheckLineBox( vector3df B1, vector3df B2, 
        vector3df L1, vector3df L2, vector3df &Hit) {
    if (L2.X < B1.X && L1.X < B1.X) return false;
    if (L2.X > B2.X && L1.X > B2.X) return false;
    if (L2.Y < B1.Y && L1.Y < B1.Y) return false;
    if (L2.Y > B2.Y && L1.Y > B2.Y) return false;
    if (L2.Z < B1.Z && L1.Z < B1.Z) return false;
    if (L2.Z > B2.Z && L1.Z > B2.Z) return false;
    if (L1.X > B1.X && L1.X < B2.X &&
            L1.Y > B1.Y && L1.Y < B2.Y &&
            L1.Z > B1.Z && L1.Z < B2.Z) {
        Hit = L1; 
        return true;
    }

    if ((GetIntersection( L1.X-B1.X, L2.X-B1.X, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 1)) || 
        (GetIntersection( L1.Y-B1.Y, L2.Y-B1.Y, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 2))  || 
        (GetIntersection( L1.Z-B1.Z, L2.Z-B1.Z, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 3)) || 
        (GetIntersection( L1.X-B2.X, L2.X-B2.X, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 1)) || 
        (GetIntersection( L1.Y-B2.Y, L2.Y-B2.Y, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 2)) || 
        (GetIntersection( L1.Z-B2.Z, L2.Z-B2.Z, L1, L2, Hit) && 
        InBox(Hit, B1, B2, 3)))
        return true;

    return false;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

扎心 2024-10-26 05:17:12

这与浮点精度问题有关。如果你想要一个稳定的算法,你不能使用 == 来比较浮点,例如以下是被禁止的:

if ( fDst1 == fDst2) 
        return 0; 

你需要做的就是用下面的 feq( ) 替换所有这些 == 比较:

static const double cEpsilon = 1e-5;

bool feq(double lhs, double rhs)
{
  return (fabs(lhs - rhs) < cEpsilon);
}

有了这个函数(你如果不喜欢函数开销,也可以将其创建为 #define)您可以将 cEpsilon (也可以更改此精度,具体取决于您和您的问题定义为接近的内容)功能到其他运算符。下面是 << 的示例运算符:

bool lessThan(double lhs, double rhs)
{
  return (lhs < rhs && !feq(lhs, rhs));
}

检查您的代码并替换 == 和 <用这些方法。你真的不需要 >运算符,因为您也可以翻转参数并使用 <反而。

干杯

This is related to problems with floating point precision. You can't compare floating points by using == if you want a stabile algorithm, e.g. the following is forbidden:

if ( fDst1 == fDst2) 
        return 0; 

What you need to do is to replace all these == comparisions with feq( ) below:

static const double cEpsilon = 1e-5;

bool feq(double lhs, double rhs)
{
  return (fabs(lhs - rhs) < cEpsilon);
}

With this function in place (you can create it as a #define too if don't like the function overhead) you can add the cEpsilon (this accuracy can also be changed, depending on what you and your problem define as close) functionality to the other operators. Below is an example of the < operator:

bool lessThan(double lhs, double rhs)
{
  return (lhs < rhs && !feq(lhs, rhs));
}

Go through your code and replace == and < with these methods. You dont really need the > operator since you might as well turn around the arguments and use < instead.

Cheers

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文