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/map_canvas.h>
00031
00032
00033 #include <cmath>
00034 #include <swri_math_util/constants.h>
00035
00036 namespace mapviz
00037 {
00038 bool compare_plugins(MapvizPluginPtr a, MapvizPluginPtr b)
00039 {
00040 return a->DrawOrder() < b->DrawOrder();
00041 }
00042
00043 MapCanvas::MapCanvas(QWidget* parent) :
00044 QGLWidget(QGLFormat(QGL::SampleBuffers), parent),
00045 has_pixel_buffers_(false),
00046 pixel_buffer_size_(0),
00047 pixel_buffer_index_(0),
00048 capture_frames_(false),
00049 initialized_(false),
00050 fix_orientation_(false),
00051 rotate_90_(false),
00052 enable_antialiasing_(true),
00053 mouse_button_(Qt::NoButton),
00054 mouse_pressed_(false),
00055 mouse_x_(0),
00056 mouse_y_(0),
00057 mouse_previous_y_(0),
00058 mouse_hovering_(false),
00059 mouse_hover_x_(0),
00060 mouse_hover_y_(0),
00061 offset_x_(0),
00062 offset_y_(0),
00063 drag_x_(0),
00064 drag_y_(0),
00065 view_center_x_(0),
00066 view_center_y_(0),
00067 view_scale_(1),
00068 view_left_(-25),
00069 view_right_(25),
00070 view_top_(10),
00071 view_bottom_(-10),
00072 scene_left_(-10),
00073 scene_right_(10),
00074 scene_top_(10),
00075 scene_bottom_(-10)
00076 {
00077 ROS_INFO("View scale: %f meters/pixel", view_scale_);
00078 setMouseTracking(true);
00079
00080 transform_.setIdentity();
00081
00082 QObject::connect(&frame_rate_timer_, SIGNAL(timeout()), this, SLOT(update()));
00083 setFrameRate(50.0);
00084 frame_rate_timer_.start();
00085 }
00086
00087 MapCanvas::~MapCanvas()
00088 {
00089 if(pixel_buffer_size_ != 0)
00090 {
00091 glDeleteBuffersARB(2, pixel_buffer_ids_);
00092 }
00093 }
00094
00095 void MapCanvas::InitializeTf(boost::shared_ptr<tf::TransformListener> tf)
00096 {
00097 tf_ = tf;
00098 }
00099
00100 void MapCanvas::InitializePixelBuffers()
00101 {
00102 if(has_pixel_buffers_)
00103 {
00104 int32_t buffer_size = width() * height() * 4;
00105
00106 if (pixel_buffer_size_ != buffer_size)
00107 {
00108 if (pixel_buffer_size_ != 0)
00109 {
00110 glDeleteBuffersARB(2, pixel_buffer_ids_);
00111 }
00112
00113 glGenBuffersARB(2, pixel_buffer_ids_);
00114 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[0]);
00115 glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, buffer_size, 0, GL_STREAM_READ_ARB);
00116 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[1]);
00117 glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, buffer_size, 0, GL_STREAM_READ_ARB);
00118 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
00119
00120 pixel_buffer_size_ = buffer_size;
00121 }
00122 }
00123 }
00124
00125 void MapCanvas::initializeGL()
00126 {
00127 GLenum err = glewInit();
00128 if (GLEW_OK != err)
00129 {
00130 ROS_ERROR("Error: %s\n", glewGetErrorString(err));
00131 }
00132 else
00133 {
00134
00135 std::string extensions = (const char*)glGetString(GL_EXTENSIONS);
00136 has_pixel_buffers_ = extensions.find("GL_ARB_pixel_buffer_object") != std::string::npos;
00137 }
00138
00139 glClearColor(0.58f, 0.56f, 0.5f, 1);
00140 if (enable_antialiasing_)
00141 {
00142 glEnable(GL_MULTISAMPLE);
00143 glEnable(GL_POINT_SMOOTH);
00144 glEnable(GL_LINE_SMOOTH);
00145 glEnable(GL_POLYGON_SMOOTH);
00146 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
00147 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
00148 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
00149 }
00150 else
00151 {
00152 glDisable(GL_MULTISAMPLE);
00153 glDisable(GL_POINT_SMOOTH);
00154 glDisable(GL_LINE_SMOOTH);
00155 glDisable(GL_POLYGON_SMOOTH);
00156 }
00157 initGlBlending();
00158
00159 initialized_ = true;
00160 }
00161
00162 void MapCanvas::initGlBlending()
00163 {
00164 glEnable(GL_BLEND);
00165 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00166 glDepthFunc(GL_NEVER);
00167 glDisable(GL_DEPTH_TEST);
00168 }
00169
00170 void MapCanvas::resizeGL(int w, int h)
00171 {
00172 UpdateView();
00173 }
00174
00175 void MapCanvas::CaptureFrame(bool force)
00176 {
00177
00178 glPixelStorei(GL_PACK_ALIGNMENT, 4);
00179
00180 if (has_pixel_buffers_ && !force)
00181 {
00182 InitializePixelBuffers();
00183
00184 pixel_buffer_index_ = (pixel_buffer_index_ + 1) % 2;
00185 int32_t next_index = (pixel_buffer_index_ + 1) % 2;
00186
00187 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[pixel_buffer_index_]);
00188 glReadPixels(0, 0, width(), height(), GL_BGRA, GL_UNSIGNED_BYTE, 0);
00189 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[next_index]);
00190 GLubyte* data = reinterpret_cast<GLubyte*>(glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB));
00191 if(data)
00192 {
00193 capture_buffer_.resize(pixel_buffer_size_);
00194
00195 memcpy(&capture_buffer_[0], data, pixel_buffer_size_);
00196
00197 glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
00198 }
00199 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
00200 }
00201 else
00202 {
00203 int32_t buffer_size = width() * height() * 4;
00204 capture_buffer_.clear();
00205 capture_buffer_.resize(buffer_size);
00206
00207 glReadPixels(0, 0, width(), height(), GL_BGRA, GL_UNSIGNED_BYTE, &capture_buffer_[0]);
00208 }
00209 }
00210
00211 void MapCanvas::paintEvent(QPaintEvent* event)
00212 {
00213 if (capture_frames_)
00214 {
00215 CaptureFrame();
00216 }
00217
00218 QPainter p(this);
00219 p.setRenderHints(QPainter::Antialiasing |
00220 QPainter::TextAntialiasing |
00221 QPainter::SmoothPixmapTransform |
00222 QPainter::HighQualityAntialiasing,
00223 enable_antialiasing_);
00224 p.beginNativePainting();
00225
00226
00227 initGlBlending();
00228 glMatrixMode(GL_MODELVIEW);
00229 glPushMatrix();
00230
00231 glClearColor(bg_color_.redF(), bg_color_.greenF(), bg_color_.blueF(), 1.0f);
00232 UpdateView();
00233 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00234
00235 TransformTarget(&p);
00236
00237
00238 glLineWidth(3);
00239 glBegin(GL_LINES);
00240
00241 glColor3f(1, 0, 0);
00242 glVertex2f(0, 0);
00243 glVertex2f(20, 0);
00244
00245
00246 glColor3f(0, 1, 0);
00247 glVertex2f(0, 0);
00248 glVertex2f(0, 20);
00249 glEnd();
00250
00251 std::list<MapvizPluginPtr>::iterator it;
00252 for (it = plugins_.begin(); it != plugins_.end(); ++it)
00253 {
00254
00255
00256
00257 pushGlMatrices();
00258
00259 (*it)->DrawPlugin(view_center_x_, view_center_y_, view_scale_);
00260
00261 if ((*it)->SupportsPainting())
00262 {
00263 p.endNativePainting();
00264 (*it)->PaintPlugin(&p, view_center_x_, view_center_y_, view_scale_);
00265 p.beginNativePainting();
00266 initGlBlending();
00267 }
00268
00269 popGlMatrices();
00270 }
00271
00272 glMatrixMode(GL_MODELVIEW);
00273 glPopMatrix();
00274 p.endNativePainting();
00275 }
00276
00277 void MapCanvas::pushGlMatrices()
00278 {
00279 glMatrixMode(GL_TEXTURE);
00280 glPushMatrix();
00281 glMatrixMode(GL_PROJECTION);
00282 glPushMatrix();
00283 glMatrixMode(GL_MODELVIEW);
00284 glPushMatrix();
00285 glPushAttrib(GL_ALL_ATTRIB_BITS);
00286 }
00287
00288 void MapCanvas::popGlMatrices()
00289 {
00290 glPopAttrib();
00291 glMatrixMode(GL_MODELVIEW);
00292 glPopMatrix();
00293 glMatrixMode(GL_PROJECTION);
00294 glPopMatrix();
00295 glMatrixMode(GL_TEXTURE);
00296 glPopMatrix();
00297 }
00298
00299 void MapCanvas::wheelEvent(QWheelEvent* e)
00300 {
00301 float numDegrees = e->delta() / -8;
00302
00303 Zoom(numDegrees / 10.0);
00304 }
00305
00306 void MapCanvas::Zoom(float factor)
00307 {
00308 view_scale_ *= std::pow(1.1, factor);
00309 UpdateView();
00310 }
00311
00312 void MapCanvas::mousePressEvent(QMouseEvent* e)
00313 {
00314 mouse_x_ = e->x();
00315 mouse_y_ = e->y();
00316 mouse_previous_y_ = mouse_y_;
00317 drag_x_ = 0;
00318 drag_y_ = 0;
00319 mouse_pressed_ = true;
00320 mouse_button_ = e->button();
00321 }
00322
00323 QPointF MapCanvas::MapGlCoordToFixedFrame(const QPointF& point)
00324 {
00325 bool invertible = true;
00326 return qtransform_.inverted(&invertible).map(point);
00327 }
00328
00329 QPointF MapCanvas::FixedFrameToMapGlCoord(const QPointF& point)
00330 {
00331 return qtransform_.map(point);
00332 }
00333
00334 void MapCanvas::mouseReleaseEvent(QMouseEvent* e)
00335 {
00336 mouse_button_ = Qt::NoButton;
00337 mouse_pressed_ = false;
00338 offset_x_ += drag_x_;
00339 offset_y_ += drag_y_;
00340 drag_x_ = 0;
00341 drag_y_ = 0;
00342 }
00343
00344 void MapCanvas::mouseMoveEvent(QMouseEvent* e)
00345 {
00346 if (mouse_pressed_)
00347 {
00348 int diff;
00349 switch (mouse_button_)
00350 {
00351 case Qt::LeftButton:
00352 case Qt::MiddleButton:
00353 if (((mouse_x_ - e->x()) != 0 || (mouse_y_ - e->y()) != 0))
00354 {
00355 drag_x_ = -((mouse_x_ - e->x()) * view_scale_);
00356 drag_y_ = ((mouse_y_ - e->y()) * view_scale_);
00357 }
00358 break;
00359 case Qt::RightButton:
00360 diff = e->y() - mouse_previous_y_;
00361 if (diff != 0)
00362 {
00363 Zoom(((float)diff) / 10.0f);
00364 }
00365 mouse_previous_y_ = e->y();
00366 break;
00367 default:
00368
00369 break;
00370 }
00371 }
00372
00373 double center_x = -offset_x_ - drag_x_;
00374 double center_y = -offset_y_ - drag_y_;
00375 double x = center_x + (e->x() - width() / 2.0) * view_scale_;
00376 double y = center_y + (height() / 2.0 - e->y()) * view_scale_;
00377
00378 tf::Point point(x, y, 0);
00379 point = transform_ * point;
00380
00381 mouse_hovering_ = true;
00382 mouse_hover_x_ = e->x();
00383 mouse_hover_y_ = e->y();
00384
00385 Q_EMIT Hover(point.x(), point.y(), view_scale_);
00386 }
00387
00388 void MapCanvas::leaveEvent(QEvent* e)
00389 {
00390 mouse_hovering_ = false;
00391 Q_EMIT Hover(0, 0, 0);
00392 }
00393
00394 void MapCanvas::SetFixedFrame(const std::string& frame)
00395 {
00396 fixed_frame_ = frame;
00397 std::list<MapvizPluginPtr>::iterator it;
00398 for (it = plugins_.begin(); it != plugins_.end(); ++it)
00399 {
00400 (*it)->SetTargetFrame(frame);
00401 }
00402 }
00403
00404 void MapCanvas::SetTargetFrame(const std::string& frame)
00405 {
00406 offset_x_ = 0;
00407 offset_y_ = 0;
00408 drag_x_ = 0;
00409 drag_y_ = 0;
00410
00411 target_frame_ = frame;
00412 }
00413
00414 void MapCanvas::ToggleFixOrientation(bool on)
00415 {
00416 fix_orientation_ = on;
00417 }
00418
00419 void MapCanvas::ToggleRotate90(bool on)
00420 {
00421 rotate_90_ = on;
00422 }
00423
00424 void MapCanvas::ToggleEnableAntialiasing(bool on)
00425 {
00426 enable_antialiasing_ = on;
00427 QGLFormat format;
00428 format.setSwapInterval(1);
00429 format.setSampleBuffers(enable_antialiasing_);
00430
00431 this->setFormat(format);
00432 }
00433
00434 void MapCanvas::ToggleUseLatestTransforms(bool on)
00435 {
00436 std::list<MapvizPluginPtr>::iterator it;
00437 for (it = plugins_.begin(); it != plugins_.end(); ++it)
00438 {
00439 (*it)->SetUseLatestTransforms(on);
00440 }
00441 }
00442
00443 void MapCanvas::AddPlugin(MapvizPluginPtr plugin, int order)
00444 {
00445 plugins_.push_back(plugin);
00446 }
00447
00448 void MapCanvas::RemovePlugin(MapvizPluginPtr plugin)
00449 {
00450 plugin->Shutdown();
00451 plugins_.remove(plugin);
00452 }
00453
00454 void MapCanvas::TransformTarget(QPainter* painter)
00455 {
00456 glTranslatef(offset_x_ + drag_x_, offset_y_ + drag_y_, 0);
00457
00458
00459
00460
00461 qtransform_ = qtransform_.translate(offset_x_ + drag_x_, -(offset_y_ + drag_y_));
00462
00463 view_center_x_ = -offset_x_ - drag_x_;
00464 view_center_y_ = -offset_y_ - drag_y_;
00465
00466 if (!tf_ || fixed_frame_.empty() || target_frame_.empty() || target_frame_ == "<none>")
00467 {
00468 qtransform_ = qtransform_.scale(1, -1);
00469 painter->setWorldTransform(qtransform_, false);
00470
00471 return;
00472 }
00473
00474 bool success = false;
00475
00476 try
00477 {
00478 tf_->lookupTransform(fixed_frame_, target_frame_, ros::Time(0), transform_);
00479
00480
00481 if (fix_orientation_)
00482 {
00483 transform_.setRotation(tf::Transform::getIdentity().getRotation());
00484 }
00485
00486 if (rotate_90_)
00487 {
00488 transform_.setRotation(
00489 tf::createQuaternionFromYaw(-swri_math_util::_half_pi) * transform_.getRotation());
00490 }
00491
00492 double roll, pitch, yaw;
00493 transform_.getBasis().getRPY(roll, pitch, yaw);
00494
00495 glRotatef(-yaw * 57.2957795, 0, 0, 1);
00496 qtransform_ = qtransform_.rotateRadians(yaw);
00497
00498 glTranslatef(-transform_.getOrigin().getX(), -transform_.getOrigin().getY(), 0);
00499 qtransform_ = qtransform_.translate(-transform_.getOrigin().getX(), transform_.getOrigin().getY());
00500
00501 tf::Point point(view_center_x_, view_center_y_, 0);
00502
00503 tf::Point center = transform_ * point;
00504
00505 view_center_x_ = center.getX();
00506 view_center_y_ = center.getY();
00507
00508 qtransform_ = qtransform_.scale(1, -1);
00509 painter->setWorldTransform(qtransform_, false);
00510
00511 if (mouse_hovering_)
00512 {
00513 double center_x = -offset_x_ - drag_x_;
00514 double center_y = -offset_y_ - drag_y_;
00515 double x = center_x + (mouse_hover_x_ - width() / 2.0) * view_scale_;
00516 double y = center_y + (height() / 2.0 - mouse_hover_y_) * view_scale_;
00517
00518 tf::Point hover(x, y, 0);
00519 hover = transform_ * hover;
00520
00521 Q_EMIT Hover(hover.x(), hover.y(), view_scale_);
00522 }
00523
00524 success = true;
00525 }
00526 catch (const tf::LookupException& e)
00527 {
00528 ROS_ERROR_THROTTLE(2.0, "%s", e.what());
00529 }
00530 catch (const tf::ConnectivityException& e)
00531 {
00532 ROS_ERROR_THROTTLE(2.0, "%s", e.what());
00533 }
00534 catch (const tf::ExtrapolationException& e)
00535 {
00536 ROS_ERROR_THROTTLE(2.0, "%s", e.what());
00537 }
00538 catch (...)
00539 {
00540 ROS_ERROR_THROTTLE(2.0, "Error looking up transform");
00541 }
00542
00543 if (!success)
00544 {
00545 qtransform_ = qtransform_.scale(1, -1);
00546 painter->setWorldTransform(qtransform_, false);
00547 }
00548 }
00549
00550 void MapCanvas::UpdateView()
00551 {
00552 if (initialized_)
00553 {
00554 Recenter();
00555
00556 glViewport(0, 0, width(), height());
00557 glMatrixMode(GL_PROJECTION);
00558 glLoadIdentity();
00559 glOrtho(view_left_, view_right_, view_top_, view_bottom_, -0.5f, 0.5f);
00560
00561 qtransform_ = QTransform::fromTranslate(width() / 2.0, height() / 2.0).
00562 scale(1.0 / view_scale_, 1.0 / view_scale_);
00563 }
00564 }
00565
00566 void MapCanvas::ResetLocation()
00567 {
00568 SetTargetFrame(target_frame_);
00569 SetViewScale(1.0);
00570 }
00571
00572 void MapCanvas::ReorderDisplays()
00573 {
00574 plugins_.sort(compare_plugins);
00575 }
00576
00577 void MapCanvas::Recenter()
00578 {
00579
00580 view_left_ = -(width() * view_scale_ * 0.5);
00581 view_top_ = -(height() * view_scale_ * 0.5);
00582 view_right_ = (width() * view_scale_ * 0.5);
00583 view_bottom_ = (height() * view_scale_ * 0.5);
00584 }
00585
00586 void MapCanvas::setFrameRate(const double fps)
00587 {
00588 if (fps <= 0.0) {
00589 ROS_ERROR("Invalid frame rate: %f", fps);
00590 return;
00591 }
00592
00593 frame_rate_timer_.setInterval(1000.0/fps);
00594 }
00595
00596 double MapCanvas::frameRate() const
00597 {
00598 return 1000.0 / frame_rate_timer_.interval();
00599 }
00600 }