如何让程序从坐标数组中识别一个正方形?

时间:2018-05-01 21:39:21

标签: python python-3.x pyqt5 qpainter

我正在尝试创建一个程序,用户可以在网格中的方块内单击并使用PyQt5(QPainter)创建方块,但是我无法让程序识别绘制线条的时间和位置。所有点击的点都存储在列表中。

clicked0 = [] #clicked points
distlist0 = [] # list of distances between 2 points
distdict0 {} = # dictionary to identify which two points go with each distance
#there are versions of these for both player 0 and player 1

这是我用来尝试让程序识别并绘制正方形的代码:

    for i in list(itertools.combinations(clicked0, 2)):
        woo = list(chain.from_iterable(i))
        dist = math.hypot(woo[2]-woo[0],woo[3]-woo[1])
        distlist0.append(dist)
        distdict0[str(dist)] = "("+str(woo[0])+","+str(woo[1])+"), ("+str(woo[2])+","+str(woo[3])+")"
    listy = list(itertools.combinations(distlist0, 4))
    for i in listy:
        if i[0] == i[1] and i[0] == i[2] and i[0] == i[3]:
            for item in i:
                diction = list(chain.from_iterable(distdict0.get(str(item))))
                diction = [int(diction[1]),int(diction[3]),int(diction[8]),int(diction[10])]
                x,y = self.cell2coord(diction[0],diction[1]) #method to turn grid coords into x,y coords
                x2,y2 = self.cell2coord(diction[2],diction[3])
                qp.setPen(QPen(QColor(40, 85, 66), 5))
                qp.drawLine(x, y, x2, y2)

这会导致Python最终变慢并崩溃,但这是视觉效果:

screenshot

当可以从它们创建正方形时,这些线应该连接彩色网格空间(角落)。我已经在我的代码的这部分工作了几个小时,我只是不确定我可以做些什么来简化/纠正这个过程。

2 个答案:

答案 0 :(得分:1)

从列表中的所有点开始,取第一个点并从列表中删除它。从中,迭代地选择列表中的每个下一个点,并将其作为从第一个点开始的段的端点。对于每个段,将有另外两个方块来检查该段是否是可能方块的一部分。如果是,则继续检查另外两个角(其两个可能的位置现在已固定。)在任何一种情况下,继续下一个点以进行测试,直到所有以第一个弹出点开始的段都已经过测试。

重复上述步骤(弹出下一个点并检查其所有段),直到列表少于4个点。

这是O(N ^ 2)。要检查是否填充了正方形,可以使用正方形数组,但如果使用其键为(x,y)坐标的dict(内容可能是颜色),则解决方案可以更好地扩展到更大的网格。

使用组合会产生更多案例。有100分,它的组合为3921225。使用上述算法,它的n(n-1)/ 2 = 4950。

我怀疑我是在解决某人的家庭作业问题,但为了学习,这里有代码来找到一组正方形,其中一个正方形是一组四个点。

#/usr/bin/python3

points = [ (0, 0), (0, 2), (0, 4), (2, 0), (2, 2), (2, 6), (4, 4) ]

grid = {}
for point in points:
    grid[point] = 1

squares = set()     # set of frozenset(p1, p2, p3, p4), each defining a square
while len(points) >= 4:
    p1 = points.pop()
    for p2 in points:
        dx = p2[0] - p1[0]
        dy = p2[1] - p1[1]
        for delta in [(dy, -dx), (-dy, dx)]:
            p3 = (p2[0] + delta[0], p2[1] + delta[1])
            if grid.get(p3, False):
                p4 = (p3[0] - dx, p3[1] - dy)
                if grid.get(p4, False):
                    square = frozenset((p1, p2, p3, p4))    # frozen so it can be a set element
                    squares.add(square) # might be duplicate but that's OK
                break

for square in squares:
    print(list(square))

输出:

[(0, 4), (4, 4), (2, 6), (2, 2)]
[(2, 0), (0, 0), (0, 2), (2, 2)]

答案 1 :(得分:0)

执行此操作的一种方法是循环遍历所有坐标并检查它们是否形成正方形,例如:

请注意:此功能仅适用于与原始轴正交的矩形,对于倾斜的矩形,请参见下文

def rectangle(a, b, c, d):
        #sort points so they can easily be compared
        points = sorted([a, b, c, d])
        #check if corners line up
        if points[0][0] == points[1][0] and\
           points[0][1] == points[2][1] and\
           points[2][0] == points[3][0] and\
           points[1][1] == points[3][1]:
                   return True
        return False

#example data
lst_points = [[1,1],
              [1,2],
              [2,2],
              [2,1],
              [3,2],
              [4,5],
              [6,7],
              [4,2],
              [2,5]]

#loop over all sets of 4 points
for i in range(len(lst_points)):
        for j in range(i+1, len(lst_points)):
                for k in range(j+1, len(lst_points)):
                        for l in range(k+1, len(lst_points)):
                              #check if rectangle   
                              if rectangle(lst_points[i],
                                             lst_points[j],
                                             lst_points[k],
                                             lst_points[l]):
                                        print lst_points[i], lst_points[j], lst_points[k], lst_points[l]

此输出

[1, 1] [1, 2] [2, 2] [2, 1]
[2, 2] [4, 5] [4, 2] [2, 5]

示例列表中只有两个方块

使用此数据绘制线条应该相对容易。

此功能还会检查角度下的矩形。

import numpy as np

def rectangleII(a,b,c,d):
        points = sorted([a,b,c,d])
        V1 = np.array(points[1]) - np.array(points[0])
        V2 = np.array(points[2]) - np.array(points[0])
        V3 = np.array(points[3]) - np.array(points[2])
        V4 = np.array(points[3]) - np.array(points[1])
        if np.all(V1 == V3) and np.all(V2 == V4):
                if np.dot(V1, V2) == 0:
                        return True
        return False