0



背景:我有一个代码,它生成规则形状网络(在本例中为三角形)的笛卡尔坐标,然后在 Tkinter 画布上将形状的顶点绘制为小圆圈。该过程是自动化的,只需要网络的高度和宽度即可获得画布输出。每个顶点都有标签“顶点”和顶点的编号。
问题:我想自动将形状的顶点连接在一起(即点到点),我已经研究过使用find_closestfind_overlapping方法来做到这一点,但由于网络是由相互成角度的顶点组成的,我经常find_overlapping发现不可靠(由于依赖于矩形信封),并且find_closest似乎仅限于找到一个连接。由于顶点不一定按顺序连接,因此不可能创建一个循环来简单地连接顶点 1 --> 顶点 2 等。
问题:有没有一种方法可以有效地获取顶点的所有相邻顶点,然后“连接”点'而不依赖于使用手动方法(例如self.c.create_line(vertex_coord[1], vertex_coord[0], fill='black')每个连接)单独创建点之间的线?是否可以分享一个这样的代码的小例子?

预先感谢您的任何帮助!

下面是我的代码的画布组件的缩写版本。

原型方法:

from data_generator import * 
run_coordinate_gen=data_generator.network_coordinates()
run_coordinate_gen.generator_go()

class Network_Canvas:
  def __init__(self, canvas):
        self.canvas=canvas
        canvas.focus_set()
        self.canvas.create_oval(Vertex_Position[0],  dimensions[0],   fill='black', tags=('Vertex1', Network_Tag, Vertex_Tag))
        self.canvas.create_oval(Vertex_Position[5],  dimensions[5],   fill='black', tags=('Vertex2', Network_Tag, Vertex_Tag))
        try:
            self.canvas.create_line(Line_Position[5] ,Line_Position[0] , fill='black' tags=(Network_Tag,'Line1', Line_Tag )) #Connection Between 1 and 6 (6_1), Line 1
        except:
            pass

#Note: Line_Position, Dimensions and Vertex_Position are all lists composed of (x,y) cartesian coordinates in this case.

这当然会在整个网络中为每条线和顶点复制,但仅用于 90 个顶点。新版本需要更多数量级的顶点,我正在这样做:
新方法:

#Import updated coordinate generator and run it as before
class Network_Canvas:
    def __init__(self, canvas):
        self.canvas=canvas
        canvas.focus_set()
        for V in range(len(vertex_coord_xy)):                                                   
            self.canvas.create_text(vertex_coord_xy[V]+Text_Distance, text=V+1, fill='black', tags=(V, 'Text'), font=('Helvetica', '9'))
            self.canvas.create_oval(vertex_coord_xy[V],vertex_coord_xy[V]+Diameter, fill='black', outline='black', tags=(V, 'Vertex'))      
    #loop to fit connections here (?) 
4

1 回答 1

0

我认为任何类型的最近邻搜索都将比仅仅跟踪顶点更耗时,并且没有我能想到的“自动”连接点方法(另外,我没有看看为什么这样的方法应该比使用 create_line 绘制它们更快)。此外,如果您不跟踪,最近邻搜索算法将如何区分两个单独的、附近(或重叠)形状的顶点?无论如何,在我看来你已经有了正确的方法;可能有优化它的方法。

我认为由于您的形状很多,并且您需要对它们做一些复杂的事情,我会为它们创建一个类,就像我在下面实现的那样。它包括“单击查看相邻顶点”功能。以下所有代码都运行没有错误。输出图像如下所示。

import Tkinter as TK
import tkMessageBox

# [Credit goes to @NadiaAlramli](http://stackoverflow.com/a/1625023/1460057) for the grouping code
def group(seq, groupSize):
    return zip(*(iter(seq),) * groupSize)

Network_Tag, Vertex_Tag, Line_Tag = "network", "vertex", "line"

class Shape:
    def __init__(self, canvas, vertexCoords, vertexDiam):
        self.vertexIDs = []
        self.perimeterID = None
        self.vertexCoords = vertexCoords
        self.vertexRadius = vertexDiam/2
        self.canvas = canvas

    def deleteVertices(self):
        for ID in self.vertexIDs:
            self.canvas.delete(ID)
        self.vertexIDs = []

    def bindClickToVertices(self):
        coordsGrouped = group(self.vertexCoords, 2)
        num = len(coordsGrouped)
        for k in range(len(self.vertexIDs)):
            others = [coordsGrouped[(k-1)%num], coordsGrouped[(k+1)%num]]
            self.canvas.tag_bind(self.vertexIDs[k], '<Button-1>',
                    lambda *args:tkMessageBox.showinfo("Vertex Click", "Neighboring vertices: "+str(others)))

    def drawVertices(self):
        for x, y in group(self.vertexCoords, 2):
            self.vertexIDs.append(self.canvas.create_oval(x-self.vertexRadius, y-self.vertexRadius, x+self.vertexRadius, y+self.vertexRadius, fill='black', tags=(Network_Tag, Vertex_Tag)))
        self.bindClickToVertices()

    def updateVertices(self):
        self.deleteVertices()
        self.drawVertices()

    def deletePerimeter(self):
        if self.perimeterID is not None:
            self.canvas.delete(self.perimeterID)
        self.perimeterID = None

    def drawPerimeter(self):
        print "creating line:", (self.vertexCoords + self.vertexCoords[0:2])
        self.perimeterID = self.canvas.create_line(*(self.vertexCoords + self.vertexCoords[0:2]), fill='black', tags=(Network_Tag, Line_Tag))

    def updatePerimeter(self):
        self.deletePerimeter()
        self.drawPerimeter()

    def deleteShape(self):
        self.deleteVertices()
        self.deletePerimeter()

    def updateShape(self):
        self.updateVertices()
        self.updatePerimeter()

它可以非常简单地使用,像这样:

root = TK.Tk()

frame = TK.Frame(root)
canvas = TK.Canvas(frame, width=1000, height=1000)
frame.grid()
canvas.grid()

# create a bunch of isoceles triangles in different places:
shapes = []
for dx, dy in zip(range(0,1000, 30), range(0,1000, 30)):
    shapes.append(Shape(canvas, [0+dx, 0+dy, 10+dx, 10+dy, 20+dx, 0+dy], 5))

# draw (or redraw) the shapes:
for shape in shapes:
    shape.updateShape()

# move one of the shapes and change it to a square
shapes[10].vertexCoords = [50, 10, 60, 10, 60, 20, 50, 20]
shapes[10].updateShape()

# delete all the odd-numbered shapes, just for fun:
for k in range(len(shapes)):
    if k%2 == 1:
        shape.deleteShape()

root.mainloop()

输出:

演示代码的输出

于 2013-08-11T12:39:01.660 回答