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/textured_marker_plugin.h>
00031
00032
00033 #include <cmath>
00034 #include <cstdio>
00035 #include <vector>
00036
00037
00038 #include <boost/algorithm/string.hpp>
00039
00040
00041 #include <QDialog>
00042 #include <QGLWidget>
00043
00044
00045 #include <ros/master.h>
00046 #include <sensor_msgs/image_encodings.h>
00047
00048 #include <swri_math_util/constants.h>
00049
00050 #include <mapviz/select_topic_dialog.h>
00051
00052
00053 #include <pluginlib/class_list_macros.h>
00054 PLUGINLIB_DECLARE_CLASS(
00055 mapviz_plugins,
00056 textured_marker,
00057 mapviz_plugins::TexturedMarkerPlugin,
00058 mapviz::MapvizPlugin)
00059
00060 namespace mapviz_plugins
00061 {
00062 TexturedMarkerPlugin::TexturedMarkerPlugin() :
00063 config_widget_(new QWidget()),
00064 is_marker_array_(false)
00065 {
00066 ui_.setupUi(config_widget_);
00067
00068
00069 QPalette p(config_widget_->palette());
00070 p.setColor(QPalette::Background, Qt::white);
00071 config_widget_->setPalette(p);
00072
00073
00074 QPalette p3(ui_.status->palette());
00075 p3.setColor(QPalette::Text, Qt::red);
00076 ui_.status->setPalette(p3);
00077
00078 QObject::connect(ui_.selecttopic, SIGNAL(clicked()), this, SLOT(SelectTopic()));
00079 QObject::connect(ui_.topic, SIGNAL(editingFinished()), this, SLOT(TopicEdited()));
00080
00081
00082
00083 qRegisterMetaType<marti_visualization_msgs::TexturedMarkerConstPtr>("TexturedMarkerConstPtr");
00084 qRegisterMetaType<marti_visualization_msgs::TexturedMarkerArrayConstPtr>("TexturedMarkerArrayConstPtr");
00085
00086 QObject::connect(this,
00087 SIGNAL(MarkerReceived(const marti_visualization_msgs::TexturedMarkerConstPtr)),
00088 this,
00089 SLOT(ProcessMarker(const marti_visualization_msgs::TexturedMarkerConstPtr)));
00090 QObject::connect(this,
00091 SIGNAL(MarkersReceived(const marti_visualization_msgs::TexturedMarkerArrayConstPtr)),
00092 this,
00093 SLOT(ProcessMarkers(const marti_visualization_msgs::TexturedMarkerArrayConstPtr)));
00094 }
00095
00096 TexturedMarkerPlugin::~TexturedMarkerPlugin()
00097 {
00098 }
00099
00100 void TexturedMarkerPlugin::SelectTopic()
00101 {
00102 ros::master::TopicInfo topic = mapviz::SelectTopicDialog::selectTopic(
00103 "marti_visualization_msgs/TexturedMarker",
00104 "marti_visualization_msgs/TexturedMarkerArray");
00105
00106 if (!topic.name.empty())
00107 {
00108 ui_.topic->setText(QString::fromStdString(topic.name));
00109
00110 if (topic.datatype == "marti_visualization_msgs/TexturedMarkerArray")
00111 {
00112 is_marker_array_ = true;
00113 }
00114
00115 TopicEdited();
00116 }
00117 }
00118
00119 void TexturedMarkerPlugin::TopicEdited()
00120 {
00121 std::string topic = ui_.topic->text().trimmed().toStdString();
00122 if (topic != topic_)
00123 {
00124 initialized_ = false;
00125 markers_.clear();
00126 has_message_ = false;
00127 PrintWarning("No messages received.");
00128
00129 marker_sub_.shutdown();
00130
00131 topic_ = topic;
00132 if (!topic.empty())
00133 {
00134 if (is_marker_array_)
00135 {
00136 marker_sub_ = node_.subscribe(topic_, 1000, &TexturedMarkerPlugin::MarkerArrayCallback, this);
00137 }
00138 else
00139 {
00140 marker_sub_ = node_.subscribe(topic_, 1000, &TexturedMarkerPlugin::MarkerCallback, this);
00141 }
00142
00143 ROS_INFO("Subscribing to %s", topic_.c_str());
00144 }
00145 }
00146 }
00147
00148 void TexturedMarkerPlugin::ProcessMarker(const marti_visualization_msgs::TexturedMarkerConstPtr marker)
00149 {
00150 ProcessMarker(*marker);
00151 }
00152
00153 void TexturedMarkerPlugin::ProcessMarker(const marti_visualization_msgs::TexturedMarker& marker)
00154 {
00155 if (!has_message_)
00156 {
00157 initialized_ = true;
00158 has_message_ = true;
00159 }
00160
00161
00162
00163
00164
00165
00166 if (marker.action == marti_visualization_msgs::TexturedMarker::ADD)
00167 {
00168 MarkerData& markerData = markers_[marker.ns][marker.id];
00169 markerData.stamp = marker.header.stamp;
00170
00171 markerData.transformed = true;
00172 markerData.alpha_ = marker.alpha;
00173 markerData.source_frame_ = marker.header.frame_id;
00174
00175 swri_transform_util::Transform transform;
00176 if (!GetTransform(markerData.source_frame_, marker.header.stamp, transform))
00177 {
00178 markerData.transformed = false;
00179 PrintError("No transform between " + markerData.source_frame_ + " and " + target_frame_);
00180 }
00181
00182
00183 ros::Duration lifetime = marker.lifetime;
00184 if (lifetime.isZero())
00185 {
00186 markerData.expire_time = ros::TIME_MAX;
00187 }
00188 else
00189 {
00190
00191 markerData.expire_time = ros::Time::now() + lifetime + ros::Duration(5);
00192 }
00193
00194 tf::Transform offset(
00195 tf::Quaternion(
00196 marker.pose.orientation.x,
00197 marker.pose.orientation.y,
00198 marker.pose.orientation.z,
00199 marker.pose.orientation.w),
00200 tf::Vector3(
00201 marker.pose.position.x,
00202 marker.pose.position.y,
00203 marker.pose.position.z));
00204
00205 double right = marker.image.width * marker.resolution / 2.0;
00206 double left = -right;
00207 double top = marker.image.height * marker.resolution / 2.0;
00208 double bottom = -top;
00209
00210 tf::Vector3 top_left(left, top, 0);
00211 tf::Vector3 top_right(right, top, 0);
00212 tf::Vector3 bottom_left(left, bottom, 0);
00213 tf::Vector3 bottom_right(right, bottom, 0);
00214
00215 top_left = offset * top_left;
00216 top_right = offset * top_right;
00217 bottom_left = offset * bottom_left;
00218 bottom_right = offset * bottom_right;
00219
00220 markerData.quad_.clear();
00221 markerData.quad_.push_back(top_left);
00222 markerData.quad_.push_back(top_right);
00223 markerData.quad_.push_back(bottom_right);
00224
00225 markerData.quad_.push_back(top_left);
00226 markerData.quad_.push_back(bottom_right);
00227 markerData.quad_.push_back(bottom_left);
00228
00229 markerData.transformed_quad_.clear();
00230 for (size_t i = 0; i < markerData.quad_.size(); i++)
00231 {
00232 markerData.transformed_quad_.push_back(transform * markerData.quad_[i]);
00233 }
00234
00235 int32_t max_dimension = std::max(marker.image.height, marker.image.width);
00236 int32_t new_size = 1;
00237 while (new_size < max_dimension)
00238 new_size = new_size << 1;
00239
00240 if (new_size != markerData.texture_size_ || markerData.encoding_ != marker.image.encoding)
00241 {
00242 markerData.texture_size_ = new_size;
00243
00244 markerData.encoding_ = marker.image.encoding;
00245
00246 GLuint ids[1];
00247
00248
00249 if (markerData.texture_id_ != -1)
00250 {
00251 ids[0] = static_cast<GLuint>(markerData.texture_id_);
00252 glDeleteTextures(1, &ids[0]);
00253 }
00254
00255
00256 glGenTextures(1, &ids[0]);
00257 markerData.texture_id_ = ids[0];
00258
00259
00260 glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(markerData.texture_id_));
00261
00262 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00263
00264 if (markerData.encoding_ == sensor_msgs::image_encodings::BGRA8)
00265 {
00266 markerData.texture_.resize(static_cast<size_t>(markerData.texture_size_ * markerData.texture_size_ * 4));
00267 }
00268 else if (markerData.encoding_ == sensor_msgs::image_encodings::BGR8)
00269 {
00270 markerData.texture_.resize(static_cast<size_t>(markerData.texture_size_ * markerData.texture_size_ * 3));
00271 }
00272 else if (markerData.encoding_ == sensor_msgs::image_encodings::MONO8)
00273 {
00274 markerData.texture_.resize(static_cast<size_t>(markerData.texture_size_ * markerData.texture_size_));
00275 }
00276 else
00277 {
00278 ROS_WARN("Unsupported encoding: %s", markerData.encoding_.c_str());
00279 }
00280
00281 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00282 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00283
00284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00285 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00286
00287 glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
00288
00289 glBindTexture(GL_TEXTURE_2D, 0);
00290 }
00291
00292 glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(markerData.texture_id_));
00293
00294 if (markerData.encoding_ == sensor_msgs::image_encodings::BGRA8)
00295 {
00296 for (size_t row = 0; row < marker.image.height; row++)
00297 {
00298 for (size_t col = 0; col < marker.image.width; col++)
00299 {
00300 size_t src_index = (row * marker.image.width + col) * 4;
00301 size_t dst_index = (row * markerData.texture_size_ + col) * 4;
00302
00303 markerData.texture_[dst_index + 0] = marker.image.data[src_index + 0];
00304 markerData.texture_[dst_index + 1] = marker.image.data[src_index + 1];
00305 markerData.texture_[dst_index + 2] = marker.image.data[src_index + 2];
00306 markerData.texture_[dst_index + 3] = marker.image.data[src_index + 3];
00307 }
00308 }
00309
00310 glTexImage2D(
00311 GL_TEXTURE_2D,
00312 0,
00313 GL_RGBA,
00314 markerData.texture_size_,
00315 markerData.texture_size_,
00316 0,
00317 GL_BGRA,
00318 GL_UNSIGNED_BYTE,
00319 markerData.texture_.data());
00320 }
00321 else if (markerData.encoding_ == sensor_msgs::image_encodings::BGR8)
00322 {
00323 for (size_t row = 0; row < marker.image.height; row++)
00324 {
00325 for (size_t col = 0; col < marker.image.width; col++)
00326 {
00327 size_t src_index = (row * marker.image.width + col) * 3;
00328 size_t dst_index = (row * markerData.texture_size_ + col) * 3;
00329
00330 markerData.texture_[dst_index + 0] = marker.image.data[src_index + 0];
00331 markerData.texture_[dst_index + 1] = marker.image.data[src_index + 1];
00332 markerData.texture_[dst_index + 2] = marker.image.data[src_index + 2];
00333 }
00334 }
00335
00336 glTexImage2D(
00337 GL_TEXTURE_2D,
00338 0,
00339 GL_RGB,
00340 markerData.texture_size_,
00341 markerData.texture_size_,
00342 0,
00343 GL_BGR,
00344 GL_UNSIGNED_BYTE,
00345 markerData.texture_.data());
00346 }
00347 else if (markerData.encoding_ == sensor_msgs::image_encodings::MONO8)
00348 {
00349 for (size_t row = 0; row < marker.image.height; row++)
00350 {
00351 for (size_t col = 0; col < marker.image.width; col++)
00352 {
00353 size_t src_index = row * marker.image.width + col;
00354 size_t dst_index = row * markerData.texture_size_ + col;
00355
00356 markerData.texture_[dst_index] = marker.image.data[src_index];
00357 }
00358 }
00359
00360 glTexImage2D(
00361 GL_TEXTURE_2D,
00362 0,
00363 GL_LUMINANCE,
00364 markerData.texture_size_,
00365 markerData.texture_size_,
00366 0,
00367 GL_LUMINANCE,
00368 GL_UNSIGNED_BYTE,
00369 markerData.texture_.data());
00370 }
00371
00372 glBindTexture(GL_TEXTURE_2D, 0);
00373
00374 markerData.texture_x_ = static_cast<float>(marker.image.width) / static_cast<float>(markerData.texture_size_);
00375 markerData.texture_y_ = static_cast<float>(marker.image.height) / static_cast<float>(markerData.texture_size_);
00376 }
00377 else
00378 {
00379 markers_[marker.ns].erase(marker.id);
00380 }
00381 }
00382
00383 void TexturedMarkerPlugin::ProcessMarkers(const marti_visualization_msgs::TexturedMarkerArrayConstPtr markers)
00384 {
00385 for (unsigned int i = 0; i < markers->markers.size(); i++)
00386 {
00387 ProcessMarker(markers->markers[i]);
00388 }
00389 }
00390
00391
00392 void TexturedMarkerPlugin::MarkerCallback(const marti_visualization_msgs::TexturedMarkerConstPtr marker)
00393 {
00394 Q_EMIT MarkerReceived(marker);
00395 }
00396
00397 void TexturedMarkerPlugin::MarkerArrayCallback(const marti_visualization_msgs::TexturedMarkerArrayConstPtr markers)
00398 {
00399 Q_EMIT MarkersReceived(markers);
00400 }
00401
00402 void TexturedMarkerPlugin::PrintError(const std::string& message)
00403 {
00404 if (message == ui_.status->text().toStdString())
00405 {
00406 return;
00407 }
00408
00409 ROS_ERROR("Error: %s", message.c_str());
00410 QPalette p(ui_.status->palette());
00411 p.setColor(QPalette::Text, Qt::red);
00412 ui_.status->setPalette(p);
00413 ui_.status->setText(message.c_str());
00414 }
00415
00416 void TexturedMarkerPlugin::PrintInfo(const std::string& message)
00417 {
00418 if (message == ui_.status->text().toStdString())
00419 {
00420 return;
00421 }
00422
00423 ROS_INFO("%s", message.c_str());
00424 QPalette p(ui_.status->palette());
00425 p.setColor(QPalette::Text, Qt::green);
00426 ui_.status->setPalette(p);
00427 ui_.status->setText(message.c_str());
00428 }
00429
00430 void TexturedMarkerPlugin::PrintWarning(const std::string& message)
00431 {
00432 if (message == ui_.status->text().toStdString())
00433 {
00434 return;
00435 }
00436
00437 ROS_WARN("%s", message.c_str());
00438 QPalette p(ui_.status->palette());
00439 p.setColor(QPalette::Text, Qt::darkYellow);
00440 ui_.status->setPalette(p);
00441 ui_.status->setText(message.c_str());
00442 }
00443
00444 QWidget* TexturedMarkerPlugin::GetConfigWidget(QWidget* parent)
00445 {
00446 config_widget_->setParent(parent);
00447
00448 return config_widget_;
00449 }
00450
00451 bool TexturedMarkerPlugin::Initialize(QGLWidget* canvas)
00452 {
00453 canvas_ = canvas;
00454
00455 return true;
00456 }
00457
00458 void TexturedMarkerPlugin::Draw(double x, double y, double scale)
00459 {
00460 ros::Time now = ros::Time::now();
00461
00462 std::map<std::string, std::map<int, MarkerData> >::iterator nsIter;
00463 for (nsIter = markers_.begin(); nsIter != markers_.end(); ++nsIter)
00464 {
00465 std::map<int, MarkerData>::iterator markerIter;
00466 for (markerIter = nsIter->second.begin(); markerIter != nsIter->second.end(); ++markerIter)
00467 {
00468 MarkerData& marker = markerIter->second;
00469
00470 if (marker.expire_time > now)
00471 {
00472 if (marker.transformed)
00473 {
00474 glEnable(GL_TEXTURE_2D);
00475
00476 glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(marker.texture_id_));
00477
00478 glBegin(GL_TRIANGLES);
00479
00480 glColor4f(1.0f, 1.0f, 1.0f, marker.alpha_);
00481
00482 double marker_x = marker.texture_x_;
00483 double marker_y = marker.texture_y_;
00484
00485 glTexCoord2d(0, 0); glVertex2d(marker.transformed_quad_[0].x(), marker.transformed_quad_[0].y());
00486 glTexCoord2d(marker_x, 0); glVertex2d(marker.transformed_quad_[1].x(), marker.transformed_quad_[1].y());
00487 glTexCoord2d(marker_x, marker_y); glVertex2d(marker.transformed_quad_[2].x(), marker.transformed_quad_[2].y());
00488
00489 glTexCoord2d(0, 0); glVertex2d(marker.transformed_quad_[3].x(), marker.transformed_quad_[3].y());
00490 glTexCoord2d(marker_x, marker_y); glVertex2d(marker.transformed_quad_[4].x(), marker.transformed_quad_[4].y());
00491 glTexCoord2d(0, marker_y); glVertex2d(marker.transformed_quad_[5].x(), marker.transformed_quad_[5].y());
00492
00493 glEnd();
00494
00495 glBindTexture(GL_TEXTURE_2D, 0);
00496
00497 glDisable(GL_TEXTURE_2D);
00498
00499 PrintInfo("OK");
00500 }
00501 }
00502 }
00503 }
00504 }
00505
00506 void TexturedMarkerPlugin::Transform()
00507 {
00508 std::map<std::string, std::map<int, MarkerData> >::iterator nsIter;
00509 for (nsIter = markers_.begin(); nsIter != markers_.end(); ++nsIter)
00510 {
00511 std::map<int, MarkerData>::iterator markerIter;
00512 for (markerIter = nsIter->second.begin(); markerIter != nsIter->second.end(); ++markerIter)
00513 {
00514 swri_transform_util::Transform transform;
00515 if (GetTransform(markerIter->second.source_frame_, markerIter->second.stamp, transform))
00516 {
00517 markerIter->second.transformed_quad_.clear();
00518 for (size_t i = 0; i < markerIter->second.quad_.size(); i++)
00519 {
00520 markerIter->second.transformed_quad_.push_back(transform * markerIter->second.quad_[i]);
00521 }
00522 }
00523 }
00524 }
00525 }
00526
00527 void TexturedMarkerPlugin::LoadConfig(const YAML::Node& node, const std::string& path)
00528 {
00529 if (node["topic"])
00530 {
00531 std::string topic;
00532 node["topic"] >> topic;
00533 ui_.topic->setText(boost::trim_copy(topic).c_str());
00534 }
00535
00536 if (node["is_marker_array"])
00537 {
00538 node["is_marker_array"] >> is_marker_array_;
00539 }
00540
00541 TopicEdited();
00542 }
00543
00544 void TexturedMarkerPlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
00545 {
00546 emitter << YAML::Key << "topic" << YAML::Value << boost::trim_copy(ui_.topic->text().toStdString());
00547 emitter << YAML::Key << "is_marker_array" << YAML::Value << is_marker_array_;
00548 }
00549 }
00550