float_plugin.cpp
Go to the documentation of this file.
1 // *****************************************************************************
2 //
3 // Copyright (c) 2019, 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 Southwest Research Institute® BE LIABLE
21 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27 // DAMAGE.
28 //
29 // *****************************************************************************
30 
32 
35 
36 #include <std_msgs/Float32.h>
37 #include <std_msgs/Float64.h>
38 #include <marti_common_msgs/Float32Stamped.h>
39 #include <marti_common_msgs/Float64Stamped.h>
40 #include <marti_sensor_msgs/Velocity.h>
41 
42 #include <QFontDialog>
43 
45 
46 namespace mapviz_plugins
47 {
48  const char* FloatPlugin::COLOR_KEY = "color";
49  const char* FloatPlugin::FONT_KEY = "font";
50  const char* FloatPlugin::TOPIC_KEY = "topic";
51  const char* FloatPlugin::ANCHOR_KEY = "anchor";
52  const char* FloatPlugin::UNITS_KEY = "units";
53  const char* FloatPlugin::OFFSET_X_KEY = "offset_x";
54  const char* FloatPlugin::OFFSET_Y_KEY = "offset_y";
55  const char* FloatPlugin::POSTFIX_KEY = "postfix_text";
56 
57  FloatPlugin::FloatPlugin() :
58  config_widget_(new QWidget()),
59  anchor_(TOP_LEFT),
60  units_(PIXELS),
61  offset_x_(0),
62  offset_y_(0),
63  has_message_(false),
64  has_painted_(false),
65  color_(Qt::black)
66  {
67  ui_.setupUi(config_widget_);
68  // Set background white
69  QPalette p(config_widget_->palette());
70  p.setColor(QPalette::Background, Qt::white);
71  config_widget_->setPalette(p);
72 
73  // Set status text red
74  QPalette p3(ui_.status->palette());
75  p3.setColor(QPalette::Text, Qt::red);
76  ui_.status->setPalette(p3);
77 
78  QObject::connect(ui_.selecttopic, SIGNAL(clicked()), this, SLOT(SelectTopic()));
79  QObject::connect(ui_.topic, SIGNAL(editingFinished()), this, SLOT(TopicEdited()));
80  QObject::connect(ui_.anchor, SIGNAL(activated(QString)), this, SLOT(SetAnchor(QString)));
81  QObject::connect(ui_.units, SIGNAL(activated(QString)), this, SLOT(SetUnits(QString)));
82  QObject::connect(ui_.offsetx, SIGNAL(valueChanged(int)), this, SLOT(SetOffsetX(int)));
83  QObject::connect(ui_.offsety, SIGNAL(valueChanged(int)), this, SLOT(SetOffsetY(int)));
84  QObject::connect(ui_.font_button, SIGNAL(clicked()), this, SLOT(SelectFont()));
85  QObject::connect(ui_.color, SIGNAL(colorEdited(const QColor &)), this, SLOT(SelectColor()));
86  QObject::connect(ui_.postfix, SIGNAL(editingFinished()), this, SLOT(PostfixEdited()));
87 
88  font_.setFamily(tr("Helvetica"));
89  ui_.font_button->setFont(font_);
90  ui_.font_button->setText(font_.family());
91 
92  ui_.color->setColor(color_);
93  }
94 
96  {
97  }
98 
99  bool FloatPlugin::Initialize(QGLWidget* canvas)
100  {
101  canvas_ = canvas;
102  return true;
103  }
104 
105  void FloatPlugin::Draw(double x, double y, double scale)
106  {
107  // This plugin doesn't do any OpenGL drawing.
108  }
109 
110  void FloatPlugin::Paint(QPainter* painter, double x, double y, double scale)
111  {
112  if (has_message_)
113  {
114  painter->save();
115  painter->resetTransform();
116  painter->setFont(font_);
117 
118  if (!has_painted_)
119  {
120  // After the first time we get a new message, we do not know how wide it's
121  // going to be when rendered, so we can't accurately calculate the top left
122  // coordinate if it's offset from the right or bottom borders.
123  // The easiest workaround I've found for this is to draw it once using
124  // a completely transparent pen, which will cause the QStaticText class to
125  // know how wide it is; then we can recalculate the offsets and draw it
126  // again with a visible pen.
127  QPen invisPen(QBrush(Qt::transparent), 1);
128  painter->setPen(invisPen);
129  PaintText(painter);
130  has_painted_ = true;
131  }
132  QPen pen(QBrush(color_), 1);
133  painter->setPen(pen);
134  PaintText(painter);
135 
136  painter->restore();
137  PrintInfo("OK");
138  }
139  else
140  {
141  PrintWarning("No messages received.");
142  }
143  }
144 
145  void FloatPlugin::PaintText(QPainter* painter)
146  {
147  // Calculate the correct offsets and dimensions
148  int x_offset = offset_x_;
149  int y_offset = offset_y_;
150  if (units_ == PERCENT)
151  {
152  x_offset = static_cast<int>((float)(offset_x_ * canvas_->width()) / 100.0);
153  y_offset = static_cast<int>((float)(offset_y_ * canvas_->height()) / 100.0);
154  }
155 
156  int right = static_cast<int>((float)canvas_->width() - message_.size().width()) - x_offset;
157  int bottom = static_cast<int>((float)canvas_->height() - message_.size().height()) - y_offset;
158  int yCenter = static_cast<int>((float)canvas_->height() / 2.0 - message_.size().height()/2.0);
159  int xCenter = static_cast<int>((float)canvas_->width() / 2.0 - message_.size().width()/2.0);
160 
161  QPoint ulPoint;
162 
163  switch (anchor_)
164  {
165  case TOP_LEFT:
166  ulPoint.setX(x_offset);
167  ulPoint.setY(y_offset);
168  break;
169  case TOP_CENTER:
170  ulPoint.setX(xCenter);
171  ulPoint.setY(y_offset);
172  break;
173  case TOP_RIGHT:
174  ulPoint.setX(right);
175  ulPoint.setY(y_offset);
176  break;
177  case CENTER_LEFT:
178  ulPoint.setX(x_offset);
179  ulPoint.setY(yCenter);
180  break;
181  case CENTER:
182  ulPoint.setX(xCenter);
183  ulPoint.setY(yCenter);
184  break;
185  case CENTER_RIGHT:
186  ulPoint.setX(right);
187  ulPoint.setY(yCenter);
188  break;
189  case BOTTOM_LEFT:
190  ulPoint.setX(x_offset);
191  ulPoint.setY(bottom);
192  break;
193  case BOTTOM_CENTER:
194  ulPoint.setX(xCenter);
195  ulPoint.setY(bottom);
196  break;
197  case BOTTOM_RIGHT:
198  ulPoint.setX(right);
199  ulPoint.setY(bottom);
200  break;
201  }
202  painter->drawStaticText(ulPoint, message_);
203  }
204 
205  void FloatPlugin::LoadConfig(const YAML::Node& node, const std::string& path)
206  {
207  if (node[TOPIC_KEY])
208  {
209  ui_.topic->setText(QString(node[TOPIC_KEY].as<std::string>().c_str()));
210  TopicEdited();
211  }
212 
213  if (node[FONT_KEY])
214  {
215  font_.fromString(QString(node[FONT_KEY].as<std::string>().c_str()));
216  ui_.font_button->setFont(font_);
217  ui_.font_button->setText(font_.family());
218  }
219 
220  if (node[COLOR_KEY])
221  {
222  color_ = QColor(node[COLOR_KEY].as<std::string>().c_str());
223  ui_.color->setColor(QColor(color_.name().toStdString().c_str()));
224  }
225 
226  if (node[ANCHOR_KEY])
227  {
228  std::string anchor = node[ANCHOR_KEY].as<std::string>();
229  ui_.anchor->setCurrentIndex(ui_.anchor->findText(anchor.c_str()));
230  SetAnchor(anchor.c_str());
231  }
232 
233  if (node[UNITS_KEY])
234  {
235  std::string units = node[UNITS_KEY].as<std::string>();
236  ui_.units->setCurrentIndex(ui_.units->findText(units.c_str()));
237  SetUnits(units.c_str());
238  }
239 
240  if (node[OFFSET_X_KEY])
241  {
242  offset_x_ = node[OFFSET_X_KEY].as<int>();
243  ui_.offsetx->setValue(offset_x_);
244  }
245 
246  if (node[OFFSET_Y_KEY])
247  {
248  offset_y_ = node[OFFSET_Y_KEY].as<int>();
249  ui_.offsety->setValue(offset_y_);
250  }
251 
252  if (node[POSTFIX_KEY])
253  {
254  postfix_ = node[POSTFIX_KEY].as<std::string>();
255  ui_.postfix->setText(QString(postfix_.c_str()));
256  }
257  }
258 
259  void FloatPlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
260  {
261  emitter << YAML::Key << FONT_KEY << YAML::Value << font_.toString().toStdString();
262  emitter << YAML::Key << COLOR_KEY << YAML::Value << color_.name().toStdString();
263  emitter << YAML::Key << TOPIC_KEY << YAML::Value << ui_.topic->text().toStdString();
264  emitter << YAML::Key << ANCHOR_KEY << YAML::Value << AnchorToString(anchor_);
265  emitter << YAML::Key << UNITS_KEY << YAML::Value << UnitsToString(units_);
266  emitter << YAML::Key << OFFSET_X_KEY << YAML::Value << offset_x_;
267  emitter << YAML::Key << OFFSET_Y_KEY << YAML::Value << offset_y_;
268  emitter << YAML::Key << POSTFIX_KEY << YAML::Value << postfix_;
269  }
270 
271  QWidget* FloatPlugin::GetConfigWidget(QWidget* parent)
272  {
273  config_widget_->setParent(parent);
274  return config_widget_;
275  }
276 
277  void FloatPlugin::PrintError(const std::string& message)
278  {
279  PrintErrorHelper(ui_.status, message);
280  }
281 
282  void FloatPlugin::PrintInfo(const std::string& message)
283  {
284  PrintInfoHelper(ui_.status, message);
285  }
286 
287  void FloatPlugin::PrintWarning(const std::string& message)
288  {
289  PrintWarningHelper(ui_.status, message);
290  }
291 
293  {
294  color_ = ui_.color->color();
295  }
296 
298  {
299  postfix_ = ui_.postfix->text().toStdString();
300  }
301 
303  {
304  bool ok;
305  QFont font = QFontDialog::getFont(&ok, font_, canvas_);
306  if (ok)
307  {
308  font_ = font;
309  message_.prepare(QTransform(), font_);
310  ui_.font_button->setFont(font_);
311  ui_.font_button->setText(font_.family());
312  }
313  }
314 
316  {
317  std::vector<std::string> topics;
318  topics.push_back("std_msgs/Float32");
319  topics.push_back("std_msgs/Float64");
320  topics.push_back("marti_common_msgs/Float32Stamped");
321  topics.push_back("marti_common_msgs/Float64Stamped");
322  topics.push_back("marti_sensor_msgs/Velocity");
324 
325  if (!topic.name.empty())
326  {
327  ui_.topic->setText(QString::fromStdString(topic.name));
328  TopicEdited();
329  }
330  }
331 
333  {
334  std::string topic = ui_.topic->text().trimmed().toStdString();
335  if (topic != topic_)
336  {
337  initialized_ = false;
338  has_message_ = false;
339  PrintWarning("No messages received.");
340 
342 
343  topic_ = topic;
344  if (!topic.empty())
345  {
347 
348  ROS_INFO("Subscribing to %s", topic_.c_str());
349  }
350  }
351  }
352 
353  void FloatPlugin::SetAnchor(QString anchor)
354  {
355  if (anchor == "top left")
356  {
357  anchor_ = TOP_LEFT;
358  }
359  else if (anchor == "top center")
360  {
362  }
363  else if (anchor == "top right")
364  {
365  anchor_ = TOP_RIGHT;
366  }
367  else if (anchor == "center left")
368  {
370  }
371  else if (anchor == "center")
372  {
373  anchor_ = CENTER;
374  }
375  else if (anchor == "center right")
376  {
378  }
379  else if (anchor == "bottom left")
380  {
382  }
383  else if (anchor == "bottom center")
384  {
386  }
387  else if (anchor == "bottom right")
388  {
390  }
391  }
392 
393  void FloatPlugin::SetUnits(QString units)
394  {
395  if (units == "pixels")
396  {
397  units_ = PIXELS;
398  }
399  else if (units == "percent")
400  {
401  units_ = PERCENT;
402  }
403  }
404 
405  void FloatPlugin::SetOffsetX(int offset)
406  {
407  offset_x_ = offset;
408  }
409 
410  void FloatPlugin::SetOffsetY(int offset)
411  {
412  offset_y_ = offset;
413  }
414 
415  template <class T, class M>
416  bool is_instance(const M& msg)
417  {
418  return msg->getDataType() == ros::message_traits::datatype<T>();
419  }
420 
422  {
423  double value = 0.0;
424  if (is_instance<std_msgs::Float32>(msg))
425  {
426  value = msg->instantiate<std_msgs::Float32>()->data;
427  }
428  if (is_instance<std_msgs::Float64>(msg))
429  {
430  value = msg->instantiate<std_msgs::Float64>()->data;
431  }
432  else if (is_instance<marti_common_msgs::Float32Stamped>(msg))
433  {
434  value = msg->instantiate<marti_common_msgs::Float32Stamped>()->value;
435  }
436  else if (is_instance<marti_common_msgs::Float64Stamped>(msg))
437  {
438  value = msg->instantiate<marti_common_msgs::Float64Stamped>()->value;
439  }
440  else if (is_instance<marti_sensor_msgs::Velocity>(msg))
441  {
442  value = msg->instantiate<marti_sensor_msgs::Velocity>()->velocity;
443  }
444 
445  std::string str = std::to_string(value);
446  str += postfix_;
447  message_.setText(QString(str.c_str()));
448 
449  message_.prepare(QTransform(), font_);
450 
451  has_message_ = true;
452  has_painted_ = false;
453  initialized_ = true;
454  }
455 
457  {
458  std::string anchor_string = "top left";
459 
460  if (anchor == TOP_LEFT)
461  {
462  anchor_string = "top left";
463  }
464  else if (anchor == TOP_CENTER)
465  {
466  anchor_string = "top center";
467  }
468  else if (anchor == TOP_RIGHT)
469  {
470  anchor_string = "top right";
471  }
472  else if (anchor == CENTER_LEFT)
473  {
474  anchor_string = "center left";
475  }
476  else if (anchor == CENTER)
477  {
478  anchor_string = "center";
479  }
480  else if (anchor == CENTER_RIGHT)
481  {
482  anchor_string = "center right";
483  }
484  else if (anchor == BOTTOM_LEFT)
485  {
486  anchor_string = "bottom left";
487  }
488  else if (anchor == BOTTOM_CENTER)
489  {
490  anchor_string = "bottom center";
491  }
492  else if (anchor == BOTTOM_RIGHT)
493  {
494  anchor_string = "bottom right";
495  }
496 
497  return anchor_string;
498  }
499 
501  {
502  std::string units_string = "pixels";
503 
504  if (units == PIXELS)
505  {
506  units_string = "pixels";
507  }
508  else if (units == PERCENT)
509  {
510  units_string = "percent";
511  }
512 
513  return units_string;
514  }
515 }
static const char * OFFSET_Y_KEY
Definition: float_plugin.h:144
static const char * FONT_KEY
Definition: float_plugin.h:142
static ros::master::TopicInfo selectTopic(const std::string &datatype, QWidget *parent=0)
void PrintWarning(const std::string &message)
void SetUnits(QString units)
ros::NodeHandle node_
ros::Subscriber float_sub_
Definition: float_plugin.h:127
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void SetAnchor(QString anchor)
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)
void LoadConfig(const YAML::Node &node, const std::string &path)
static const char * OFFSET_X_KEY
Definition: float_plugin.h:143
data
std::string AnchorToString(Anchor anchor)
static void PrintInfoHelper(QLabel *status_label, const std::string &message, double throttle=0.0)
void Paint(QPainter *painter, double x, double y, double scale)
static const char * UNITS_KEY
Definition: float_plugin.h:146
static const char * TOPIC_KEY
Definition: float_plugin.h:145
std::string UnitsToString(Units units)
static const char * POSTFIX_KEY
Definition: float_plugin.h:147
void Draw(double x, double y, double scale)
#define ROS_INFO(...)
static const char * COLOR_KEY
Definition: float_plugin.h:141
static const char * ANCHOR_KEY
Definition: float_plugin.h:140
void PaintText(QPainter *painter)
void SaveConfig(YAML::Emitter &emitter, const std::string &path)
void floatCallback(const topic_tools::ShapeShifter::ConstPtr &msg)
bool Initialize(QGLWidget *canvas)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
void PrintError(const std::string &message)
QWidget * GetConfigWidget(QWidget *parent)
void PrintInfo(const std::string &message)
bool is_instance(const M &msg)


mapviz_plugins
Author(s): Marc Alban
autogenerated on Fri Mar 19 2021 02:44:32