使用获取三角形内部点的方法得到奇怪的结果

时间:2014-10-05 15:19:01

标签: java opengl math lwjgl

我正在使用我在互联网上找到的cpp中的方法,我为java改了一下。它似乎只有一半的时间工作。这是java的错误吗?因为它会返回true或false,具体取决于你在三角形内的位置。任何人都可以帮我修复它或找到一个更好的方法来测试三角形内的一个点吗?继承人的方法。对不起,如果很难理解这个问题

    public static float area(float x1, float y1, float x2, float y2, float x3, float y3)
{
   return (float) Math.abs((x1*(y2-y3) + x2*(y3-y1)+ x3*(y1-y2))/2.0);
}

/* A function to check whether point P(x, y) lies inside the triangle formed 
   by A(x1, y1), B(x2, y2) and C(x3, y3) */
public static boolean isInside(float x1, float y1, float x2, float y2, float x3, float y3, float x, float y)
{   
   /* Calculate area of triangle ABC */
   float A = area (x1, y1, x2, y2, x3, y3);

   /* Calculate area of triangle PBC */  
   float A1 = area (x, y, x2, y2, x3, y3);

   /* Calculate area of triangle PAC */  
   float A2 = area (x1, y1, x, y, x3, y3);

   /* Calculate area of triangle PAB */   
   float A3 = area (x1, y1, x2, y2, x, y);

   /* Check if sum of A1, A2 and A3 is same as A */
   return (A == A1 + A2 + A3);
}

1 个答案:

答案 0 :(得分:1)

这是浮点精度的问题。请记住,浮点计算以有限的精度执行。因此,如果您进行数学上应该产生相同结果的不同计算,则计算机产生的实际结果通常不会相同。

因此,问题在于这个测试:

return (A == A1 + A2 + A3);

如果该点位于三角形内,AA1 + A2 + A3将具有非常相似的值,但由于计算过程中浮点精度有限,因此不一定相同。

解决问题的最直接方法是在比较中允许一些不精确的方法:

return Math.abs(A - (A1 + A2 + A3) < eps);

其中eps是一个小的浮点常数。为这些公差选择一个好的值总是很棘手,因此最好避免使算法成为必要(如果可能的话)(参见下面提出的解决方案)。如果使公差太小,则测试将失败三角形内的点。如果你把它做得太大,你就会允许更多误报,因为三角形之外的点会通过测试。

如果你真的想要使用这种测试,那么测试相对差异而不是绝对差异会更稳定,因为绝对误差通常会随着值本身变大而增加。测试相对差异将如下所示:

return Math.abs((A - A1 - A2 - A3) / A) < eps;

然后对于eps的值,我会从一个安全地大于float值的相对精度的东西开始,大约是7位数。像1.0e-5f这样的东西似乎是合理的。

有更好的方法可以做三角形&#34;三角形&#34;测试。实际上,我认为你可以使用你已有的大部分数学。我根本没有对以下内容进行过测试,所以它没有任何保修,但我相信它应该可行。

您的想法是,您并不需要关心所有部分区域总和到三角形区域。我相信它们都是积极的。您可以通过删除area电话来更改abs()功能以返回已签名的区域:

public static float area(float x1, float y1, float x2, float y2, float x3, float y3)
{
    return 0.5f * (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
}

然后像以前一样计算A1A2A3,并检查它们是否都是正面的:

return A1 >= 0.0f && A2 >= 0.0f && A3 >= 0.0f;

这假定三角形具有逆时针方向。如果您希望它也适用于顺时针方向,则需要检查所有三个值是否具有相同的符号。