textured_marker_plugin.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2014, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 //     * Redistributions of source code must retain the above copyright
00009 //       notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above copyright
00011 //       notice, this list of conditions and the following disclaimer in the
00012 //       documentation and/or other materials provided with the distribution.
00013 //     * Neither the name of Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //
00028 // *****************************************************************************
00029 
00030 #include <mapviz_plugins/textured_marker_plugin.h>
00031 
00032 // C++ standard libraries
00033 #include <cmath>
00034 #include <cstdio>
00035 #include <vector>
00036 
00037 // Boost libraries
00038 #include <boost/algorithm/string.hpp>
00039 
00040 // QT libraries
00041 #include <QDialog>
00042 #include <QGLWidget>
00043 
00044 // ROS libraries
00045 #include <ros/master.h>
00046 #include <sensor_msgs/image_encodings.h>
00047 
00048 #include <swri_math_util/constants.h>
00049 
00050 #include <mapviz/select_topic_dialog.h>
00051 
00052 // Declare plugin
00053 #include <pluginlib/class_list_macros.h>
00054 PLUGINLIB_DECLARE_CLASS(
00055     mapviz_plugins,
00056     textured_marker,
00057     mapviz_plugins::TexturedMarkerPlugin,
00058     mapviz::MapvizPlugin)
00059 
00060 namespace mapviz_plugins
00061 {
00062   TexturedMarkerPlugin::TexturedMarkerPlugin() :
00063     config_widget_(new QWidget()),
00064     is_marker_array_(false)
00065   {
00066     ui_.setupUi(config_widget_);
00067 
00068     // Set background white
00069     QPalette p(config_widget_->palette());
00070     p.setColor(QPalette::Background, Qt::white);
00071     config_widget_->setPalette(p);
00072 
00073     // Set status text red
00074     QPalette p3(ui_.status->palette());
00075     p3.setColor(QPalette::Text, Qt::red);
00076     ui_.status->setPalette(p3);
00077 
00078     QObject::connect(ui_.selecttopic, SIGNAL(clicked()), this, SLOT(SelectTopic()));
00079     QObject::connect(ui_.topic, SIGNAL(editingFinished()), this, SLOT(TopicEdited()));
00080 
00081     // By using a signal/slot connection, we ensure that we only generate GL textures on the
00082     // main thread in case a non-main thread handles the ROS callbacks.
00083     qRegisterMetaType<marti_visualization_msgs::TexturedMarkerConstPtr>("TexturedMarkerConstPtr");
00084     qRegisterMetaType<marti_visualization_msgs::TexturedMarkerArrayConstPtr>("TexturedMarkerArrayConstPtr");
00085 
00086     QObject::connect(this, 
00087                      SIGNAL(MarkerReceived(const marti_visualization_msgs::TexturedMarkerConstPtr)),
00088                      this,
00089                      SLOT(ProcessMarker(const marti_visualization_msgs::TexturedMarkerConstPtr)));
00090     QObject::connect(this,
00091                      SIGNAL(MarkersReceived(const marti_visualization_msgs::TexturedMarkerArrayConstPtr)),
00092                      this,
00093                      SLOT(ProcessMarkers(const marti_visualization_msgs::TexturedMarkerArrayConstPtr)));
00094   }
00095 
00096   TexturedMarkerPlugin::~TexturedMarkerPlugin()
00097   {
00098   }
00099 
00100   void TexturedMarkerPlugin::SelectTopic()
00101   {
00102     ros::master::TopicInfo topic = mapviz::SelectTopicDialog::selectTopic(
00103       "marti_visualization_msgs/TexturedMarker",
00104       "marti_visualization_msgs/TexturedMarkerArray");
00105 
00106     if (!topic.name.empty())
00107     {
00108       ui_.topic->setText(QString::fromStdString(topic.name));
00109 
00110       if (topic.datatype == "marti_visualization_msgs/TexturedMarkerArray")
00111       {
00112         is_marker_array_ = true;
00113       }
00114 
00115       TopicEdited();
00116     }
00117   }
00118 
00119   void TexturedMarkerPlugin::TopicEdited()
00120   {
00121     std::string topic = ui_.topic->text().trimmed().toStdString();
00122     if (topic != topic_)
00123     {
00124       initialized_ = false;
00125       markers_.clear();
00126       has_message_ = false;
00127       PrintWarning("No messages received.");
00128 
00129       marker_sub_.shutdown();
00130 
00131       topic_ = topic;
00132       if (!topic.empty())
00133       {
00134         if (is_marker_array_)
00135         {
00136           marker_sub_ = node_.subscribe(topic_, 1000, &TexturedMarkerPlugin::MarkerArrayCallback, this);
00137         }
00138         else
00139         {
00140           marker_sub_ = node_.subscribe(topic_, 1000, &TexturedMarkerPlugin::MarkerCallback, this);
00141         }
00142 
00143         ROS_INFO("Subscribing to %s", topic_.c_str());
00144       }
00145     }
00146   }
00147 
00148   void TexturedMarkerPlugin::ProcessMarker(const marti_visualization_msgs::TexturedMarkerConstPtr marker)
00149   {
00150     ProcessMarker(*marker);
00151   }
00152 
00153   void TexturedMarkerPlugin::ProcessMarker(const marti_visualization_msgs::TexturedMarker& marker)
00154   {
00155     if (!has_message_)
00156     {
00157       initialized_ = true;
00158       has_message_ = true;
00159     }
00160 
00161     // Note that unlike some plugins, this one does not store nor rely on the
00162     // source_frame_ member variable.  This one can potentially store many
00163     // messages with different source frames, so we need to store and transform
00164     // them individually.
00165 
00166     if (marker.action == marti_visualization_msgs::TexturedMarker::ADD)
00167     {
00168       MarkerData& markerData = markers_[marker.ns][marker.id];
00169       markerData.stamp = marker.header.stamp;
00170 
00171       markerData.transformed = true;
00172       markerData.alpha_ = marker.alpha;
00173       markerData.source_frame_ = marker.header.frame_id;
00174 
00175       swri_transform_util::Transform transform;
00176       if (!GetTransform(markerData.source_frame_, marker.header.stamp, transform))
00177       {
00178         markerData.transformed = false;
00179         PrintError("No transform between " + markerData.source_frame_ + " and " + target_frame_);
00180       }
00181 
00182       // Handle lifetime parameter
00183       ros::Duration lifetime = marker.lifetime;
00184       if (lifetime.isZero())
00185       {
00186         markerData.expire_time = ros::TIME_MAX;
00187       }
00188       else
00189       {
00190         // Temporarily add 5 seconds to fix some existing markers.
00191         markerData.expire_time = ros::Time::now() + lifetime + ros::Duration(5);
00192       }
00193 
00194       tf::Transform offset(
00195         tf::Quaternion(
00196           marker.pose.orientation.x,
00197           marker.pose.orientation.y,
00198           marker.pose.orientation.z,
00199           marker.pose.orientation.w), 
00200         tf::Vector3(
00201           marker.pose.position.x,
00202           marker.pose.position.y,
00203           marker.pose.position.z));
00204 
00205       double right = marker.image.width * marker.resolution / 2.0;
00206       double left = -right;
00207       double top = marker.image.height * marker.resolution / 2.0;
00208       double bottom = -top;
00209 
00210       tf::Vector3 top_left(left, top, 0);
00211       tf::Vector3 top_right(right, top, 0);
00212       tf::Vector3 bottom_left(left, bottom, 0);
00213       tf::Vector3 bottom_right(right, bottom, 0);
00214       
00215       top_left = offset * top_left;
00216       top_right = offset * top_right;
00217       bottom_left = offset * bottom_left;
00218       bottom_right = offset * bottom_right;
00219       
00220       markerData.quad_.clear();
00221       markerData.quad_.push_back(top_left);
00222       markerData.quad_.push_back(top_right);
00223       markerData.quad_.push_back(bottom_right);
00224       
00225       markerData.quad_.push_back(top_left);
00226       markerData.quad_.push_back(bottom_right);
00227       markerData.quad_.push_back(bottom_left);
00228       
00229       markerData.transformed_quad_.clear();
00230       for (size_t i = 0; i < markerData.quad_.size(); i++)
00231       {
00232         markerData.transformed_quad_.push_back(transform * markerData.quad_[i]);
00233       }
00234       
00235       int32_t max_dimension = std::max(marker.image.height, marker.image.width);
00236       int32_t new_size = 1;
00237       while (new_size < max_dimension)
00238         new_size = new_size << 1;
00239       
00240       if (new_size != markerData.texture_size_ || markerData.encoding_ != marker.image.encoding)
00241       {
00242         markerData.texture_size_ = new_size;
00243         
00244         markerData.encoding_ = marker.image.encoding;
00245         
00246         GLuint ids[1];
00247 
00248         //  Free the current texture.
00249         if (markerData.texture_id_ != -1)
00250         {
00251           ids[0] = static_cast<GLuint>(markerData.texture_id_);
00252           glDeleteTextures(1, &ids[0]);
00253         }
00254         
00255         // Get a new texture id.
00256         glGenTextures(1, &ids[0]);
00257         markerData.texture_id_ = ids[0];
00258 
00259         // Bind the texture with the correct size and null memory.
00260         glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(markerData.texture_id_));
00261 
00262         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00263 
00264         if (markerData.encoding_ == sensor_msgs::image_encodings::BGRA8)
00265         {
00266           markerData.texture_.resize(static_cast<size_t>(markerData.texture_size_ * markerData.texture_size_ * 4));
00267         }
00268         else if (markerData.encoding_ == sensor_msgs::image_encodings::BGR8)
00269         {
00270           markerData.texture_.resize(static_cast<size_t>(markerData.texture_size_ * markerData.texture_size_ * 3));
00271         }
00272         else if (markerData.encoding_ == sensor_msgs::image_encodings::MONO8)
00273         {
00274           markerData.texture_.resize(static_cast<size_t>(markerData.texture_size_ * markerData.texture_size_));
00275         }
00276         else
00277         {
00278           ROS_WARN("Unsupported encoding: %s", markerData.encoding_.c_str());
00279         }
00280 
00281         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00282         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00283 
00284         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00285         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00286 
00287         glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
00288 
00289         glBindTexture(GL_TEXTURE_2D, 0);
00290       }
00291       
00292       glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(markerData.texture_id_));
00293       
00294       if (markerData.encoding_ == sensor_msgs::image_encodings::BGRA8)
00295       {
00296         for (size_t row = 0; row < marker.image.height; row++)
00297         {
00298           for (size_t col = 0; col < marker.image.width; col++)
00299           {
00300             size_t src_index = (row * marker.image.width + col) * 4;
00301             size_t dst_index = (row * markerData.texture_size_ + col) * 4;
00302             
00303             markerData.texture_[dst_index + 0] = marker.image.data[src_index + 0];
00304             markerData.texture_[dst_index + 1] = marker.image.data[src_index + 1];
00305             markerData.texture_[dst_index + 2] = marker.image.data[src_index + 2];
00306             markerData.texture_[dst_index + 3] = marker.image.data[src_index + 3];
00307           }
00308         }
00309       
00310         glTexImage2D(
00311             GL_TEXTURE_2D, 
00312             0, 
00313             GL_RGBA, 
00314             markerData.texture_size_, 
00315             markerData.texture_size_, 
00316             0, 
00317             GL_BGRA, 
00318             GL_UNSIGNED_BYTE, 
00319             markerData.texture_.data());
00320       }
00321       else if (markerData.encoding_ == sensor_msgs::image_encodings::BGR8)
00322       {
00323         for (size_t row = 0; row < marker.image.height; row++)
00324         {
00325           for (size_t col = 0; col < marker.image.width; col++)
00326           {
00327             size_t src_index = (row * marker.image.width + col) * 3;
00328             size_t dst_index = (row * markerData.texture_size_ + col) * 3;
00329             
00330             markerData.texture_[dst_index + 0] = marker.image.data[src_index + 0];
00331             markerData.texture_[dst_index + 1] = marker.image.data[src_index + 1];
00332             markerData.texture_[dst_index + 2] = marker.image.data[src_index + 2];
00333           }
00334         }
00335       
00336         glTexImage2D(
00337             GL_TEXTURE_2D, 
00338             0, 
00339             GL_RGB, 
00340             markerData.texture_size_, 
00341             markerData.texture_size_, 
00342             0, 
00343             GL_BGR, 
00344             GL_UNSIGNED_BYTE, 
00345             markerData.texture_.data());
00346       }
00347       else if (markerData.encoding_ == sensor_msgs::image_encodings::MONO8)
00348       {
00349         for (size_t row = 0; row < marker.image.height; row++)
00350         {
00351           for (size_t col = 0; col < marker.image.width; col++)
00352           {
00353             size_t src_index = row * marker.image.width + col;
00354             size_t dst_index = row * markerData.texture_size_ + col;
00355             
00356             markerData.texture_[dst_index] = marker.image.data[src_index];
00357           }
00358         }
00359       
00360         glTexImage2D(
00361             GL_TEXTURE_2D, 
00362             0, 
00363             GL_LUMINANCE, 
00364             markerData.texture_size_, 
00365             markerData.texture_size_, 
00366             0, 
00367             GL_LUMINANCE, 
00368             GL_UNSIGNED_BYTE, 
00369             markerData.texture_.data());
00370       }
00371       
00372       glBindTexture(GL_TEXTURE_2D, 0);
00373       
00374       markerData.texture_x_ = static_cast<float>(marker.image.width) / static_cast<float>(markerData.texture_size_);
00375       markerData.texture_y_ = static_cast<float>(marker.image.height) / static_cast<float>(markerData.texture_size_);
00376     }
00377     else
00378     {
00379       markers_[marker.ns].erase(marker.id);
00380     }
00381   }
00382   
00383   void TexturedMarkerPlugin::ProcessMarkers(const marti_visualization_msgs::TexturedMarkerArrayConstPtr markers)
00384   {
00385     for (unsigned int i = 0; i < markers->markers.size(); i++)
00386     {
00387       ProcessMarker(markers->markers[i]);
00388     }
00389   }
00390   
00391 
00392   void TexturedMarkerPlugin::MarkerCallback(const marti_visualization_msgs::TexturedMarkerConstPtr marker)
00393   {
00394     Q_EMIT MarkerReceived(marker);
00395   }
00396 
00397   void TexturedMarkerPlugin::MarkerArrayCallback(const marti_visualization_msgs::TexturedMarkerArrayConstPtr markers)
00398   {
00399     Q_EMIT MarkersReceived(markers);
00400   }
00401 
00402   void TexturedMarkerPlugin::PrintError(const std::string& message)
00403   {
00404     if (message == ui_.status->text().toStdString())
00405     {
00406       return;
00407     }
00408 
00409     ROS_ERROR("Error: %s", message.c_str());
00410     QPalette p(ui_.status->palette());
00411     p.setColor(QPalette::Text, Qt::red);
00412     ui_.status->setPalette(p);
00413     ui_.status->setText(message.c_str());
00414   }
00415 
00416   void TexturedMarkerPlugin::PrintInfo(const std::string& message)
00417   {
00418     if (message == ui_.status->text().toStdString())
00419     {
00420       return;
00421     }
00422 
00423     ROS_INFO("%s", message.c_str());
00424     QPalette p(ui_.status->palette());
00425     p.setColor(QPalette::Text, Qt::green);
00426     ui_.status->setPalette(p);
00427     ui_.status->setText(message.c_str());
00428   }
00429 
00430   void TexturedMarkerPlugin::PrintWarning(const std::string& message)
00431   {
00432     if (message == ui_.status->text().toStdString())
00433     {
00434       return;
00435     }
00436 
00437     ROS_WARN("%s", message.c_str());
00438     QPalette p(ui_.status->palette());
00439     p.setColor(QPalette::Text, Qt::darkYellow);
00440     ui_.status->setPalette(p);
00441     ui_.status->setText(message.c_str());
00442   }
00443 
00444   QWidget* TexturedMarkerPlugin::GetConfigWidget(QWidget* parent)
00445   {
00446     config_widget_->setParent(parent);
00447 
00448     return config_widget_;
00449   }
00450 
00451   bool TexturedMarkerPlugin::Initialize(QGLWidget* canvas)
00452   {
00453     canvas_ = canvas;
00454 
00455     return true;
00456   }
00457 
00458   void TexturedMarkerPlugin::Draw(double x, double y, double scale)
00459   {
00460     ros::Time now = ros::Time::now();
00461 
00462     std::map<std::string, std::map<int, MarkerData> >::iterator nsIter;
00463     for (nsIter = markers_.begin(); nsIter != markers_.end(); ++nsIter)
00464     {
00465       std::map<int, MarkerData>::iterator markerIter;
00466       for (markerIter = nsIter->second.begin(); markerIter != nsIter->second.end(); ++markerIter)
00467       {
00468         MarkerData& marker = markerIter->second;
00469 
00470         if (marker.expire_time > now)
00471         {
00472           if (marker.transformed)
00473           {
00474             glEnable(GL_TEXTURE_2D);
00475 
00476             glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(marker.texture_id_));
00477           
00478             glBegin(GL_TRIANGLES);
00479             
00480             glColor4f(1.0f, 1.0f, 1.0f, marker.alpha_);
00481 
00482             double marker_x = marker.texture_x_;
00483             double marker_y = marker.texture_y_;
00484 
00485             glTexCoord2d(0, 0); glVertex2d(marker.transformed_quad_[0].x(), marker.transformed_quad_[0].y());
00486             glTexCoord2d(marker_x, 0); glVertex2d(marker.transformed_quad_[1].x(), marker.transformed_quad_[1].y());
00487             glTexCoord2d(marker_x, marker_y); glVertex2d(marker.transformed_quad_[2].x(), marker.transformed_quad_[2].y());
00488 
00489             glTexCoord2d(0, 0); glVertex2d(marker.transformed_quad_[3].x(), marker.transformed_quad_[3].y());
00490             glTexCoord2d(marker_x, marker_y); glVertex2d(marker.transformed_quad_[4].x(), marker.transformed_quad_[4].y());
00491             glTexCoord2d(0, marker_y); glVertex2d(marker.transformed_quad_[5].x(), marker.transformed_quad_[5].y());
00492 
00493             glEnd();
00494             
00495             glBindTexture(GL_TEXTURE_2D, 0);
00496 
00497             glDisable(GL_TEXTURE_2D);
00498             
00499             PrintInfo("OK");
00500           }
00501         }
00502       }
00503     }
00504   }
00505 
00506   void TexturedMarkerPlugin::Transform()
00507   {  
00508     std::map<std::string, std::map<int, MarkerData> >::iterator nsIter;
00509     for (nsIter = markers_.begin(); nsIter != markers_.end(); ++nsIter)
00510     {
00511       std::map<int, MarkerData>::iterator markerIter;
00512       for (markerIter = nsIter->second.begin(); markerIter != nsIter->second.end(); ++markerIter)
00513       {
00514         swri_transform_util::Transform transform;
00515         if (GetTransform(markerIter->second.source_frame_, markerIter->second.stamp, transform))
00516         {
00517           markerIter->second.transformed_quad_.clear();
00518           for (size_t i = 0; i < markerIter->second.quad_.size(); i++)
00519           {
00520             markerIter->second.transformed_quad_.push_back(transform * markerIter->second.quad_[i]);
00521           }
00522         }
00523       }
00524     }
00525   }
00526 
00527   void TexturedMarkerPlugin::LoadConfig(const YAML::Node& node, const std::string& path)
00528   {
00529     if (node["topic"])
00530     {
00531       std::string topic;
00532       node["topic"] >> topic;
00533       ui_.topic->setText(boost::trim_copy(topic).c_str());
00534     }
00535 
00536     if (node["is_marker_array"])
00537     {
00538       node["is_marker_array"] >> is_marker_array_;
00539     }
00540 
00541     TopicEdited();
00542   }
00543 
00544   void TexturedMarkerPlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
00545   {
00546     emitter << YAML::Key << "topic" << YAML::Value << boost::trim_copy(ui_.topic->text().toStdString());
00547     emitter << YAML::Key << "is_marker_array" << YAML::Value << is_marker_array_;
00548   }
00549 }
00550 


mapviz_plugins
Author(s): Marc Alban
autogenerated on Thu Aug 24 2017 02:46:09