【问题标题】:How to get a program to identify a square from an array of coordinates?如何让程序从坐标数组中识别正方形?
【发布时间】:2018-05-01 21:39:20
【问题描述】:

我正在尝试创建一个程序,用户可以在其中单击网格上的正方形并使用 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 最终变慢并崩溃,但这是视觉结果:

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

【问题讨论】:

  • 你的意思是在同一条线上的任意两个正方形都应该连接起来,还是只有四个成对的正方形组成一个矩形?
  • @Nathan 只有四个成对的彩色方格。
  • 为什么有 2 个用户问同一个问题? Given a list of coordinates, check whether any form a square
  • 如果您与另一个问题中的人是同一个人。我建议关闭您的任何一个问题或合并它们。它将帮助未来的读者。
  • 下次发布代码时。请务必发布我们可以在不添加任何内容的情况下运行的代码(请参阅Minimal, Complete, Verifiable Example)。在下面的答案中,帖子是完整的程序,省略了图形 I/O 和其他不必要的细节。

标签: python python-3.x pyqt5 qpainter


【解决方案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)]

【讨论】:

  • 顺便说一句,上面构建grid 的“pythonic”方式是grid = {p:1 for p in points},但我不想增加混淆。
【解决方案2】:

这样做的一种方法是遍历所有坐标并检查它们是否形成正方形,例如:

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

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

【讨论】:

  • 是的,那将是非常缓慢的方式! O(N^4)。稍微考虑一下,你会发现你可以省略内部的两个循环(或者实际上,将它们显着减少到最多 4 个测试)。给定一个段,您必须测试多少个位置才能确定它是否是正方形的一部分?
  • 您的检查例程似乎有问题,因为它只找到[ (0,0), (0,2), (0,4), (2,0), (2,2), (2,6), (4,4) ] 的两个方块中较小的那个。就是上图中的绿点。
  • @JeffLearman 我认为 OP 仅表示与原始轴系正交的矩形。我解释说“当可以从它们创建正方形时,这些线条应该连接彩色网格空间(角)。”像这样。
  • @JeffLearman 添加了一个函数,该函数也考虑了倾斜的正方形
猜你喜欢
  • 2019-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多