map_canvas.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2014, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 //     * Redistributions of source code must retain the above copyright
00009 //       notice, this list of conditions and the following disclaimer.
00010 //     * Redistributions in binary form must reproduce the above copyright
00011 //       notice, this list of conditions and the following disclaimer in the
00012 //       documentation and/or other materials provided with the distribution.
00013 //     * Neither the name of Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from this software without specific prior written permission.
00016 //
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //
00028 // *****************************************************************************
00029 
00030 #include <mapviz/map_canvas.h>
00031 
00032 // C++ standard libraries
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     // Check if pixel buffers are available for asynchronous capturing
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   // Ensure the pixel size is actually 4
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   // .beginNativePainting() disables blending and clears a handful of other
00226   // values that we need to manually reset.
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   // Draw test pattern
00238   glLineWidth(3);
00239   glBegin(GL_LINES);
00240   // Red line to the right
00241   glColor3f(1, 0, 0);
00242   glVertex2f(0, 0);
00243   glVertex2f(20, 0);
00244 
00245   // Green line to the top
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     // Before we let a plugin do any drawing, push all matrices and attributes.
00255     // This helps to ensure that plugins can't accidentally mess something up
00256     // for the next plugin.
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         // Unexpected mouse button
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   // After setting the format, initializeGL will automatically be called again, then paintGL.
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   // In order for plugins drawing with a QPainter to be able to use the same coordinates
00458   // as plugins using drawing using native GL commands, we have to replicate the
00459   // GL transforms using a QTransform.  Note that a QPainter's coordinate system is
00460   // flipped on the Y axis relative to OpenGL's.
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     // If the viewer orientation is fixed don't rotate the center point.
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   // Recalculate the bounds of the view
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 }  // namespace mapviz


mapviz
Author(s): Marc Alban
autogenerated on Thu Aug 24 2017 02:45:59