Skip to content

Commit 5ad8e4e

Browse files
Add the possibility to draw 3d arrows
1 parent 5d3df3d commit 5ad8e4e

File tree

3 files changed

+86
-2
lines changed

3 files changed

+86
-2
lines changed

robot_log_visualizer/file_reader/signal_provider.py

+30
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ def __init__(self, period: float):
5151
self._3d_trajectories_path = {}
5252
self._3d_trajectories_path_lock = QMutex()
5353

54+
self._3d_arrows = {}
55+
self._3d_arrows_path_lock = QMutex()
56+
self.max_arrow = 0
57+
5458
self.period = period
5559

5660
self.data = {}
@@ -319,6 +323,18 @@ def get_3d_point_at_index(self, index):
319323

320324
return points
321325

326+
def get_3d_arrow_at_index(self, index):
327+
arrows = {}
328+
329+
self._3d_arrows_path_lock.lock()
330+
331+
for key, value in self._3d_arrows.items():
332+
arrows[key] = self.get_item_from_path_at_index(value, index)
333+
334+
self._3d_arrows_path_lock.unlock()
335+
336+
return arrows
337+
322338
def get_3d_trajectory_at_index(self, index):
323339
trajectories = {}
324340

@@ -354,6 +370,20 @@ def unregister_3d_point(self, key):
354370
del self._3d_points_path[key]
355371
self._3d_points_path_lock.unlock()
356372

373+
def register_3d_arrow(self, key, arrow_path):
374+
self._3d_arrows_path_lock.lock()
375+
self._3d_arrows[key] = arrow_path
376+
for _, value in self._3d_arrows.items():
377+
data, _ = self.get_item_from_path(arrow_path)
378+
arrow = data[:, 3:]
379+
self.max_arrow = max(np.max(np.linalg.norm(arrow, axis=1)), self.max_arrow)
380+
self._3d_arrows_path_lock.unlock()
381+
382+
def unregister_3d_arrow(self, key):
383+
self._3d_arrows_path_lock.lock()
384+
del self._3d_arrows[key]
385+
self._3d_arrows_path_lock.unlock()
386+
357387
def register_3d_trajectory(self, key, trajectory_path):
358388
self._3d_trajectories_path_lock.lock()
359389
self._3d_trajectories_path[key] = trajectory_path

robot_log_visualizer/robot_visualizer/meshcat_provider.py

+27
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def __init__(self, signal_provider, period):
3636
self.env_list = ["GAZEBO_MODEL_PATH", "ROS_PACKAGE_PATH", "AMENT_PREFIX_PATH"]
3737
self._registered_3d_points = set()
3838
self._registered_3d_trajectories = dict()
39+
self._register_3d_arrow = set()
3940

4041
@property
4142
def state(self):
@@ -56,6 +57,14 @@ def register_3d_point(self, point_path, color):
5657
radius=radius, color=color, shape_name=point_path
5758
)
5859

60+
def register_3d_arrow(self, arrow_path, color):
61+
radius = 0.02
62+
locker = QMutexLocker(self.meshcat_visualizer_mutex)
63+
self._register_3d_arrow.add(arrow_path)
64+
self._meshcat_visualizer.load_arrow(
65+
radius=radius, color=color, shape_name=arrow_path
66+
)
67+
5968
def register_3d_trajectory(self, trajectory_path, color):
6069
locker = QMutexLocker(self.meshcat_visualizer_mutex)
6170
self._registered_3d_trajectories[trajectory_path] = (False, color)
@@ -70,6 +79,11 @@ def unregister_3d_trajectory(self, trajectory_path):
7079
self._registered_3d_trajectories.pop(trajectory_path, None)
7180
self._meshcat_visualizer.delete(shape_name=trajectory_path)
7281

82+
def unregister_3d_arrow(self, arrow_path):
83+
locker = QMutexLocker(self.meshcat_visualizer_mutex)
84+
self._register_3d_arrow.remove(arrow_path)
85+
self._meshcat_visualizer.delete(shape_name=arrow_path)
86+
7387
def load_model(self, considered_joints, model_name):
7488
def get_model_path_from_envs(env_list):
7589
return [
@@ -216,6 +230,19 @@ def run(self):
216230
color=self._registered_3d_trajectories[trajectory_path][1],
217231
)
218232

233+
for (
234+
arrow_path,
235+
arrow,
236+
) in self._signal_provider.get_3d_arrow_at_index(index).items():
237+
if arrow_path not in self._register_3d_arrow:
238+
continue
239+
240+
self._meshcat_visualizer.set_arrow_transform(
241+
origin=arrow[0:3],
242+
vector=arrow[3:6] / self._signal_provider.max_arrow,
243+
shape_name=arrow_path,
244+
)
245+
219246
self.meshcat_visualizer_mutex.unlock()
220247

221248
sleep_time = self._period - (time.time() - start)

robot_log_visualizer/ui/gui.py

+29-2
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ def __init__(self, signal_provider, meshcat_provider, animation_period):
166166
self.video_items = []
167167
self.visualized_3d_points = set()
168168
self.visualized_3d_trajectories = set()
169+
self.visualized_3d_arrows = set()
169170
self.visualized_3d_points_colors_palette = ColorPalette()
170171

171172
self.toolButton_on_click()
@@ -731,8 +732,10 @@ def variableTreeWidget_on_right_click(self, item_position):
731732

732733
add_3d_point_str = "Show as a 3D point"
733734
add_3d_trajectory_str = "Show as a 3D trajectory"
735+
add_3d_arrow_str = "Show as a 3D arrow"
734736
remove_3d_point_str = "Remove the 3D point"
735737
remove_3d_trajectory_str = "Remove the 3D trajectory"
738+
remove_3d_arrow_str = "Remove the 3D arrow"
736739
use_as_base_position_str = "Use as base position"
737740
use_as_base_orientation_str = "Use as base orientation"
738741
dont_use_as_base_position_str = "Don't use as base position"
@@ -784,14 +787,24 @@ def variableTreeWidget_on_right_click(self, item_position):
784787
else:
785788
menu.addAction(use_as_base_orientation_str + " (xyzw Quaternion)")
786789

790+
if item_size == 6:
791+
if item_key in self.visualized_3d_arrows:
792+
menu.addAction(remove_3d_arrow_str)
793+
else:
794+
menu.addAction(add_3d_arrow_str)
795+
787796
# show the menu
788797
action = menu.exec_(self.ui.variableTreeWidget.mapToGlobal(item_position))
789798
if action is None:
790799
return
791800

792801
item_path = self.get_item_path(item)
793802

794-
if action.text() == add_3d_point_str or action.text() == add_3d_trajectory_str:
803+
if (
804+
action.text() == add_3d_point_str
805+
or action.text() == add_3d_trajectory_str
806+
or action.text() == add_3d_arrow_str
807+
):
795808
color = next(self.visualized_3d_points_colors_palette)
796809

797810
item.setForeground(0, QtGui.QBrush(QtGui.QColor(color.as_hex())))
@@ -802,12 +815,20 @@ def variableTreeWidget_on_right_click(self, item_position):
802815
)
803816
self.signal_provider.register_3d_point(item_key, item_path)
804817
self.visualized_3d_points.add(item_key)
805-
else:
818+
elif action.text() == add_3d_trajectory_str:
806819
self.meshcat_provider.register_3d_trajectory(
807820
item_key, list(color.as_normalized_rgb())
808821
)
809822
self.signal_provider.register_3d_trajectory(item_key, item_path)
810823
self.visualized_3d_trajectories.add(item_key)
824+
elif action.text() == add_3d_arrow_str:
825+
self.meshcat_provider.register_3d_arrow(
826+
item_key, list(color.as_normalized_rgb())
827+
)
828+
self.signal_provider.register_3d_arrow(item_key, item_path)
829+
self.visualized_3d_arrows.add(item_key)
830+
else:
831+
raise ValueError("Unknown action")
811832

812833
if action.text() == remove_3d_point_str:
813834
self.meshcat_provider.unregister_3d_point(item_key)
@@ -821,6 +842,12 @@ def variableTreeWidget_on_right_click(self, item_position):
821842
self.visualized_3d_trajectories.remove(item_key)
822843
item.setForeground(0, QtGui.QBrush(QtGui.QColor(0, 0, 0)))
823844

845+
if action.text() == remove_3d_arrow_str:
846+
self.meshcat_provider.unregister_3d_arrow(item_key)
847+
self.signal_provider.unregister_3d_arrow(item_key)
848+
self.visualized_3d_arrows.remove(item_key)
849+
item.setForeground(0, QtGui.QBrush(QtGui.QColor(0, 0, 0)))
850+
824851
if (
825852
use_as_base_orientation_str in action.text()
826853
or action.text() == use_as_base_position_str

0 commit comments

Comments
 (0)