plan_route_plugin.cpp
Go to the documentation of this file.
1 // *****************************************************************************
2 //
3 // Copyright (c) 2014, Southwest Research Institute® (SwRI®)
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Southwest Research Institute® (SwRI®) nor the
14 // names of its contributors may be used to endorse or promote products
15 // derived from this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //
28 // *****************************************************************************
29 
31 
32 // C++ standard libraries
33 #include <cstdio>
34 #include <vector>
35 
36 // QT libraries
37 #include <QDateTime>
38 #include <QDialog>
39 #include <QGLWidget>
40 #include <QMouseEvent>
41 #include <QPainter>
42 #include <QPalette>
43 #include <QStaticText>
44 
45 #include <opencv2/core/core.hpp>
46 
47 // ROS libraries
48 #include <ros/master.h>
49 
50 #include <swri_route_util/util.h>
52 
53 #include <marti_nav_msgs/PlanRoute.h>
54 
55 // Declare plugin
58 
59 namespace mnm = marti_nav_msgs;
60 namespace sru = swri_route_util;
61 namespace stu = swri_transform_util;
62 
63 namespace mapviz_plugins
64 {
65  PlanRoutePlugin::PlanRoutePlugin() :
66  config_widget_(new QWidget()),
67  map_canvas_(NULL),
68  failed_service_(false),
69  selected_point_(-1),
70  is_mouse_down_(false),
71  max_ms_(Q_INT64_C(500)),
72  max_distance_(2.0)
73  {
74  ui_.setupUi(config_widget_);
75 
76  ui_.color->setColor(Qt::green);
77  // Set background white
78  QPalette p(config_widget_->palette());
79  p.setColor(QPalette::Background, Qt::white);
80  config_widget_->setPalette(p);
81  // Set status text red
82  QPalette p3(ui_.status->palette());
83  p3.setColor(QPalette::Text, Qt::red);
84  ui_.status->setPalette(p3);
85  QObject::connect(ui_.service, SIGNAL(editingFinished()), this,
86  SLOT(PlanRoute()));
87  QObject::connect(ui_.publish, SIGNAL(clicked()), this,
88  SLOT(PublishRoute()));
89  QObject::connect(ui_.clear, SIGNAL(clicked()), this,
90  SLOT(Clear()));
91  }
92 
94  {
95  if (map_canvas_)
96  {
97  map_canvas_->removeEventFilter(this);
98  }
99  }
100 
102  {
103  if (route_preview_)
104  {
105  if (route_topic_ != ui_.topic->text().toStdString())
106  {
107  route_topic_ = ui_.topic->text().toStdString();
110  }
111 
113  }
114  }
115 
117  {
119  bool start_from_vehicle = ui_.start_from_vehicle->isChecked();
120  if (waypoints_.size() + start_from_vehicle < 2)
121  {
122  return;
123  }
124 
125  std::string service = ui_.service->text().toStdString();
126  ros::ServiceClient client = node_.serviceClient<mnm::PlanRoute>(service);
127 
128  mnm::PlanRoute plan_route;
129  plan_route.request.header.frame_id = stu::_wgs84_frame;
130  plan_route.request.header.stamp = ros::Time::now();
131  plan_route.request.plan_from_vehicle = static_cast<unsigned char>(start_from_vehicle);
132  plan_route.request.waypoints = waypoints_;
133 
134  if (client.call(plan_route))
135  {
136  if (plan_route.response.success)
137  {
138  route_preview_ = boost::make_shared<sru::Route>(plan_route.response.route);
139  failed_service_ = false;
140  }
141  else
142  {
143  PrintError(plan_route.response.message);
144  failed_service_ = true;
145  }
146  }
147  else
148  {
149  PrintError("Failed to plan route.");
150  failed_service_ = true;
151  }
152  }
153 
155  {
156  PlanRoute();
157  }
158 
160  {
161  waypoints_.clear();
163  }
164 
165  void PlanRoutePlugin::PrintError(const std::string& message)
166  {
167  PrintErrorHelper(ui_.status, message, 1.0);
168  }
169 
170  void PlanRoutePlugin::PrintInfo(const std::string& message)
171  {
172  PrintInfoHelper(ui_.status, message, 1.0);
173  }
174 
175  void PlanRoutePlugin::PrintWarning(const std::string& message)
176  {
177  PrintWarningHelper(ui_.status, message, 1.0);
178  }
179 
180  QWidget* PlanRoutePlugin::GetConfigWidget(QWidget* parent)
181  {
182  config_widget_->setParent(parent);
183 
184  return config_widget_;
185  }
186 
187  bool PlanRoutePlugin::Initialize(QGLWidget* canvas)
188  {
189  map_canvas_ = static_cast<mapviz::MapCanvas*>(canvas);
190  map_canvas_->installEventFilter(this);
191 
193 
194  initialized_ = true;
195  return true;
196  }
197 
198  bool PlanRoutePlugin::eventFilter(QObject *object, QEvent* event)
199  {
200  switch (event->type())
201  {
202  case QEvent::MouseButtonPress:
203  return handleMousePress(static_cast<QMouseEvent*>(event));
204  case QEvent::MouseButtonRelease:
205  return handleMouseRelease(static_cast<QMouseEvent*>(event));
206  case QEvent::MouseMove:
207  return handleMouseMove(static_cast<QMouseEvent*>(event));
208  default:
209  return false;
210  }
211  }
212 
213  bool PlanRoutePlugin::handleMousePress(QMouseEvent* event)
214  {
215  selected_point_ = -1;
216  int closest_point = 0;
217  double closest_distance = std::numeric_limits<double>::max();
218 
219  QPointF point = event->localPos();
221  if (tf_manager_.GetTransform(target_frame_, stu::_wgs84_frame, transform))
222  {
223  for (size_t i = 0; i < waypoints_.size(); i++)
224  {
225  tf::Vector3 waypoint(
226  waypoints_[i].position.x,
227  waypoints_[i].position.y,
228  0.0);
229  waypoint = transform * waypoint;
230 
231  QPointF transformed = map_canvas_->FixedFrameToMapGlCoord(QPointF(waypoint.x(), waypoint.y()));
232 
233  double distance = QLineF(transformed, point).length();
234 
235  if (distance < closest_distance)
236  {
237  closest_distance = distance;
238  closest_point = static_cast<int>(i);
239  }
240  }
241  }
242 
243  if (event->button() == Qt::LeftButton)
244  {
245  if (closest_distance < 15)
246  {
247  selected_point_ = closest_point;
248  return true;
249  }
250  else
251  {
252  is_mouse_down_ = true;
253  mouse_down_pos_ = event->localPos();
254  mouse_down_time_ = QDateTime::currentMSecsSinceEpoch();
255  return false;
256  }
257  }
258  else if (event->button() == Qt::RightButton)
259  {
260  if (closest_distance < 15)
261  {
262  waypoints_.erase(waypoints_.begin() + closest_point);
263  PlanRoute();
264  return true;
265  }
266  }
267 
268  return false;
269  }
270 
271  bool PlanRoutePlugin::handleMouseRelease(QMouseEvent* event)
272  {
273  if (selected_point_ >= 0 && static_cast<size_t>(selected_point_) < waypoints_.size())
274  {
275  QPointF point = event->localPos();
277  if (tf_manager_.GetTransform(stu::_wgs84_frame, target_frame_, transform))
278  {
279  QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
280  tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
281  position = transform * position;
282  waypoints_[selected_point_].position.x = position.x();
283  waypoints_[selected_point_].position.y = position.y();
284  PlanRoute();
285  }
286 
287  selected_point_ = -1;
288  return true;
289  }
290  else if (is_mouse_down_)
291  {
292  qreal distance = QLineF(mouse_down_pos_, event->localPos()).length();
293  qint64 msecsDiff = QDateTime::currentMSecsSinceEpoch() - mouse_down_time_;
294 
295  // Only fire the event if the mouse has moved less than the maximum distance
296  // and was held for shorter than the maximum time.. This prevents click
297  // events from being fired if the user is dragging the mouse across the map
298  // or just holding the cursor in place.
299  if (msecsDiff < max_ms_ && distance <= max_distance_)
300  {
301  QPointF point = event->localPos();
302 
303 
304  QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
305 
307  tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
308  if (tf_manager_.GetTransform(stu::_wgs84_frame, target_frame_, transform))
309  {
310  position = transform * position;
311 
312  geometry_msgs::Pose pose;
313  pose.position.x = position.x();
314  pose.position.y = position.y();
315  waypoints_.push_back(pose);
316  PlanRoute();
317  }
318  }
319  }
320  is_mouse_down_ = false;
321 
322  return false;
323  }
324 
325  bool PlanRoutePlugin::handleMouseMove(QMouseEvent* event)
326  {
327  if (selected_point_ >= 0 && static_cast<size_t>(selected_point_) < waypoints_.size())
328  {
329  QPointF point = event->localPos();
331  if (tf_manager_.GetTransform(stu::_wgs84_frame, target_frame_, transform))
332  {
333  QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
334  tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
335  position = transform * position;
336  waypoints_[selected_point_].position.y = position.y();
337  waypoints_[selected_point_].position.x = position.x();
338  PlanRoute();
339  }
340 
341  return true;
342  }
343  return false;
344  }
345 
346  void PlanRoutePlugin::Draw(double x, double y, double scale)
347  {
349  if (tf_manager_.GetTransform(target_frame_, stu::_wgs84_frame, transform))
350  {
351  if (!failed_service_)
352  {
353  if (route_preview_)
354  {
355  sru::Route route = *route_preview_;
356  sru::transform(route, transform, target_frame_);
357 
358  glLineWidth(2);
359  const QColor color = ui_.color->color();
360  glColor4d(color.redF(), color.greenF(), color.blueF(), 1.0);
361  glBegin(GL_LINE_STRIP);
362 
363  for (size_t i = 0; i < route.points.size(); i++)
364  {
365  glVertex2d(route.points[i].position().x(), route.points[i].position().y());
366  }
367 
368  glEnd();
369  }
370 
371  PrintInfo("OK");
372  }
373 
374  // Draw waypoints
375 
376  glPointSize(20);
377  glColor4f(0.0, 1.0, 1.0, 1.0);
378  glBegin(GL_POINTS);
379 
380  for (size_t i = 0; i < waypoints_.size(); i++)
381  {
382  tf::Vector3 point(waypoints_[i].position.x, waypoints_[i].position.y, 0);
383  point = transform * point;
384  glVertex2d(point.x(), point.y());
385  }
386  glEnd();
387  }
388  else
389  {
390  PrintError("Failed to transform.");
391  }
392  }
393 
394  void PlanRoutePlugin::Paint(QPainter* painter, double x, double y, double scale)
395  {
396  painter->save();
397  painter->resetTransform();
398 
399  QPen pen(QBrush(QColor(Qt::darkCyan).darker()), 1);
400  painter->setPen(pen);
401  painter->setFont(QFont("DejaVu Sans Mono", 7));
402 
404  if (tf_manager_.GetTransform(target_frame_, stu::_wgs84_frame, transform))
405  {
406  for (size_t i = 0; i < waypoints_.size(); i++)
407  {
408  tf::Vector3 point(waypoints_[i].position.x, waypoints_[i].position.y, 0);
409  point = transform * point;
410  QPointF gl_point = map_canvas_->FixedFrameToMapGlCoord(QPointF(point.x(), point.y()));
411  QPointF corner(gl_point.x() - 20, gl_point.y() - 20);
412  QRectF rect(corner, QSizeF(40, 40));
413  painter->drawText(rect, Qt::AlignHCenter | Qt::AlignVCenter, QString::fromStdString(boost::lexical_cast<std::string>(i + 1)));
414  }
415  }
416 
417  painter->restore();
418  }
419 
420  void PlanRoutePlugin::LoadConfig(const YAML::Node& node, const std::string& path)
421  {
422  if (node["route_topic"])
423  {
424  std::string route_topic;
425  node["route_topic"] >> route_topic;
426  ui_.topic->setText(route_topic.c_str());
427  }
428  if (node["color"])
429  {
430  std::string color;
431  node["color"] >> color;
432  ui_.color->setColor(QColor(color.c_str()));
433  }
434  if (node["service"])
435  {
436  std::string service;
437  node["service"] >> service;
438  ui_.service->setText(service.c_str());
439  }
440  if (node["start_from_vehicle"])
441  {
442  bool start_from_vehicle;
443  node["start_from_vehicle"] >> start_from_vehicle;
444  ui_.start_from_vehicle->setChecked(start_from_vehicle);
445  }
446 
447  PlanRoute();
448  }
449 
450  void PlanRoutePlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
451  {
452  std::string route_topic = ui_.topic->text().toStdString();
453  emitter << YAML::Key << "route_topic" << YAML::Value << route_topic;
454 
455  std::string color = ui_.color->color().name().toStdString();
456  emitter << YAML::Key << "color" << YAML::Value << color;
457 
458  std::string service = ui_.service->text().toStdString();
459  emitter << YAML::Key << "service" << YAML::Value << service;
460 
461  bool start_from_vehicle = ui_.start_from_vehicle->isChecked();
462  emitter << YAML::Key << "start_from_vehicle" << YAML::Value << start_from_vehicle;
463  }
464 }
#define NULL
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
void Retry(const ros::TimerEvent &e)
QPointF MapGlCoordToFixedFrame(const QPointF &point)
std::vector< geometry_msgs::Pose > waypoints_
swri_transform_util::TransformManager tf_manager_
ros::NodeHandle node_
void publish(const boost::shared_ptr< M > &message) const
void transform(Route &route, const swri_transform_util::Transform &transform, const std::string &target_frame)
void SaveConfig(YAML::Emitter &emitter, const std::string &path)
void Paint(QPainter *painter, double x, double y, double scale)
bool call(MReq &req, MRes &res)
static void PrintWarningHelper(QLabel *status_label, const std::string &message, double throttle=0.0)
static void PrintErrorHelper(QLabel *status_label, const std::string &message, double throttle=0.0)
swri_route_util::RoutePtr route_preview_
TFSIMD_FORCE_INLINE tfScalar distance(const Vector3 &v) const
std::string target_frame_
static void PrintInfoHelper(QLabel *status_label, const std::string &message, double throttle=0.0)
void LoadConfig(const YAML::Node &node, const std::string &path)
void PrintError(const std::string &message)
void PrintInfo(const std::string &message)
void Draw(double x, double y, double scale)
bool eventFilter(QObject *object, QEvent *event)
TFSIMD_FORCE_INLINE const tfScalar & x() const
QPointF FixedFrameToMapGlCoord(const QPointF &point)
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
std::vector< RoutePoint > points
bool Initialize(QGLWidget *canvas)
bool GetTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, Transform &transform) const
void PrintWarning(const std::string &message)
static Time now()
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
QWidget * GetConfigWidget(QWidget *parent)


mapviz_plugins
Author(s): Marc Alban
autogenerated on Thu Jun 6 2019 19:25:16