00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <mapviz_plugins/route_plugin.h>
00031
00032
00033 #include <cstdio>
00034 #include <vector>
00035
00036
00037 #include <QDialog>
00038 #include <QGLWidget>
00039 #include <QPainter>
00040 #include <QPalette>
00041
00042 #include <opencv2/core/core.hpp>
00043
00044
00045 #include <ros/master.h>
00046
00047 #include <swri_image_util/geometry_util.h>
00048 #include <swri_route_util/util.h>
00049 #include <swri_transform_util/transform_util.h>
00050 #include <mapviz/select_topic_dialog.h>
00051
00052 #include <marti_nav_msgs/Route.h>
00053
00054
00055 #include <pluginlib/class_list_macros.h>
00056
00057 PLUGINLIB_DECLARE_CLASS(mapviz_plugins, route, mapviz_plugins::RoutePlugin,
00058 mapviz::MapvizPlugin);
00059
00060 namespace sru = swri_route_util;
00061 namespace stu = swri_transform_util;
00062
00063 namespace mapviz_plugins
00064 {
00065 RoutePlugin::RoutePlugin() : config_widget_(new QWidget()), draw_style_(LINES)
00066 {
00067 ui_.setupUi(config_widget_);
00068
00069 ui_.color->setColor(Qt::green);
00070
00071 QPalette p(config_widget_->palette());
00072 p.setColor(QPalette::Background, Qt::white);
00073 config_widget_->setPalette(p);
00074
00075 QPalette p3(ui_.status->palette());
00076 p3.setColor(QPalette::Text, Qt::red);
00077 ui_.status->setPalette(p3);
00078 QObject::connect(ui_.selecttopic, SIGNAL(clicked()), this,
00079 SLOT(SelectTopic()));
00080 QObject::connect(ui_.topic, SIGNAL(editingFinished()), this,
00081 SLOT(TopicEdited()));
00082 QObject::connect(ui_.selectpositiontopic, SIGNAL(clicked()), this,
00083 SLOT(SelectPositionTopic()));
00084 QObject::connect(ui_.positiontopic, SIGNAL(editingFinished()), this,
00085 SLOT(PositionTopicEdited()));
00086 QObject::connect(ui_.drawstyle, SIGNAL(activated(QString)), this,
00087 SLOT(SetDrawStyle(QString)));
00088 QObject::connect(ui_.color, SIGNAL(colorEdited(const QColor&)), this,
00089 SLOT(DrawIcon()));
00090 }
00091
00092 RoutePlugin::~RoutePlugin()
00093 {
00094 }
00095
00096 void RoutePlugin::DrawIcon()
00097 {
00098 if (icon_)
00099 {
00100 QPixmap icon(16, 16);
00101 icon.fill(Qt::transparent);
00102
00103 QPainter painter(&icon);
00104 painter.setRenderHint(QPainter::Antialiasing, true);
00105
00106 QPen pen(ui_.color->color());
00107
00108 if (draw_style_ == POINTS)
00109 {
00110 pen.setWidth(7);
00111 pen.setCapStyle(Qt::RoundCap);
00112 painter.setPen(pen);
00113 painter.drawPoint(8, 8);
00114 }
00115 else if (draw_style_ == LINES)
00116 {
00117 pen.setWidth(3);
00118 pen.setCapStyle(Qt::FlatCap);
00119 painter.setPen(pen);
00120 painter.drawLine(1, 14, 14, 1);
00121 }
00122
00123 icon_->SetPixmap(icon);
00124 }
00125 }
00126
00127 void RoutePlugin::SetDrawStyle(QString style)
00128 {
00129 if (style == "lines")
00130 {
00131 draw_style_ = LINES;
00132 }
00133 else if (style == "points")
00134 {
00135 draw_style_ = POINTS;
00136 }
00137 DrawIcon();
00138 }
00139
00140 void RoutePlugin::SelectTopic()
00141 {
00142 ros::master::TopicInfo topic =
00143 mapviz::SelectTopicDialog::selectTopic("marti_nav_msgs/Route");
00144
00145 if (topic.name.empty())
00146 {
00147 return;
00148 }
00149
00150 ui_.topic->setText(QString::fromStdString(topic.name));
00151 TopicEdited();
00152 }
00153
00154 void RoutePlugin::SelectPositionTopic()
00155 {
00156 ros::master::TopicInfo topic =
00157 mapviz::SelectTopicDialog::selectTopic("marti_nav_msgs/RoutePosition");
00158
00159 if (topic.name.empty())
00160 {
00161 return;
00162 }
00163
00164 ui_.positiontopic->setText(QString::fromStdString(topic.name));
00165 PositionTopicEdited();
00166 }
00167
00168 void RoutePlugin::TopicEdited()
00169 {
00170 std::string topic = ui_.topic->text().trimmed().toStdString();
00171 if (topic != topic_)
00172 {
00173 src_route_ = sru::Route();
00174
00175 route_sub_.shutdown();
00176
00177 topic_ = topic;
00178 if (!topic.empty())
00179 {
00180 route_sub_ =
00181 node_.subscribe(topic_, 1, &RoutePlugin::RouteCallback, this);
00182
00183 ROS_INFO("Subscribing to %s", topic_.c_str());
00184 }
00185 }
00186 }
00187
00188 void RoutePlugin::PositionTopicEdited()
00189 {
00190 std::string topic = ui_.positiontopic->text().trimmed().toStdString();
00191 if (topic != position_topic_)
00192 {
00193 src_route_position_.reset();
00194 position_sub_.shutdown();
00195
00196 if (!topic.empty())
00197 {
00198 position_topic_ = topic;
00199 position_sub_ = node_.subscribe(position_topic_, 1,
00200 &RoutePlugin::PositionCallback, this);
00201
00202 ROS_INFO("Subscribing to %s", position_topic_.c_str());
00203 }
00204 }
00205 }
00206
00207 void RoutePlugin::PositionCallback(
00208 const marti_nav_msgs::RoutePositionConstPtr& msg)
00209 {
00210 src_route_position_ = msg;
00211 }
00212
00213 void RoutePlugin::RouteCallback(const marti_nav_msgs::RouteConstPtr& msg)
00214 {
00215 src_route_ = sru::Route(*msg);
00216 }
00217
00218 void RoutePlugin::PrintError(const std::string& message)
00219 {
00220 if (message == ui_.status->text().toStdString())
00221 {
00222 return;
00223 }
00224
00225 ROS_ERROR_THROTTLE(1.0, "Error: %s", message.c_str());
00226 QPalette p(ui_.status->palette());
00227 p.setColor(QPalette::Text, Qt::red);
00228 ui_.status->setPalette(p);
00229 ui_.status->setText(message.c_str());
00230 }
00231
00232 void RoutePlugin::PrintInfo(const std::string& message)
00233 {
00234 if (message == ui_.status->text().toStdString())
00235 {
00236 return;
00237 }
00238
00239 ROS_INFO_THROTTLE(1.0, "%s", message.c_str());
00240 QPalette p(ui_.status->palette());
00241 p.setColor(QPalette::Text, Qt::green);
00242 ui_.status->setPalette(p);
00243 ui_.status->setText(message.c_str());
00244 }
00245
00246 void RoutePlugin::PrintWarning(const std::string& message)
00247 {
00248 if (message == ui_.status->text().toStdString())
00249 {
00250 return;
00251 }
00252
00253 ROS_WARN_THROTTLE(1.0, "%s", message.c_str());
00254 QPalette p(ui_.status->palette());
00255 p.setColor(QPalette::Text, Qt::darkYellow);
00256 ui_.status->setPalette(p);
00257 ui_.status->setText(message.c_str());
00258 }
00259
00260 QWidget* RoutePlugin::GetConfigWidget(QWidget* parent)
00261 {
00262 config_widget_->setParent(parent);
00263
00264 return config_widget_;
00265 }
00266
00267 bool RoutePlugin::Initialize(QGLWidget* canvas)
00268 {
00269 canvas_ = canvas;
00270
00271 DrawIcon();
00272
00273 initialized_ = true;
00274 return true;
00275 }
00276
00277 void RoutePlugin::Draw(double x, double y, double scale)
00278 {
00279 if (!src_route_.valid())
00280 {
00281 PrintError("No valid route received.");
00282 return;
00283 }
00284
00285 sru::Route route = src_route_;
00286 if (route.header.frame_id.empty())
00287 {
00288 route.header.frame_id = "/wgs84";
00289 }
00290
00291 stu::Transform transform;
00292 if (!GetTransform(route.header.frame_id, ros::Time(), transform))
00293 {
00294 PrintError("Failed to transform route");
00295 return;
00296 }
00297
00298 sru::transform(route, transform, target_frame_);
00299 sru::projectToXY(route);
00300 sru::fillOrientations(route);
00301
00302 DrawRoute(route);
00303
00304 bool ok = true;
00305 if (route.valid() && src_route_position_)
00306 {
00307 sru::RoutePoint point;
00308 if (sru::interpolateRoutePosition(point, route, *src_route_position_, true))
00309 {
00310 DrawRoutePoint(point);
00311 }
00312 else
00313 {
00314 PrintError("Failed to find route position in route.");
00315 ok = false;
00316 }
00317 }
00318
00319 if (ok)
00320 {
00321 PrintInfo("OK");
00322 }
00323 }
00324
00325 void RoutePlugin::DrawStopWaypoint(double x, double y)
00326 {
00327 const double a = 2;
00328 const double S = a * 2.414213562373095;
00329
00330 glBegin(GL_POLYGON);
00331
00332 glColor3f(1.0, 0.0, 0.0);
00333
00334 glVertex2d(x + S / 2.0, y - a / 2.0);
00335 glVertex2d(x + S / 2.0, y + a / 2.0);
00336 glVertex2d(x + a / 2.0, y + S / 2.0);
00337 glVertex2d(x - a / 2.0, y + S / 2.0);
00338 glVertex2d(x - S / 2.0, y + a / 2.0);
00339 glVertex2d(x - S / 2.0, y - a / 2.0);
00340 glVertex2d(x - a / 2.0, y - S / 2.0);
00341 glVertex2d(x + a / 2.0, y - S / 2.0);
00342
00343 glEnd();
00344 }
00345
00346 void RoutePlugin::DrawRoute(const sru::Route& route)
00347 {
00348 const QColor color = ui_.color->color();
00349 glColor4d(color.redF(), color.greenF(), color.blueF(), 1.0);
00350
00351 if (draw_style_ == LINES)
00352 {
00353 glLineWidth(3);
00354 glBegin(GL_LINE_STRIP);
00355 }
00356 else
00357 {
00358 glPointSize(2);
00359 glBegin(GL_POINTS);
00360 }
00361
00362 for (size_t i = 0; i < route.points.size(); i++)
00363 {
00364 glVertex2d(route.points[i].position().x(),
00365 route.points[i].position().y());
00366 }
00367 glEnd();
00368 }
00369
00370 void RoutePlugin::DrawRoutePoint(const sru::RoutePoint& point)
00371 {
00372 const double arrow_size = ui_.iconsize->value();
00373
00374 tf::Vector3 v1(arrow_size, 0.0, 0.0);
00375 tf::Vector3 v2(0.0, arrow_size / 2.0, 0.0);
00376 tf::Vector3 v3(0.0, -arrow_size / 2.0, 0.0);
00377
00378 tf::Transform point_g(point.orientation(), point.position());
00379
00380 v1 = point_g * v1;
00381 v2 = point_g * v2;
00382 v3 = point_g * v3;
00383
00384 const QColor color = ui_.positioncolor->color();
00385 glLineWidth(3);
00386 glBegin(GL_POLYGON);
00387 glColor4d(color.redF(), color.greenF(), color.blueF(), 1.0);
00388 glVertex2d(v1.x(), v1.y());
00389 glVertex2d(v2.x(), v2.y());
00390 glVertex2d(v3.x(), v3.y());
00391 glEnd();
00392 }
00393
00394 void RoutePlugin::LoadConfig(const YAML::Node& node, const std::string& path)
00395 {
00396 if (node["topic"])
00397 {
00398 std::string route_topic;
00399 node["topic"] >> route_topic;
00400 ui_.topic->setText(route_topic.c_str());
00401 }
00402 if (node["color"])
00403 {
00404 std::string color;
00405 node["color"] >> color;
00406 ui_.color->setColor(QColor(color.c_str()));
00407 }
00408 if (node["postopic"])
00409 {
00410 std::string pos_topic;
00411 node["postopic"] >> pos_topic;
00412 ui_.positiontopic->setText(pos_topic.c_str());
00413 }
00414 if (node["poscolor"])
00415 {
00416 std::string poscolor;
00417 node["poscolor"] >> poscolor;
00418 ui_.positioncolor->setColor(QColor(poscolor.c_str()));
00419 }
00420
00421 if (node["draw_style"])
00422 {
00423 std::string draw_style;
00424 node["draw_style"] >> draw_style;
00425
00426 if (draw_style == "lines")
00427 {
00428 draw_style_ = LINES;
00429 ui_.drawstyle->setCurrentIndex(0);
00430 }
00431 else if (draw_style == "points")
00432 {
00433 draw_style_ = POINTS;
00434 ui_.drawstyle->setCurrentIndex(1);
00435 }
00436 }
00437
00438 TopicEdited();
00439 PositionTopicEdited();
00440 }
00441
00442 void RoutePlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
00443 {
00444 std::string route_topic = ui_.topic->text().toStdString();
00445 emitter << YAML::Key << "topic" << YAML::Value << route_topic;
00446
00447 std::string color = ui_.color->color().name().toStdString();
00448 emitter << YAML::Key << "color" << YAML::Value << color;
00449
00450 std::string pos_topic = ui_.positiontopic->text().toStdString();
00451 emitter << YAML::Key << "postopic" << YAML::Value << pos_topic;
00452
00453 std::string pos_color = ui_.positioncolor->color().name().toStdString();
00454 emitter << YAML::Key << "poscolor" << YAML::Value << pos_color;
00455
00456 std::string draw_style = ui_.drawstyle->currentText().toStdString();
00457 emitter << YAML::Key << "draw_style" << YAML::Value << draw_style;
00458 }
00459 }