textured_marker_plugin.cpp
Go to the documentation of this file.
1 // *****************************************************************************
2 //
3 // Copyright (c) 2014, Southwest Research Institute® (SwRI®)
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Southwest Research Institute® (SwRI®) nor the
14 // names of its contributors may be used to endorse or promote products
15 // derived from this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //
28 // *****************************************************************************
29 
31 
32 // C++ standard libraries
33 #include <cmath>
34 #include <cstdio>
35 #include <vector>
36 
37 // Boost libraries
38 #include <boost/algorithm/string.hpp>
39 
40 // QT libraries
41 #include <QDialog>
42 #include <QGLWidget>
43 
44 // ROS libraries
45 #include <ros/master.h>
47 
49 
51 
52 // Declare plugin
55 
56 namespace mapviz_plugins
57 {
58  TexturedMarkerPlugin::TexturedMarkerPlugin() :
59  config_widget_(new QWidget()),
60  is_marker_array_(false)
61  {
62  ui_.setupUi(config_widget_);
63 
64  // Set background white
65  QPalette p(config_widget_->palette());
66  p.setColor(QPalette::Background, Qt::white);
67  config_widget_->setPalette(p);
68 
69  // Set status text red
70  QPalette p3(ui_.status->palette());
71  p3.setColor(QPalette::Text, Qt::red);
72  ui_.status->setPalette(p3);
73 
74  QObject::connect(ui_.selecttopic, SIGNAL(clicked()), this, SLOT(SelectTopic()));
75  QObject::connect(ui_.topic, SIGNAL(editingFinished()), this, SLOT(TopicEdited()));
76 
77  // By using a signal/slot connection, we ensure that we only generate GL textures on the
78  // main thread in case a non-main thread handles the ROS callbacks.
79  qRegisterMetaType<marti_visualization_msgs::TexturedMarkerConstPtr>("TexturedMarkerConstPtr");
80  qRegisterMetaType<marti_visualization_msgs::TexturedMarkerArrayConstPtr>("TexturedMarkerArrayConstPtr");
81 
82  QObject::connect(this,
83  SIGNAL(MarkerReceived(const marti_visualization_msgs::TexturedMarkerConstPtr)),
84  this,
85  SLOT(ProcessMarker(const marti_visualization_msgs::TexturedMarkerConstPtr)));
86  QObject::connect(this,
87  SIGNAL(MarkersReceived(const marti_visualization_msgs::TexturedMarkerArrayConstPtr)),
88  this,
89  SLOT(ProcessMarkers(const marti_visualization_msgs::TexturedMarkerArrayConstPtr)));
90  }
91 
93  {
94  }
95 
97  {
98  markers_.clear();
99  }
100 
102  {
104  "marti_visualization_msgs/TexturedMarker",
105  "marti_visualization_msgs/TexturedMarkerArray");
106 
107  if (!topic.name.empty())
108  {
109  ui_.topic->setText(QString::fromStdString(topic.name));
110 
111  if (topic.datatype == "marti_visualization_msgs/TexturedMarkerArray")
112  {
113  is_marker_array_ = true;
114  }
115 
116  TopicEdited();
117  }
118  }
119 
121  {
122  std::string topic = ui_.topic->text().trimmed().toStdString();
123  if (topic != topic_)
124  {
125  initialized_ = false;
126  markers_.clear();
127  has_message_ = false;
128  PrintWarning("No messages received.");
129 
131 
132  topic_ = topic;
133  if (!topic.empty())
134  {
135  if (is_marker_array_)
136  {
138  }
139  else
140  {
142  }
143 
144  ROS_INFO("Subscribing to %s", topic_.c_str());
145  }
146  }
147  }
148 
149  void TexturedMarkerPlugin::ProcessMarker(const marti_visualization_msgs::TexturedMarkerConstPtr marker)
150  {
151  ProcessMarker(*marker);
152  }
153 
154  void TexturedMarkerPlugin::ProcessMarker(const marti_visualization_msgs::TexturedMarker& marker)
155  {
156  if (!has_message_)
157  {
158  initialized_ = true;
159  has_message_ = true;
160  }
161 
162  // Note that unlike some plugins, this one does not store nor rely on the
163  // source_frame_ member variable. This one can potentially store many
164  // messages with different source frames, so we need to store and transform
165  // them individually.
166 
167  if (marker.action == marti_visualization_msgs::TexturedMarker::ADD)
168  {
169  MarkerData& markerData = markers_[marker.ns][marker.id];
170  markerData.stamp = marker.header.stamp;
171 
172  markerData.transformed = true;
173  markerData.alpha_ = marker.alpha;
174  markerData.source_frame_ = marker.header.frame_id;
175 
177  if (!GetTransform(markerData.source_frame_, marker.header.stamp, transform))
178  {
179  markerData.transformed = false;
180  PrintError("No transform between " + markerData.source_frame_ + " and " + target_frame_);
181  }
182 
183  // Handle lifetime parameter
184  ros::Duration lifetime = marker.lifetime;
185  if (lifetime.isZero())
186  {
187  markerData.expire_time = ros::TIME_MAX;
188  }
189  else
190  {
191  // Temporarily add 5 seconds to fix some existing markers.
192  markerData.expire_time = ros::Time::now() + lifetime + ros::Duration(5);
193  }
194 
195  tf::Transform offset(
197  marker.pose.orientation.x,
198  marker.pose.orientation.y,
199  marker.pose.orientation.z,
200  marker.pose.orientation.w),
201  tf::Vector3(
202  marker.pose.position.x,
203  marker.pose.position.y,
204  marker.pose.position.z));
205 
206  double right = marker.image.width * marker.resolution / 2.0;
207  double left = -right;
208  double top = marker.image.height * marker.resolution / 2.0;
209  double bottom = -top;
210 
211  tf::Vector3 top_left(left, top, 0);
212  tf::Vector3 top_right(right, top, 0);
213  tf::Vector3 bottom_left(left, bottom, 0);
214  tf::Vector3 bottom_right(right, bottom, 0);
215 
216  top_left = offset * top_left;
217  top_right = offset * top_right;
218  bottom_left = offset * bottom_left;
219  bottom_right = offset * bottom_right;
220 
221  markerData.quad_.clear();
222  markerData.quad_.push_back(top_left);
223  markerData.quad_.push_back(top_right);
224  markerData.quad_.push_back(bottom_right);
225 
226  markerData.quad_.push_back(top_left);
227  markerData.quad_.push_back(bottom_right);
228  markerData.quad_.push_back(bottom_left);
229 
230  markerData.transformed_quad_.clear();
231  for (size_t i = 0; i < markerData.quad_.size(); i++)
232  {
233  markerData.transformed_quad_.push_back(transform * markerData.quad_[i]);
234  }
235 
236  int32_t max_dimension = std::max(marker.image.height, marker.image.width);
237  int32_t new_size = 1;
238  while (new_size < max_dimension)
239  new_size = new_size << 1;
240 
241  if (new_size != markerData.texture_size_ || markerData.encoding_ != marker.image.encoding)
242  {
243  markerData.texture_size_ = new_size;
244 
245  markerData.encoding_ = marker.image.encoding;
246 
247  GLuint ids[1];
248 
249  // Free the current texture.
250  if (markerData.texture_id_ != -1)
251  {
252  ids[0] = static_cast<GLuint>(markerData.texture_id_);
253  glDeleteTextures(1, &ids[0]);
254  }
255 
256  // Get a new texture id.
257  glGenTextures(1, &ids[0]);
258  markerData.texture_id_ = ids[0];
259 
260  // Bind the texture with the correct size and null memory.
261  glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(markerData.texture_id_));
262 
263  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
264 
266  {
267  markerData.texture_.resize(static_cast<size_t>(markerData.texture_size_ * markerData.texture_size_ * 4));
268  }
269  else if (markerData.encoding_ == sensor_msgs::image_encodings::BGR8)
270  {
271  markerData.texture_.resize(static_cast<size_t>(markerData.texture_size_ * markerData.texture_size_ * 3));
272  }
273  else if (markerData.encoding_ == sensor_msgs::image_encodings::MONO8)
274  {
275  markerData.texture_.resize(static_cast<size_t>(markerData.texture_size_ * markerData.texture_size_));
276  }
277  else
278  {
279  ROS_WARN("Unsupported encoding: %s", markerData.encoding_.c_str());
280  }
281 
282  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
283  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
284 
285  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
286  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
287 
288  glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
289 
290  glBindTexture(GL_TEXTURE_2D, 0);
291  }
292 
293  glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(markerData.texture_id_));
294 
296  {
297  for (size_t row = 0; row < marker.image.height; row++)
298  {
299  for (size_t col = 0; col < marker.image.width; col++)
300  {
301  size_t src_index = (row * marker.image.width + col) * 4;
302  size_t dst_index = (row * markerData.texture_size_ + col) * 4;
303 
304  markerData.texture_[dst_index + 0] = marker.image.data[src_index + 0];
305  markerData.texture_[dst_index + 1] = marker.image.data[src_index + 1];
306  markerData.texture_[dst_index + 2] = marker.image.data[src_index + 2];
307  markerData.texture_[dst_index + 3] = marker.image.data[src_index + 3];
308  }
309  }
310 
311  glTexImage2D(
312  GL_TEXTURE_2D,
313  0,
314  GL_RGBA,
315  markerData.texture_size_,
316  markerData.texture_size_,
317  0,
318  GL_BGRA,
319  GL_UNSIGNED_BYTE,
320  markerData.texture_.data());
321  }
322  else if (markerData.encoding_ == sensor_msgs::image_encodings::BGR8)
323  {
324  for (size_t row = 0; row < marker.image.height; row++)
325  {
326  for (size_t col = 0; col < marker.image.width; col++)
327  {
328  size_t src_index = (row * marker.image.width + col) * 3;
329  size_t dst_index = (row * markerData.texture_size_ + col) * 3;
330 
331  markerData.texture_[dst_index + 0] = marker.image.data[src_index + 0];
332  markerData.texture_[dst_index + 1] = marker.image.data[src_index + 1];
333  markerData.texture_[dst_index + 2] = marker.image.data[src_index + 2];
334  }
335  }
336 
337  glTexImage2D(
338  GL_TEXTURE_2D,
339  0,
340  GL_RGB,
341  markerData.texture_size_,
342  markerData.texture_size_,
343  0,
344  GL_BGR,
345  GL_UNSIGNED_BYTE,
346  markerData.texture_.data());
347  }
348  else if (markerData.encoding_ == sensor_msgs::image_encodings::MONO8)
349  {
350  for (size_t row = 0; row < marker.image.height; row++)
351  {
352  for (size_t col = 0; col < marker.image.width; col++)
353  {
354  size_t src_index = row * marker.image.width + col;
355  size_t dst_index = row * markerData.texture_size_ + col;
356 
357  markerData.texture_[dst_index] = marker.image.data[src_index];
358  }
359  }
360 
361  glTexImage2D(
362  GL_TEXTURE_2D,
363  0,
364  GL_LUMINANCE,
365  markerData.texture_size_,
366  markerData.texture_size_,
367  0,
368  GL_LUMINANCE,
369  GL_UNSIGNED_BYTE,
370  markerData.texture_.data());
371  }
372 
373  glBindTexture(GL_TEXTURE_2D, 0);
374 
375  markerData.texture_x_ = static_cast<float>(marker.image.width) / static_cast<float>(markerData.texture_size_);
376  markerData.texture_y_ = static_cast<float>(marker.image.height) / static_cast<float>(markerData.texture_size_);
377  }
378  else
379  {
380  markers_[marker.ns].erase(marker.id);
381  }
382  }
383 
384  void TexturedMarkerPlugin::ProcessMarkers(const marti_visualization_msgs::TexturedMarkerArrayConstPtr markers)
385  {
386  for (unsigned int i = 0; i < markers->markers.size(); i++)
387  {
388  ProcessMarker(markers->markers[i]);
389  }
390  }
391 
392 
393  void TexturedMarkerPlugin::MarkerCallback(const marti_visualization_msgs::TexturedMarkerConstPtr marker)
394  {
395  Q_EMIT MarkerReceived(marker);
396  }
397 
398  void TexturedMarkerPlugin::MarkerArrayCallback(const marti_visualization_msgs::TexturedMarkerArrayConstPtr markers)
399  {
400  Q_EMIT MarkersReceived(markers);
401  }
402 
403  void TexturedMarkerPlugin::PrintError(const std::string& message)
404  {
405  PrintErrorHelper(ui_.status, message);
406  }
407 
408  void TexturedMarkerPlugin::PrintInfo(const std::string& message)
409  {
410  PrintInfoHelper(ui_.status, message);
411  }
412 
413  void TexturedMarkerPlugin::PrintWarning(const std::string& message)
414  {
415  PrintWarningHelper(ui_.status, message);
416  }
417 
418  QWidget* TexturedMarkerPlugin::GetConfigWidget(QWidget* parent)
419  {
420  config_widget_->setParent(parent);
421 
422  return config_widget_;
423  }
424 
425  bool TexturedMarkerPlugin::Initialize(QGLWidget* canvas)
426  {
427  canvas_ = canvas;
428 
429  return true;
430  }
431 
432  void TexturedMarkerPlugin::Draw(double x, double y, double scale)
433  {
434  ros::Time now = ros::Time::now();
435 
436  std::map<std::string, std::map<int, MarkerData> >::iterator nsIter;
437  for (nsIter = markers_.begin(); nsIter != markers_.end(); ++nsIter)
438  {
439  std::map<int, MarkerData>::iterator markerIter;
440  for (markerIter = nsIter->second.begin(); markerIter != nsIter->second.end(); ++markerIter)
441  {
442  MarkerData& marker = markerIter->second;
443 
444  if (marker.expire_time > now)
445  {
446  if (marker.transformed)
447  {
448  glEnable(GL_TEXTURE_2D);
449 
450  glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(marker.texture_id_));
451 
452  glBegin(GL_TRIANGLES);
453 
454  glColor4f(1.0f, 1.0f, 1.0f, marker.alpha_);
455 
456  double marker_x = marker.texture_x_;
457  double marker_y = marker.texture_y_;
458 
459  glTexCoord2d(0, 0); glVertex2d(marker.transformed_quad_[0].x(), marker.transformed_quad_[0].y());
460  glTexCoord2d(marker_x, 0); glVertex2d(marker.transformed_quad_[1].x(), marker.transformed_quad_[1].y());
461  glTexCoord2d(marker_x, marker_y); glVertex2d(marker.transformed_quad_[2].x(), marker.transformed_quad_[2].y());
462 
463  glTexCoord2d(0, 0); glVertex2d(marker.transformed_quad_[3].x(), marker.transformed_quad_[3].y());
464  glTexCoord2d(marker_x, marker_y); glVertex2d(marker.transformed_quad_[4].x(), marker.transformed_quad_[4].y());
465  glTexCoord2d(0, marker_y); glVertex2d(marker.transformed_quad_[5].x(), marker.transformed_quad_[5].y());
466 
467  glEnd();
468 
469  glBindTexture(GL_TEXTURE_2D, 0);
470 
471  glDisable(GL_TEXTURE_2D);
472 
473  PrintInfo("OK");
474  }
475  }
476  }
477  }
478  }
479 
481  {
482  std::map<std::string, std::map<int, MarkerData> >::iterator nsIter;
483  for (nsIter = markers_.begin(); nsIter != markers_.end(); ++nsIter)
484  {
485  std::map<int, MarkerData>::iterator markerIter;
486  for (markerIter = nsIter->second.begin(); markerIter != nsIter->second.end(); ++markerIter)
487  {
489  if (GetTransform(markerIter->second.source_frame_, markerIter->second.stamp, transform))
490  {
491  markerIter->second.transformed_quad_.clear();
492  for (size_t i = 0; i < markerIter->second.quad_.size(); i++)
493  {
494  markerIter->second.transformed_quad_.push_back(transform * markerIter->second.quad_[i]);
495  }
496  }
497  }
498  }
499  }
500 
501  void TexturedMarkerPlugin::LoadConfig(const YAML::Node& node, const std::string& path)
502  {
503  if (node["topic"])
504  {
505  std::string topic;
506  node["topic"] >> topic;
507  ui_.topic->setText(boost::trim_copy(topic).c_str());
508  }
509 
510  if (node["is_marker_array"])
511  {
512  node["is_marker_array"] >> is_marker_array_;
513  }
514 
515  TopicEdited();
516  }
517 
518  void TexturedMarkerPlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
519  {
520  emitter << YAML::Key << "topic" << YAML::Value << boost::trim_copy(ui_.topic->text().toStdString());
521  emitter << YAML::Key << "is_marker_array" << YAML::Value << is_marker_array_;
522  }
523 }
524 
bool GetTransform(const ros::Time &stamp, swri_transform_util::Transform &transform, bool use_latest_transforms=true)
static ros::master::TopicInfo selectTopic(const std::string &datatype, QWidget *parent=0)
void MarkersReceived(const marti_visualization_msgs::TexturedMarkerArrayConstPtr markers)
void PrintInfo(const std::string &message)
ros::NodeHandle node_
void MarkerArrayCallback(const marti_visualization_msgs::TexturedMarkerArrayConstPtr markers)
void ProcessMarkers(const marti_visualization_msgs::TexturedMarkerArrayConstPtr markers)
void transform(Route &route, const swri_transform_util::Transform &transform, const std::string &target_frame)
f
void LoadConfig(const YAML::Node &node, const std::string &path)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
static void PrintWarningHelper(QLabel *status_label, const std::string &message, double throttle=0.0)
static void PrintErrorHelper(QLabel *status_label, const std::string &message, double throttle=0.0)
std::string target_frame_
#define ROS_WARN(...)
static void PrintInfoHelper(QLabel *status_label, const std::string &message, double throttle=0.0)
void PrintError(const std::string &message)
std::map< std::string, std::map< int, MarkerData > > markers_
void MarkerCallback(const marti_visualization_msgs::TexturedMarkerConstPtr marker)
void PrintWarning(const std::string &message)
#define ROS_INFO(...)
void MarkerReceived(const marti_visualization_msgs::TexturedMarkerConstPtr marker)
ROSTIME_DECL const Time TIME_MAX
void SaveConfig(YAML::Emitter &emitter, const std::string &path)
static Time now()
void ProcessMarker(const marti_visualization_msgs::TexturedMarkerConstPtr marker)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
void Draw(double x, double y, double scale)


mapviz_plugins
Author(s): Marc Alban
autogenerated on Thu Jun 6 2019 19:25:16