0



背景:通常の形状 (この場合は三角形) のネットワークのデカルト座標を生成し、Tkinter キャンバス上の形状の頂点を小さな円としてプロットするコードがあります。このプロセスは自動化されており、ネットワークの高さと幅だけでキャンバス出力を取得できます。各頂点には、「Vertex」というタグと頂点の番号があります。
問題:形状の頂点を自動的に接続したい (点と点)。これを行う方法を調べましfind_closestfind_overlappingが、ネットワークは互いに角度を成す頂点で構成されているため、多くの場合find_overlapping、信頼できない (長方形のエンベロープに依存しているため)、およびfind_closest接続が 1 つしか見つからないように見えます。頂点は必ずしも順番に接続されているとは限らないため、単純に頂点 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 で描画するよりも高速である理由を確認してください)。また、追跡していない場合、最近傍検索アルゴリズムは、2 つの別個の近くにある (または重なっている) 形状の頂点をどのように区別しますか? とにかく、私の意見では、あなたはすでに正しい方法を手に入れています。おそらくそれを最適化する方法があります。

あなたの形状は数多くあり、それらを使用する必要がある複雑なものがあるため、以下で実装したようなクラスを作成すると思います。「クリックして隣接する頂点を表示」機能が含まれています。次のコードはすべてエラーなしで実行されました。以下に示す出力の画像。

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 に答える