Почему этот код возвращает точку пересечения с изнаночной стороны прямоугольника под некоторыми углами? - PullRequest
2 голосов
/ 24 февраля 2011

Под некоторыми углами это покажет пересечение на неправильной стороне (назад, когда это должно быть впереди ИЛИ налево, когда это должно быть направо).

Что не так?

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;
}

1 Ответ

2 голосов
/ 17 марта 2011

Это связано с проблемами с точностью с плавающей запятой. Вы не можете сравнивать числа с плавающей запятой, используя ==, если вам нужен стабильный алгоритм, например, запрещено следующее:

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 (эту точность также можно изменить, в зависимости от того, что вы и ваша задача определяете как близкие ) функциональность для других операторов. Ниже приведен пример оператора <: </p>

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

Просмотрите ваш код и замените == и <этими методами. Вы действительно не нуждаетесь в операторе>, так как вы можете повернуть аргументы и использовать вместо него <. </p>

Приветствия

...