plan_route_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/plan_route_plugin.h>
00031 
00032 // C++ standard libraries
00033 #include <cstdio>
00034 #include <vector>
00035 
00036 // QT libraries
00037 #include <QDateTime>
00038 #include <QDialog>
00039 #include <QGLWidget>
00040 #include <QMouseEvent>
00041 #include <QPainter>
00042 #include <QPalette>
00043 #include <QStaticText>
00044 
00045 #include <opencv2/core/core.hpp>
00046 
00047 // ROS libraries
00048 #include <ros/master.h>
00049 
00050 #include <swri_route_util/util.h>
00051 #include <swri_transform_util/frames.h>
00052 
00053 #include <marti_nav_msgs/PlanRoute.h>
00054 
00055 // Declare plugin
00056 #include <pluginlib/class_list_macros.h>
00057 PLUGINLIB_DECLARE_CLASS(mapviz_plugins, plan_route, mapviz_plugins::PlanRoutePlugin,
00058                         mapviz::MapvizPlugin);
00059 
00060 namespace mnm = marti_nav_msgs;
00061 namespace sru = swri_route_util;
00062 namespace stu = swri_transform_util;
00063 
00064 namespace mapviz_plugins
00065 {
00066   PlanRoutePlugin::PlanRoutePlugin() :
00067     config_widget_(new QWidget()),
00068     map_canvas_(NULL),
00069     failed_service_(false),
00070     selected_point_(-1),
00071     is_mouse_down_(false),
00072     max_ms_(Q_INT64_C(500)),
00073     max_distance_(2.0)
00074   {
00075     ui_.setupUi(config_widget_);
00076 
00077     ui_.color->setColor(Qt::green);
00078     // Set background white
00079     QPalette p(config_widget_->palette());
00080     p.setColor(QPalette::Background, Qt::white);
00081     config_widget_->setPalette(p);
00082     // Set status text red
00083     QPalette p3(ui_.status->palette());
00084     p3.setColor(QPalette::Text, Qt::red);
00085     ui_.status->setPalette(p3);
00086     QObject::connect(ui_.service, SIGNAL(editingFinished()), this,
00087                      SLOT(PlanRoute()));
00088     QObject::connect(ui_.publish, SIGNAL(clicked()), this,
00089                      SLOT(PublishRoute()));
00090     QObject::connect(ui_.clear, SIGNAL(clicked()), this,
00091                      SLOT(Clear()));
00092   }
00093 
00094   PlanRoutePlugin::~PlanRoutePlugin()
00095   {
00096     if (map_canvas_)
00097     {
00098       map_canvas_->removeEventFilter(this);
00099     }
00100   }
00101 
00102   void PlanRoutePlugin::PublishRoute()
00103   {
00104     if (route_preview_)
00105     {
00106       if (route_topic_ != ui_.topic->text().toStdString())
00107       {
00108         route_topic_ = ui_.topic->text().toStdString();
00109         route_pub_.shutdown();
00110         route_pub_ = node_.advertise<sru::Route>(route_topic_, 1, true);
00111       }
00112 
00113       route_pub_.publish(route_preview_);
00114     }
00115   }
00116 
00117   void PlanRoutePlugin::PlanRoute()
00118   {
00119     route_preview_ = sru::RoutePtr();
00120     bool start_from_vehicle = ui_.start_from_vehicle->isChecked();
00121     if (waypoints_.size() + start_from_vehicle < 2)
00122     {
00123       return;
00124     }
00125 
00126     std::string service = ui_.service->text().toStdString();
00127     ros::ServiceClient client = node_.serviceClient<mnm::PlanRoute>(service);
00128 
00129     mnm::PlanRoute plan_route;
00130     plan_route.request.header.frame_id = stu::_wgs84_frame;
00131     plan_route.request.header.stamp = ros::Time::now();
00132     plan_route.request.plan_from_vehicle = static_cast<unsigned char>(start_from_vehicle);
00133     plan_route.request.waypoints = waypoints_;
00134 
00135     if (client.call(plan_route))
00136     {
00137       if (plan_route.response.success)
00138       {
00139         route_preview_ = boost::make_shared<sru::Route>(plan_route.response.route);
00140         failed_service_ = false;
00141       }
00142       else
00143       {
00144         PrintError(plan_route.response.message);
00145         failed_service_ = true;
00146       }
00147     }
00148     else
00149     {
00150       PrintError("Failed to plan route.");
00151       failed_service_ = true;
00152     }
00153   }
00154 
00155   void PlanRoutePlugin::Retry(const ros::TimerEvent& e)
00156   {
00157     PlanRoute();
00158   }
00159 
00160   void PlanRoutePlugin::Clear()
00161   {
00162     waypoints_.clear();
00163     route_preview_ = sru::RoutePtr();
00164   }
00165 
00166   void PlanRoutePlugin::PrintError(const std::string& message)
00167   {
00168     if (message == ui_.status->text().toStdString())
00169     {
00170       return;
00171     }
00172 
00173     ROS_ERROR_THROTTLE(1.0, "Error: %s", message.c_str());
00174     QPalette p(ui_.status->palette());
00175     p.setColor(QPalette::Text, Qt::red);
00176     ui_.status->setPalette(p);
00177     ui_.status->setText(message.c_str());
00178   }
00179 
00180   void PlanRoutePlugin::PrintInfo(const std::string& message)
00181   {
00182     if (message == ui_.status->text().toStdString())
00183     {
00184       return;
00185     }
00186 
00187     ROS_INFO_THROTTLE(1.0, "%s", message.c_str());
00188     QPalette p(ui_.status->palette());
00189     p.setColor(QPalette::Text, Qt::green);
00190     ui_.status->setPalette(p);
00191     ui_.status->setText(message.c_str());
00192   }
00193 
00194   void PlanRoutePlugin::PrintWarning(const std::string& message)
00195   {
00196     if (message == ui_.status->text().toStdString())
00197     {
00198       return;
00199     }
00200 
00201     ROS_WARN_THROTTLE(1.0, "%s", message.c_str());
00202     QPalette p(ui_.status->palette());
00203     p.setColor(QPalette::Text, Qt::darkYellow);
00204     ui_.status->setPalette(p);
00205     ui_.status->setText(message.c_str());
00206   }
00207 
00208   QWidget* PlanRoutePlugin::GetConfigWidget(QWidget* parent)
00209   {
00210     config_widget_->setParent(parent);
00211 
00212     return config_widget_;
00213   }
00214 
00215   bool PlanRoutePlugin::Initialize(QGLWidget* canvas)
00216   {
00217     map_canvas_ = static_cast<mapviz::MapCanvas*>(canvas);
00218     map_canvas_->installEventFilter(this);
00219 
00220     retry_timer_ = node_.createTimer(ros::Duration(1), &PlanRoutePlugin::Retry, this);
00221 
00222     initialized_ = true;
00223     return true;
00224   }
00225 
00226   bool PlanRoutePlugin::eventFilter(QObject *object, QEvent* event)
00227   {
00228     switch (event->type())
00229     {
00230       case QEvent::MouseButtonPress:
00231         return handleMousePress(static_cast<QMouseEvent*>(event));
00232       case QEvent::MouseButtonRelease:
00233         return handleMouseRelease(static_cast<QMouseEvent*>(event));
00234       case QEvent::MouseMove:
00235         return handleMouseMove(static_cast<QMouseEvent*>(event));
00236       default:
00237         return false;
00238     }
00239   }
00240 
00241   bool PlanRoutePlugin::handleMousePress(QMouseEvent* event)
00242   {
00243     selected_point_ = -1;
00244     int closest_point = 0;
00245     double closest_distance = std::numeric_limits<double>::max();
00246 
00247     QPointF point = event->posF();
00248     stu::Transform transform;
00249     if (tf_manager_.GetTransform(target_frame_, stu::_wgs84_frame, transform))
00250     {
00251       for (size_t i = 0; i < waypoints_.size(); i++)
00252       {
00253         tf::Vector3 waypoint(
00254             waypoints_[i].position.x,
00255             waypoints_[i].position.y,
00256             0.0);
00257         waypoint = transform * waypoint;
00258 
00259         QPointF transformed = map_canvas_->FixedFrameToMapGlCoord(QPointF(waypoint.x(), waypoint.y()));
00260 
00261         double distance = QLineF(transformed, point).length();
00262 
00263         if (distance < closest_distance)
00264         {
00265           closest_distance = distance;
00266           closest_point = static_cast<int>(i);
00267         }
00268       }
00269     }
00270 
00271     if (event->button() == Qt::LeftButton)
00272     {
00273       if (closest_distance < 15)
00274       {
00275         selected_point_ = closest_point;
00276         return true;
00277       }
00278       else
00279       {
00280         is_mouse_down_ = true;
00281         mouse_down_pos_ = event->posF();
00282         mouse_down_time_ = QDateTime::currentMSecsSinceEpoch();
00283         return false;
00284       }
00285     }
00286     else if (event->button() == Qt::RightButton)
00287     {
00288       if (closest_distance < 15)
00289       {
00290         waypoints_.erase(waypoints_.begin() + closest_point);
00291         PlanRoute();
00292         return true;
00293       }
00294     }
00295 
00296     return false;
00297   }
00298 
00299   bool PlanRoutePlugin::handleMouseRelease(QMouseEvent* event)
00300   {
00301     if (selected_point_ >= 0 && static_cast<size_t>(selected_point_) < waypoints_.size())
00302     {
00303       QPointF point = event->posF();
00304       stu::Transform transform;
00305       if (tf_manager_.GetTransform(stu::_wgs84_frame, target_frame_, transform))
00306       {
00307         QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
00308         tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
00309         position = transform * position;
00310         waypoints_[selected_point_].position.x = position.x();
00311         waypoints_[selected_point_].position.y = position.y();
00312         PlanRoute();
00313       }
00314 
00315       selected_point_ = -1;
00316       return true;
00317     }
00318     else if (is_mouse_down_)
00319     {
00320       qreal distance = QLineF(mouse_down_pos_, event->posF()).length();
00321       qint64 msecsDiff = QDateTime::currentMSecsSinceEpoch() - mouse_down_time_;
00322 
00323       // Only fire the event if the mouse has moved less than the maximum distance
00324       // and was held for shorter than the maximum time..  This prevents click
00325       // events from being fired if the user is dragging the mouse across the map
00326       // or just holding the cursor in place.
00327       if (msecsDiff < max_ms_ && distance <= max_distance_)
00328       {
00329         QPointF point = event->posF();
00330 
00331 
00332         QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
00333 
00334         stu::Transform transform;
00335         tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
00336         if (tf_manager_.GetTransform(stu::_wgs84_frame, target_frame_, transform))
00337         {
00338           position = transform * position;
00339 
00340           geometry_msgs::Pose pose;
00341           pose.position.x = position.x();
00342           pose.position.y = position.y();
00343           waypoints_.push_back(pose);
00344           PlanRoute();
00345         }
00346       }
00347     }
00348     is_mouse_down_ = false;
00349 
00350     return false;
00351   }
00352 
00353   bool PlanRoutePlugin::handleMouseMove(QMouseEvent* event)
00354   {
00355     if (selected_point_ >= 0 && static_cast<size_t>(selected_point_) < waypoints_.size())
00356     {
00357       QPointF point = event->posF();
00358       stu::Transform transform;
00359       if (tf_manager_.GetTransform(stu::_wgs84_frame, target_frame_, transform))
00360       {
00361         QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
00362         tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
00363         position = transform * position;
00364         waypoints_[selected_point_].position.y = position.y();
00365         waypoints_[selected_point_].position.x = position.x();
00366         PlanRoute();
00367       }
00368 
00369       return true;
00370     }
00371     return false;
00372   }
00373 
00374   void PlanRoutePlugin::Draw(double x, double y, double scale)
00375   {
00376     stu::Transform transform;
00377     if (tf_manager_.GetTransform(target_frame_, stu::_wgs84_frame, transform))
00378     {
00379       if (!failed_service_)
00380       {
00381         if (route_preview_)
00382         {
00383           sru::Route route = *route_preview_;
00384           sru::transform(route, transform, target_frame_);
00385 
00386           glLineWidth(2);
00387           const QColor color = ui_.color->color();
00388           glColor4d(color.redF(), color.greenF(), color.blueF(), 1.0);
00389           glBegin(GL_LINE_STRIP);
00390 
00391           for (size_t i = 0; i < route.points.size(); i++)
00392           {
00393             glVertex2d(route.points[i].position().x(), route.points[i].position().y());
00394           }
00395 
00396           glEnd();
00397         }
00398 
00399         PrintInfo("OK");
00400       }
00401 
00402       // Draw waypoints
00403 
00404       glPointSize(20);
00405       glColor4f(0.0, 1.0, 1.0, 1.0);
00406       glBegin(GL_POINTS);
00407 
00408       for (size_t i = 0; i < waypoints_.size(); i++)
00409       {
00410         tf::Vector3 point(waypoints_[i].position.x, waypoints_[i].position.y, 0);
00411         point = transform * point;
00412         glVertex2d(point.x(), point.y());
00413       }
00414       glEnd();
00415     }
00416     else
00417     {
00418       PrintError("Failed to transform.");
00419     }
00420   }
00421 
00422   void PlanRoutePlugin::Paint(QPainter* painter, double x, double y, double scale)
00423   {
00424     painter->save();
00425     painter->resetTransform();
00426 
00427     QPen pen(QBrush(QColor(Qt::darkCyan).darker()), 1);
00428     painter->setPen(pen);
00429     painter->setFont(QFont("DejaVu Sans Mono", 7));
00430 
00431     stu::Transform transform;
00432     if (tf_manager_.GetTransform(target_frame_, stu::_wgs84_frame, transform))
00433     {
00434       for (size_t i = 0; i < waypoints_.size(); i++)
00435       {
00436         tf::Vector3 point(waypoints_[i].position.x, waypoints_[i].position.y, 0);
00437         point = transform * point;
00438         QPointF gl_point = map_canvas_->FixedFrameToMapGlCoord(QPointF(point.x(), point.y()));
00439         QPointF corner(gl_point.x() - 20, gl_point.y() - 20);
00440         QRectF rect(corner, QSizeF(40, 40));
00441         painter->drawText(rect, Qt::AlignHCenter | Qt::AlignVCenter, QString::fromStdString(boost::lexical_cast<std::string>(i + 1)));
00442       }
00443     }
00444 
00445     painter->restore();
00446   }
00447 
00448   void PlanRoutePlugin::LoadConfig(const YAML::Node& node, const std::string& path)
00449   {
00450     if (node["route_topic"])
00451     {
00452       std::string route_topic;
00453       node["route_topic"] >> route_topic;
00454       ui_.topic->setText(route_topic.c_str());
00455     }
00456     if (node["color"])
00457     {
00458       std::string color;
00459       node["color"] >> color;
00460       ui_.color->setColor(QColor(color.c_str()));
00461     }
00462     if (node["service"])
00463     {
00464       std::string service;
00465       node["service"] >> service;
00466       ui_.service->setText(service.c_str());
00467     }
00468     if (node["start_from_vehicle"])
00469     {
00470       bool start_from_vehicle;
00471       node["start_from_vehicle"] >> start_from_vehicle;
00472       ui_.start_from_vehicle->setChecked(start_from_vehicle);
00473     }
00474 
00475     PlanRoute();
00476   }
00477 
00478   void PlanRoutePlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
00479   {
00480     std::string route_topic = ui_.topic->text().toStdString();
00481     emitter << YAML::Key << "route_topic" << YAML::Value << route_topic;
00482 
00483     std::string color = ui_.color->color().name().toStdString();
00484     emitter << YAML::Key << "color" << YAML::Value << color;
00485 
00486     std::string service = ui_.service->text().toStdString();
00487     emitter << YAML::Key << "service" << YAML::Value << service;
00488 
00489     bool start_from_vehicle = ui_.start_from_vehicle->isChecked();
00490     emitter << YAML::Key << "start_from_vehicle" << YAML::Value << start_from_vehicle;
00491   }
00492 }


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