点在三角形内:重心坐标

时间:2014-08-19 13:58:38

标签: c++ geometry

我正在解决一个确定点是否在三角形内的经典问题,而我正在使用重心坐标方法。 由于某种原因(我认为这是逻辑,而不是精度)它没有通过所有测试。 可能有什么不对?

代码是这样的:

#include <iostream>

using namespace std;

struct point
{
    int x;
    int y;
};


bool Place(point &A, point &B, point &C, point &P)
{

    double det = (B.y - C.y)*(A.x - C.x) + (C.x - B.x)*(A.y - C.y);
    double factor_alpha = (B.y - C.y)*(P.x - C.x) + (C.x - B.x)*(P.y - C.y);
    double factor_beta = (C.y - A.y)*(P.x - C.x) + (A.x - C.x)*(P.y - C.y);
    double alpha =  factor_alpha / det;
    double beta =  factor_beta / det;
    double gamma = 1.0 - alpha - beta;

    bool In = false;

    if (((A.x == P.x) & (A.y == P.y)) | ((B.x == P.x) & (B.y == P.y)) | ((C.x == P.x) & (C.y == P.y))) 
        In = true; // the sneaky guys are trying to see if the vertice of the triangle belongs to it
                    // the problem statement says it does.
    if ((alpha == 0) | (beta == 0) | (gamma == 0))
            In =  true; // the point is on the edge of the triangle
    if (( (0 < alpha) & (alpha < 1)) & ((0 < beta) & (beta < 1)) & ((0 < gamma) & (gamma < 1)))
            In =  true; // in this case P is actually within the triangle area

    return In;
}


int main()
{
    point A, B, C, P;
    cin >> A.x >> A.y >> B.x >> B.y >> C.x >> C.y >> P.x >> P.y;
    Place(A, B, C, P) ? cout << "In\n" : cout << "Out\n";
    return 0;
}

2 个答案:

答案 0 :(得分:1)

您的逻辑表明,如果alphabetagamma中至少有一个为0,则该点就在边缘。 这是必要但不充分的;其他的也必须在[0, 1]区间。

由于您对&#34; edge&#34;不感兴趣具体而言,你可以写

if (0 <= alpha && alpha <= 1 && 0 <= beta && beta <= 1 && 0 <= gamma && gamma <= 1)
        In = true; 

(我删除了一些括号,并用逻辑&替换了按位&&。)


可读性建议:
引入一些函数使得代码看起来更像是一个数学定义:

bool operator ==(const point& a, const point& b)
{
    return a.x == b.x && a.y == b.y;
}

bool within(double x)
{
    return 0 <= x <= 1;
}

bool Place(const point &A, const point &B, const point &C, const  point &P)
{   
    double det = (B.y - C.y)*(A.x - C.x) + (C.x - B.x)*(A.y - C.y);
    double factor_alpha = (B.y - C.y)*(P.x - C.x) + (C.x - B.x)*(P.y - C.y);
    double factor_beta = (C.y - A.y)*(P.x - C.x) + (A.x - C.x)*(P.y - C.y);
    double alpha = factor_alpha / det;
    double beta = factor_beta / det;
    double gamma = 1.0 - alpha - beta;

    return P == A || P == B || P == C || (within(alpha) && within(beta) && within(gamma));
}

答案 1 :(得分:1)

尝试此功能(假设您有一个Point类模板,其中T是存储类型,并且您已经超载operator*来计算点积:)

template <typename T>
bool is_point_in_triangle(const Point<3,T>& p,
                          const Point<3,T>& a,
                          const Point<3,T>& b,
                          const Point<3,T>& c) {

  typedef Point<3,T> point_type;

  point_type v0 = b-a, v1 = c-a, v2 = p-a;

  T d00 = v0*v0;
  T d01 = v0*v1;
  T d11 = v1*v1;
  T d20 = v2*v0;
  T d21 = v2*v1;
  T denom = d00*d11 - d01*d01;

  // compute parametric coordinates
  Real v = (d11 * d20 - d01 * d21) / denom;
  Real w = (d00 * d21 - d01 * d20) / denom;  
  return v >= 0. && w >= 0. && v + w <= 1.;
}

作为旁注,您使用int来存储坐标,因此截断时您的测试可能会失败? 祝你好运!