按顺序放置矩形的顶点

时间:2013-03-28 11:14:05

标签: python algorithm sorting math geometry

我正在尝试在python(2.7)中编写一个函数。 此函数将获取8个值的列表,这些值表示顶点的坐标 (输入的形式是[Ax,Ay,Bx,By,Cx,Cy,Dx,Dy])
该函数将确定是否给出这些顶点以形成有效的矩形。

如果没有,它将按顺序放置它们并返回这些顶点的排序列表。 起点或方向(无论是顺时针还是逆时针)并不重要。

让我模仿我想要的东西:
如果给定的输入在下面的链接中形成第二或第三形状;该函数将其转换为第一个。 http://i.stack.imgur.com/IsRqr.png

我可以使用哪种算法来执行此操作?

我使用了Alexey建议的方式并编写了我的代码。 它可能需要一些优化,但对我来说这不是必要的。

def crossProduct(vector1,vector2) :
    a,b,c = vector1
    d,e,f = vector2
    vector3 = (b*f-c*e , -a*f+c*d , a*e-b*d)
    return vector3

def fixRect(rectList) :
    Ax,Ay,Bx,By,Cx,Cy,Dx,Dy = rectList[:]
    v12 = (Bx-Ax,By-Ay,0)
    v13 = (Cx-Ax,Cy-Ay,0)
    v14 = (Dx-Ax,Dy-Ay,0)
    z1 = crossProduct(v13,v12)[2]
    z2 = crossProduct(v13,v14)[2]
    if z1*z2 < 0 : # if two z values have different sign, they are in order
        return [Ax,Ay,Bx,By,Cx,Cy,Dx,Dy]
    # else swap 2 and 3
    Ax,Ay,Cx,Cy,Bx,By,Dx,Dy = rectList[:]
    # repeat
    v12 = (Bx-Ax,By-Ay,0)
    v13 = (Cx-Ax,Cy-Ay,0)
    v14 = (Dx-Ax,Dy-Ay,0)
    z1 = crossProduct(v13,v12)[2]
    z2 = crossProduct(v13,v14)[2]
    if z1*z2 < 0 : # if two z values have different sign, they are in order
        return [Ax,Ay,Bx,By,Cx,Cy,Dx,Dy]
    # else swap 3 and 4
    Ax,Ay,Bx,By,Dx,Dy,Cx,Cy = rectList[:]
    # repeat
    v12 = (Bx-Ax,By-Ay,0)
    v13 = (Cx-Ax,Cy-Ay,0)
    v14 = (Dx-Ax,Dy-Ay,0)
    z1 = crossProduct(v13,v12)[2]
    z2 = crossProduct(v13,v14)[2]
    if z1*z2 < 0 : # if two z values have different sign, they are in order
        return [Ax,Ay,Bx,By,Cx,Cy,Dx,Dy]
    else: raise Exception("Couldn't fix the rectangle")

2 个答案:

答案 0 :(得分:2)

从第1点到第2点制作一个矢量。

从第1点到第3点制作一个矢量。

从第1点到第4点制作一个矢量。

计算向量1-> 3和1-> 2的叉积的z分量。

计算向量1-> 3和1-> 4的叉积的z分量。

如果这两个z有不同的符号(一个是负面的而另一个是正面的),那么你的点数就是正确的。

如果它们没有顺序,重复以上所有,首先交换点3和2.如果这还不够,那么在原始列表/数组中交换点3和4。

答案 1 :(得分:1)

我知道这是一个僵尸问题,但我找不到相关的新问题。所以我会发布这个,以防它帮助某人。

这是我用过的算法。它依赖于以下假设:

  • 它的正方形/矩形:4个顶点,彼此成90度的边缘
  • 顶点已按顺序排列(顺时针或逆时针)
  • 将其旋转R使得-45 < R&lt; +45度

注意:它使用坐标约定:(Y,X),左上角有(0,0)。

import numpy as np
def sorted_rect(vec):
    # returns vec in clockwise order, starting with topleft
    normd = vec - np.average(vec,axis=0) # vertices relative to centroid
    tl_idx = np.argmax(np.dot(normd,np.array([-1,-1]))) #index of top left vertex
    clockwise = np.cross(vec[(tl_idx+1) % 4] - vec[tl_idx],
                         vec[tl_idx] - vec[tl_idx-1]) > 0
    return np.roll(vec,-tl_idx,axis=0) if clockwise else np.roll(vec,-1-tl_idx,axis=0)[::-1]