6 from GraphViewer import GraphViewer
10 from pygraphviz import graphviz as gv
15 class MyCanvas(QCanvas):
16 def customEvent(self,event):
18 object.customEvent(event)
22 def __init__(self,item,parent):
26 #initial canvas size : 1000x1000
27 self.canvas=MyCanvas(1000,1000)
28 self.editor=GraphViewer(self.canvas,parent,"example",0)
30 root=self.node.getRootNode()
31 rootItem=Item.adapt(root)
32 CONNECTOR.Connect(rootItem,"selected",self.selectItem,())
33 CONNECTOR.Connect(self.item,"add",self.addItem,())
34 CONNECTOR.Connect(self.item.datalinks,"add",self.addLink,())
36 def createGraph(self):
37 #citems dict helps finding items in canvas from swig proxy
38 #To find an item node make : citems[node.ptr()]
41 #pitems dict helps finding items in canvas from swig proxy
42 #To find an item port make : pitems[port.ptr()]
46 lnode=self.node.edGetDirectDescendants()
48 c=CItems.Cell(n,self.canvas)
52 for k,n in citems.items():
54 pitems[p.port.ptr()]=p
56 pitems[p.port.ptr()]=p
58 for pout,pin in self.node.getSetOfInternalLinks():
59 if pout.getNode().getFather() != self.node and pin.getNode().getFather() != self.node:
61 po=pitems.get(pout.ptr())
62 pi=pitems.get(pin.ptr())
64 CItems.LinkItem(po,pi,self.canvas)
67 itemup=citems[n.ptr()]
68 for ndown in n.getOutNodes():
69 itemdown=citems[ndown.ptr()]
70 CItems.ControlLinkItem(itemup.outgate,itemdown.ingate,self.canvas)
74 def addLink(self,link):
75 print "graph.addLink",link
77 nodeS=self.citems[link.pout.getNode().ptr()]
78 nodeE=self.citems[link.pin.getNode().ptr()]
80 for p in nodeS.outports:
81 if p.port == link.pout:
84 for p in nodeE.inports:
85 if p.port == link.pin:
90 l=CItems.LinkItem(po,pi,self.canvas)
93 def addItem(self,item):
94 #print "graph.addItem",item
95 node=CItems.Cell(item.node,self.canvas)
96 self.citems[item.node.ptr()]=node
100 def selectItem(self,item):
101 #print "graph.selectItem",item
102 self.editor.selectItem(item)
104 def layout(self,rankdir):
105 """Compute graph layout with graphviz package"""
106 G=pygraphviz.AGraph(strict=False,directed=True)
107 G.graph_attr["rankdir"]=rankdir
108 G.graph_attr["dpi"]="72"
111 for k,n in self.citems.items():
112 #k is node address (YACS)
116 for pout,pin in self.node.getSetOfInternalLinks():
117 if pout.getNode().ptr() not in self.citems :
119 if pin.getNode().ptr() not in self.citems:
121 G.add_edge(pout.getNode().ptr(),pin.getNode().ptr())
123 for k,n in self.citems.items():
124 for ndown in n.node.getOutNodes():
125 G.add_edge(n.node.ptr(),ndown.ptr())
127 #By default graphviz uses 96.0 pixel per inch (dpi=96.0)
129 item=self.citems[int(n)]
130 h=item.height()/dpi #height in inch
131 w=item.width()/dpi #width in inch
132 n.attr['height']=str(h)
133 n.attr['width']=str(w)
134 n.attr['fixedsize']="true"
135 n.attr['shape']="box"
136 #n.attr['label']=item.node.getName()
138 G.layout(prog='dot') # use dot
139 #G.write("layout.dot")
140 #G.draw("layout.png")
142 graph_attr=dict(attrs(G))
143 bbox=graph_attr["bb"]
144 x1,y1,x2,y2=eval(bbox)
145 h=self.canvas.height()
146 w=self.canvas.width()
150 self.canvas.resize(w2,h2)
153 pos=n.attr['pos'] #position is given in points (72 points par inch, so 1 point = dpi/72=1.34)
157 item=self.citems[int(n)]
166 def clearLinks(self):
167 items=self.citems.values()
169 for port in node.outports:
170 if not hasattr(port,"links"):
172 for link in port.links():
176 def orthoLinks(self):
177 items=self.citems.values()
180 for port in node.outports:
181 if not hasattr(port,"links"):
183 for link in port.links():
184 #clear all intermediate points of the link
186 #if isinstance(link,CItems.ControlLinkItem):
187 # print port.port.getNode().getName() +"->"+link.toPort.port.getNode().getName()
189 # print port.port.getNode().getName() +":"+port.port.getName()+"->"+link.toPort.port.getNode().getName()+":"+link.toPort.port.getName()
190 #print (port.x(),port.y()),(link.toPort.x(),link.toPort.y())
191 x0,y0=port.x()+5,port.y()
192 while g.get((x0,y0)).blocked:
194 x1,y1=link.toPort.x()-5,link.toPort.y()
195 while g.get((x1,y1)).blocked:
197 path=g.findPath((x0,y0),(x1,y1))
200 if port.y() == link.toPort.y():
201 #near ports face to face
205 path=[(x,port.y()),(x,link.toPort.y())]
211 path=[(x1,port.y()),(x1,link.toPort.y())]
214 if port.y() == link.toPort.y():
215 #near ports face to face
218 #transform it into a vertical line
220 path=[(x,port.y()),(x,link.toPort.y())]
222 #adjust the first point to the same y as port
226 #remove first point and adjust second one
230 #adjust the last point to the same y as link.toPort
234 #remove last point and adjust new last one
237 path[-1]=x0,link.toPort.y()
240 #add intermediate points
243 link.splitLine(line,x,y)
246 def attrs(g,t=gv.AGRAPH):
249 ah=gv.agnxtattr(g.handle,t,ah)
250 value=gv.agxget(g.handle,ah)
251 yield gv.agattrname(ah),value
253 def h(x,y,destx,desty):
254 return abs(destx-x)+abs(desty-y)
256 def distance(node,new_node):
259 d= abs(x1-x)+abs(y1-y)
260 if node.parent != None:
261 x0,y0=node.parent.coord
262 if (x1-x)*(y0-y)-(y1-y)*(x0-x) != 0:
263 #corner add some cost to penalize
268 def __init__(self,coord,index):
279 def __init__(self,graph):
312 for w in xrange(len(xs)-1):
315 for h in xrange(len(ys)-1):
317 col.append(node((x,y),(w,h)))
318 self.cols.append(col)
325 l1,l2=bisect.bisect_left(ys,y-ymargin),bisect.bisect_left(ys,y+h+ymargin)
326 i1,i2=bisect.bisect_left(xs,x-xmargin),bisect.bisect_left(xs,x+w+xmargin)
327 for c in self.cols[i1:i2]:
331 #for col in self.cols:
332 # print [e.coord +(e.blocked,) for e in col]
338 n.total= n.path_cost=0
343 col= bisect.bisect_left(self.xs,x)-1
344 if col < 0 or col >= len(self.cols):
347 row=bisect.bisect_left(self.ys,y)-1
348 if row < 0 or row >= len(col):
352 def getPath(self,node):
360 #if points are aligned don't keep the middle point
364 if (x1-x)*(y0-y)-(y1-y)*(x0-x) == 0:
366 path.append(node.coord)
370 def neighbours(self,node):
373 steps=((0, +1), (+1, 0), (0, -1), (-1, 0 ))
377 if c < 0 or c >=len(self.cols):
380 if r <0 or r >= len(co):
388 def findPath(self,fromLoc,toLoc):
389 """Find shortest path from fromLoc to toLoc"""
392 fromNode=self.get(fromLoc)
393 self.open.append((fromNode.total,fromNode))
394 toNode=self.get(toLoc)
396 print "toNode is blocked"
398 destx,desty=toNode.coord
400 #if open is not void, take the best node (the first one)
401 t,node=self.open.pop(0)
405 return self.getPath(node)
407 for new_node in self.neighbours(node):
411 path_cost=node.path_cost+distance(node,new_node)
412 total=path_cost+h(x,y,destx,desty)
414 #the node is already in open
415 if total < new_node.total:
416 self.open.remove((new_node.total,new_node))
417 new_node.path_cost=path_cost
420 bisect.insort(self.open,(new_node.total,new_node))
422 #the node is not yet in open
423 new_node.path_cost=path_cost
426 bisect.insort(self.open,(new_node.total,new_node))