平面中四点的相对位置

时间:2015-08-31 16:36:24

标签: algorithm graph geometry

飞机上有四个点有两个不同的相对位置:

Points

在位置1中,四个点可以形成凸四边形(即convex hull),而在位置2,它们可以是(并且它们的凸包是三角形)。我的问题是:如何编写算法来确定点是在1位还是2位? (我知道所有四个点的坐标。)

1 个答案:

答案 0 :(得分:4)

对于平面中P,Q和R的任意三个点(不共线),您可以通过查看数量的符号来确定角度P-Q-R是逆时针还是顺时针转弯:

(P[0] - R[0]) * (Q[1] - R[1]) - (P[1] - R[1]) * (Q[0] - R[0])

其中P[0]P[1]分别指代P的x坐标和y坐标,对于Q和R也是如此。

现在调用您的四个点P1,P2,P3和P4,并为四个三元组(P1,P2,P3),(P1,P2,P4),(P1,P3,P4)中的每一个计算这些符号, (P2,P3,P4)(这里要小心:上面表达式中点(P,Q,R)的顺序很重要)。如果所有符号相等,或者有两个正号和两个负号,则凸包是四边形。如果有三个正号和一个负号(或相反的方向),则四个点的凸包是一个三角形。或者更简单地说,如果您的符号表示为+1和-1,则将这四个符号相乘。如果产品是+1,则属于四边形;如果为-1,那么你就处于三角形的情况下。

以上假设四个点中没有三个是共线的;我留给你来列举堕落的案例。

由于这是StackOverflow,这里有一些代码(在Python中)。首先是ccw的定义(使用sign辅助函数)。

def sign(x):
    """ Return the sign of a finite number x. """
    if x > 0:
        return 1
    elif x < 0:
        return -1
    else:
        return 0

def ccw(P, Q, R):
    """ Return 1 if P-Q-R is a counterclockwise turn, -1 for clockwise,
        and 0 if the points are collinear (or not all distinct). """
    disc = (P[0] - R[0]) * (Q[1] - R[1]) - (P[1] - R[1]) * (Q[0] - R[0])
    return sign(disc)

然后对四个点进行分类。

def classify_points(P, Q, R, S):
    """ Return 1 if the convex hull of P, Q, R and S is a quadrilateral,
        -1 if a triangle, and 0 if any three of P, Q, R and S are
        collinear (or if not all points are distinct). """
    return ccw(P, Q, R) * ccw(P, Q, S) * ccw(P, R, S) * ccw(Q, R, S)

简单测试:应使用结果1对广场进行分类。

>>> # Test case 1: quadrilateral convex hull
>>> P = 0, 0
>>> Q = 0, 1
>>> R = 1, 0
>>> S = 1, 1
>>> classify_points(P, Q, R, S)
1

结果为-1的三角形。

>>> # Test case 2: triangle.
>>> P = 0, 0
>>> Q = 0, 3
>>> R = 3, 0
>>> S = 1, 1
>>> classify_points(P, Q, R, S)
-1

这是一个退化的情况(P,Q和S是共线的):

>>> P = 1, 1
>>> Q = 2, 2
>>> R = 5, 7
>>> S = 4, 4
>>> classify_points(P, Q, R, S)
0

请注意,如果您使用不精确的浮点运算,则数值错误可能导致近简并情况被归类为退化,反之亦然。

为了证明上述原因:很容易检查交换ccw定义中的任何两个输入是否会反转结果的符号,并且交换classify_points定义中的任何两个输入都会留下符号产品不变。因此,我们可以任意对点进行重新排序,同时影响classify_points结果。

现在假设P1,P2,P3和P4有一个四边形凸包。然后通过上述观察,我们可以对点进行重新排序,以假设P1,P2,P3和P4以逆时针顺序绕过该四边形的边界。然后,每个ccw表达式都是1,因此classify_points的结果为1。类似地,如果P1,P2,P3和P4具有三角形凸包,我们可以重新排列,使P1,P2和P3围绕三角形边界逆时针转动,P4在三角形内,并且在这种情况下ccw符号是11-11