glviewer.cpp
Go to the documentation of this file.
00001 /* This file is part of RGBDSLAM.
00002  * 
00003  * RGBDSLAM is free software: you can redistribute it and/or modify
00004  * it under the terms of the GNU General Public License as published by
00005  * the Free Software Foundation, either version 3 of the License, or
00006  * (at your option) any later version.
00007  * 
00008  * RGBDSLAM is distributed in the hope that it will be useful,
00009  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  * GNU General Public License for more details.
00012  * 
00013  * You should have received a copy of the GNU General Public License
00014  * along with RGBDSLAM.  If not, see <http://www.gnu.org/licenses/>.
00015  */
00016 
00017 
00018 #include "ros/ros.h"
00019 #include <QtGui>
00020 #include <QtOpenGL>
00021 #include <QThread>
00022 #include <GL/gl.h>
00023 #include <GL/glut.h>
00024 #include "boost/foreach.hpp"
00025 #include <cmath>
00026 #ifdef GL2PS
00027 #include <gl2ps.h>
00028 #endif
00029 #include "glviewer.h"
00030 
00031 #ifndef GL_MULTISAMPLE
00032 #define GL_MULTISAMPLE  0x809D
00033 #endif
00034 
00035 const double PI= 3.14159265358979323846;
00036 
00037 template <typename PointType>
00038 inline bool validXYZ(const PointType& p){
00039       return std::isfinite(p.x) && std::isfinite(p.y) && std::isfinite(p.z);
00040 };
00041 
00042 GLViewer::GLViewer(QWidget *parent)
00043     : QGLWidget(QGLFormat(QGL::SampleBuffers|QGL::StereoBuffers), parent),
00044       xRot(180*16.0),
00045       yRot(0),
00046       zRot(0),
00047       xTra(0),
00048       yTra(0),
00049       zTra(-50),//go back 50 (pixels?)
00050       polygon_mode(GL_FILL),
00051       cloud_list_indices(),
00052       edge_list_(NULL),
00053       cloud_matrices(new QList<QMatrix4x4>()),
00054       show_poses_(ParameterServer::instance()->get<bool>("show_axis")),
00055       show_ids_(false), //more or less for debuging
00056       show_edges_(ParameterServer::instance()->get<bool>("show_axis")),
00057       show_clouds_(true),
00058       follow_mode_(true),
00059       stereo_(false),
00060       width_(0),
00061       height_(0),
00062       stereo_shift_(0.1),
00063       fov_(100.0/180.0*PI),
00064       rotation_stepping_(1.0)
00065 {
00066     bg_col_[0] = bg_col_[1] = bg_col_[2] = bg_col_[3] = 0.0;//black background
00067     ROS_DEBUG_COND(!this->format().stereo(), "Stereo not supported");
00068     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //can make good use of more space
00069     viewpoint_tf_.setToIdentity();
00070 }
00071 
00072 GLViewer::~GLViewer() { }
00073 
00074 QSize GLViewer::minimumSizeHint() const {
00075     return QSize(400, 400);
00076 }
00077 
00078 QSize GLViewer::sizeHint() const {
00079     return QSize(640, 480);
00080 }
00081 
00082 static void qNormalizeAngle(int &angle) {
00083     while (angle < 0)
00084         angle += 360 * 16;
00085     while (angle > 360 * 16)
00086         angle -= 360 * 16;
00087 }
00088 
00089 void GLViewer::setXRotation(int angle) { 
00090     qNormalizeAngle(angle);
00091     if (angle != xRot) {
00092         xRot = angle;
00093         updateGL();
00094     }
00095 }
00096 
00097 
00098 void GLViewer::setYRotation(int angle) {
00099     qNormalizeAngle(angle);
00100     if (angle != yRot) {
00101         yRot = angle;
00102         updateGL();
00103     }
00104 }
00105 
00106 void GLViewer::setRotationGrid(double rot_step_in_degree) {
00107   rotation_stepping_ = rot_step_in_degree;
00108 }
00109 
00110 void GLViewer::setStereoShift(double shift) {
00111   stereo_shift_ = shift;
00112   updateGL();
00113 }
00114 
00115 void GLViewer::setZRotation(int angle) {
00116     qNormalizeAngle(angle);
00117     if (angle != zRot) {
00118         zRot = angle;
00119         updateGL();
00120     }
00121 }
00122 
00123 void GLViewer::initializeGL() {
00124     glClearColor(bg_col_[0],bg_col_[1],bg_col_[2],bg_col_[3]); 
00125     glEnable (GL_BLEND); 
00126     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00127     glEnable(GL_DEPTH_TEST);
00128     glEnable(GL_CULL_FACE);
00129     glEnable(GL_LINE_SMOOTH);
00130     //glShadeModel(GL_SMOOTH);
00131     //glEnable(GL_LIGHTING);
00132     //glEnable(GL_LIGHT0);
00133     //glEnable(GL_MULTISAMPLE);
00134     //gluPerspective(fov_, 1.00, 0.01, 1e9); //1.38 = tan(57/2°)/tan(43/2°)
00136     //static GLfloat lightPosition[4] = { 0.5, 5.0, 7.0, 1.0 };
00137     //glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
00138 }
00139 //assumes gl mode for triangles
00140 inline
00141 void GLViewer::drawTriangle(const point_type& p1, const point_type& p2, const point_type& p3){
00142     unsigned char b,g,r;
00143     b = *(  (unsigned char*)(&p1.rgb));
00144     g = *(1+(unsigned char*)(&p1.rgb));
00145     r = *(2+(unsigned char*)(&p1.rgb));
00146     glColor3ub(r,g,b); //glColor3f(1.0,1.0,1.0);
00147     glColor3ub(255,0,0); 
00148     glVertex3f(p1.x, p1.y, p1.z);
00149 
00150     b = *(  (unsigned char*)(&p2.rgb));
00151     g = *(1+(unsigned char*)(&p2.rgb));
00152     r = *(2+(unsigned char*)(&p2.rgb));
00153     glColor3ub(r,g,b); //glColor3f(1.0,1.0,1.0);
00154     glColor3ub(0,255,0); 
00155     glVertex3f(p2.x, p2.y, p2.z);
00156 
00157     b = *(  (unsigned char*)(&p3.rgb));
00158     g = *(1+(unsigned char*)(&p3.rgb));
00159     r = *(2+(unsigned char*)(&p3.rgb));
00160     //glColor3ub(r,g,b); //glColor3f(1.0,1.0,1.0);
00161     glColor3ub(0,0,255); 
00162     glVertex3f(p3.x, p3.y, p3.z);
00163 }
00164 
00165 void GLViewer::drawAxis(float scale){
00166     glBegin(GL_LINES);
00167     glLineWidth(4);
00168     glColor4f (0.9, 0, 0, 1.0);
00169     glVertex3f(0, 0, 0);
00170     glColor4f (0.9, 0, 0, 0.0);
00171     glVertex3f(scale, 0, 0);
00172     glColor4f (0, 0.9, 0, 1.0);
00173     glVertex3f(0, 0, 0);
00174     glColor4f (0, 0.9, 0, 0.0);
00175     glVertex3f(0, scale, 0);
00176     glColor4f (0, 0, 0.9, 1.0);
00177     glVertex3f(0, 0, 0);
00178     glColor4f (0, 0, 0.9, 0.0);
00179     glVertex3f(0, 0, scale);
00180     glEnd();
00181 }
00182 
00183 void GLViewer::paintGL() {
00184     if(!this->isVisible()) return;
00185     //ROS_INFO("This is paint-thread %d", (unsigned int)QThread::currentThreadId());
00186     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00187     if(stereo_){
00188         float ratio = (float)(width_) / (float) height_;
00189         glViewport(0, 0, width_/2, height_);
00190         glMatrixMode(GL_PROJECTION);
00191         glLoadIdentity();
00192         gluPerspective(fov_, ratio, 0.1, 1e4); 
00193         glMatrixMode(GL_MODELVIEW);
00194         drawClouds(stereo_shift_);
00195 
00196         glViewport(width_/2, 0, width_/2, height_);
00197         glMatrixMode(GL_PROJECTION);
00198         glLoadIdentity();
00199         gluPerspective(fov_, ratio, 0.1, 1e4); 
00200         glMatrixMode(GL_MODELVIEW);
00201     }
00202     drawClouds(0.0);
00203 }
00204 
00205 void GLViewer::drawClouds(float xshift) {
00206     if(follow_mode_){
00207         int id = cloud_matrices->size()-1;
00208         if(id >= 0)setViewPoint((*cloud_matrices)[id]);
00209     }
00210     glLoadIdentity();
00211     //Camera transformation
00212     glTranslatef(xTra+xshift, yTra, zTra);
00213     int x_steps = (xRot / 16.0)/rotation_stepping_;
00214     int y_steps = (yRot / 16.0)/rotation_stepping_;
00215     int z_steps = (zRot / 16.0)/rotation_stepping_;
00216     glRotatef(x_steps*rotation_stepping_, 1.0, 0.0, 0.0);
00217     glRotatef(y_steps*rotation_stepping_, 0.0, 1.0, 0.0);
00218     glRotatef(z_steps*rotation_stepping_, 0.0, 0.0, 1.0);
00219     glMultMatrixd(static_cast<GLdouble*>( viewpoint_tf_.data() ));//works as long as qreal and GLdouble are typedefs to double (might depend on hardware)
00220     ROS_DEBUG("Drawing %i PointClouds", cloud_list_indices.size());
00221     for(int i = 0; i<cloud_list_indices.size() && i<cloud_matrices->size(); i++){
00222         //GLdouble* entry = static_cast<GLdouble*>( cloud_matrices[i].data() );
00223         //for(int j = 0; j < 16; j++, entry++){
00224         //    ROS_INFO("Matrix[%d]: %f", j, *entry);
00225         //}
00226         glPushMatrix();
00227         glMultMatrixd(static_cast<GLdouble*>( (*cloud_matrices)[i].data() ));//works as long as qreal and GLdouble are typedefs to double (might depend on hardware)
00228         if(show_clouds_) glCallList(cloud_list_indices[i]);
00229         if(show_poses_) drawAxis(0.075);
00230         if(show_ids_) {
00231           glColor4f(1-bg_col_[0],1-bg_col_[1],1-bg_col_[2],1.0); //inverse of bg color, but transp
00232           this->renderText(0.,0.,0.,QString::number(i));
00233         }
00234         glPopMatrix();
00235     }
00236     if(show_poses_) drawAxis(0.2);//Show origin as big axis
00237     if(show_edges_) drawEdges();
00238 }
00239 
00240 void GLViewer::resizeGL(int width, int height)
00241 {
00242     width_ = width;
00243     height_ = height;
00244     //int side = qMin(width, height);
00245     glViewport(0, 0, width, height);
00246     //glViewport((width - side) / 2, (height - side) / 2, side, side);
00247 
00248     glMatrixMode(GL_PROJECTION);
00249     glLoadIdentity();
00250 //#ifdef QT_OPENGL_ES_1
00251 //    glOrthof(-0.5, +0.5, -0.5, +0.5, 1.0, 15.0);
00252 //#else
00253 //    glOrtho(-0.5, +0.5, -0.5, +0.5, 1.0, 15.0);
00254 //#endif
00255     //gluPerspective(fov_, 1.38, 0.01, 1e9); //1.38 = tan(57/2°)/tan(43/2°) as kinect has viewing angles 57 and 43
00256     float ratio = (float)width / (float) height;
00257     gluPerspective(fov_, ratio, 0.1, 1e4); 
00258     glMatrixMode(GL_MODELVIEW);
00259 }
00260 
00261 void GLViewer::mouseDoubleClickEvent(QMouseEvent *event) {
00262     xRot=180*16.0;
00263     yRot=0;
00264     zRot=0;
00265     xTra=0;
00266     yTra=0;
00267     if(cloud_matrices->size()>0){
00268       if(!setClickedPosition(event->x(), event->y())){
00269         if (event->buttons() & Qt::LeftButton) {
00270           int id = cloud_matrices->size()-1;
00271           setViewPoint((*cloud_matrices)[id]);
00272         } else if (event->buttons() & Qt::RightButton) {
00273           int id = 0;
00274           setViewPoint((*cloud_matrices)[id]);
00275         } else if (event->buttons() & Qt::MidButton) { 
00276           viewpoint_tf_.setToIdentity();
00277           zTra=-50;
00278         }
00279       }
00280     }
00281     updateGL();
00282 }
00283 void GLViewer::toggleStereo(bool flag){
00284   stereo_ = flag;
00285   resizeGL(width_, height_);
00286   updateGL();
00287 }
00288 void GLViewer::toggleBackgroundColor(bool flag){
00289   if(flag){
00290     bg_col_[0] = bg_col_[1] = bg_col_[2] = bg_col_[3] = 0.0;//black background
00291   }
00292   else{
00293     bg_col_[0] = bg_col_[1] = bg_col_[2] = 1.0;//white background
00294   }
00295   glClearColor(bg_col_[0],bg_col_[1],bg_col_[2],bg_col_[3]); 
00296   updateGL();
00297 }
00298 void GLViewer::toggleShowClouds(bool flag){
00299   show_clouds_ = flag;
00300   updateGL();
00301 }
00302 void GLViewer::toggleShowIDs(bool flag){
00303   show_ids_ = flag;
00304   updateGL();
00305 }
00306 void GLViewer::toggleShowEdges(bool flag){
00307   show_edges_ = flag;
00308   updateGL();
00309 }
00310 void GLViewer::toggleShowPoses(bool flag){
00311   show_poses_ = flag;
00312   updateGL();
00313 }
00314 void GLViewer::toggleFollowMode(bool flag){
00315   follow_mode_ = flag;
00316 }
00317 void GLViewer::mousePressEvent(QMouseEvent *event) {
00318     lastPos = event->pos();
00319 }
00320 
00321 void GLViewer::wheelEvent(QWheelEvent *event) {
00322     zTra += ((float)event->delta())/25.0; 
00323     updateGL();
00324 }
00325 void GLViewer::mouseMoveEvent(QMouseEvent *event) {//TODO: consolidate setRotation methods
00326     int dx = event->x() - lastPos.x();
00327     int dy = event->y() - lastPos.y();
00328 
00329     if (event->buttons() & Qt::LeftButton) {
00330         setXRotation(xRot - 8 * dy);
00331         setYRotation(yRot + 8 * dx);
00332     } else if (event->buttons() & Qt::RightButton) {
00333         setXRotation(xRot - 8 * dy);
00334         setZRotation(zRot + 8 * dx);
00335     } else if (event->buttons() & Qt::MidButton) {
00336         xTra += dx/200.0;
00337         yTra -= dy/200.0;
00338         updateGL();
00339     }
00340     lastPos = event->pos();
00341 }
00342 
00343 void GLViewer::updateTransforms(QList<QMatrix4x4>* transforms){
00344     ROS_WARN_COND(transforms->size() < cloud_matrices->size(), "Got less transforms than before!");
00345     // This doesn't deep copy, but should work, as qlist maintains a reference count 
00346     delete cloud_matrices;
00347     cloud_matrices = transforms; 
00348     ROS_DEBUG("New Cloud matrices size: %d", cloud_matrices->size());
00349     updateGL();
00350 }
00351 
00352 void GLViewer::addPointCloud(pointcloud_type * pc, QMatrix4x4 transform){
00353     ROS_DEBUG("pc pointer in addPointCloud: %p (this is %p in thread %d)", pc, this, (unsigned int)QThread::currentThreadId());
00354     pointCloud2GLStrip(pc);
00355     cloud_matrices->push_back(transform); //keep for later
00356     updateGL();
00357 }
00358 
00359 void GLViewer::pointCloud2GLStrip(pointcloud_type * pc){
00360     struct timespec starttime, finish; double elapsed; clock_gettime(CLOCK_MONOTONIC, &starttime);
00361     ROS_DEBUG("Making GL list from point-cloud pointer %p in thread %d", pc, (unsigned int)QThread::currentThreadId());
00362     GLuint cloud_list_index = glGenLists(1);
00363     if(!cloud_list_index) {
00364         ROS_ERROR("No display list could be created");
00365         return;
00366     }
00367     float mesh_thresh = ParameterServer::instance()->get<double>("squared_meshing_threshold");
00368     glNewList(cloud_list_index, GL_COMPILE);
00369     cloud_list_indices.push_back(cloud_list_index);
00370     //ROS_INFO_COND(!pc->is_dense, "Expected dense cloud for opengl drawing");
00371     point_type origin;
00372     origin.x = 0;
00373     origin.y = 0;
00374     origin.z = 0;
00375 
00376     float depth;
00377     bool strip_on = false, flip = false; //if flip is true, first the lower then the upper is inserted
00378     const int w=pc->width, h=pc->height;
00379     unsigned char b,g,r;
00380     const int step = ParameterServer::instance()->get<int>("visualization_skip_step");
00381     for( int y = 0; y < h-step; y+=step){ //go through every point and make two triangles 
00382         for( int x = 0; x < w-step; x+=step){//for it and its neighbours right and/or down
00383             using namespace pcl;
00384             if(!strip_on){ //Generate vertices for new triangle
00385                 const point_type* ll = &pc->points[(x)+(y+step)*w]; //one down (lower left corner)
00386                 if(!validXYZ(*ll)) continue; // both new triangles in this step would use this point
00387                 const point_type* ur = &pc->points[(x+step)+y*w]; //one right (upper right corner)
00388                 if(!validXYZ(*ur)) continue; // both new triangles in this step would use this point
00389           
00390                 const point_type* ul = &pc->points[x+y*w]; //current point (upper right)
00391                 if(validXYZ(*ul)){ //ul, ur, ll all valid
00392                   depth = squaredEuclideanDistance(*ul,origin);
00393                   if (squaredEuclideanDistance(*ul,*ll)/depth <= mesh_thresh  and 
00394                       squaredEuclideanDistance(*ul,*ll)/depth <= mesh_thresh  and
00395                       squaredEuclideanDistance(*ur,*ll)/depth <= mesh_thresh){
00396                     glBegin(GL_TRIANGLE_STRIP);
00397                     strip_on = true;
00398                     flip = false; //correct order, upper first
00399                     //Prepare the first two vertices of a triangle strip
00400                     //drawTriangle(*ul, *ll, *ur);
00401                     b = *(  (unsigned char*)(&ul->rgb));
00402                     g = *(1+(unsigned char*)(&ul->rgb));
00403                     r = *(2+(unsigned char*)(&ul->rgb));
00404                     glColor3ub(r,g,b);
00405 
00406                     //glColor3ub(255,0,0);
00407                     glVertex3f(ul->x, ul->y, ul->z);
00408                   }
00409                 } 
00410                 if(!strip_on) { //can't use the point on the upper left, should I still init a triangle?
00411                   const point_type* lr = &pc->points[(x+step)+(y+step)*w]; //one right-down (lower right)
00412                   if(!validXYZ(*lr)) {
00413                     //if this is not valid, there is no way to make a new triangle in the next step
00414                     //and one could have been drawn starting in this step, only if ul had been valid
00415                     x++;
00416                     continue;
00417                   } else { //at least one can be started at the lower left
00418                     depth = squaredEuclideanDistance(*ur,origin);
00419                     if (squaredEuclideanDistance(*ur,*ll)/depth <= mesh_thresh  and 
00420                         squaredEuclideanDistance(*lr,*ll)/depth <= mesh_thresh  and
00421                         squaredEuclideanDistance(*ur,*lr)/depth <= mesh_thresh){
00422                       glBegin(GL_TRIANGLE_STRIP);
00423                       strip_on = true;
00424                       flip = true; //but the lower has to be inserted first, for correct order
00425                     }
00426                   }
00427                 }
00428                 if(strip_on) { //Be this the second or the first vertex, insert it
00429                   b = *(  (unsigned char*)(&ll->rgb));
00430                   g = *(1+(unsigned char*)(&ll->rgb));
00431                   r = *(2+(unsigned char*)(&ll->rgb));
00432                   glColor3ub(r,g,b);
00433 
00434                   //glColor3ub(0,255,0);
00435                   glVertex3f(ll->x, ll->y, ll->z);
00436                 }
00437                 continue; //not relevant but demonstrate that nothing else is done in this iteration
00438             } // end strip was off
00439             else 
00440             {//neighbours to the left and left down are already set
00441               const point_type* ul;
00442               if(flip){ ul = &pc->points[(x)+(y+step)*w]; } //one down (lower left corner) 
00443               else { ul = &pc->points[x+y*w]; } //current point (upper right)
00444               if(validXYZ(*ul)){ //Neighbours to the left are prepared
00445                 depth = squaredEuclideanDistance(*ul,origin);
00446                 if (squaredEuclideanDistance(*ul,*(ul-step))/depth > mesh_thresh){
00447                   glEnd();
00448                   strip_on = false;
00449                   continue;
00450                 }
00451                 //Complete the triangle with both leftern neighbors
00452                 //drawTriangle(*ul, *ll, *ur);
00453                 b = *(  (unsigned char*)(&ul->rgb));
00454                 g = *(1+(unsigned char*)(&ul->rgb));
00455                 r = *(2+(unsigned char*)(&ul->rgb));
00456                 glColor3ub(r,g,b);
00457 
00458                 //glColor3ub(255,0,0);
00459                 glVertex3f(ul->x, ul->y, ul->z);
00460               } else {
00461                 glEnd();
00462                 strip_on = false;
00463                 continue; //TODO: Could restart with next point instead
00464               }
00465               //The following point connects one to the left with the other on this horizontal level
00466               const point_type* ll;
00467               if(flip){ ll = &pc->points[x+y*w]; } //current point (upper right)
00468               else { ll = &pc->points[(x)+(y+step)*w]; } //one down (lower left corner) 
00469               if(validXYZ(*ll)){ 
00470                 depth = squaredEuclideanDistance(*ll,origin);
00471                 if (squaredEuclideanDistance(*ul,*ll)/depth > mesh_thresh or
00472                     squaredEuclideanDistance(*ul,*(ul-step))/depth > mesh_thresh or
00473                     squaredEuclideanDistance(*ll,*(ll-step))/depth > mesh_thresh){
00474                   glEnd();
00475                   strip_on = false;
00476                   continue;
00477                 }
00478                 b = *(  (unsigned char*)(&ll->rgb));
00479                 g = *(1+(unsigned char*)(&ll->rgb));
00480                 r = *(2+(unsigned char*)(&ll->rgb));
00481                 glColor3ub(r,g,b);
00482 
00483                 glVertex3f(ll->x, ll->y, ll->z);
00484               } else {
00485                 glEnd();
00486                 strip_on = false;
00487                 continue;
00488               }
00489             }//completed triangles if strip is running
00490         }
00491         if(strip_on) glEnd();
00492         strip_on = false;
00493     }
00494     ROS_DEBUG("Compiled pointcloud into list %i",  cloud_list_index);
00495     glEndList();
00496     //pointcloud_type pc_empty;
00497     //pc_empty.points.swap(pc->points);
00498     //pc->width = 0;
00499     //pc->height = 0;
00500     Q_EMIT cloudRendered(pc);
00501     clock_gettime(CLOCK_MONOTONIC, &finish); elapsed = (finish.tv_sec - starttime.tv_sec); elapsed += (finish.tv_nsec - starttime.tv_nsec) / 1000000000.0; ROS_INFO_STREAM_COND_NAMED(elapsed > ParameterServer::instance()->get<double>("min_time_reported"), "timings", __FUNCTION__ << " runtime: "<< elapsed <<" s");
00502 }
00503 
00504 void GLViewer::deleteLastNode(){
00505   if(cloud_list_indices.size() <= 1){
00506     this->reset();
00507     return;
00508   }
00509         GLuint nodeId = cloud_list_indices.back();
00510         cloud_list_indices.pop_back();
00511         glDeleteLists(nodeId,1);
00512 }
00513 
00514 void GLViewer::pointCloud2GLList(pointcloud_type const * pc){
00515     struct timespec starttime, finish; double elapsed; clock_gettime(CLOCK_MONOTONIC, &starttime);
00516     ROS_DEBUG("Making GL list from point-cloud pointer %p in thread %d", pc, (unsigned int)QThread::currentThreadId());
00517     GLuint cloud_list_index = glGenLists(1);
00518     if(!cloud_list_index) {
00519         ROS_ERROR("No display list could be created");
00520         return;
00521     }
00522     float mesh_thresh = ParameterServer::instance()->get<double>("squared_meshing_threshold");
00523     cloud_list_indices.push_back(cloud_list_index);
00524     glNewList(cloud_list_index, GL_COMPILE);
00525     glBegin(GL_TRIANGLES);
00526     //ROS_INFO_COND(!pc->is_dense, "Expected dense cloud for opengl drawing");
00527     point_type origin;
00528     origin.x = 0;
00529     origin.y = 0;
00530     origin.z = 0;
00531 
00532     float depth;
00533     unsigned int w=pc->width, h=pc->height;
00534     for(unsigned int x = 0; x < w-1; x++){
00535         for(unsigned int y = 0; y < h-1; y++){
00536             using namespace pcl;
00537 
00538             const point_type* pi = &pc->points[x+y*w]; //current point
00539 
00540             if(!(validXYZ(*pi))) continue;
00541             depth = squaredEuclideanDistance(*pi,origin);
00542 
00543             const point_type* pl = &pc->points[(x+1)+(y+1)*w]; //one right-down
00544             if(!(validXYZ(*pl)) or squaredEuclideanDistance(*pi,*pl)/depth > mesh_thresh)  
00545               continue;
00546 
00547             const point_type* pj = &pc->points[(x+1)+y*w]; //one right
00548             if(validXYZ(*pj)
00549                and squaredEuclideanDistance(*pi,*pj)/depth <= mesh_thresh  
00550                and squaredEuclideanDistance(*pj,*pl)/depth <= mesh_thresh){
00551               drawTriangle(*pi, *pj, *pl);
00552             }
00553             const point_type* pk = &pc->points[(x)+(y+1)*w]; //one down
00554             
00555             if(validXYZ(*pk)
00556                and squaredEuclideanDistance(*pi,*pk)/depth <= mesh_thresh  
00557                and squaredEuclideanDistance(*pk,*pl)/depth <= mesh_thresh){
00558               drawTriangle(*pi, *pk, *pl);
00559             }
00560         }
00561     }
00562     glEnd();
00563     ROS_DEBUG("Compiled pointcloud into list %i",  cloud_list_index);
00564     glEndList();
00565     clock_gettime(CLOCK_MONOTONIC, &finish); elapsed = (finish.tv_sec - starttime.tv_sec); elapsed += (finish.tv_nsec - starttime.tv_nsec) / 1000000000.0; ROS_INFO_STREAM_COND_NAMED(elapsed > ParameterServer::instance()->get<double>("min_time_reported"), "timings", __FUNCTION__ << " runtime: "<< elapsed <<" s");
00566 }
00567 
00568 void GLViewer::reset(){
00569     glDeleteLists(1,cloud_list_indices.back());
00570     cloud_list_indices.clear();
00571     cloud_matrices->clear();
00572     if(edge_list_) {
00573       delete edge_list_;
00574       edge_list_ = NULL;
00575     }
00576     updateGL();
00577 }
00578 QImage GLViewer::renderList(QMatrix4x4 transform, int list_id){
00579     return QImage();
00580 }
00581 
00582 void GLViewer::setEdges(QList<QPair<int, int> >* edge_list){
00583   if(edge_list_) delete edge_list_;
00584   edge_list_ = edge_list;
00585 }
00586 
00587 void GLViewer::drawEdges(){
00588   if(edge_list_ == NULL) return;
00589   glBegin(GL_LINES);
00590   glLineWidth(12);
00591   for(int i = 0; i < edge_list_->size(); i++){
00592     int id1 = (*edge_list_)[i].first;
00593     int id2 = (*edge_list_)[i].second;
00594     float x,y,z;
00595     if(cloud_matrices->size() > id1 && cloud_matrices->size() > id2){//only happens in weird circumstances
00596       if(abs(id1 - id2) == 1){//consecutive
00597         glColor4f(bg_col_[0],1-bg_col_[1],1-bg_col_[2],1.0); //cyan on black, red on white
00598       } else if(abs(id1 - id2) > 20){//consider a loop closure
00599         glColor4f(1-bg_col_[0],1-bg_col_[1],bg_col_[2],0.4); //orange on black, blue on black, transp
00600       } else { //near predecessor
00601         glColor4f(1-bg_col_[0],1-bg_col_[1],1-bg_col_[2],0.4); //inverse of bg color, but transp
00602       }
00603       x = (*cloud_matrices)[id1](0,3);
00604       y = (*cloud_matrices)[id1](1,3);
00605       z = (*cloud_matrices)[id1](2,3);
00606       glVertex3f(x,y,z);
00607       x = (*cloud_matrices)[id2](0,3);
00608       y = (*cloud_matrices)[id2](1,3);
00609       z = (*cloud_matrices)[id2](2,3);
00610       glVertex3f(x,y,z);
00611     }
00612     else ROS_ERROR("Not enough cloud matrices (%d) for vertex ids (%d and %d)", cloud_matrices->size(), id1, id2);
00613   }
00614   glEnd();
00615 }
00616 
00617 
00618 void GLViewer::setViewPoint(QMatrix4x4 new_vp){
00620     viewpoint_tf_ = new_vp.inverted();
00621 }
00622 
00623 bool GLViewer::setClickedPosition(int x, int y) {
00624     GLint viewport[4];
00625     GLdouble modelview[16];
00626     GLdouble projection[16];
00627     GLfloat winX, winY, winZ;
00628     GLdouble posX, posY, posZ;
00629 
00630     glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
00631     glGetDoublev( GL_PROJECTION_MATRIX, projection );
00632     glGetIntegerv( GL_VIEWPORT, viewport );
00633 
00634     winX = (float)x;
00635     winY = (float)viewport[3] - (float)y;
00636     glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
00637     if(winZ != 1){ //default value, where nothing was rendered
00638       gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
00639       ROS_INFO_STREAM((float)winZ << ", " << posX << "," << posY << "," << posZ);
00640       viewpoint_tf_(0,3) = -posX;
00641       viewpoint_tf_(1,3) = -posY;
00642       viewpoint_tf_(2,3) = -posZ;
00643       return true;
00644     } else {
00645       return false;
00646     }
00647 }
00648 
00649 void GLViewer::toggleTriangulation() {
00650     ROS_INFO("Toggling Triangulation");
00651     if(polygon_mode == GL_FILL){ // Turn on Pointcloud mode
00652         polygon_mode = GL_POINT;
00653     } else if(polygon_mode == GL_POINT){ // Turn on Wireframe mode
00654         polygon_mode = GL_LINE;
00655     } else { // Turn on Surface mode
00656         polygon_mode = GL_FILL;
00657     }
00658     glPolygonMode(GL_FRONT_AND_BACK, polygon_mode);
00659     updateGL();
00660 }
00661 
00662 void GLViewer::drawToPS(QString filname){
00663 #ifdef GL2PS
00664 
00665   FILE *fp = fopen("glviewer.pdf", "wb");
00666   GLint buffsize = 0, state = GL2PS_OVERFLOW;
00667   GLint viewport[4];
00668   char *oldlocale = setlocale(LC_NUMERIC, "C");
00669 
00670 
00671   glGetIntegerv(GL_VIEWPORT, viewport);
00672 
00673   while( state == GL2PS_OVERFLOW ){
00674     buffsize += 1024*1024;
00675     gl2psBeginPage ( "GL View", "RGBD-SLAM", viewport,
00676                      GL2PS_PDF, GL2PS_BSP_SORT, GL2PS_SILENT |
00677                      GL2PS_SIMPLE_LINE_OFFSET | GL2PS_NO_BLENDING |
00678                      GL2PS_OCCLUSION_CULL | GL2PS_BEST_ROOT,
00679                      GL_RGBA, 0, NULL, 0, 0, 0, buffsize,
00680                      fp, "LatexFile" );
00681     drawClouds(0.0);
00682     state = gl2psEndPage();
00683   }
00684   setlocale(LC_NUMERIC, oldlocale);
00685   fclose(fp);
00686 #else
00687   QMessageBox::warning(this, tr("This functionality is not supported."), tr("This feature needs to be compiled in. To do so, install libgl2ps-dev and set the USE_GL2PS flag at the top of CMakeLists.txt. The feature has been removed to ease the installation process, sorry for the inconvenience."));
00688 #endif
00689 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


rgbdslam
Author(s): Felix Endres, Juergen Hess, Nikolas Engelhard
autogenerated on Wed Dec 26 2012 15:53:08