如何使用半空间测试确定点是在线段的前面还是后面?

时间:2018-04-28 00:21:33

标签: c++ opengl line point glm-math

如何确定一个点是否在半空间测试的前面?我尝试了以下内容。它的工作时间大多数,但其他人失败了。是否存在不起作用的情况?例如,只有当所有点都在某些象限内时它才会起作用吗?如果没有,我做错了什么?

我试过了:

bool PointInFrontOfLine(Point testPoint, Point v1, Point v2)
{
    // Compute line normal
    double dx = v2.x - v1.x;
    double dy = v2.y - v1.y;
    double nx = -dy;
    double ny = dx;
    double length = sqrt(dx * dx + dy * dy);
    nx /= length;
    ny /= length;
    glm::vec3 normal(nx, 0, ny);

    glm::vec3 vec(testPoint.x - v1.x, 0, testPoint.y - v1.y);

    double distance = glm::dot(vecTemp, normal);

    if (distance > 0)
        return true;
    else
        return false;
}

1 个答案:

答案 0 :(得分:2)

你实际做的是计算由点v1v2定义的线的(左转)法线向量:

double dx = v2.x - v1.x;
double dy = v2.y - v1.y;
double nx = -dy;
double ny = dx;
double length = sqrt(dx * dx + dy * dy);
nx /= length;
ny /= length;
glm::vec3 normal(nx, 0, ny);

这可以简化:

glm::vec3 normal(v1.y - v2.y, 0, v2.x - v1.x);
normal = glm::normalize(normal);

注意,对于算法,您甚至可以跳过规范化,然后您将无法获得正确的法线distance,但distance的符号仍然正确。这样就足够了,因为您只需检查distance > 0

glm::vec3 normal(v1.y - v2.y, 0, v2.x - v1.x);

然后检查normal向量与v1testPoint的向量之间的角度是否大于-90度且小于+90度:

glm::vec3 vec(testPoint.x - v1.x, 0, testPoint.y - v1.y);
double distance = glm::dot(vecTemp, normal);

这是有效的,因为通常2个向量的 dot 乘积等于2个向量之间的角度的余弦乘以两个向量的幅度(长度) 。如果角度的余弦>> 0,则角度在[-90°,90°]范围内。

dot( A, B ) == length( A ) * length( B ) * cos( angle_A_B )  

A dot B

但算法只有v2.x < v1.x(在下面的图片中,x轴从左到右指向,y轴指向从下到上):

v2.x < v1.x

如果交换了2个点(v2.x > v1.x),那么你会得到相反的结果:

v2.x > v1.x

最后,代码可以这样表达:

glm::dot(glm::vec2(testPoint.x-v1.x, testPoint.y-v1.y),
         glm::vec2(v1.y-v2.y, v2.x-v1.x)) * glm::sign(v1.x-v2.x) > 0

结果仍然取决于“前面”的意思。在我的假设中,它意味着,testPoint的y坐标小于线v1v2的交点的y坐标,并且通过y轴的平行线testPoint。这意味着如果此算法始终计算“在前面”或“在后面”,它取决于您的程序逻辑和坐标系。