robot_image_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/robot_image_plugin.h>
00031 
00032 // C++ standard libraries
00033 #include <cstdio>
00034 #include <algorithm>
00035 #include <vector>
00036 
00037 // QT libraries
00038 #include <QGLWidget>
00039 #include <QPalette>
00040 #include <QImage>
00041 #include <QFileDialog>
00042 
00043 // ROS libraries
00044 #include <ros/master.h>
00045 
00046 #include <mapviz/select_frame_dialog.h>
00047 
00048 // Declare plugin
00049 #include <pluginlib/class_list_macros.h>
00050 PLUGINLIB_DECLARE_CLASS(
00051     mapviz_plugins,
00052     robot_image,
00053     mapviz_plugins::RobotImagePlugin,
00054     mapviz::MapvizPlugin);
00055 
00056 namespace mapviz_plugins
00057 {
00058   RobotImagePlugin::RobotImagePlugin() :
00059     config_widget_(new QWidget()),
00060     width_(1),
00061     height_(1),
00062     texture_loaded_(false),
00063     transformed_(false)
00064   {
00065     ui_.setupUi(config_widget_);
00066 
00067     // Set background white
00068     QPalette p(config_widget_->palette());
00069     p.setColor(QPalette::Background, Qt::white);
00070     config_widget_->setPalette(p);
00071 
00072     // Set status text red
00073     QPalette p3(ui_.status->palette());
00074     p3.setColor(QPalette::Text, Qt::red);
00075     ui_.status->setPalette(p3);
00076 
00077     UpdateShape();
00078 
00079     QObject::connect(ui_.browse, SIGNAL(clicked()), this, SLOT(SelectFile()));
00080     QObject::connect(ui_.selectframe, SIGNAL(clicked()), this, SLOT(SelectFrame()));
00081     QObject::connect(ui_.frame, SIGNAL(editingFinished()), this, SLOT(FrameEdited()));
00082     QObject::connect(ui_.width, SIGNAL(valueChanged(double)), this, SLOT(WidthChanged(double)));
00083     QObject::connect(ui_.height, SIGNAL(valueChanged(double)), this, SLOT(HeightChanged(double)));
00084   }
00085 
00086   RobotImagePlugin::~RobotImagePlugin()
00087   {
00088   }
00089 
00090   void RobotImagePlugin::SelectFile()
00091   {
00092     QFileDialog dialog(config_widget_, "Select PNG Image");
00093     dialog.setFileMode(QFileDialog::ExistingFile);
00094     dialog.setNameFilter(tr("PNG Image Files (*.png)"));
00095 
00096     dialog.exec();
00097 
00098     if (dialog.result() == QDialog::Accepted && dialog.selectedFiles().count() == 1)
00099     {
00100       ui_.image->setText(dialog.selectedFiles().first());
00101       filename_ = dialog.selectedFiles().first().toStdString();
00102       LoadImage();
00103     }
00104   }
00105 
00106   void RobotImagePlugin::SelectFrame()
00107   {
00108     std::string frame = mapviz::SelectFrameDialog::selectFrame(tf_);
00109     if (!frame.empty())
00110     {
00111       ui_.frame->setText(QString::fromStdString(frame));
00112       FrameEdited();
00113     }
00114   }
00115 
00116   void RobotImagePlugin::FrameEdited()
00117   {
00118     source_frame_ = ui_.frame->text().toStdString();
00119     PrintWarning("Waiting for transform.");
00120 
00121     ROS_INFO("Setting target frame to to %s", source_frame_.c_str());
00122 
00123     initialized_ = true;
00124 
00125     UpdateShape();
00126   }
00127 
00128   void RobotImagePlugin::WidthChanged(double value)
00129   {
00130     width_ = value;
00131 
00132     UpdateShape();
00133   }
00134 
00135   void RobotImagePlugin::HeightChanged(double value)
00136   {
00137     height_ = value;
00138 
00139     UpdateShape();
00140   }
00141 
00142   void RobotImagePlugin::UpdateShape()
00143   {
00144     top_left_ = tf::Point(-width_ / 2.0, height_ / 2.0, 0);
00145     top_right_ = tf::Point(width_ / 2.0, height_ / 2.0, 0);
00146     bottom_left_ = tf::Point(-width_ / 2.0, -height_/2.0, 0);
00147     bottom_right_ = tf::Point(width_ / 2.0, -height_ / 2.0, 0);
00148   }
00149 
00150   void RobotImagePlugin::PrintError(const std::string& message)
00151   {
00152     if (message == ui_.status->text().toStdString())
00153     {
00154       return;
00155     }
00156 
00157     ROS_ERROR("Error: %s", message.c_str());
00158     QPalette p(ui_.status->palette());
00159     p.setColor(QPalette::Text, Qt::red);
00160     ui_.status->setPalette(p);
00161     ui_.status->setText(message.c_str());
00162   }
00163 
00164   void RobotImagePlugin::PrintInfo(const std::string& message)
00165   {
00166     if (message == ui_.status->text().toStdString())
00167     {
00168       return;
00169     }
00170 
00171     ROS_INFO("%s", message.c_str());
00172     QPalette p(ui_.status->palette());
00173     p.setColor(QPalette::Text, Qt::green);
00174     ui_.status->setPalette(p);
00175     ui_.status->setText(message.c_str());
00176   }
00177 
00178   void RobotImagePlugin::PrintWarning(const std::string& message)
00179   {
00180     if (message == ui_.status->text().toStdString())
00181     {
00182       return;
00183     }
00184 
00185     ROS_WARN("%s", message.c_str());
00186     QPalette p(ui_.status->palette());
00187     p.setColor(QPalette::Text, Qt::darkYellow);
00188     ui_.status->setPalette(p);
00189     ui_.status->setText(message.c_str());
00190   }
00191 
00192   QWidget* RobotImagePlugin::GetConfigWidget(QWidget* parent)
00193   {
00194     config_widget_->setParent(parent);
00195 
00196     return config_widget_;
00197   }
00198 
00199   bool RobotImagePlugin::Initialize(QGLWidget* canvas)
00200   {
00201     canvas_ = canvas;
00202 
00203     return true;
00204   }
00205 
00206   void RobotImagePlugin::Draw(double x, double y, double scale)
00207   {
00208     if (texture_loaded_ && transformed_)
00209     {
00210       glColor3f(1.0f, 1.0f, 1.0f);
00211       glEnable(GL_TEXTURE_2D);
00212       glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(texture_id_));
00213 
00214       glBegin(GL_QUADS);
00215 
00216 
00217       glTexCoord2f(0, 1); glVertex2d(top_left_transformed_.x(), top_left_transformed_.y());
00218       glTexCoord2f(1, 1); glVertex2d(top_right_transformed_.x(), top_right_transformed_.y());
00219       glTexCoord2f(1, 0); glVertex2d(bottom_right_transformed_.x(), bottom_right_transformed_.y());
00220       glTexCoord2f(0, 0); glVertex2d(bottom_left_transformed_.x(), bottom_left_transformed_.y());
00221 
00222       glEnd();
00223 
00224       glDisable(GL_TEXTURE_2D);
00225 
00226       PrintInfo("OK");
00227     }
00228   }
00229 
00230   void RobotImagePlugin::Transform()
00231   {
00232     transformed_ = false;
00233 
00234     swri_transform_util::Transform transform;
00235     if (GetTransform(ros::Time(), transform))
00236     {
00237       top_left_transformed_ = transform * top_left_;
00238       top_right_transformed_ = transform * top_right_;
00239       bottom_left_transformed_ = transform * bottom_left_;
00240       bottom_right_transformed_ = transform * bottom_right_;
00241       transformed_ = true;
00242     }
00243     else
00244     {
00245       PrintError("No transform between " + source_frame_ + " and " + target_frame_);
00246     }
00247   }
00248 
00249   void RobotImagePlugin::LoadImage()
00250   {
00251     ROS_INFO("Loading image");
00252     try
00253     {
00254       QImage nullImage;
00255       image_ = nullImage;
00256 
00257       if (texture_loaded_)
00258       {
00259         GLuint ids[1];
00260         ids[0] = static_cast<GLuint>(texture_id_);
00261         glDeleteTextures(1, &ids[0]);
00262         texture_loaded_ = false;
00263       }
00264 
00265       if (image_.load(filename_.c_str()))
00266       {
00267         int width = image_.width();
00268         int height = image_.height();
00269 
00270         float max_dim = std::max(width, height);
00271         dimension_ = static_cast<int>(std::pow(2, std::ceil(std::log(max_dim) / std::log(2.0f))));
00272 
00273         if (width != dimension_ || height != dimension_)
00274         {
00275           image_ = image_.scaled(dimension_, dimension_, Qt::IgnoreAspectRatio, Qt::FastTransformation);
00276         }
00277 
00278         image_ = QGLWidget::convertToGLFormat(image_);
00279 
00280         GLuint ids[1];
00281         glGenTextures(1, &ids[0]);
00282         texture_id_ = ids[0];
00283 
00284         glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(texture_id_));
00285         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dimension_, dimension_, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_.bits());
00286 
00287         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00288         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00289 
00290         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00291         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00292 
00293         texture_loaded_ = true;
00294       }
00295       else
00296       {
00297         PrintError("Failed to load image.");
00298       }
00299     }
00300     catch (const std::exception& e)
00301     {
00302       PrintError("Failed to load image.  Exception occured.");
00303     }
00304   }
00305 
00306   void RobotImagePlugin::LoadConfig(const YAML::Node& node, const std::string& path)
00307   {
00308     if (node["frame"])
00309     {
00310       node["frame"] >> source_frame_;
00311       ui_.frame->setText(source_frame_.c_str());
00312     }
00313 
00314     if (node["image"])
00315     {
00316       node["image"] >> filename_;
00317       ui_.image->setText(filename_.c_str());
00318     }
00319 
00320     if (node["width"])
00321     {
00322       node["width"] >> width_;
00323       ui_.width->setValue(width_);
00324     }
00325 
00326     if (node["height"])
00327     {
00328       node["height"] >> height_;
00329       ui_.height->setValue(height_);
00330     }
00331 
00332     UpdateShape();
00333     LoadImage();
00334     FrameEdited();
00335   }
00336 
00337   void RobotImagePlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
00338   {
00339     emitter << YAML::Key << "frame" << YAML::Value << ui_.frame->text().toStdString();
00340     emitter << YAML::Key << "image" << YAML::Value << ui_.image->text().toStdString();
00341     emitter << YAML::Key << "width" << YAML::Value << width_;
00342     emitter << YAML::Key << "height" << YAML::Value << height_;
00343   }
00344 }
00345 


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