overlay_text_display.cpp
Go to the documentation of this file.
1 // -*- mode: c++; -*-
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2014, JSK Lab
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the JSK Lab nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 
36 #include "overlay_text_display.h"
37 #include <OGRE/OgreMaterialManager.h>
39 #include <OGRE/OgreTexture.h>
40 #include <OGRE/OgreHardwarePixelBuffer.h>
41 #include <QFontDatabase>
42 #include <QPainter>
43 #include <QStaticText>
44 #include <QTextDocument>
45 #include <boost/algorithm/string.hpp>
46 #include <boost/format.hpp>
48 #include <regex>
49 
50 namespace jsk_rviz_plugins
51 {
53  texture_width_(0), texture_height_(0),
54  text_size_(14),
55  line_width_(2),
56  text_(""), font_(""),
57  bg_color_(0, 0, 0, 0),
58  fg_color_(255, 255, 255, 255.0),
59  require_update_texture_(false)
60  {
62  "Topic", "",
63  ros::message_traits::datatype<jsk_rviz_plugins::OverlayText>(),
64  "jsk_rviz_plugins::OverlayText topic to subscribe to.",
65  this, SLOT( updateTopic() ));
67  "Overtake Position Properties", false,
68  "overtake position properties specified by message such as left, top and font",
69  this, SLOT(updateOvertakePositionProperties()));
71  "Overtake FG Color Properties", false,
72  "overtake color properties specified by message such as foreground color and alpha",
73  this, SLOT(updateOvertakeFGColorProperties()));
75  "Overtake BG Color Properties", false,
76  "overtake color properties specified by message such as background color and alpha",
77  this, SLOT(updateOvertakeBGColorProperties()));
79  "Align Bottom", false,
80  "align text with the bottom of the overlay region",
81  this, SLOT(updateAlignBottom()));
83  "Invert Shadow", false,
84  "make shadow lighter than original text",
85  this, SLOT(updateInvertShadow()));
87  "top", 0,
88  "top position",
89  this, SLOT(updateTop()));
92  "left", 0,
93  "left position",
94  this, SLOT(updateLeft()));
97  "width", 128,
98  "width position",
99  this, SLOT(updateWidth()));
102  "height", 128,
103  "height position",
104  this, SLOT(updateHeight()));
107  "text size", 12,
108  "text size",
109  this, SLOT(updateTextSize()));
112  "line width", 2,
113  "line width",
114  this, SLOT(updateLineWidth()));
117  "Foreground Color", QColor(25, 255, 240),
118  "Foreground Color",
119  this, SLOT(updateFGColor()));
121  "Foreground Alpha", 0.8, "Foreground Alpha",
122  this, SLOT(updateFGAlpha()));
126  "Background Color", QColor(0, 0, 0),
127  "Background Color",
128  this, SLOT(updateBGColor()));
130  "Background Alpha", 0.8, "Background Alpha",
131  this, SLOT(updateBGAlpha()));
134 
135  QFontDatabase database;
136  font_families_ = database.families();
138  "font", "DejaVu Sans Mono",
139  "font", this,
140  SLOT(updateFont()));
141  for (size_t i = 0; i < font_families_.size(); i++) {
143  }
144  }
145 
147  {
148  onDisable();
149  //delete overlay_;
150  delete update_topic_property_;
154  delete align_bottom_property_;
156  delete top_property_;
157  delete left_property_;
158  delete width_property_;
159  delete height_property_;
160  delete text_size_property_;
161  delete line_width_property_;
162  delete bg_color_property_;
163  delete bg_alpha_property_;
164  delete fg_color_property_;
165  delete fg_alpha_property_;
166  delete font_property_;
167  }
168 
170  {
171  if (overlay_) {
172  overlay_->show();
173  }
174  subscribe();
175  }
176 
178  {
179  if (overlay_) {
180  overlay_->hide();
181  }
182  unsubscribe();
183  }
184 
186  {
187  sub_.shutdown();
188  }
189 
191  {
192  std::string topic_name = update_topic_property_->getTopicStd();
193  if (topic_name.length() > 0 && topic_name != "/") {
194  sub_ = ros::NodeHandle().subscribe(topic_name, 1, &OverlayTextDisplay::processMessage, this);
195  }
196  }
197 
199  {
200  unsubscribe();
201  subscribe();
202  }
203 
204  // only the first time
206  {
207  onEnable();
208  updateTopic();
214  updateTop();
215  updateLeft();
216  updateWidth();
217  updateHeight();
218  updateTextSize();
219  updateFGColor();
220  updateFGAlpha();
221  updateBGColor();
222  updateBGAlpha();
223  updateFont();
224  updateLineWidth();
226  }
227 
228  void OverlayTextDisplay::update(float wall_dt, float ros_dt)
229  {
231  return;
232  }
233  if (!isEnabled()) {
234  return;
235  }
236  if (!overlay_) {
237  return;
238  }
239  overlay_->updateTextureSize(texture_width_, texture_height_);
240  {
241  jsk_rviz_plugins::ScopedPixelBuffer buffer = overlay_->getBuffer();
242  QImage Hud = buffer.getQImage(*overlay_, bg_color_);
243  QPainter painter( &Hud );
244  painter.setRenderHint(QPainter::Antialiasing, true);
245  painter.setPen(QPen(fg_color_, std::max(line_width_,1), Qt::SolidLine));
246  uint16_t w = overlay_->getTextureWidth();
247  uint16_t h = overlay_->getTextureHeight();
248 
249  // font
250  if (text_size_ != 0) {
251  //QFont font = painter.font();
252  QFont font(font_.length() > 0 ? font_.c_str(): "Liberation Sans");
253  font.setPointSize(text_size_);
254  font.setBold(true);
255  painter.setFont(font);
256  }
257  if (text_.length() > 0) {
258 
259  QColor shadow_color;
260  if (invert_shadow_)
261  shadow_color = Qt::white; //fg_color_.lighter();
262  else
263  shadow_color = Qt::black; //fg_color_.darker();
264  shadow_color.setAlpha(fg_color_.alpha());
265 
266  std::string color_wrapped_text
267  = (boost::format("<span style=\"color: rgba(%2%, %3%, %4%, %5%)\">%1%</span>")
268  % text_ % fg_color_.red() % fg_color_.green() % fg_color_.blue() %
269  fg_color_.alpha()).str();
270 
271  // find a remove "color: XXX;" regex match to generate a proper shadow
272  std::regex color_tag_re("color:.+?;");
273  std::string null_char("");
274  std::string formatted_text_ = std::regex_replace(text_, color_tag_re, null_char);
275  std::string color_wrapped_shadow
276  = (boost::format("<span style=\"color: rgba(%2%, %3%, %4%, %5%)\">%1%</span>")
277  % formatted_text_ % shadow_color.red() % shadow_color.green() % shadow_color.blue() % shadow_color.alpha()).str();
278 
279  QStaticText static_text(
280  boost::algorithm::replace_all_copy(color_wrapped_text, "\n", "<br >").c_str());
281  static_text.setTextWidth(w);
282 
283  painter.setPen(QPen(shadow_color, std::max(line_width_,1), Qt::SolidLine));
284  QStaticText static_shadow(
285  boost::algorithm::replace_all_copy(color_wrapped_shadow, "\n", "<br >").c_str());
286  static_shadow.setTextWidth(w);
287 
288  if (!align_bottom_) {
289  painter.drawStaticText(1, 1, static_shadow);
290  painter.drawStaticText(0, 0, static_text);
291  } else {
292  QStaticText only_wrapped_text(color_wrapped_text.c_str());
293  QFontMetrics fm(painter.fontMetrics());
294  QRect text_rect = fm.boundingRect(0, 0, w, h,
295  Qt::TextWordWrap | Qt::AlignLeft | Qt::AlignTop,
296  only_wrapped_text.text().remove(QRegExp("<[^>]*>")));
297  painter.drawStaticText(1, h - text_rect.height()+1, static_shadow);
298  painter.drawStaticText(0, h - text_rect.height(), static_text);
299  }
300  }
301  painter.end();
302  }
303  overlay_->setDimensions(overlay_->getTextureWidth(), overlay_->getTextureHeight());
304  require_update_texture_ = false;
305  }
306 
308  (const jsk_rviz_plugins::OverlayText::ConstPtr& msg)
309  {
310  if (!isEnabled()) {
311  return;
312  }
313  if (!overlay_) {
314  static int count = 0;
316  ss << "OverlayTextDisplayObject" << count++;
317  overlay_.reset(new jsk_rviz_plugins::OverlayObject(ss.str()));
318  overlay_->show();
319  }
320  if (overlay_) {
321  if (msg->action == jsk_rviz_plugins::OverlayText::DELETE) {
322  overlay_->hide();
323  }
324  else if (msg->action == jsk_rviz_plugins::OverlayText::ADD) {
325  overlay_->show();
326  }
327  }
328 
329  // store message for update method
330  text_ = msg->text;
332  texture_width_ = msg->width;
333  texture_height_ = msg->height;
334  text_size_ = msg->text_size;
335  left_ = msg->left;
336  top_ = msg->top;
337  }
339  bg_color_ = QColor(msg->bg_color.r * 255.0,
340  msg->bg_color.g * 255.0,
341  msg->bg_color.b * 255.0,
342  msg->bg_color.a * 255.0);
344  fg_color_ = QColor(msg->fg_color.r * 255.0,
345  msg->fg_color.g * 255.0,
346  msg->fg_color.b * 255.0,
347  msg->fg_color.a * 255.0);
348  font_ = msg->font;
349  line_width_ = msg->line_width;
350  }
351  if (overlay_) {
352  overlay_->setPosition(left_, top_);
353  }
355  }
356 
358  {
359 
362  updateTop();
363  updateLeft();
364  updateWidth();
365  updateHeight();
366  updateTextSize();
368  }
372  top_property_->show();
373  left_property_->show();
377  }
378  else {
379  top_property_->hide();
380  left_property_->hide();
384  }
385  }
386 
388  {
391  // read all the parameters from properties
392  updateFGColor();
393  updateFGAlpha();
394  updateFont();
395  updateLineWidth();
397  }
403  font_property_->show();
404  }
405  else {
409  font_property_->hide();
410  }
411  }
412 
414  {
417  // read all the parameters from properties
418  updateBGColor();
419  updateBGAlpha();
421  }
426  }
427  else {
430  }
431  }
432 
434  {
437  }
439  }
440 
442  {
445  }
447  }
448 
449 
451  {
455  }
456  }
457 
459  {
463  }
464  }
465 
467  {
471  }
472  }
473 
475  {
479  }
480  }
481 
483  {
487  }
488  }
489 
491  {
492  QColor c = bg_color_property_->getColor();
493  bg_color_.setRed(c.red());
494  bg_color_.setGreen(c.green());
495  bg_color_.setBlue(c.blue());
498  }
499  }
500 
502  {
503  bg_color_.setAlpha(bg_alpha_property_->getFloat() * 255.0);
506  }
507  }
508 
510  {
511  QColor c = fg_color_property_->getColor();
512  fg_color_.setRed(c.red());
513  fg_color_.setGreen(c.green());
514  fg_color_.setBlue(c.blue());
517  }
518  }
519 
521  {
522  fg_color_.setAlpha(fg_alpha_property_->getFloat() * 255.0);
525  }
526  }
527 
529  {
530  int font_index = font_property_->getOptionInt();
531  if (font_index < font_families_.size()) {
532  font_ = font_families_[font_index].toStdString();
533  } else {
534  ROS_FATAL("Unexpected error at selecting font index %d.", font_index);
535  return;
536  }
539  }
540  }
541 
543  {
547  }
548  }
549 
551  {
552  return (top_ < y && top_ + texture_height_ > y &&
553  left_ < x && left_ + texture_width_ > x);
554  }
555 
557  {
558  top_ = y;
559  left_ = x;
560  }
561 
563  {
566  }
567 
568 }
569 
void setMin(float min)
#define ROS_FATAL(...)
void setMax(float max)
virtual void update(float wall_dt, float ros_dt)
virtual QImage getQImage(unsigned int width, unsigned int height)
PLUGINLIB_EXPORT_CLASS(jsk_rviz_plugins::PictogramArrayDisplay, rviz::Display)
virtual QColor getColor() const
jsk_rviz_plugins::OverlayObject::Ptr overlay_
void setMin(int min)
std::string getTopicStd() const
void processMessage(const jsk_rviz_plugins::OverlayText::ConstPtr &msg)
virtual void addOption(const QString &option, int value=0)
rviz::BoolProperty * overtake_position_properties_property_
virtual int getInt() const
bool isEnabled() const
bool setValue(const QVariant &new_value) override
rviz::RosTopicProperty * update_topic_property_
string str
w
virtual float getFloat() const
rviz::BoolProperty * overtake_fg_color_properties_property_
rviz::BoolProperty * overtake_bg_color_properties_property_
virtual bool getBool() const
virtual int getOptionInt()


jsk_rviz_plugins
Author(s): Kei Okada , Yohei Kakiuchi , Shohei Fujii , Ryohei Ueda
autogenerated on Thu Jun 1 2023 02:45:58