overlay_text_display.cpp
Go to the documentation of this file.
00001 // -*- mode: c++; -*-
00002 /*********************************************************************
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2014, JSK Lab
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/o2r other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the JSK Lab nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *********************************************************************/
00035 
00036 #include "overlay_text_display.h"
00037 #include <OGRE/OgreMaterialManager.h>
00038 #include <rviz/uniform_string_stream.h>
00039 #include <OGRE/OgreTexture.h>
00040 #include <OGRE/OgreHardwarePixelBuffer.h>
00041 #include <QFontDatabase>
00042 #include <QPainter>
00043 #include <QStaticText>
00044 #include <QTextDocument>
00045 #include <boost/algorithm/string.hpp>
00046 #include <boost/format.hpp>
00047 #include <jsk_topic_tools/log_utils.h>
00048 
00049 namespace jsk_rviz_plugins
00050 {
00051   OverlayTextDisplay::OverlayTextDisplay() : Display(),
00052                                              texture_width_(0), texture_height_(0),
00053                                              text_size_(14),
00054                                              line_width_(2),
00055                                              text_(""), font_(""),
00056                                              bg_color_(0, 0, 0, 0),
00057                                              fg_color_(255, 255, 255, 255.0),
00058                                              require_update_texture_(false)
00059   {
00060     update_topic_property_ = new rviz::RosTopicProperty(
00061       "Topic", "",
00062       ros::message_traits::datatype<jsk_rviz_plugins::OverlayText>(),
00063       "jsk_rviz_plugins::OverlayText topic to subscribe to.",
00064       this, SLOT( updateTopic() ));
00065     overtake_position_properties_property_ = new rviz::BoolProperty(
00066       "Overtake Position Properties", false,
00067       "overtake position properties specified by message such as left, top and font",
00068       this, SLOT(updateOvertakePositionProperties()));
00069     overtake_color_properties_property_ = new rviz::BoolProperty(
00070       "Overtake Color Properties", false,
00071       "overtake color properties specified by message such as foreground/background color and alpha",
00072       this, SLOT(updateOvertakeColorProperties()));
00073     align_bottom_property_ = new rviz::BoolProperty(
00074       "Align Bottom", false,
00075       "align text with the bottom of the overlay region",
00076       this, SLOT(updateAlignBottom()));
00077     top_property_ = new rviz::IntProperty(
00078       "top", 0,
00079       "top position",
00080       this, SLOT(updateTop()));
00081     top_property_->setMin(0);
00082     left_property_ = new rviz::IntProperty(
00083       "left", 0,
00084       "left position",
00085       this, SLOT(updateLeft()));
00086     left_property_->setMin(0);
00087     width_property_ = new rviz::IntProperty(
00088       "width", 128,
00089       "width position",
00090       this, SLOT(updateWidth()));
00091     width_property_->setMin(0);
00092     height_property_ = new rviz::IntProperty(
00093       "height", 128,
00094       "height position",
00095       this, SLOT(updateHeight()));
00096     height_property_->setMin(0);
00097     text_size_property_ = new rviz::IntProperty(
00098       "text size", 12,
00099       "text size",
00100       this, SLOT(updateTextSize()));
00101     text_size_property_->setMin(0);
00102     line_width_property_ = new rviz::IntProperty(
00103       "line width", 2,
00104       "line width",
00105       this, SLOT(updateLineWidth()));
00106     line_width_property_->setMin(0);
00107     fg_color_property_ = new rviz::ColorProperty(
00108       "Foreground Color", QColor(25, 255, 240),
00109       "Foreground Color",
00110       this, SLOT(updateFGColor()));
00111     fg_alpha_property_ = new rviz::FloatProperty(
00112       "Foreground Alpha", 0.8, "Foreground Alpha",
00113       this, SLOT(updateFGAlpha()));
00114     fg_alpha_property_->setMin(0.0);
00115     fg_alpha_property_->setMax(1.0);
00116     bg_color_property_ = new rviz::ColorProperty(
00117       "Background Color", QColor(0, 0, 0),
00118       "Background Color",
00119       this, SLOT(updateBGColor()));
00120     bg_alpha_property_ = new rviz::FloatProperty(
00121       "Background Alpha", 0.8, "Background Alpha",
00122       this, SLOT(updateBGAlpha()));
00123     bg_alpha_property_->setMin(0.0);
00124     bg_alpha_property_->setMax(1.0);
00125 
00126     QFontDatabase database;
00127     font_families_ = database.families();
00128     font_property_ = new rviz::EnumProperty(
00129       "font", "DejaVu Sans Mono",
00130       "font", this,
00131       SLOT(updateFont()));
00132     for (size_t i = 0; i < font_families_.size(); i++) {
00133       font_property_->addOption(font_families_[i], (int)i);
00134     }
00135   }
00136   
00137   OverlayTextDisplay::~OverlayTextDisplay()
00138   {
00139     onDisable();
00140     //delete overlay_;
00141     delete update_topic_property_;
00142     delete overtake_color_properties_property_;
00143     delete overtake_position_properties_property_;
00144     delete align_bottom_property_;
00145     delete top_property_;
00146     delete left_property_;
00147     delete width_property_;
00148     delete height_property_;
00149     delete text_size_property_;
00150     delete line_width_property_;
00151     delete bg_color_property_;
00152     delete bg_alpha_property_;
00153     delete fg_color_property_;
00154     delete fg_alpha_property_;
00155     delete font_property_;
00156   }
00157 
00158   void OverlayTextDisplay::onEnable()
00159   {
00160     if (overlay_) {
00161       overlay_->show();
00162     }
00163     subscribe();
00164   }
00165 
00166   void OverlayTextDisplay::onDisable()
00167   {
00168     if (overlay_) {
00169       overlay_->hide();
00170     }
00171     unsubscribe();
00172   }
00173   
00174   void OverlayTextDisplay::unsubscribe()
00175   {
00176     sub_.shutdown();
00177   }
00178 
00179   void OverlayTextDisplay::subscribe()
00180   {
00181     std::string topic_name = update_topic_property_->getTopicStd();
00182     if (topic_name.length() > 0 && topic_name != "/") {
00183       sub_ = ros::NodeHandle().subscribe(topic_name, 1, &OverlayTextDisplay::processMessage, this);
00184     }
00185   }
00186   
00187   void OverlayTextDisplay::updateTopic()
00188   {
00189     unsubscribe();
00190     subscribe();
00191   }
00192     
00193   // only the first time
00194   void OverlayTextDisplay::onInitialize()
00195   {
00196     onEnable();
00197     updateTopic();
00198     updateOvertakePositionProperties();
00199     updateOvertakeColorProperties();
00200     updateAlignBottom();
00201     updateTop();
00202     updateLeft();
00203     updateWidth();
00204     updateHeight();
00205     updateTextSize();
00206     updateFGColor();
00207     updateFGAlpha();
00208     updateBGColor();
00209     updateBGAlpha();
00210     updateFont();
00211     updateLineWidth();
00212     require_update_texture_ = true;
00213   }
00214   
00215   void OverlayTextDisplay::update(float wall_dt, float ros_dt)
00216   {
00217     if (!require_update_texture_) {
00218       return;
00219     }
00220     if (!isEnabled()) {
00221       return;
00222     }
00223     if (!overlay_) {
00224       return;
00225     }
00226     overlay_->updateTextureSize(texture_width_, texture_height_);
00227     {
00228       ScopedPixelBuffer buffer = overlay_->getBuffer();
00229       QImage Hud = buffer.getQImage(*overlay_, bg_color_);
00230       QPainter painter( &Hud );
00231       painter.setRenderHint(QPainter::Antialiasing, true);
00232       painter.setPen(QPen(fg_color_, line_width_ || 1, Qt::SolidLine));
00233       uint16_t w = overlay_->getTextureWidth();
00234       uint16_t h = overlay_->getTextureHeight();
00235 
00236       // font
00237       if (text_size_ != 0) {
00238         //QFont font = painter.font();
00239         QFont font(font_.length() > 0 ? font_.c_str(): "Liberation Sans");
00240         font.setPointSize(text_size_);
00241         font.setBold(true);
00242         painter.setFont(font);
00243       }
00244       if (text_.length() > 0) {
00245         // painter.drawText(0, 0, w, h,
00246         //                  Qt::TextWordWrap | Qt::AlignLeft | Qt::AlignTop,
00247         //                  text_.c_str());
00248         std::string color_wrapped_text
00249           = (boost::format("<span style=\"color: rgba(%2%, %3%, %4%, %5%)\">%1%</span>")
00250              % text_ % fg_color_.red() % fg_color_.green() % fg_color_.blue() %
00251              fg_color_.alpha()).str();
00252         QStaticText static_text(
00253           boost::algorithm::replace_all_copy(color_wrapped_text, "\n", "<br >").c_str());
00254         static_text.setTextWidth(w);
00255         if (!align_bottom_) {
00256           painter.drawStaticText(0, 0, static_text);
00257         } else {
00258           QStaticText only_wrapped_text(color_wrapped_text.c_str());
00259           QFontMetrics fm(painter.fontMetrics());
00260           QRect text_rect = fm.boundingRect(0, 0, w, h,
00261                                             Qt::TextWordWrap | Qt::AlignLeft | Qt::AlignTop,
00262                                             only_wrapped_text.text().remove(QRegExp("<[^>]*>")));
00263           painter.drawStaticText(0, h - text_rect.height(), static_text);
00264         }
00265       }
00266       painter.end();
00267     }
00268     overlay_->setDimensions(overlay_->getTextureWidth(), overlay_->getTextureHeight());
00269     require_update_texture_ = false;
00270   }
00271   
00272   void OverlayTextDisplay::processMessage
00273   (const jsk_rviz_plugins::OverlayText::ConstPtr& msg)
00274   {
00275     if (!isEnabled()) {
00276       return;
00277     }
00278     if (!overlay_) {
00279       static int count = 0;
00280       rviz::UniformStringStream ss;
00281       ss << "OverlayTextDisplayObject" << count++;
00282       overlay_.reset(new OverlayObject(ss.str()));
00283       overlay_->show();
00284     }
00285     if (overlay_) {
00286       if (msg->action == jsk_rviz_plugins::OverlayText::DELETE) {
00287         overlay_->hide();
00288       }
00289       else if (msg->action == jsk_rviz_plugins::OverlayText::ADD) {
00290         overlay_->show();
00291       }
00292     }
00293     
00294     // store message for update method
00295     text_ = msg->text;
00296     if (!overtake_position_properties_) {
00297       texture_width_ = msg->width;
00298       texture_height_ = msg->height;
00299       text_size_ = msg->text_size;
00300       left_ = msg->left;
00301       top_ = msg->top;
00302     }
00303     if (!overtake_color_properties_) {
00304       bg_color_ = QColor(msg->bg_color.r * 255.0,
00305                          msg->bg_color.g * 255.0,
00306                          msg->bg_color.b * 255.0,
00307                          msg->bg_color.a * 255.0);
00308       fg_color_ = QColor(msg->fg_color.r * 255.0,
00309                          msg->fg_color.g * 255.0,
00310                          msg->fg_color.b * 255.0,
00311                          msg->fg_color.a * 255.0);
00312       font_ = msg->font;
00313       line_width_ = msg->line_width;
00314     }
00315     if (overlay_) {
00316       overlay_->setPosition(left_, top_);
00317     }
00318     require_update_texture_ = true;
00319   }
00320 
00321   void OverlayTextDisplay::updateOvertakePositionProperties()
00322   {
00323     
00324     if (!overtake_position_properties_ &&
00325         overtake_position_properties_property_->getBool()) {
00326       updateTop();
00327       updateLeft();
00328       updateWidth();
00329       updateHeight();
00330       updateTextSize();
00331       require_update_texture_ = true;
00332     }
00333     overtake_position_properties_
00334       = overtake_position_properties_property_->getBool();
00335     if (overtake_position_properties_) {
00336       top_property_->show();
00337       left_property_->show();
00338       width_property_->show();
00339       height_property_->show();
00340       text_size_property_->show();
00341     }
00342     else {
00343       top_property_->hide();
00344       left_property_->hide();
00345       width_property_->hide();
00346       height_property_->hide();
00347       text_size_property_->hide();
00348     }
00349   }
00350   
00351   void OverlayTextDisplay::updateOvertakeColorProperties()
00352   {
00353     if (!overtake_color_properties_ &&
00354         overtake_color_properties_property_->getBool()) {
00355       // read all the parameters from properties
00356       updateFGColor();
00357       updateFGAlpha();
00358       updateBGColor();
00359       updateBGAlpha();
00360       updateFont();
00361       updateLineWidth();
00362       require_update_texture_ = true;
00363     }
00364     overtake_color_properties_ = overtake_color_properties_property_->getBool();
00365     if (overtake_color_properties_) {
00366       fg_color_property_->show();
00367       fg_alpha_property_->show();
00368       bg_color_property_->show();
00369       bg_alpha_property_->show();
00370       line_width_property_->show();
00371       font_property_->show();
00372     }
00373     else {
00374       fg_color_property_->hide();
00375       fg_alpha_property_->hide();
00376       bg_color_property_->hide();
00377       bg_alpha_property_->hide();
00378       line_width_property_->hide();
00379       font_property_->hide();
00380     }
00381   }
00382 
00383   void OverlayTextDisplay::updateAlignBottom()
00384   {
00385     if (align_bottom_ != align_bottom_property_->getBool()) {
00386       require_update_texture_ = true;
00387     }
00388     align_bottom_ = align_bottom_property_->getBool();
00389   }
00390 
00391   void OverlayTextDisplay::updateTop()
00392   {
00393     top_ = top_property_->getInt();
00394     if (overtake_position_properties_) {
00395       require_update_texture_ = true;
00396     }
00397   }
00398   
00399   void OverlayTextDisplay::updateLeft()
00400   {
00401     left_ = left_property_->getInt();
00402     if (overtake_position_properties_) {
00403       require_update_texture_ = true;
00404     }
00405   }
00406   
00407   void OverlayTextDisplay::updateWidth()
00408   {
00409     texture_width_ = width_property_->getInt();
00410     if (overtake_position_properties_) {
00411       require_update_texture_ = true;
00412     }
00413   }
00414   
00415   void OverlayTextDisplay::updateHeight()
00416   {
00417     texture_height_ = height_property_->getInt();
00418     if (overtake_position_properties_) {
00419       require_update_texture_ = true;
00420     }
00421   }
00422 
00423   void OverlayTextDisplay::updateTextSize()
00424   {
00425     text_size_ = text_size_property_->getInt();
00426     if (overtake_position_properties_) {
00427       require_update_texture_ = true;
00428     }
00429   }
00430 
00431   void OverlayTextDisplay::updateBGColor()
00432   {
00433     QColor c = bg_color_property_->getColor();
00434     bg_color_.setRed(c.red());
00435     bg_color_.setGreen(c.green());
00436     bg_color_.setBlue(c.blue());
00437     if (overtake_color_properties_) {
00438       require_update_texture_ = true;
00439     }
00440   }
00441 
00442   void OverlayTextDisplay::updateBGAlpha()
00443   {
00444     bg_color_.setAlpha(bg_alpha_property_->getFloat() * 255.0);
00445     if (overtake_color_properties_) {
00446       require_update_texture_ = true;
00447     }
00448   }
00449 
00450   void OverlayTextDisplay::updateFGColor()
00451   {
00452     QColor c = fg_color_property_->getColor();
00453     fg_color_.setRed(c.red());
00454     fg_color_.setGreen(c.green());
00455     fg_color_.setBlue(c.blue());
00456     if (overtake_color_properties_) {
00457       require_update_texture_ = true;
00458     }
00459   }
00460 
00461   void OverlayTextDisplay::updateFGAlpha()
00462   {
00463     fg_color_.setAlpha(fg_alpha_property_->getFloat() * 255.0);
00464     if (overtake_color_properties_) {
00465       require_update_texture_ = true;
00466     }
00467   }
00468 
00469   void OverlayTextDisplay::updateFont()
00470   {
00471     int font_index = font_property_->getOptionInt();
00472     if (font_index < font_families_.size()) {
00473       font_ = font_families_[font_index].toStdString();
00474     } else {
00475       ROS_FATAL("Unexpected error at selecting font index %d.", font_index);
00476       return;
00477     }
00478     if (overtake_color_properties_) {
00479       require_update_texture_ = true;
00480     }
00481   }
00482 
00483   void OverlayTextDisplay::updateLineWidth()
00484   {
00485     line_width_ = line_width_property_->getInt();
00486     if (overtake_color_properties_) {
00487       require_update_texture_ = true;
00488     }
00489   }
00490 
00491   bool OverlayTextDisplay::isInRegion(int x, int y)
00492   {
00493     return (top_ < y && top_ + texture_height_ > y &&
00494             left_ < x && left_ + texture_width_ > x);
00495   }
00496 
00497   void OverlayTextDisplay::movePosition(int x, int y)
00498   {
00499     top_ = y;
00500     left_ = x;
00501   }
00502 
00503   void OverlayTextDisplay::setPosition(int x, int y)
00504   {
00505     top_property_->setValue(y);
00506     left_property_->setValue(x);
00507   }
00508   
00509 }
00510 
00511 #include <pluginlib/class_list_macros.h>
00512 PLUGINLIB_EXPORT_CLASS( jsk_rviz_plugins::OverlayTextDisplay, rviz::Display )


jsk_rviz_plugins
Author(s): Kei Okada , Yohei Kakiuchi , Shohei Fujii , Ryohei Ueda
autogenerated on Wed May 1 2019 02:40:22