00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 import roslib; roslib.load_manifest('tf2_visualization')
00038 import rospy
00039
00040 import os
00041 import sys
00042 import yaml
00043
00044 import wxversion
00045 WXVER = '2.8'
00046 if wxversion.checkInstalled(WXVER):
00047 wxversion.select(WXVER)
00048 else:
00049 print >> sys.stderr, 'This application requires wxPython version %s' % WXVER
00050 sys.exit(1)
00051
00052 import wx
00053 import wx.richtext
00054 import xdot
00055 import threading
00056
00057 class FrameViewerPanel(wx.Panel):
00058 def __init__(self, parent, tf_interface, auto_update_list=True):
00059 wx.Panel.__init__(self, parent, -1)
00060
00061 self.tf_interface = tf_interface
00062 self.namespace = ('local', False)
00063 self.tf_namespaces = []
00064 self.loaded_files = []
00065 self.need_dot_zoom = True
00066 self.keep_running = True
00067 self.ns_list_lock = threading.RLock()
00068
00069
00070 vbox = wx.BoxSizer(wx.VERTICAL)
00071
00072
00073 self.content_splitter = wx.SplitterWindow(self, -1, style=wx.SP_LIVE_UPDATE)
00074 self.content_splitter.SetMinimumPaneSize(24)
00075 self.content_splitter.SetSashGravity(0.85)
00076
00077
00078 viewer = wx.Panel(self.content_splitter, -1)
00079
00080
00081 graph_viewer = wx.Panel(viewer, -1)
00082 gv_vbox = wx.BoxSizer(wx.VERTICAL)
00083 graph_viewer.SetSizer(gv_vbox)
00084
00085 viewer_box = wx.BoxSizer()
00086 viewer_box.Add(graph_viewer,1,wx.EXPAND | wx.ALL, 4)
00087 viewer.SetSizer(viewer_box)
00088
00089
00090 toolbar = wx.ToolBar(graph_viewer, -1)
00091 toolbar.AddControl(wx.StaticText(toolbar, -1, "Graph: "))
00092 self.namespaces = wx.ComboBox(toolbar, 1, value='local', choices=['local'], size=(-1, -1), style=wx.CB_DROPDOWN)
00093 self.namespaces.Editable = False
00094 toolbar.AddControl(self.namespaces)
00095 self.Bind(wx.EVT_COMBOBOX, self.on_select_ns, id=1)
00096
00097 if auto_update_list:
00098 self.namespace_list_thread = threading.Thread(target=self._update_namespace_list)
00099 self.namespace_list_thread.start()
00100
00101 toolbar.Realize();
00102
00103
00104 self.widget = xdot.wxxdot.WxDotWindow(graph_viewer, -1)
00105 self.widget.zoom_to_fit()
00106
00107 gv_vbox.Add(toolbar, 0, wx.EXPAND)
00108 gv_vbox.Add(self.widget, 1, wx.EXPAND)
00109
00110 nb = wx.Notebook(self.content_splitter, -1, style=wx.NB_TOP | wx.WANTS_CHARS)
00111 nb_box = wx.BoxSizer()
00112 nb_box.Add(nb, 1, wx.EXPAND | wx.ALL, 4)
00113
00114
00115 borders = wx.LEFT | wx.RIGHT | wx.TOP
00116 border = 4
00117 self.info_win = wx.ScrolledWindow(nb, -1)
00118 self.info_sizer = wx.BoxSizer(wx.VERTICAL)
00119 self.info_txt = wx.TextCtrl(self.info_win, -1, style=wx.TE_MULTILINE | wx.TE_READONLY)
00120 self.info_sizer.Add(self.info_txt, 1, wx.EXPAND | borders, border)
00121 self.info_win.SetSizer(self.info_sizer)
00122
00123
00124 echo_panel = wx.Panel(nb, -1)
00125 echo_box = wx.BoxSizer(wx.VERTICAL)
00126 echo_panel.SetSizer(echo_box)
00127 wx.StaticText(echo_panel, -1, "Target: ", pos=(5, 15))
00128 self.target_frame = wx.ComboBox(echo_panel, 2, value='Select Target', choices=['Select Target'], pos=(60, 10), size=(200, -1), style=wx.CB_DROPDOWN)
00129 self.target_frame.SetEditable(False)
00130 self.Bind(wx.EVT_COMBOBOX, self.on_select_target, id=2)
00131
00132 wx.StaticText(echo_panel, -1, "Source: ", pos=(5, 55))
00133 self.source_frame = wx.ComboBox(echo_panel, 3, value='Select Source', choices=['Select Source'], pos=(60, 50), size=(200, -1), style=wx.CB_DROPDOWN)
00134 self.source_frame.SetEditable(False)
00135 self.Bind(wx.EVT_COMBOBOX, self.on_select_source, id=3)
00136
00137 self.echo_txt = wx.TextCtrl(echo_panel, -1, style=wx.TE_MULTILINE | wx.TE_READONLY, pos=(5, 90), size=(255,500))
00138
00139
00140 nb.AddPage(self.info_win, "Info")
00141 nb.AddPage(echo_panel, "TF Echo")
00142
00143
00144
00145
00146 vbox.Add(self.content_splitter, 1, wx.EXPAND | wx.ALL)
00147 self.SetSizer(vbox)
00148 self.Center()
00149
00150 self.content_splitter.SplitVertically(nb, viewer, 300)
00151
00152 self.timer = wx.Timer(self)
00153
00154 self.Bind(wx.EVT_TIMER, lambda event: self.update_tf_data(), self.timer)
00155 self.widget.register_select_callback(self.select_cb)
00156
00157 self.timer.Start(1000)
00158
00159 def update_file_list(self, file):
00160 if file:
00161 filename = file.rstrip('.tf')+'.tf'
00162 self.loaded_files.append(filename)
00163 self.refresh_list()
00164 self.namespaces.SetValue(filename)
00165 cmd = wx.CommandEvent(wx.EVT_COMBOBOX.evtType[0])
00166 cmd.SetEventObject(self.namespaces)
00167 cmd.SetId(self.namespaces.GetId())
00168 self.namespaces.GetEventHandler().ProcessEvent(cmd)
00169
00170 def reset_frame_lists(self):
00171 self.source_frame.SetItems(['Select Source'])
00172 self.source_frame.SetValue('Select Source')
00173 self.target_frame.SetItems(['Select Target'])
00174 self.target_frame.SetValue('Select Target')
00175 self.set_echo_text("")
00176
00177 def update_tf_data(self):
00178 self.tf_interface.update_data(*self.namespace)
00179
00180 dotcode = self.tf_interface.get_dot()
00181 frame_list = self.tf_interface.get_frame_list()
00182
00183 if self.namespace[0] == 'local':
00184 self.source_frame.SetItems(frame_list)
00185 self.target_frame.SetItems(frame_list)
00186 else:
00187 self.reset_frame_lists()
00188
00189 self.set_info_text(yaml.dump(self.tf_interface.get_info(), default_flow_style=False))
00190 self.set_dotcode(dotcode)
00191
00192 self.check_echo()
00193 self.refresh_list()
00194
00195 def set_dotcode(self, dotcode):
00196 if not dotcode:
00197 return
00198
00199 self.widget.set_dotcode(dotcode, None)
00200
00201
00202 if self.need_dot_zoom:
00203 self.need_dot_zoom = False
00204 self.widget.zoom_to_fit()
00205
00206 wx.CallAfter(self.Refresh)
00207
00208 def set_info_text(self, text):
00209 self.info_txt.Value = text
00210 self.Refresh()
00211
00212 def set_echo_text(self, text):
00213 self.echo_txt.Value = text
00214 self.Refresh()
00215
00216
00217
00218 def select_cb(self, target, event):
00219 if event.ButtonDown(wx.MOUSE_BTN_LEFT) and target.url is not None:
00220 self.tf_interface.set_detail(target.url)
00221
00222 def _update_namespace_list(self):
00223 r = rospy.Rate(0.5)
00224 while not rospy.is_shutdown() and self.keep_running:
00225 tf_namespaces = self.tf_interface.find_tf_namespaces()
00226 with self.ns_list_lock:
00227 self.tf_namespaces = tf_namespaces
00228 r.sleep()
00229
00230 def refresh_list(self):
00231 with self.ns_list_lock:
00232 self.namespaces.Items = ['local'] + self.tf_namespaces + self.loaded_files
00233
00234 def on_select_ns(self, event):
00235 value = event.EventObject.Value
00236
00237 if value == self.namespace[0]:
00238 return
00239
00240 with self.ns_list_lock:
00241 if value == 'local' or self.tf_namespaces.count(value) > 0:
00242 self.namespace = (value, False)
00243 else:
00244 self.namespace = (value, True)
00245
00246 self.tf_interface.clear_detail()
00247 self.reset_frame_lists()
00248 self.need_dot_zoom = True
00249
00250 def on_select_target(self, event):
00251 print "target"
00252 print type(event)
00253 print event.EventObject.Value
00254
00255 def on_select_source(self, event):
00256 print "source"
00257 print type(event)
00258 print event.EventObject.Value
00259
00260 def check_echo(self):
00261 target = self.target_frame.GetValue()
00262 source = self.source_frame.GetValue()
00263 if source != 'Select Source' and target != 'Select Target':
00264 self.set_echo_text(self.tf_interface.get_echo_string(target, source))
00265