TAMSVIZ
Visualization and annotation tool for ROS
geometry.h
1 // TAMSVIZ
2 // (c) 2020 Philipp Ruppel
3 
4 #pragma once
5 
6 #include "marker.h"
7 
8 #include <geometry_msgs/PointStamped.h>
9 #include <geometry_msgs/PoseStamped.h>
10 #include <geometry_msgs/QuaternionStamped.h>
11 #include <geometry_msgs/Vector3Stamped.h>
12 
13 #include <eigen_conversions/eigen_msg.h>
14 
15 #include "../core/interaction.h"
16 #include "../core/workspace.h"
17 #include "axes.h"
18 #include "interactive.h"
19 #include "shapes.h"
20 
22  std::shared_ptr<MeshRenderer> _mesh_renderer;
23  Watcher _mesh_watcher;
24 
25 protected:
26  PointDisplayBase() {}
27 
28 public:
29  PROPERTY(double, radius, 0.1, min = 0.0);
30  PROPERTY(std::shared_ptr<Material>, material,
31  std::make_shared<Material>(1, 1, 1));
32  virtual void renderSync(const RenderSyncContext &context) override {
33  if (_mesh_watcher.changed(radius())) {
34  _mesh_renderer = node()->create<MeshRenderer>(
35  std::make_shared<Mesh>(makeSphere(16, 8).scale(radius())),
36  material());
37  }
38  MeshDisplayBase::renderSync(context);
39  }
40 };
41 DECLARE_TYPE(PointDisplayBase, MeshDisplayBase);
42 
44 
45 public:
46  PROPERTY(TopicProperty<geometry_msgs::PointStamped>, topic, "");
47  virtual void renderSync(const RenderSyncContext &context) override {
48  if (auto message = topic().message()) {
49  node()->frame(message->header.frame_id);
50  Eigen::Vector3d point;
51  tf::pointMsgToEigen(message->point, point);
52  Eigen::Isometry3d transform;
53  transform.translation() = point;
54  node()->pose(transform);
55  node()->show();
56  } else {
57  node()->hide();
58  }
59  PointDisplayBase::renderSync(context);
60  }
61 };
62 DECLARE_TYPE_C(PointStampedDisplay, PointDisplayBase, Geometry);
63 
66 
67 public:
68  PROPERTY(std::string, topic);
70  visualization_msgs::InteractiveMarkerInit init;
71  init.markers.push_back(makePointMarker());
72  _markers->init(init);
73  }
74  virtual void publish(const std::string &frame,
75  const Eigen::Isometry3d &pose) override {
76  if (_publish_watcher.changed(topic(), frame, poseToArray(pose),
77  publisherClock())) {
78  geometry_msgs::PointStamped m;
79  tf::pointEigenToMsg(pose.translation(), m.point);
80  m.header.frame_id = frame;
81  _publisher.publish(topic(), m);
82  }
83  }
84 };
86  Geometry);
87 
89 
90 public:
91  PROPERTY(Frame, frame);
92  PROPERTY(TopicProperty<geometry_msgs::Point>, topic, "");
93  virtual void renderSync(const RenderSyncContext &context) override {
94  node()->frame(frame());
95  if (auto message = topic().message()) {
96  Eigen::Vector3d point;
97  tf::pointMsgToEigen(*message, point);
98  Eigen::Isometry3d transform;
99  transform.translation() = point;
100  node()->pose(transform);
101  node()->show();
102  } else {
103  node()->hide();
104  }
105  PointDisplayBase::renderSync(context);
106  }
107 };
108 DECLARE_TYPE_C(PointDisplay, PointDisplayBase, Geometry);
109 
112 
113 public:
114  PROPERTY(std::string, topic);
116  visualization_msgs::InteractiveMarkerInit init;
117  init.markers.push_back(makePointMarker());
118  _markers->init(init);
119  }
120  virtual void publish(const std::string &frame,
121  const Eigen::Isometry3d &pose) override {
122  if (_publish_watcher.changed(topic(), frame, poseToArray(pose),
123  publisherClock())) {
124  geometry_msgs::Point m;
125  tf::pointEigenToMsg(pose.translation(), m);
126  _publisher.publish(topic(), m);
127  }
128  }
129 };
130 DECLARE_TYPE_C(PointPublisherDisplay, InteractivePoseDisplayBase, Geometry);
131 
133  std::shared_ptr<MeshRenderer> _mesh_renderer;
134  Watcher _mesh_watcher;
135 
136 protected:
137  PoseDisplayBase() {}
138 
139 public:
140  PROPERTY(double, radius, 0.1, min = 0.0);
141  PROPERTY(double, length, 1.0, min = 0.0);
142  PROPERTY(std::shared_ptr<Material>, material,
143  std::make_shared<Material>(1, 1, 1));
144  virtual void renderSync(const RenderSyncContext &context) override {
145  if (_mesh_watcher.changed(length(), radius())) {
146  _mesh_renderer = node()->create<MeshRenderer>(
147  std::make_shared<Mesh>(makeAxes(length(), radius(), 24)), material());
148  }
149  MeshDisplayBase::renderSync(context);
150  }
151 };
152 DECLARE_TYPE(PoseDisplayBase, MeshDisplayBase);
153 
154 class PoseDisplay : public PoseDisplayBase {
155 public:
156  PROPERTY(Frame, frame);
157  PROPERTY(TopicProperty<geometry_msgs::Pose>, topic, "");
158  virtual void renderSync(const RenderSyncContext &context) override {
159  node()->frame(frame());
160  if (auto message = topic().message()) {
161  Eigen::Isometry3d transform;
162  tf::poseMsgToEigen(*message, transform);
163  node()->pose(transform);
164  node()->show();
165  } else {
166  node()->hide();
167  }
168  PoseDisplayBase::renderSync(context);
169  }
170 };
171 DECLARE_TYPE_C(PoseDisplay, PoseDisplayBase, Geometry);
172 
175 
176 public:
177  PROPERTY(std::string, topic);
179  visualization_msgs::InteractiveMarkerInit init;
180  init.markers.push_back(makePoseMarker());
181  _markers->init(init);
182  }
183  virtual void publish(const std::string &frame,
184  const Eigen::Isometry3d &pose) override {
185  if (_publish_watcher.changed(topic(), frame, poseToArray(pose),
186  publisherClock())) {
187  geometry_msgs::Pose m;
188  tf::poseEigenToMsg(pose, m);
189  _publisher.publish(topic(), m);
190  }
191  }
192 };
193 DECLARE_TYPE_C(PosePublisherDisplay, InteractivePoseDisplayBase, Geometry);
194 
196 public:
197  PROPERTY(TopicProperty<geometry_msgs::PoseStamped>, topic, "");
198  virtual void renderSync(const RenderSyncContext &context) override {
199  if (auto message = topic().message()) {
200  node()->frame(message->header.frame_id);
201  Eigen::Isometry3d transform;
202  tf::poseMsgToEigen(message->pose, transform);
203  node()->pose(transform);
204  node()->show();
205  } else {
206  node()->hide();
207  }
208  PoseDisplayBase::renderSync(context);
209  }
210 };
211 DECLARE_TYPE_C(PoseStampedDisplay, PoseDisplayBase, Geometry);
212 
215 
216 public:
217  PROPERTY(std::string, topic);
219  visualization_msgs::InteractiveMarkerInit init;
220  init.markers.push_back(makePoseMarker());
221  _markers->init(init);
222  }
223  virtual void publish(const std::string &frame,
224  const Eigen::Isometry3d &pose) override {
225  if (_publish_watcher.changed(topic(), frame, poseToArray(pose),
226  publisherClock())) {
227  geometry_msgs::PoseStamped m;
228  tf::poseEigenToMsg(pose, m.pose);
229  m.header.frame_id = frame;
230  _publisher.publish(topic(), m);
231  }
232  }
233 };
235  Geometry);
236 
238 public:
239  PROPERTY(Frame, frame);
240  PROPERTY(TopicProperty<geometry_msgs::Quaternion>, topic, "");
241  virtual void renderSync(const RenderSyncContext &context) override {
242  node()->frame(frame());
243  if (auto message = topic().message()) {
244  Eigen::Quaterniond quat;
245  tf::quaternionMsgToEigen(*message, quat);
246  node()->pose(Eigen::Isometry3d(quat));
247  node()->show();
248  } else {
249  node()->hide();
250  }
251  PoseDisplayBase::renderSync(context);
252  }
253 };
254 DECLARE_TYPE_C(QuaternionDisplay, PoseDisplayBase, Geometry);
255 
258 
259 public:
260  PROPERTY(std::string, topic);
262  visualization_msgs::InteractiveMarkerInit init;
263  init.markers.push_back(makeRotationMarker());
264  _markers->init(init);
265  }
266  virtual void publish(const std::string &frame,
267  const Eigen::Isometry3d &pose) override {
268  if (_publish_watcher.changed(topic(), frame, poseToArray(pose),
269  publisherClock())) {
270  geometry_msgs::Quaternion m;
271  tf::quaternionEigenToMsg(Eigen::Quaterniond(pose.linear()), m);
272  _publisher.publish(topic(), m);
273  }
274  }
275 };
277  Geometry);
278 
280 public:
282  virtual void renderSync(const RenderSyncContext &context) override {
283  if (auto message = topic().message()) {
284  Eigen::Quaterniond quat;
285  tf::quaternionMsgToEigen(message->quaternion, quat);
286  node()->pose(Eigen::Isometry3d(quat));
287  node()->show();
288  } else {
289  node()->hide();
290  }
291  PoseDisplayBase::renderSync(context);
292  }
293 };
294 DECLARE_TYPE_C(QuaternionStampedDisplay, PoseDisplayBase, Geometry);
295 
298 
299 public:
300  PROPERTY(std::string, topic);
302  visualization_msgs::InteractiveMarkerInit init;
303  init.markers.push_back(makeRotationMarker());
304  _markers->init(init);
305  }
306  virtual void publish(const std::string &frame,
307  const Eigen::Isometry3d &pose) override {
308  if (_publish_watcher.changed(topic(), frame, poseToArray(pose),
309  publisherClock())) {
310  geometry_msgs::QuaternionStamped m;
311  tf::quaternionEigenToMsg(Eigen::Quaterniond(pose.linear()), m.quaternion);
312  m.header.frame_id = frame;
313  _publisher.publish(topic(), m);
314  }
315  }
316 };
318  Geometry);
319 
321  struct Data {
322  std::mutex mutex;
323  std::condition_variable condition;
324  std::weak_ptr<GeometryPublisherDisplayBase> display;
325  volatile bool exit_flag = false;
326  };
327  std::shared_ptr<Data> _data;
328 
329 public:
331  std::unique_lock<std::mutex> lock(_data->mutex);
332  _data->exit_flag = true;
333  _data->condition.notify_all();
334  }
335  virtual void refresh() override {
336  if (!_data) {
337  auto data = _data = std::make_shared<Data>();
338  data->display = std::dynamic_pointer_cast<GeometryPublisherDisplayBase>(
339  shared_from_this());
340  std::thread([data]() {
341  LOG_DEBUG("start publisher thread");
342  auto t = std::chrono::steady_clock::now();
343  while (true) {
344  t += std::chrono::seconds(1);
345  {
346  std::unique_lock<std::mutex> lock(data->mutex);
347  while (true) {
348  if (data->exit_flag) {
349  LOG_DEBUG("exit publisher thread");
350  return;
351  }
352  if (std::chrono::steady_clock::now() >= t) {
353  break;
354  }
355  data->condition.wait_until(lock, t);
356  }
357  }
358  if (auto me = data->display.lock()) {
359  LockScope ws;
360  me->publish();
361  }
362  }
363  })
364  .detach();
365  }
366  publish();
367  }
368  virtual void publish() = 0;
369 };
371 
372 class Vector3Node : public SceneNode {
373  std::shared_ptr<MeshRenderer> _line_renderer, _tip_renderer;
374 
375 public:
376  Vector3Node(const std::shared_ptr<Material> &material) {
377  _line_renderer = create<MeshRenderer>(
378  std::make_shared<Mesh>(
379  makeCylinder(16).scale(1, 1, 0.5).translate(0, 0, 0.5)),
380  material);
381  _tip_renderer = create<MeshRenderer>(
382  std::make_shared<Mesh>(makeCone(16).scale(1, 1, 1).translate(0, 0, 0)),
383  material);
384  }
385  void setVector(const Eigen::Vector3d &vector, double arrow_length,
386  double arrow_radius) {
387  double length = arrow_length * vector.norm();
388  double tip_length =
389  std::max(1e-6, std::min(length * 0.5, arrow_radius * 4));
390  double tip_radius = tip_length * 0.5;
391  double line_length = std::max(1e-6, length - tip_length);
392  double line_radius = tip_length * 0.25;
393  Eigen::Vector3d z = vector.normalized();
394  Eigen::Vector3d y = z.unitOrthogonal();
395  Eigen::Vector3d x = y.cross(z).normalized();
396  {
397  Eigen::Affine3d transform;
398  transform.setIdentity();
399  transform.linear().col(0) = x * line_radius;
400  transform.linear().col(1) = y * line_radius;
401  transform.linear().col(2) = z * line_length;
402  _line_renderer->pose(transform);
403  }
404  {
405  Eigen::Affine3d transform;
406  transform.setIdentity();
407  transform.linear().col(0) = x * tip_radius;
408  transform.linear().col(1) = y * tip_radius;
409  transform.linear().col(2) = z * tip_length;
410  transform.translation() = z * line_length;
411  _tip_renderer->pose(transform);
412  }
413  }
414 };
415 
417  std::shared_ptr<Vector3Node> _node;
418 
419 protected:
420  void _setVector(const Eigen::Vector3d &vector) {
421  _node->setVector(vector, length(), radius());
422  }
423 
424 public:
425  PROPERTY(double, radius, 0.1, min = 0.0);
426  PROPERTY(double, length, 1.0, min = 0.0);
427  PROPERTY(std::shared_ptr<Material>, material,
428  std::make_shared<Material>(1, 1, 1));
429  virtual void refresh() override {
430  if (!_node) {
431  _node = node()->create<Vector3Node>(material());
432  MeshDisplayBase::refresh();
433  }
434  }
435 };
436 DECLARE_TYPE(Vector3DisplayBase, MeshDisplayBase);
437 
439 
440 public:
441  PROPERTY(Frame, frame);
442  PROPERTY(TopicProperty<geometry_msgs::Vector3>, topic, "");
443  virtual void renderSync(const RenderSyncContext &context) override {
444  node()->frame(frame());
445  if (auto message = topic().message()) {
446  Eigen::Vector3d vector;
447  tf::vectorMsgToEigen(*message, vector);
448  _setVector(vector);
449  node()->show();
450  } else {
451  node()->hide();
452  }
453  Vector3DisplayBase::renderSync(context);
454  }
455 };
456 DECLARE_TYPE_C(Vector3Display, Vector3DisplayBase, Geometry);
457 
459  std::shared_ptr<Vector3Node> _node;
460  Watcher _watcher;
461  double _interaction_factor = 1;
462 
463 public:
464  PROPERTY(Frame, frame);
465  PROPERTY(Eigen::Vector3d, vector);
466  PROPERTY(double, radius, 0.1, min = 0.0);
467  PROPERTY(double, length, 1.0, min = 0.0);
468  PROPERTY(std::shared_ptr<Material>, material,
469  std::make_shared<Material>(1, 1, 1));
470  virtual void renderSync(const RenderSyncContext &context) override {
471  if (_watcher.changed(vector().x(), vector().y(), vector().z())) {
472  publish();
473  }
474  _node->setVector(vector(), length(), radius());
475  _node->frame(frame());
476  GeometryPublisherDisplayBase::renderSync(context);
477  }
478  virtual void refresh() override {
479  if (!_node) {
480  _node = node()->create<Vector3Node>(material());
481  GeometryPublisherDisplayBase::refresh();
482  }
483  }
484  virtual bool interact(const Interaction &interaction) override {
485  if (GeometryPublisherDisplayBase::interact(interaction)) {
486  return true;
487  }
488  Eigen::Affine3d inverse_pose = _node->framePose().inverse();
489  if (interaction.pressed) {
490  _interaction_factor =
491  1.0 /
492  std::max(1e-3,
493  std::min(1.0, vector().normalized().dot(
494  inverse_pose * interaction.begin.point) /
495  (vector().norm() * length()))) /
496  length();
497  }
498  vector() += (inverse_pose * interaction.current.point -
499  inverse_pose * interaction.previous.point) *
500  _interaction_factor;
501  return true;
502  }
503 };
505 
508 
509 public:
510  PROPERTY(std::string, topic);
511  virtual void publish() override {
512  Eigen::Vector3d v = vector();
513  geometry_msgs::Vector3 m;
514  tf::vectorEigenToMsg(v, m);
515  _publisher.publish(topic(), m);
516  }
517 };
518 DECLARE_TYPE_C(Vector3PublisherDisplay, Vector3PublisherDisplayBase, Geometry);
519 
522 
523 public:
524  PROPERTY(std::string, topic);
525  virtual void publish() override {
526  Eigen::Vector3d v = vector();
527  geometry_msgs::Vector3Stamped m;
528  tf::vectorEigenToMsg(v, m.vector);
529  m.header.frame_id = frame().name();
530  _publisher.publish(topic(), m);
531  }
532 };
534  Geometry);
535 
537 
538 public:
540  virtual void renderSync(const RenderSyncContext &context) override {
541  if (auto message = topic().message()) {
542  node()->frame(message->header.frame_id);
543  Eigen::Vector3d vector;
544  tf::vectorMsgToEigen(message->vector, vector);
545  _setVector(vector);
546  node()->show();
547  } else {
548  node()->hide();
549  }
550  Vector3DisplayBase::renderSync(context);
551  }
552 };
553 DECLARE_TYPE_C(Vector3StampedDisplay, Vector3DisplayBase, Geometry);
Definition: node.h:20
Definition: watcher.h:8