draw_polygon_plugin.cpp
Go to the documentation of this file.
1 // *****************************************************************************
2 //
3 // Copyright (c) 2016, 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 
44 #include <opencv2/core/core.hpp>
45 
46 #include <geometry_msgs/Point32.h>
47 #include <geometry_msgs/PolygonStamped.h>
48 #include <ros/master.h>
51 
52 // Declare plugin
55 
56 namespace stu = swri_transform_util;
57 
58 namespace mapviz_plugins
59 {
60  DrawPolygonPlugin::DrawPolygonPlugin() :
61  config_widget_(new QWidget()),
62  map_canvas_(NULL),
63  selected_point_(-1),
64  is_mouse_down_(false),
65  max_ms_(Q_INT64_C(500)),
66  max_distance_(2.0)
67  {
68  ui_.setupUi(config_widget_);
69 
70  ui_.color->setColor(Qt::green);
71  // Set background white
72  QPalette p(config_widget_->palette());
73  p.setColor(QPalette::Background, Qt::white);
74  config_widget_->setPalette(p);
75  // Set status text red
76  QPalette p3(ui_.status->palette());
77  p3.setColor(QPalette::Text, Qt::red);
78  ui_.status->setPalette(p3);
79 
80  QObject::connect(ui_.selectframe, SIGNAL(clicked()), this,
81  SLOT(SelectFrame()));
82  QObject::connect(ui_.frame, SIGNAL(editingFinished()), this,
83  SLOT(FrameEdited()));
84  QObject::connect(ui_.publish, SIGNAL(clicked()), this,
85  SLOT(PublishPolygon()));
86  QObject::connect(ui_.clear, SIGNAL(clicked()), this,
87  SLOT(Clear()));
88  }
89 
91  {
92  if (map_canvas_)
93  {
94  map_canvas_->removeEventFilter(this);
95  }
96  }
97 
99  {
100  std::string frame = mapviz::SelectFrameDialog::selectFrame(tf_);
101  if (!frame.empty())
102  {
103  ui_.frame->setText(QString::fromStdString(frame));
104  FrameEdited();
105  }
106  }
107 
109  {
110  source_frame_ = ui_.frame->text().toStdString();
111  PrintWarning("Waiting for transform.");
112 
113  ROS_INFO("Setting target frame to to %s", source_frame_.c_str());
114 
115  initialized_ = true;
116  }
117 
119  {
120  if (polygon_topic_ != ui_.topic->text().toStdString())
121  {
122  polygon_topic_ = ui_.topic->text().toStdString();
124  polygon_pub_ = node_.advertise<geometry_msgs::PolygonStamped>(polygon_topic_, 1, true);
125  }
126 
127  geometry_msgs::PolygonStamped polygon;
128  polygon.header.stamp = ros::Time::now();
129  polygon.header.frame_id = ui_.frame->text().toStdString();
130 
131  for (const auto& vertex: vertices_)
132  {
133  geometry_msgs::Point32 point;
134  point.x = vertex.x();
135  point.y = vertex.y();
136  point.z = 0;
137  polygon.polygon.points.push_back(point);
138  }
139 
140  polygon_pub_.publish(polygon);
141  }
142 
144  {
145  vertices_.clear();
146  transformed_vertices_.clear();
147  }
148 
149  void DrawPolygonPlugin::PrintError(const std::string& message)
150  {
151  PrintErrorHelper(ui_.status, message, 1.0);
152  }
153 
154  void DrawPolygonPlugin::PrintInfo(const std::string& message)
155  {
156  PrintInfoHelper(ui_.status, message, 1.0);
157  }
158 
159  void DrawPolygonPlugin::PrintWarning(const std::string& message)
160  {
161  PrintWarningHelper(ui_.status, message, 1.0);
162  }
163 
164  QWidget* DrawPolygonPlugin::GetConfigWidget(QWidget* parent)
165  {
166  config_widget_->setParent(parent);
167 
168  return config_widget_;
169  }
170 
171  bool DrawPolygonPlugin::Initialize(QGLWidget* canvas)
172  {
173  map_canvas_ = static_cast<mapviz::MapCanvas*>(canvas);
174  map_canvas_->installEventFilter(this);
175 
176  initialized_ = true;
177  return true;
178  }
179 
180  bool DrawPolygonPlugin::eventFilter(QObject *object, QEvent* event)
181  {
182  switch (event->type())
183  {
184  case QEvent::MouseButtonPress:
185  return handleMousePress(static_cast<QMouseEvent*>(event));
186  case QEvent::MouseButtonRelease:
187  return handleMouseRelease(static_cast<QMouseEvent*>(event));
188  case QEvent::MouseMove:
189  return handleMouseMove(static_cast<QMouseEvent*>(event));
190  default:
191  return false;
192  }
193  }
194 
195  bool DrawPolygonPlugin::handleMousePress(QMouseEvent* event)
196  {
197  if(!this->Visible())
198  {
199  ROS_DEBUG("Ignoring mouse press, since draw polygon plugin is hidden");
200  return false;
201  }
202 
203  selected_point_ = -1;
204  int closest_point = 0;
205  double closest_distance = std::numeric_limits<double>::max();
206 
207 #if QT_VERSION >= 0x050000
208  QPointF point = event->localPos();
209 #else
210  QPointF point = event->posF();
211 #endif
213  std::string frame = ui_.frame->text().toStdString();
214  if (tf_manager_->GetTransform(target_frame_, frame, transform))
215  {
216  for (size_t i = 0; i < vertices_.size(); i++)
217  {
218  tf::Vector3 vertex = vertices_[i];
219  vertex = transform * vertex;
220 
221  QPointF transformed = map_canvas_->FixedFrameToMapGlCoord(QPointF(vertex.x(), vertex.y()));
222 
223  double distance = QLineF(transformed, point).length();
224 
225  if (distance < closest_distance)
226  {
227  closest_distance = distance;
228  closest_point = static_cast<int>(i);
229  }
230  }
231  }
232 
233  if (event->button() == Qt::LeftButton)
234  {
235  if (closest_distance < 15)
236  {
237  selected_point_ = closest_point;
238  return true;
239  }
240  else
241  {
242  is_mouse_down_ = true;
243 #if QT_VERSION >= 0x050000
244  mouse_down_pos_ = event->localPos();
245 #else
246  mouse_down_pos_ = event->posF();
247 #endif
248  mouse_down_time_ = QDateTime::currentMSecsSinceEpoch();
249  return false;
250  }
251  }
252  else if (event->button() == Qt::RightButton)
253  {
254  if (closest_distance < 15)
255  {
256  vertices_.erase(vertices_.begin() + closest_point);
257  transformed_vertices_.resize(vertices_.size());
258  return true;
259  }
260  }
261 
262  return false;
263  }
264 
265  bool DrawPolygonPlugin::handleMouseRelease(QMouseEvent* event)
266  {
267  std::string frame = ui_.frame->text().toStdString();
268  if (selected_point_ >= 0 && static_cast<size_t>(selected_point_) < vertices_.size())
269  {
270 #if QT_VERSION >= 0x050000
271  QPointF point = event->localPos();
272 #else
273  QPointF point = event->posF();
274 #endif
276  if (tf_manager_->GetTransform(frame, target_frame_, transform))
277  {
278  QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
279  tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
280  position = transform * position;
281  vertices_[selected_point_].setX(position.x());
282  vertices_[selected_point_].setY(position.y());
283  }
284 
285  selected_point_ = -1;
286  return true;
287  }
288  else if (is_mouse_down_)
289  {
290 #if QT_VERSION >= 0x050000
291  qreal distance = QLineF(mouse_down_pos_, event->localPos()).length();
292 #else
293  qreal distance = QLineF(mouse_down_pos_, event->posF()).length();
294 #endif
295  qint64 msecsDiff = QDateTime::currentMSecsSinceEpoch() - mouse_down_time_;
296 
297  // Only fire the event if the mouse has moved less than the maximum distance
298  // and was held for shorter than the maximum time.. This prevents click
299  // events from being fired if the user is dragging the mouse across the map
300  // or just holding the cursor in place.
301  if (msecsDiff < max_ms_ && distance <= max_distance_)
302  {
303 #if QT_VERSION >= 0x050000
304  QPointF point = event->localPos();
305 #else
306  QPointF point = event->posF();
307 #endif
308 
309  QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
310  ROS_INFO("mouse point at %f, %f -> %f, %f", point.x(), point.y(), transformed.x(), transformed.y());
311 
313  tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
314 
315  if (tf_manager_->GetTransform(frame, target_frame_, transform))
316  {
317  position = transform * position;
318  vertices_.push_back(position);
319  transformed_vertices_.resize(vertices_.size());
320  ROS_INFO("Adding vertex at %lf, %lf %s", position.x(), position.y(), frame.c_str());
321  }
322  }
323  }
324  is_mouse_down_ = false;
325 
326  return false;
327  }
328 
329  bool DrawPolygonPlugin::handleMouseMove(QMouseEvent* event)
330  {
331  if (selected_point_ >= 0 && static_cast<size_t>(selected_point_) < vertices_.size())
332  {
333 #if QT_VERSION >= 0x050000
334  QPointF point = event->localPos();
335 #else
336  QPointF point = event->posF();
337 #endif
339  std::string frame = ui_.frame->text().toStdString();
340  if (tf_manager_->GetTransform(frame, target_frame_, transform))
341  {
342  QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
343  tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
344  position = transform * position;
345  vertices_[selected_point_].setY(position.y());
346  vertices_[selected_point_].setX(position.x());
347  }
348 
349  return true;
350  }
351  return false;
352  }
353 
354  void DrawPolygonPlugin::Draw(double x, double y, double scale)
355  {
357  std::string frame = ui_.frame->text().toStdString();
358  if (!tf_manager_->GetTransform(target_frame_, frame, transform))
359  {
360  return;
361  }
362 
363  // Transform polygon
364  for (size_t i = 0; i < vertices_.size(); i++)
365  {
366  transformed_vertices_[i] = transform * vertices_[i];
367  }
368 
369  glLineWidth(1);
370  const QColor color = ui_.color->color();
371  glColor4d(color.redF(), color.greenF(), color.blueF(), 1.0);
372  glBegin(GL_LINE_STRIP);
373 
374  for (const auto& vertex: transformed_vertices_)
375  {
376  glVertex2d(vertex.x(), vertex.y());
377  }
378 
379  glEnd();
380 
381  glBegin(GL_LINES);
382 
383  glColor4d(color.redF(), color.greenF(), color.blueF(), 0.25);
384 
385  if (transformed_vertices_.size() > 2)
386  {
387  glVertex2d(transformed_vertices_.front().x(), transformed_vertices_.front().y());
388  glVertex2d(transformed_vertices_.back().x(), transformed_vertices_.back().y());
389  }
390 
391  glEnd();
392 
393  // Draw vertices
394  glPointSize(9);
395  glBegin(GL_POINTS);
396 
397  for (const auto& vertex: transformed_vertices_)
398  {
399  glVertex2d(vertex.x(), vertex.y());
400  }
401  glEnd();
402 
403 
404 
405  PrintInfo("OK");
406  }
407 
408  void DrawPolygonPlugin::LoadConfig(const YAML::Node& node, const std::string& path)
409  {
410  if (node["frame"])
411  {
412  node["frame"] >> source_frame_;
413  ui_.frame->setText(source_frame_.c_str());
414  }
415 
416  if (node["polygon_topic"])
417  {
418  std::string polygon_topic;
419  node["polygon_topic"] >> polygon_topic;
420  ui_.topic->setText(polygon_topic.c_str());
421  }
422  if (node["color"])
423  {
424  std::string color;
425  node["color"] >> color;
426  ui_.color->setColor(QColor(color.c_str()));
427  }
428  }
429 
430  void DrawPolygonPlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
431  {
432  std::string frame = ui_.frame->text().toStdString();
433  emitter << YAML::Key << "frame" << YAML::Value << frame;
434 
435  std::string polygon_topic = ui_.topic->text().toStdString();
436  emitter << YAML::Key << "polygon_topic" << YAML::Value << polygon_topic;
437 
438  std::string color = ui_.color->color().name().toStdString();
439  emitter << YAML::Key << "color" << YAML::Value << color;
440  }
441 }
#define NULL
void SaveConfig(YAML::Emitter &emitter, const std::string &path)
QPointF MapGlCoordToFixedFrame(const QPointF &point)
bool Visible() const
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 PrintWarning(const std::string &message)
std::vector< tf::Vector3 > transformed_vertices_
void LoadConfig(const YAML::Node &node, const std::string &path)
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)
void PrintInfo(const std::string &message)
TFSIMD_FORCE_INLINE tfScalar distance(const Vector3 &v) const
std::string target_frame_
static std::string selectFrame(boost::shared_ptr< tf::TransformListener > tf_listener, QWidget *parent=0)
static void PrintInfoHelper(QLabel *status_label, const std::string &message, double throttle=0.0)
std::string source_frame_
void PrintError(const std::string &message)
QWidget * GetConfigWidget(QWidget *parent)
QPointF FixedFrameToMapGlCoord(const QPointF &point)
#define ROS_INFO(...)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
std::vector< tf::Vector3 > vertices_
static Time now()
boost::shared_ptr< tf::TransformListener > tf_
bool eventFilter(QObject *object, QEvent *event)
swri_transform_util::TransformManagerPtr tf_manager_
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
void Draw(double x, double y, double scale)
#define ROS_DEBUG(...)


mapviz_plugins
Author(s): Marc Alban
autogenerated on Fri Mar 19 2021 02:44:32