graph_view.py
Go to the documentation of this file.
00001 #import roslib; roslib.load_manifest('rcommander_core')
00002 
00003 import graph.style as gs
00004 import graph
00005 import graph.layout as gl
00006 
00007 import tool_utils as tu
00008 import graph_model as gm
00009 
00010 import numpy as np
00011 import time
00012 import copy
00013 
00014 def copy_style(astyle, bstyle):
00015     bstyle.background  = astyle.background  
00016     bstyle.fill        = astyle.fill       
00017     bstyle.stroke      = astyle.stroke     
00018     bstyle.strokewidth = astyle.strokewidth
00019     bstyle.text        = astyle.text       
00020     bstyle.font        = astyle.font       
00021     bstyle.fontsize    = astyle.fontsize   
00022     bstyle.textwidth   = astyle.textwidth  
00023     bstyle.align       = astyle.align      
00024     bstyle.depth       = astyle.depth      
00025 
00026 class GraphView:
00027 
00028     def __init__(self, context, graph_model):
00029         self.graph_model = graph_model
00030         g = self.graph_model.gve
00031         self.gve = g
00032         self.context = context 
00033 
00034         node_outlines = self.context.color(0.4, 0.4, 0.4, 1.)
00035         text_color = self.context.color(0.3, 0.3, 0.3, 1.)
00036         node_font_size = 14
00037 
00038         #Customizations
00039         g.styles.default.depth = True
00040         g.styles.default.background = self.context.color(1., 1., 1., 1.)
00041         g.styles.default.stroke = node_outlines
00042         g.styles.default.text = text_color
00043         g.styles.default.fontsize = node_font_size
00044         g.styles.root.text = self.context.color(255/255., 153/255., 51/255., 1.)
00045 
00046         g.styles.important.fontsize = node_font_size
00047         g.styles.important.text = text_color
00048         g.styles.important.stroke = node_outlines
00049 
00050         g.styles.marked.fontsize = node_font_size
00051         g.styles.marked.text = text_color
00052         g.styles.marked.stroke = node_outlines
00053         #g.styles.default.fontsize = 12
00054         #g.styles.light.fontsize = 12
00055         #g.styles.back.fontsize = 12
00056         #g.styles.marked.fontsize = 12
00057 
00058         #g.styles.dark.fontsize = 12
00059         #g.styles.highlight.fontsize = 12
00060         #g.styles.root.fontsize = 12
00061 
00062 
00063         self.refresh = self.gve.layout.refresh
00064 
00065         old_outcome_style = g.styles.create('old_outcome')
00066         active_node_style = g.styles.create('active_node')
00067         selected_style = g.styles.create('selected')
00068         normal_style   = g.styles.create('normal')
00069         normal_edge_style   = g.styles.create('normal_edge')
00070         selected_edge_style = g.styles.create('selected_edge')
00071         graph_circle = g.styles.create('graph_circle')
00072         container = g.styles.create('container')
00073         container_selected = g.styles.create('container_selected')
00074 
00075         copy_style(g.styles.important, old_outcome_style)
00076         copy_style(g.styles.important, active_node_style)
00077         copy_style(g.styles.important, selected_style)
00078         copy_style(g.styles.default, normal_style)
00079         copy_style(g.styles.default, normal_edge_style)
00080         copy_style(g.styles.default, selected_edge_style)
00081         copy_style(g.styles.default, graph_circle)
00082         copy_style(g.styles.default, container)
00083         copy_style(g.styles.default, container_selected)
00084 
00085         graph_circle.fill = self.context.color(.96, .96, .96, .96)
00086         graph_circle.stroke = self.context.color(.8, .8, .8, 1.)
00087         graph_circle.strokewidth = 3
00088         graph_circle.fontsize = 24
00089         graph_circle.textwidth = 800
00090         graph_circle.text = self.context.color(.5, .5, .5, 1.)
00091 
00092         container.fill = self.context.color(255./255, 204./255, 102./255., .4)
00093         container.node = g.styles.important.node
00094 
00095         container_selected.fill = self.context.color(255./255, 204./255, 102./255., 1.)
00096         container_selected.node = g.styles.important.node
00097 
00098         selected_style.text = text_color
00099         selected_edge_style.stroke = self.context.color(0.80, 0.00, 0.00, 0.75)
00100         selected_edge_style.strokewidth = 1.0
00101 
00102         active_node_style.text = text_color
00103         active_node_style.fill = self.context.color(153./255, 255./255, 51/255, .75)
00104         active_node_style.strokewidth = 3
00105 
00106         old_outcome_style.text = text_color
00107         old_outcome_style.fill = self.context.color(153./255, 255./255, 51/255, .4)
00108 
00109         self.radii_increment = 150
00110         self.fsm_start_color = 1.
00111         self.fsm_end_color = .96
00112         self.fsm_stroke_color = .85
00113         self.fsm_current_context_node = None
00114         self.fsm_dclick_cb = None
00115 
00116         self.right_clicked = None
00117         self.dx = 0.
00118         self.dy = 0.
00119         self.tx = 0.
00120         self.ty = 0.
00121         #g.node('start').style = 'marked'
00122 
00123     def set_node_style(self, node_name, style):
00124         self.gve.node(node_name).style = style
00125         self.gve.layout.refresh()
00126 
00127     def get_node_style(self, node_name):
00128         return self.gve.node(node_name).style
00129     
00130     #def drag_background_cb(self, s, e):
00131     #    #print start_click.x, start_click.y
00132     #    #print curr_pos.x, curr_pos.y
00133 
00134     #    #transform.scale(self.zoom, self.zoom)
00135     #    self.dx = e.x - s.x
00136     #    self.dy = e.y - s.y
00137     #    #print dx, dy
00138     #    #transform = QTransform()
00139     #    ##transform.scale(abs(dx), abs(dy))
00140     #    #transform.translate(dx, dy)
00141     #    #self.graphicsView.superView.setTransform(transform)
00142 
00143     def _background_drag(self, properties_dict):
00144         mouse_pose = properties_dict['MOUSEX'], properties_dict['MOUSEY']
00145 
00146         if properties_dict['rightdown']:
00147             if not self.right_clicked:
00148                 self.right_clicked = mouse_pose
00149             else:
00150                 self.tx = mouse_pose[0] - self.right_clicked[0]
00151                 self.ty = mouse_pose[1] - self.right_clicked[1]
00152         else:
00153             #Commit transform
00154             self.right_clicked = None
00155             self.dx += self.tx
00156             self.dy += self.ty
00157             self.ty = 0.
00158             self.tx = 0.
00159 
00160         #if self._ctx._ns["rightdown"]:
00161         #    #Make sure we're not in any nodes
00162         #    in_nodes = False
00163         #    for n in self.graph.nodes:
00164         #        if self.mouse in n:
00165         #            in_nodes = True
00166         #            break
00167 
00168         #    #Set pose first time
00169         #    if not in_nodes and not self.right_clicked:
00170         #        self.right_clicked = self.mouse
00171         #    else:
00172         #        self.right_drag(self.right_clicked, self.mouse)
00173 
00174         #else:
00175         #    self.right_clicked = None
00176 
00177     def setup(self):
00178         self.times = {}
00179         self.times['draw'] = 0.
00180         self.times['check'] = 0.
00181         self.times['iter'] = 0
00182 
00183 
00184     def draw(self, properties_dict):
00185         START_TIME = time.time()
00186         self.context.size(properties_dict['width'], properties_dict['height'])
00187         cx = self.context
00188         g  = self.gve
00189 
00190 
00191         for n in g.nodes:
00192             if properties_dict['selected_node'] == n.id:
00193                 self.set_node_style(n.id, 'selected')
00194             else:
00195                 self.set_node_style(n.id, 'normal')
00196 
00197             if self.graph_model.get_start_state() == n.id:
00198                 if self.get_node_style(n.id) == 'selected':
00199                     self.set_node_style(n.id, 'important')
00200                 else:
00201                     self.set_node_style(n.id, 'marked')
00202 
00203             if hasattr(self.graph_model.get_state(n.id), 'get_child'):
00204                 if self.get_node_style(n.id) == 'selected':
00205                     self.set_node_style(n.id, 'container_selected')
00206                 else:
00207                     self.set_node_style(n.id, 'container')
00208 
00209             if self.graph_model.is_running():
00210                 if not self.graph_model.sm_thread.has_key('current_states'):
00211                     print 'KEYS!', self.graph_model.sm_thread.keys()
00212                 if self.graph_model.sm_thread['current_states'] != None and \
00213                         (len(set(self.graph_model.sm_thread['current_states']).intersection(set([n.id]))) > 0):
00214                     self.set_node_style(n.id, 'active_node')
00215 
00216             if self.graph_model.get_last_outcome() != None:
00217                 outcome, t = self.graph_model.get_last_outcome() 
00218                 if outcome == n.id:
00219                     if time.time() - t < 10.:
00220                         self.set_node_style(n.id, 'old_outcome')
00221 
00222         #self.set_node_style(tu.InfoStateBase.GLOBAL_NAME, 'root')
00223 
00224         draw_func = None
00225         #if properties_dict['selected_edge'] != None:
00226 
00227         def draw_selected():
00228             if properties_dict['selected_edge'] == None:
00229                 return
00230             cx = self.context
00231             g  = self.gve
00232             #edge = self.selected_edge 
00233             edge = properties_dict['selected_edge']
00234             x0, y0 = edge.node1.x, edge.node1.y
00235             x1, y1 = edge.node2.x, edge.node2.y
00236             coordinates = lambda x, y, d, a: (x+math.cos(math.radians(a))*d, y+math.sin(math.radians(a))*d)
00237 
00238             # Find the edge's angle based on node1 and node2 position.
00239             a = math.degrees(math.atan2(y1-y0, x1-x0))
00240             # draw line from node's edge instead of it's center.
00241             r = edge.node2.r
00242             d = math.sqrt(pow(x1-x0, 2) + pow(y1-y0, 2))
00243             x00, y00 = coordinates(x0, y0, r+1, a)
00244             x01, y01 = coordinates(x0, y0, d-r-1, a)
00245 
00246             # draw
00247             p1 = [x00, y00]
00248             p2 = [x01, y01]
00249             cx.fill()
00250             cx.strokewidth(1.0)
00251             cx.stroke(1., 153./255., 0, .75)
00252             cx.beginpath(p1[0], p1[1])
00253             cx.lineto(p2[0], p2[1])
00254             path = cx.endpath(False)
00255             gs.edge_arrow(g.styles[edge.node1.style], path, edge, radius=10)
00256             cx.drawpath(path)
00257 
00258         def draw_fsm_circles():
00259             g = self.gve
00260 
00261             #figure out where centroids should be
00262             coords = []
00263             [coords.append([n.x, n.y]) for n in g.nodes]
00264             coords = np.matrix(coords).T
00265             centroid = np.median(coords, 1)
00266             if len(coords) == 0:
00267                 return
00268 
00269             #calculate where radii should be
00270             radius = np.max(np.power(np.sum(np.power((coords - centroid), 2), 0), .5)) + gm.GraphModel.NODE_RADIUS*2
00271             radius = max(radius, 200.)
00272             container_style = g.styles.graph_circle
00273             container_stroke = container_style.stroke
00274             
00275             ##
00276             #Draw fsm_stack
00277             stack = copy.copy(properties_dict['fsm_stack'])
00278             #stack.reverse()
00279             #smallest_radii = radius
00280             largest_radii = radius + len(stack) * self.radii_increment
00281             color = self.fsm_start_color
00282             if len(stack) > 0:
00283                 color_incre = (self.fsm_start_color - self.fsm_end_color) / len(stack)
00284 
00285             #draw stack
00286             for el in stack:
00287                 #smallest_radii = smallest_radii + self.radii_increment
00288                 name = el.model.document.get_name()#el.document.get_name()
00289 
00290                 #Draw node
00291                 stack_node = graph.node(g, radius = largest_radii, id = name)
00292                 stack_node.x, stack_node.y = centroid[0,0], centroid[1,0]
00293                 el.graph_node = stack_node
00294                 container_style.fill = self.context.color(color, color, color, 1.)
00295                 container_style.stroke = self.context.color(self.fsm_stroke_color, self.fsm_stroke_color, 1.)
00296                 gs.node(container_style, stack_node, g.alpha)
00297 
00298                 #Draw label
00299                 node_label_node_ = graph.node(g, radius = largest_radii, id = name)
00300                 node_label_node_.x, node_label_node_.y = centroid[0,0], centroid[1,0] - largest_radii
00301                 gs.node_label(container_style, node_label_node_, g.alpha)
00302 
00303                 color -= color_incre
00304                 largest_radii -= self.radii_increment
00305 
00306             ##
00307             #Draw node
00308 
00309             #Draw node circle
00310             graph_name_node = graph.node(g, radius=radius, id = properties_dict['name'])
00311             graph_name_node.x, graph_name_node.y = centroid[0,0], centroid[1,0]
00312             self.fsm_current_context_node = graph_name_node
00313             container_style.fill = self.context.color(self.fsm_end_color, self.fsm_end_color, self.fsm_end_color, 1.)
00314             container_style.stroke = container_stroke
00315             gs.node(container_style, graph_name_node, g.alpha)
00316 
00317             #draw node label
00318             node_label_node = graph.node(g, radius=radius, id = properties_dict['name'])
00319             node_label_node.x, node_label_node.y = centroid[0,0], centroid[1,0] - radius
00320             gs.node_label(container_style, node_label_node, g.alpha)
00321 
00322         def detect_fsm_click():
00323             def in_node(x, y, n):
00324                 return (abs(x - n.x) < n.r) and (abs(y - n.y) < n.r)
00325 
00326             mousex_g = self.context._ns['MOUSEX'] - self.gve.x
00327             mousey_g = self.context._ns['MOUSEY'] - self.gve.y
00328             if self.context._ns['mousedoubleclick'] and len(properties_dict['fsm_stack']) > 0:
00329                 if not in_node(mousex_g, mousey_g, self.fsm_current_context_node):
00330                     stack = copy.copy(properties_dict['fsm_stack'])
00331                     stack.reverse()
00332                     selected_el = None
00333                     for el in stack:
00334                         if in_node(mousex_g, mousey_g, el.graph_node):
00335                         #if p in el.graph_node:
00336                             selected_el = el
00337                             break
00338 
00339                     #selected something so load it
00340                     if selected_el != None and self.fsm_dclick_cb != None:
00341                         self.fsm_dclick_cb(selected_el)
00342 
00343         def final_func():
00344             draw_selected()
00345             detect_fsm_click()
00346 
00347         CHECK_TIME = time.time()
00348         self._background_drag(properties_dict)
00349         properties_dict['MOUSEX'] -= self.dx+self.tx
00350         properties_dict['MOUSEY'] -= self.dy+self.ty
00351         g.draw(dx=self.dx+self.tx, dy=self.dy+self.ty, directed=True, traffic=False, user_draw_start=draw_fsm_circles, user_draw_final=final_func)
00352 
00353         DRAW_TIME = time.time()
00354 
00355         total_draw = DRAW_TIME - CHECK_TIME
00356         total_check = CHECK_TIME - START_TIME
00357         self.times['draw'] += total_draw
00358         self.times['check'] +- total_check
00359         self.times['iter'] += 1
00360         #print 'draw', (1000.* self.times['draw'] / self.times['iter']), 'check', (1000.* self.times['check'] / self.times['iter'])


rcommander
Author(s): Hai Nguyen (haidai@gmail.com)
autogenerated on Thu Nov 28 2013 11:46:34