实现“三角内检查点”算法时出错

时间:2012-07-08 10:47:14

标签: java algorithm collision-detection

我正在跟踪this article中的算法1来检查一个点是否在三角形内。这是我的代码:

//========================================================================================================================//
// Methods
//========================================================================================================================//

private float getPerpDotProduct(final PointF p1, final PointF p2) {
    return p1.x * p2.y - p1.y * p2.x;
}

private boolean isInside(final PointF pPoint) { 
    final float c1 = this.getPerpDotProduct(this.mA, pPoint);
    final float c2 = this.getPerpDotProduct(this.mB, pPoint);
    final float c3 = this.getPerpDotProduct(this.mC, pPoint);

    return ((c1 >= 0 && c2 >= 0 & c3 >= 0) || (c1 <= 0 && c2 <= 0 && c3 <= 0));
}

这是我的测试: enter image description here

青色区域:我给出的真正三角形。

粉红色区域:“内部”三角形

蓝色区域:三角形“外面”

修改

这是我用向量计算的新代码:

private PointF getVector(final PointF pPoint1, final PointF pPoint2) {
    return new PointF(pPoint2.x - pPoint1.x, pPoint2.y - pPoint1.y);
}

private float getPerpDotProduct(final PointF p1, final PointF p2) {
    return p1.x * p2.y - p1.y * p2.x;
}

private boolean isInside(final PointF pPoint) { 
    final float c1 = this.getPerpDotProduct(getVector(this.mA, this.mB), getVector(this.mA, pPoint));
    final float c2 = this.getPerpDotProduct(getVector(this.mB, this.mC), getVector(this.mB, pPoint));
    final float c3 = this.getPerpDotProduct(getVector(this.mC, this.mA), getVector(this.mC, pPoint));

    return ((c1 > 0 && c2 > 0 & c3 > 0) || (c1 < 0 && c2 < 0 && c3 < 0));
}

请澄清我的代码。谢谢。

2 个答案:

答案 0 :(得分:1)

文章描述了需要做什么的“bug”:

  

使用测试点P计算所有三个点V1,V2,V3的perpDotProduct / crossproduct

应为“使用矢量到测试点P计算所有三个向量的perpDotProduct / crossproduct”。

正如文章中所解释的,如果所有三个点在距离原点(图片的左上角)相同的“角度方向”处可见,则算法返回true。你的照片也准确地显示了它:如果所有粉红点都在蓝色区域之上,则所有粉红点的矢量(0, p)需要顺时针转动才能到达三角形;如果它们低于蓝色区域,则向量需要逆时针移动。

要修复算法,您需要计算向量{(V1-V2), (V1-P)}{(V2-V3), (V2-P)}{(V3-V1), (V3-P)}的叉积。看一下this article伪代码。

答案 1 :(得分:1)

我通常使用重心坐标来做这样的数学计算: (考虑4点,其中p1,p2,p3是三角形,p4是你要检查的点: 将(p1,p3)视为向量p1 - > P3

dot00 = (p1,p3).(p1,p3)
dot01 = (p1,p3).(p1,p2)
dot02 = (p1,p3).(p1,p4)
dot11 = (p1,p2).(p1,p2)
dot12 = (p1,p2).(p1,p4)


inverseDenominator = (1 / (dot00*dot11 - dot01*dot01)

u = (dot11 * dot02 - dot01*dot12) * inverseDenominator
v = (dot00 * dot12 - dot01*dot02) * inverseDenominator

现在我们已经计算了重心坐标,验证很简单,如果P4位于三角形内(P1,P2,P3)$那么uv必须都是正数并总结它们必须小于一个:

u >= 0 && v >= 0 && u + v < 1 

这篇文章是我在撰写论文时学会了如何做到的:http://www.blackpawn.com/texts/pointinpoly/default.html (你会发现变量名的相似之处:p)