背景:我有一个代码,用于生成规则形状网络(在本例中为三角形)的笛卡尔坐标,然后将Tkinter Canvas上形状的顶点绘制为小圆圈。该过程是自动化的,只需要网络的高度和宽度即可获得画布输出。每个顶点都有标签'Vertex'和顶点的数字。
问题:我想自动将形状的顶点连接在一起(即点到点),我已经研究过使用find_closest
和find_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 (?)
答案 0 :(得分: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()
输出: