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 #include "rtabmap/gui/CloudViewer.h"
00029
00030 #include <rtabmap/core/Version.h>
00031 #include <rtabmap/utilite/ULogger.h>
00032 #include <rtabmap/utilite/UTimer.h>
00033 #include <rtabmap/utilite/UMath.h>
00034 #include <rtabmap/utilite/UConversion.h>
00035 #include <rtabmap/utilite/UStl.h>
00036 #include <pcl/visualization/pcl_visualizer.h>
00037 #include <pcl/common/transforms.h>
00038 #include <QMenu>
00039 #include <QAction>
00040 #include <QtGui/QContextMenuEvent>
00041 #include <QInputDialog>
00042 #include <QtGui/QWheelEvent>
00043 #include <QtGui/QKeyEvent>
00044 #include <QColorDialog>
00045 #include <QtGui/QVector3D>
00046 #include <QMainWindow>
00047 #include <set>
00048
00049 #include <vtkCamera.h>
00050 #include <vtkRenderWindow.h>
00051 #include <vtkCubeSource.h>
00052 #include <vtkGlyph3D.h>
00053 #include <vtkGlyph3DMapper.h>
00054 #include <vtkLookupTable.h>
00055
00056 #ifdef RTABMAP_OCTOMAP
00057 #include <rtabmap/core/OctoMap.h>
00058 #endif
00059
00060 namespace rtabmap {
00061
00062 class MyInteractorStyle: public pcl::visualization::PCLVisualizerInteractorStyle
00063 {
00064 public:
00065 virtual void Rotate()
00066 {
00067 if (this->CurrentRenderer == NULL)
00068 {
00069 return;
00070 }
00071
00072 vtkRenderWindowInteractor *rwi = this->Interactor;
00073
00074 int dx = rwi->GetEventPosition()[0] - rwi->GetLastEventPosition()[0];
00075 int dy = rwi->GetEventPosition()[1] - rwi->GetLastEventPosition()[1];
00076
00077 int *size = this->CurrentRenderer->GetRenderWindow()->GetSize();
00078
00079 double delta_elevation = -20.0 / size[1];
00080 double delta_azimuth = -20.0 / size[0];
00081
00082 double rxf = dx * delta_azimuth * this->MotionFactor;
00083 double ryf = dy * delta_elevation * this->MotionFactor;
00084
00085 vtkCamera *camera = this->CurrentRenderer->GetActiveCamera();
00086 camera->Azimuth(rxf);
00087 camera->Elevation(ryf);
00088 camera->OrthogonalizeViewUp();
00089
00090 if (this->AutoAdjustCameraClippingRange)
00091 {
00092 this->CurrentRenderer->ResetCameraClippingRange();
00093 }
00094
00095 if (rwi->GetLightFollowCamera())
00096 {
00097 this->CurrentRenderer->UpdateLightsGeometryToFollowCamera();
00098 }
00099
00100
00101 }
00102 };
00103
00104
00105 CloudViewer::CloudViewer(QWidget *parent) :
00106 QVTKWidget(parent),
00107 _aLockCamera(0),
00108 _aFollowCamera(0),
00109 _aResetCamera(0),
00110 _aLockViewZ(0),
00111 _aShowTrajectory(0),
00112 _aSetTrajectorySize(0),
00113 _aClearTrajectory(0),
00114 _aShowFrustum(0),
00115 _aSetFrustumScale(0),
00116 _aSetFrustumColor(0),
00117 _aShowGrid(0),
00118 _aSetGridCellCount(0),
00119 _aSetGridCellSize(0),
00120 _aSetBackgroundColor(0),
00121 _menu(0),
00122 _trajectory(new pcl::PointCloud<pcl::PointXYZ>),
00123 _maxTrajectorySize(100),
00124 _frustumScale(0.5f),
00125 _frustumColor(Qt::gray),
00126 _gridCellCount(50),
00127 _gridCellSize(1),
00128 _lastCameraOrientation(0,0,0),
00129 _lastCameraPose(0,0,0),
00130 _workingDirectory("."),
00131 _defaultBgColor(Qt::black),
00132 _currentBgColor(Qt::black),
00133 _backfaceCulling(false),
00134 _frontfaceCulling(false),
00135 _renderingRate(5.0),
00136 _octomapActor(0)
00137 {
00138 UDEBUG("");
00139 this->setMinimumSize(200, 200);
00140
00141 int argc = 0;
00142 _visualizer = new pcl::visualization::PCLVisualizer(
00143 argc,
00144 0,
00145 "PCLVisualizer",
00146 vtkSmartPointer<MyInteractorStyle>(new MyInteractorStyle()),
00147 false);
00148
00149 _visualizer->setShowFPS(false);
00150
00151 this->SetRenderWindow(_visualizer->getRenderWindow());
00152
00153
00154
00155
00156 this->GetInteractor()->SetInteractorStyle (_visualizer->getInteractorStyle());
00157 setRenderingRate(_renderingRate);
00158
00159 _visualizer->setCameraPosition(
00160 -1, 0, 0,
00161 0, 0, 0,
00162 0, 0, 1);
00163 #ifndef _WIN32
00164
00165 this->addOrUpdateCoordinate("reference", Transform::getIdentity(), 0.2);
00166 #endif
00167
00168
00169 createMenu();
00170
00171 setMouseTracking(false);
00172 }
00173
00174 CloudViewer::~CloudViewer()
00175 {
00176 UDEBUG("");
00177 this->clear();
00178 delete _visualizer;
00179 UDEBUG("");
00180 }
00181
00182 void CloudViewer::clear()
00183 {
00184 this->removeAllClouds();
00185 this->removeAllGraphs();
00186 this->removeAllCoordinates();
00187 this->removeAllLines();
00188 this->removeAllFrustums();
00189 this->removeAllTexts();
00190 this->clearTrajectory();
00191 this->removeOccupancyGridMap();
00192 this->removeOctomap();
00193
00194 this->addOrUpdateCoordinate("reference", Transform::getIdentity(), 0.2);
00195 }
00196
00197 void CloudViewer::createMenu()
00198 {
00199 _aLockCamera = new QAction("Lock target", this);
00200 _aLockCamera->setCheckable(true);
00201 _aLockCamera->setChecked(false);
00202 _aFollowCamera = new QAction("Follow", this);
00203 _aFollowCamera->setCheckable(true);
00204 _aFollowCamera->setChecked(true);
00205 QAction * freeCamera = new QAction("Free", this);
00206 freeCamera->setCheckable(true);
00207 freeCamera->setChecked(false);
00208 _aLockViewZ = new QAction("Lock view Z", this);
00209 _aLockViewZ->setCheckable(true);
00210 _aLockViewZ->setChecked(true);
00211 _aResetCamera = new QAction("Reset position", this);
00212 _aShowTrajectory= new QAction("Show trajectory", this);
00213 _aShowTrajectory->setCheckable(true);
00214 _aShowTrajectory->setChecked(true);
00215 _aSetTrajectorySize = new QAction("Set trajectory size...", this);
00216 _aClearTrajectory = new QAction("Clear trajectory", this);
00217 _aShowFrustum= new QAction("Show frustum", this);
00218 _aShowFrustum->setCheckable(true);
00219 _aShowFrustum->setChecked(false);
00220 _aSetFrustumScale = new QAction("Set frustum scale...", this);
00221 _aSetFrustumColor = new QAction("Set frustum color...", this);
00222 _aShowGrid = new QAction("Show grid", this);
00223 _aShowGrid->setCheckable(true);
00224 _aSetGridCellCount = new QAction("Set cell count...", this);
00225 _aSetGridCellSize = new QAction("Set cell size...", this);
00226 _aSetBackgroundColor = new QAction("Set background color...", this);
00227 _aSetRenderingRate = new QAction("Set rendering rate...", this);
00228
00229 QMenu * cameraMenu = new QMenu("Camera", this);
00230 cameraMenu->addAction(_aLockCamera);
00231 cameraMenu->addAction(_aFollowCamera);
00232 cameraMenu->addAction(freeCamera);
00233 cameraMenu->addSeparator();
00234 cameraMenu->addAction(_aLockViewZ);
00235 cameraMenu->addAction(_aResetCamera);
00236 QActionGroup * group = new QActionGroup(this);
00237 group->addAction(_aLockCamera);
00238 group->addAction(_aFollowCamera);
00239 group->addAction(freeCamera);
00240
00241 QMenu * trajectoryMenu = new QMenu("Trajectory", this);
00242 trajectoryMenu->addAction(_aShowTrajectory);
00243 trajectoryMenu->addAction(_aSetTrajectorySize);
00244 trajectoryMenu->addAction(_aClearTrajectory);
00245
00246 QMenu * frustumMenu = new QMenu("Frustum", this);
00247 frustumMenu->addAction(_aShowFrustum);
00248 frustumMenu->addAction(_aSetFrustumScale);
00249 frustumMenu->addAction(_aSetFrustumColor);
00250
00251 QMenu * gridMenu = new QMenu("Grid", this);
00252 gridMenu->addAction(_aShowGrid);
00253 gridMenu->addAction(_aSetGridCellCount);
00254 gridMenu->addAction(_aSetGridCellSize);
00255
00256
00257 _menu = new QMenu(this);
00258 _menu->addMenu(cameraMenu);
00259 _menu->addMenu(trajectoryMenu);
00260 _menu->addMenu(frustumMenu);
00261 _menu->addMenu(gridMenu);
00262 _menu->addAction(_aSetBackgroundColor);
00263 _menu->addAction(_aSetRenderingRate);
00264 }
00265
00266 void CloudViewer::saveSettings(QSettings & settings, const QString & group) const
00267 {
00268 if(!group.isEmpty())
00269 {
00270 settings.beginGroup(group);
00271 }
00272
00273 float poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ;
00274 this->getCameraPosition(poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ);
00275 QVector3D pose(poseX, poseY, poseZ);
00276 QVector3D focal(focalX, focalY, focalZ);
00277 if(!this->isCameraFree())
00278 {
00279
00280 Transform T = this->getTargetPose();
00281 if(this->isCameraTargetLocked())
00282 {
00283 T = Transform(T.x(), T.y(), T.z(), 0,0,0);
00284 }
00285 Transform F(focalX, focalY, focalZ, 0,0,0);
00286 Transform P(poseX, poseY, poseZ, 0,0,0);
00287 Transform newFocal = T.inverse() * F;
00288 Transform newPose = newFocal * F.inverse() * P;
00289 pose = QVector3D(newPose.x(), newPose.y(), newPose.z());
00290 focal = QVector3D(newFocal.x(), newFocal.y(), newFocal.z());
00291 }
00292 settings.setValue("camera_pose", pose);
00293 settings.setValue("camera_focal", focal);
00294 settings.setValue("camera_up", QVector3D(upX, upY, upZ));
00295
00296 settings.setValue("grid", this->isGridShown());
00297 settings.setValue("grid_cell_count", this->getGridCellCount());
00298 settings.setValue("grid_cell_size", (double)this->getGridCellSize());
00299
00300 settings.setValue("trajectory_shown", this->isTrajectoryShown());
00301 settings.setValue("trajectory_size", this->getTrajectorySize());
00302
00303 settings.setValue("frustum_shown", this->isFrustumShown());
00304 settings.setValue("frustum_scale", this->getFrustumScale());
00305 settings.setValue("frustum_color", this->getFrustumColor());
00306
00307 settings.setValue("camera_target_locked", this->isCameraTargetLocked());
00308 settings.setValue("camera_target_follow", this->isCameraTargetFollow());
00309 settings.setValue("camera_free", this->isCameraFree());
00310 settings.setValue("camera_lockZ", this->isCameraLockZ());
00311
00312 settings.setValue("bg_color", this->getDefaultBackgroundColor());
00313 settings.setValue("rendering_rate", this->getRenderingRate());
00314 if(!group.isEmpty())
00315 {
00316 settings.endGroup();
00317 }
00318 }
00319
00320 void CloudViewer::loadSettings(QSettings & settings, const QString & group)
00321 {
00322 if(!group.isEmpty())
00323 {
00324 settings.beginGroup(group);
00325 }
00326
00327 float poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ;
00328 this->getCameraPosition(poseX, poseY, poseZ, focalX, focalY, focalZ, upX, upY, upZ);
00329 QVector3D pose(poseX, poseY, poseZ), focal(focalX, focalY, focalZ), up(upX, upY, upZ);
00330 pose = settings.value("camera_pose", pose).value<QVector3D>();
00331 focal = settings.value("camera_focal", focal).value<QVector3D>();
00332 up = settings.value("camera_up", up).value<QVector3D>();
00333 this->setCameraPosition(pose.x(),pose.y(),pose.z(), focal.x(),focal.y(),focal.z(), up.x(),up.y(),up.z());
00334
00335 this->setGridShown(settings.value("grid", this->isGridShown()).toBool());
00336 this->setGridCellCount(settings.value("grid_cell_count", this->getGridCellCount()).toUInt());
00337 this->setGridCellSize(settings.value("grid_cell_size", this->getGridCellSize()).toFloat());
00338
00339 this->setTrajectoryShown(settings.value("trajectory_shown", this->isTrajectoryShown()).toBool());
00340 this->setTrajectorySize(settings.value("trajectory_size", this->getTrajectorySize()).toUInt());
00341
00342 this->setFrustumShown(settings.value("frustum_shown", this->isFrustumShown()).toBool());
00343 this->setFrustumScale(settings.value("frustum_scale", this->getFrustumScale()).toDouble());
00344 this->setFrustumColor(settings.value("frustum_color", this->getFrustumColor()).value<QColor>());
00345
00346 this->setCameraTargetLocked(settings.value("camera_target_locked", this->isCameraTargetLocked()).toBool());
00347 this->setCameraTargetFollow(settings.value("camera_target_follow", this->isCameraTargetFollow()).toBool());
00348 if(settings.value("camera_free", this->isCameraFree()).toBool())
00349 {
00350 this->setCameraFree();
00351 }
00352 this->setCameraLockZ(settings.value("camera_lockZ", this->isCameraLockZ()).toBool());
00353
00354 this->setDefaultBackgroundColor(settings.value("bg_color", this->getDefaultBackgroundColor()).value<QColor>());
00355
00356 this->setRenderingRate(settings.value("rendering_rate", this->getRenderingRate()).toDouble());
00357
00358 if(!group.isEmpty())
00359 {
00360 settings.endGroup();
00361 }
00362
00363 this->update();
00364 }
00365
00366 bool CloudViewer::updateCloudPose(
00367 const std::string & id,
00368 const Transform & pose)
00369 {
00370 if(_addedClouds.contains(id))
00371 {
00372 UDEBUG("Updating pose %s to %s", id.c_str(), pose.prettyPrint().c_str());
00373 if(_addedClouds.find(id).value() == pose ||
00374 _visualizer->updatePointCloudPose(id, pose.toEigen3f()))
00375 {
00376 _addedClouds.find(id).value() = pose;
00377 return true;
00378 }
00379 }
00380 return false;
00381 }
00382
00383 bool CloudViewer::addCloud(
00384 const std::string & id,
00385 const pcl::PCLPointCloud2Ptr & binaryCloud,
00386 const Transform & pose,
00387 bool rgb,
00388 bool haveNormals,
00389 const QColor & color)
00390 {
00391 int previousColorIndex = -1;
00392 if(_addedClouds.contains(id))
00393 {
00394 previousColorIndex = _visualizer->getColorHandlerIndex(id);
00395 this->removeCloud(id);
00396 }
00397
00398 Eigen::Vector4f origin(pose.x(), pose.y(), pose.z(), 0.0f);
00399 Eigen::Quaternionf orientation = Eigen::Quaternionf(pose.toEigen3f().rotation());
00400
00401
00402 pcl::visualization::PointCloudColorHandler<pcl::PCLPointCloud2>::Ptr colorHandler;
00403 colorHandler.reset (new pcl::visualization::PointCloudColorHandlerRandom<pcl::PCLPointCloud2> (binaryCloud));
00404 if(_visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id))
00405 {
00406 QColor c = Qt::gray;
00407 if(color.isValid())
00408 {
00409 c = color;
00410 }
00411 colorHandler.reset (new pcl::visualization::PointCloudColorHandlerCustom<pcl::PCLPointCloud2> (binaryCloud, c.red(), c.green(), c.blue()));
00412 _visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id);
00413
00414
00415 colorHandler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<pcl::PCLPointCloud2> (binaryCloud, "x"));
00416 _visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id);
00417 colorHandler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<pcl::PCLPointCloud2> (binaryCloud, "y"));
00418 _visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id);
00419 colorHandler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<pcl::PCLPointCloud2> (binaryCloud, "z"));
00420 _visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id);
00421
00422 if(rgb)
00423 {
00424
00425 colorHandler.reset(new pcl::visualization::PointCloudColorHandlerRGBField<pcl::PCLPointCloud2>(binaryCloud));
00426 _visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id);
00427 }
00428 else if(previousColorIndex == 5)
00429 {
00430 previousColorIndex = -1;
00431 }
00432
00433 if(haveNormals)
00434 {
00435
00436 colorHandler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<pcl::PCLPointCloud2> (binaryCloud, "normal_x"));
00437 _visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id);
00438 colorHandler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<pcl::PCLPointCloud2> (binaryCloud, "normal_y"));
00439 _visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id);
00440 colorHandler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<pcl::PCLPointCloud2> (binaryCloud, "normal_z"));
00441 _visualizer->addPointCloud (binaryCloud, colorHandler, origin, orientation, id);
00442 }
00443 else if(previousColorIndex > 5)
00444 {
00445 previousColorIndex = -1;
00446 }
00447
00448 if(previousColorIndex>=0)
00449 {
00450 _visualizer->updateColorHandlerIndex(id, previousColorIndex);
00451 }
00452 else if(rgb)
00453 {
00454 _visualizer->updateColorHandlerIndex(id, 5);
00455 }
00456 else if(color.isValid())
00457 {
00458 _visualizer->updateColorHandlerIndex(id, 1);
00459 }
00460
00461 _addedClouds.insert(id, pose);
00462 return true;
00463 }
00464 return false;
00465 }
00466
00467 bool CloudViewer::addCloud(
00468 const std::string & id,
00469 const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
00470 const Transform & pose,
00471 const QColor & color)
00472 {
00473 pcl::PCLPointCloud2Ptr binaryCloud(new pcl::PCLPointCloud2);
00474 pcl::toPCLPointCloud2(*cloud, *binaryCloud);
00475 return addCloud(id, binaryCloud, pose, true, true, color);
00476 }
00477
00478 bool CloudViewer::addCloud(
00479 const std::string & id,
00480 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
00481 const Transform & pose,
00482 const QColor & color)
00483 {
00484 pcl::PCLPointCloud2Ptr binaryCloud(new pcl::PCLPointCloud2);
00485 pcl::toPCLPointCloud2(*cloud, *binaryCloud);
00486 return addCloud(id, binaryCloud, pose, true, false, color);
00487 }
00488
00489 bool CloudViewer::addCloud(
00490 const std::string & id,
00491 const pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
00492 const Transform & pose,
00493 const QColor & color)
00494 {
00495 pcl::PCLPointCloud2Ptr binaryCloud(new pcl::PCLPointCloud2);
00496 pcl::toPCLPointCloud2(*cloud, *binaryCloud);
00497 return addCloud(id, binaryCloud, pose, false, true, color);
00498 }
00499
00500 bool CloudViewer::addCloud(
00501 const std::string & id,
00502 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
00503 const Transform & pose,
00504 const QColor & color)
00505 {
00506 pcl::PCLPointCloud2Ptr binaryCloud(new pcl::PCLPointCloud2);
00507 pcl::toPCLPointCloud2(*cloud, *binaryCloud);
00508 return addCloud(id, binaryCloud, pose, false, false, color);
00509 }
00510
00511 bool CloudViewer::addCloudMesh(
00512 const std::string & id,
00513 const pcl::PointCloud<pcl::PointXYZ>::Ptr & cloud,
00514 const std::vector<pcl::Vertices> & polygons,
00515 const Transform & pose)
00516 {
00517 if(_addedClouds.contains(id))
00518 {
00519 this->removeCloud(id);
00520 }
00521
00522 UDEBUG("Adding %s with %d points and %d polygons", id.c_str(), (int)cloud->size(), (int)polygons.size());
00523 if(_visualizer->addPolygonMesh<pcl::PointXYZ>(cloud, polygons, id))
00524 {
00525 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->LightingOff();
00526 if(_backfaceCulling)
00527 {
00528 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->BackfaceCullingOn();
00529 }
00530 if(_frontfaceCulling)
00531 {
00532 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->FrontfaceCullingOn();
00533 }
00534 _visualizer->updatePointCloudPose(id, pose.toEigen3f());
00535 _addedClouds.insert(id, pose);
00536 return true;
00537 }
00538 return false;
00539 }
00540
00541 bool CloudViewer::addCloudMesh(
00542 const std::string & id,
00543 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
00544 const std::vector<pcl::Vertices> & polygons,
00545 const Transform & pose)
00546 {
00547 if(_addedClouds.contains(id))
00548 {
00549 this->removeCloud(id);
00550 }
00551
00552 UDEBUG("Adding %s with %d points and %d polygons", id.c_str(), (int)cloud->size(), (int)polygons.size());
00553 if(_visualizer->addPolygonMesh<pcl::PointXYZRGB>(cloud, polygons, id))
00554 {
00555 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->LightingOff();
00556 if(_backfaceCulling)
00557 {
00558 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->BackfaceCullingOn();
00559 }
00560 if(_frontfaceCulling)
00561 {
00562 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->FrontfaceCullingOn();
00563 }
00564 _visualizer->updatePointCloudPose(id, pose.toEigen3f());
00565 _addedClouds.insert(id, pose);
00566 return true;
00567 }
00568 return false;
00569 }
00570
00571 bool CloudViewer::addCloudMesh(
00572 const std::string & id,
00573 const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
00574 const std::vector<pcl::Vertices> & polygons,
00575 const Transform & pose)
00576 {
00577 if(_addedClouds.contains(id))
00578 {
00579 this->removeCloud(id);
00580 }
00581
00582 UDEBUG("Adding %s with %d points and %d polygons", id.c_str(), (int)cloud->size(), (int)polygons.size());
00583 if(_visualizer->addPolygonMesh<pcl::PointXYZRGBNormal>(cloud, polygons, id))
00584 {
00585 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->LightingOff();
00586 if(_backfaceCulling)
00587 {
00588 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->BackfaceCullingOn();
00589 }
00590 if(_frontfaceCulling)
00591 {
00592 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->FrontfaceCullingOn();
00593 }
00594 _visualizer->updatePointCloudPose(id, pose.toEigen3f());
00595 _addedClouds.insert(id, pose);
00596 return true;
00597 }
00598 return false;
00599 }
00600
00601 bool CloudViewer::addCloudMesh(
00602 const std::string & id,
00603 const pcl::PolygonMesh::Ptr & mesh,
00604 const Transform & pose)
00605 {
00606 if(_addedClouds.contains(id))
00607 {
00608 this->removeCloud(id);
00609 }
00610
00611 UDEBUG("Adding %s with %d polygons", id.c_str(), (int)mesh->polygons.size());
00612 if(_visualizer->addPolygonMesh(*mesh, id))
00613 {
00614 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->LightingOff();
00615 if(_backfaceCulling)
00616 {
00617 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->BackfaceCullingOn();
00618 }
00619 if(_frontfaceCulling)
00620 {
00621 _visualizer->getCloudActorMap()->find(id)->second.actor->GetProperty()->FrontfaceCullingOn();
00622 }
00623 _visualizer->updatePointCloudPose(id, pose.toEigen3f());
00624 _addedClouds.insert(id, pose);
00625 return true;
00626 }
00627
00628 return false;
00629 }
00630
00631 bool CloudViewer::addCloudTextureMesh(
00632 const std::string & id,
00633 const pcl::TextureMesh::Ptr & textureMesh,
00634 const Transform & pose)
00635 {
00636 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
00637 if(_addedClouds.contains(id))
00638 {
00639 this->removeCloud(id);
00640 }
00641
00642 UDEBUG("Adding %s", id.c_str());
00643 if(_visualizer->addTextureMesh(*textureMesh, id))
00644 {
00645 _visualizer->updatePointCloudPose(id, pose.toEigen3f());
00646 _addedClouds.insert(id, pose);
00647 return true;
00648 }
00649
00650 #endif
00651
00652 return false;
00653 }
00654
00655 bool CloudViewer::addOctomap(const OctoMap * octomap, unsigned int treeDepth, bool showEdges, bool lightingOn)
00656 {
00657 UDEBUG("");
00658 #ifdef RTABMAP_OCTOMAP
00659 UASSERT(octomap!=0);
00660
00661 pcl::IndicesPtr obstacles(new std::vector<int>);
00662
00663 if(treeDepth > octomap->octree()->getTreeDepth())
00664 {
00665 UWARN("Tree depth requested (%d) is deeper than the "
00666 "actual maximum tree depth of %d. Using maximum depth.",
00667 (int)treeDepth, (int)octomap->octree()->getTreeDepth());
00668 }
00669
00670 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = octomap->createCloud(treeDepth, obstacles.get());
00671 if(obstacles->size())
00672 {
00673
00674 vtkRenderer *renderer = _visualizer->getRenderWindow()->GetRenderers()->GetFirstRenderer();
00675
00676 if(_octomapActor)
00677 {
00678 renderer->RemoveActor(_octomapActor);
00679 _octomapActor = 0;
00680 }
00681
00682
00683
00684
00685 vtkSmartPointer<vtkFloatArray> colors = vtkSmartPointer<vtkFloatArray>::New();
00686 colors->SetName("colors");
00687 colors->SetNumberOfValues(obstacles->size());
00688
00689 vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
00690 lut->SetNumberOfTableValues(obstacles->size());
00691 lut->Build();
00692
00693
00694 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
00695 double s = octomap->octree()->getNodeSize(treeDepth) / 2.0;
00696 for (unsigned int i = 0; i < obstacles->size(); i++)
00697 {
00698 points->InsertNextPoint(
00699 cloud->at(obstacles->at(i)).x,
00700 cloud->at(obstacles->at(i)).y,
00701 cloud->at(obstacles->at(i)).z);
00702 colors->InsertValue(i,i);
00703
00704 lut->SetTableValue(i,
00705 double(cloud->at(obstacles->at(i)).r) / 255.0,
00706 double(cloud->at(obstacles->at(i)).g) / 255.0,
00707 double(cloud->at(obstacles->at(i)).b) / 255.0);
00708 }
00709
00710
00711 vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
00712 polydata->SetPoints(points);
00713 polydata->GetPointData()->SetScalars(colors);
00714
00715
00716 vtkSmartPointer<vtkCubeSource> cubeSource = vtkSmartPointer<vtkCubeSource>::New();
00717 cubeSource->SetBounds(-s, s, -s, s, -s, s);
00718
00719 vtkSmartPointer<vtkGlyph3DMapper> mapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
00720 mapper->SetSourceConnection(cubeSource->GetOutputPort());
00721 #if VTK_MAJOR_VERSION <= 5
00722 mapper->SetInputConnection(polydata->GetProducerPort());
00723 #else
00724 mapper->SetInputData(polydata);
00725 #endif
00726 mapper->SetScalarRange(0, obstacles->size() - 1);
00727 mapper->SetLookupTable(lut);
00728 mapper->ScalingOff();
00729 mapper->Update();
00730
00731 vtkSmartPointer<vtkActor> octomapActor = vtkSmartPointer<vtkActor>::New();
00732 octomapActor->SetMapper(mapper);
00733
00734 octomapActor->GetProperty()->SetRepresentationToSurface();
00735 octomapActor->GetProperty()->SetEdgeVisibility(showEdges);
00736 octomapActor->GetProperty()->SetLighting(lightingOn);
00737
00738 renderer->AddActor(octomapActor);
00739 _octomapActor = octomapActor.GetPointer();
00740
00741 return true;
00742 }
00743 #endif
00744 return false;
00745 }
00746
00747 void CloudViewer::removeOctomap()
00748 {
00749 UDEBUG("");
00750 #ifdef RTABMAP_OCTOMAP
00751 if(_octomapActor)
00752 {
00753 vtkRenderer *renderer = _visualizer->getRenderWindow()->GetRenderers()->GetFirstRenderer();
00754 renderer->RemoveActor(_octomapActor);
00755 _octomapActor = 0;
00756 }
00757 #endif
00758 }
00759
00760 bool CloudViewer::addOccupancyGridMap(
00761 const cv::Mat & map8U,
00762 float resolution,
00763 float xMin,
00764 float yMin,
00765 float opacity)
00766 {
00767 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
00768 UASSERT(map8U.channels() == 1 && map8U.type() == CV_8U);
00769
00770 float xSize = float(map8U.cols) * resolution;
00771 float ySize = float(map8U.rows) * resolution;
00772
00773 UDEBUG("resolution=%f, xSize=%f, ySize=%f, xMin=%f, yMin=%f", resolution, xSize, ySize, xMin, yMin);
00774 if(_visualizer->getShapeActorMap()->find("map") == _visualizer->getShapeActorMap()->end())
00775 {
00776 _visualizer->removeShape("map");
00777 }
00778
00779 if(xSize > 0.0f && ySize > 0.0f)
00780 {
00781 pcl::TextureMeshPtr mesh(new pcl::TextureMesh());
00782 pcl::PointCloud<pcl::PointXYZ> cloud;
00783 cloud.push_back(pcl::PointXYZ(xMin, yMin, 0));
00784 cloud.push_back(pcl::PointXYZ(xSize+xMin, yMin, 0));
00785 cloud.push_back(pcl::PointXYZ(xSize+xMin, ySize+yMin, 0));
00786 cloud.push_back(pcl::PointXYZ(xMin, ySize+yMin, 0));
00787 pcl::toPCLPointCloud2(cloud, mesh->cloud);
00788
00789 std::vector<pcl::Vertices> polygons(1);
00790 polygons[0].vertices.push_back(0);
00791 polygons[0].vertices.push_back(1);
00792 polygons[0].vertices.push_back(2);
00793 polygons[0].vertices.push_back(3);
00794 polygons[0].vertices.push_back(0);
00795 mesh->tex_polygons.push_back(polygons);
00796
00797
00798 pcl::TexMaterial material;
00799
00800 std::string tmpPath = (_workingDirectory+"/.tmp_map.png").toStdString();
00801 cv::imwrite(tmpPath, map8U);
00802 material.tex_file = tmpPath;
00803 mesh->tex_materials.push_back(material);
00804
00805 #if PCL_VERSION_COMPARE(>=, 1, 8, 0)
00806 std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > coordinates;
00807 #else
00808 std::vector<Eigen::Vector2f> coordinates;
00809 #endif
00810 coordinates.push_back(Eigen::Vector2f(0,1));
00811 coordinates.push_back(Eigen::Vector2f(1,1));
00812 coordinates.push_back(Eigen::Vector2f(1,0));
00813 coordinates.push_back(Eigen::Vector2f(0,0));
00814 mesh->tex_coordinates.push_back(coordinates);
00815
00816 _visualizer->addTextureMesh(*mesh, "map");
00817 _visualizer->getCloudActorMap()->find("map")->second.actor->GetProperty()->LightingOff();
00818 setCloudOpacity("map", 0.7);
00819
00820
00821 QFile::remove(tmpPath.c_str());
00822 }
00823 return true;
00824 #else
00825
00826 return false;
00827 #endif
00828 }
00829
00830 void CloudViewer::removeOccupancyGridMap()
00831 {
00832 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
00833 if(_visualizer->getShapeActorMap()->find("map") == _visualizer->getShapeActorMap()->end())
00834 {
00835 _visualizer->removeShape("map");
00836 }
00837 #endif
00838 }
00839
00840 void CloudViewer::addOrUpdateCoordinate(
00841 const std::string & id,
00842 const Transform & transform,
00843 double scale)
00844 {
00845 if(id.empty())
00846 {
00847 UERROR("id should not be empty!");
00848 return;
00849 }
00850
00851 removeCoordinate(id);
00852
00853 if(!transform.isNull())
00854 {
00855 _coordinates.insert(id);
00856 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
00857 _visualizer->addCoordinateSystem(scale, transform.toEigen3f(), id);
00858 #else
00859
00860 _visualizer->addCoordinateSystem(scale, transform.toEigen3f(), 0);
00861 #endif
00862 }
00863 }
00864
00865 bool CloudViewer::updateCoordinatePose(
00866 const std::string & id,
00867 const Transform & pose)
00868 {
00869 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
00870 if(_coordinates.find(id) != _coordinates.end() && !pose.isNull())
00871 {
00872 UDEBUG("Updating pose %s to %s", id.c_str(), pose.prettyPrint().c_str());
00873 return _visualizer->updateCoordinateSystemPose(id, pose.toEigen3f());
00874 }
00875 #else
00876 UERROR("CloudViewer::updateCoordinatePose() is not available on PCL < 1.7.2");
00877 #endif
00878 return false;
00879 }
00880
00881 void CloudViewer::removeCoordinate(const std::string & id)
00882 {
00883 if(id.empty())
00884 {
00885 UERROR("id should not be empty!");
00886 return;
00887 }
00888
00889 if(_coordinates.find(id) != _coordinates.end())
00890 {
00891 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
00892 _visualizer->removeCoordinateSystem(id);
00893 #else
00894
00895 _visualizer->removeCoordinateSystem(0);
00896 #endif
00897 _coordinates.erase(id);
00898 }
00899 }
00900
00901 void CloudViewer::removeAllCoordinates()
00902 {
00903 std::set<std::string> coordinates = _coordinates;
00904 for(std::set<std::string>::iterator iter = coordinates.begin(); iter!=coordinates.end(); ++iter)
00905 {
00906 this->removeCoordinate(*iter);
00907 }
00908 UASSERT(_coordinates.empty());
00909 }
00910
00911 void CloudViewer::addOrUpdateLine(
00912 const std::string & id,
00913 const Transform & from,
00914 const Transform & to,
00915 const QColor & color,
00916 bool arrow)
00917 {
00918 if(id.empty())
00919 {
00920 UERROR("id should not be empty!");
00921 return;
00922 }
00923
00924 removeLine(id);
00925
00926 if(!from.isNull() && !to.isNull())
00927 {
00928 _lines.insert(id);
00929
00930 QColor c = Qt::gray;
00931 if(color.isValid())
00932 {
00933 c = color;
00934 }
00935
00936 pcl::PointXYZ pt1(from.x(), from.y(), from.z());
00937 pcl::PointXYZ pt2(to.x(), to.y(), to.z());
00938
00939 if(arrow)
00940 {
00941 _visualizer->addArrow(pt2, pt1, c.redF(), c.greenF(), c.blueF(), false, id);
00942 }
00943 else
00944 {
00945 _visualizer->addLine(pt2, pt1, c.redF(), c.greenF(), c.blueF(), id);
00946 }
00947 }
00948 }
00949
00950 void CloudViewer::removeLine(const std::string & id)
00951 {
00952 if(id.empty())
00953 {
00954 UERROR("id should not be empty!");
00955 return;
00956 }
00957
00958 if(_lines.find(id) != _lines.end())
00959 {
00960 _visualizer->removeShape(id);
00961 _lines.erase(id);
00962 }
00963 }
00964
00965 void CloudViewer::removeAllLines()
00966 {
00967 std::set<std::string> arrows = _lines;
00968 for(std::set<std::string>::iterator iter = arrows.begin(); iter!=arrows.end(); ++iter)
00969 {
00970 this->removeLine(*iter);
00971 }
00972 UASSERT(_lines.empty());
00973 }
00974
00975 static const float frustum_vertices[] = {
00976 0.0f, 0.0f, 0.0f,
00977 1.0f, 1.0f, 1.0f,
00978 1.0f, -1.0f, 1.0f,
00979 1.0f, -1.0f, -1.0f,
00980 1.0f, 1.0f, -1.0f};
00981
00982 static const int frustum_indices[] = {
00983 1, 2, 3, 4, 1, 0, 2, 0, 3, 0, 4};
00984
00985 void CloudViewer::addOrUpdateFrustum(
00986 const std::string & id,
00987 const Transform & transform,
00988 double scale,
00989 const QColor & color)
00990 {
00991 if(id.empty())
00992 {
00993 UERROR("id should not be empty!");
00994 return;
00995 }
00996
00997 removeFrustum(id);
00998
00999 if(!transform.isNull())
01000 {
01001 _frustums.insert(id);
01002
01003 int frustumSize = sizeof(frustum_vertices)/sizeof(float);
01004 UASSERT(frustumSize>0 && frustumSize % 3 == 0);
01005 frustumSize/=3;
01006 pcl::PointCloud<pcl::PointXYZ> frustumPoints;
01007 frustumPoints.resize(frustumSize);
01008 float scaleX = 0.5f * scale;
01009 float scaleY = 0.4f * scale;
01010 float scaleZ = 0.3f * scale;
01011 QColor c = Qt::gray;
01012 if(color.isValid())
01013 {
01014 c = color;
01015 }
01016 Eigen::Affine3f t = transform.toEigen3f();
01017 for(int i=0; i<frustumSize; ++i)
01018 {
01019 frustumPoints[i].x = frustum_vertices[i*3]*scaleX;
01020 frustumPoints[i].y = frustum_vertices[i*3+1]*scaleY;
01021 frustumPoints[i].z = frustum_vertices[i*3+2]*scaleZ;
01022 frustumPoints[i] = pcl::transformPoint(frustumPoints[i], t);
01023 }
01024
01025 pcl::PolygonMesh mesh;
01026 pcl::Vertices vertices;
01027 vertices.vertices.resize(sizeof(frustum_indices)/sizeof(int));
01028 for(unsigned int i=0; i<vertices.vertices.size(); ++i)
01029 {
01030 vertices.vertices[i] = frustum_indices[i];
01031 }
01032 pcl::toPCLPointCloud2(frustumPoints, mesh.cloud);
01033 mesh.polygons.push_back(vertices);
01034 _visualizer->addPolylineFromPolygonMesh(mesh, id);
01035 _visualizer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, c.redF(), c.greenF(), c.blueF(), id);
01036
01037 }
01038 }
01039
01040 bool CloudViewer::updateFrustumPose(
01041 const std::string & id,
01042 const Transform & pose)
01043 {
01044 if(_frustums.find(id) != _frustums.end() && !pose.isNull())
01045 {
01046 UDEBUG("Updating pose %s to %s", id.c_str(), pose.prettyPrint().c_str());
01047 return _visualizer->updateShapePose(id, pose.toEigen3f());
01048 }
01049 return false;
01050 }
01051
01052 void CloudViewer::removeFrustum(const std::string & id)
01053 {
01054 if(id.empty())
01055 {
01056 UERROR("id should not be empty!");
01057 return;
01058 }
01059
01060 if(_frustums.find(id) != _frustums.end())
01061 {
01062 _visualizer->removeShape(id);
01063 _frustums.erase(id);
01064 }
01065 }
01066
01067 void CloudViewer::removeAllFrustums()
01068 {
01069 std::set<std::string> frustums = _frustums;
01070 for(std::set<std::string>::iterator iter = frustums.begin(); iter!=frustums.end(); ++iter)
01071 {
01072 this->removeFrustum(*iter);
01073 }
01074 UASSERT(_frustums.empty());
01075 }
01076
01077 void CloudViewer::addOrUpdateGraph(
01078 const std::string & id,
01079 const pcl::PointCloud<pcl::PointXYZ>::Ptr & graph,
01080 const QColor & color)
01081 {
01082 if(id.empty())
01083 {
01084 UERROR("id should not be empty!");
01085 return;
01086 }
01087
01088 removeGraph(id);
01089
01090 if(graph->size())
01091 {
01092 _graphes.insert(id);
01093
01094 pcl::PolygonMesh mesh;
01095 pcl::Vertices vertices;
01096 vertices.vertices.resize(graph->size());
01097 for(unsigned int i=0; i<vertices.vertices.size(); ++i)
01098 {
01099 vertices.vertices[i] = i;
01100 }
01101 pcl::toPCLPointCloud2(*graph, mesh.cloud);
01102 mesh.polygons.push_back(vertices);
01103 _visualizer->addPolylineFromPolygonMesh(mesh, id);
01104 _visualizer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, color.redF(), color.greenF(), color.blueF(), id);
01105
01106 this->addCloud(id+"_nodes", graph, Transform::getIdentity(), color);
01107 this->setCloudPointSize(id+"_nodes", 5);
01108 }
01109 }
01110
01111 void CloudViewer::removeGraph(const std::string & id)
01112 {
01113 if(id.empty())
01114 {
01115 UERROR("id should not be empty!");
01116 return;
01117 }
01118
01119 if(_graphes.find(id) != _graphes.end())
01120 {
01121 _visualizer->removeShape(id);
01122 _graphes.erase(id);
01123 removeCloud(id+"_nodes");
01124 }
01125 }
01126
01127 void CloudViewer::removeAllGraphs()
01128 {
01129 std::set<std::string> graphes = _graphes;
01130 for(std::set<std::string>::iterator iter = graphes.begin(); iter!=graphes.end(); ++iter)
01131 {
01132 this->removeGraph(*iter);
01133 }
01134 UASSERT(_graphes.empty());
01135 }
01136
01137 void CloudViewer::addOrUpdateText(
01138 const std::string & id,
01139 const std::string & text,
01140 const Transform & position,
01141 double scale,
01142 const QColor & color)
01143 {
01144 if(id.empty())
01145 {
01146 UERROR("id should not be empty!");
01147 return;
01148 }
01149
01150 removeCoordinate(id);
01151
01152 if(!position.isNull())
01153 {
01154 _texts.insert(id);
01155 _visualizer->addText3D(
01156 text,
01157 pcl::PointXYZ(position.x(), position.y(), position.z()),
01158 scale,
01159 color.redF(),
01160 color.greenF(),
01161 color.blueF(),
01162 id);
01163 }
01164 }
01165
01166 void CloudViewer::removeText(const std::string & id)
01167 {
01168 if(id.empty())
01169 {
01170 UERROR("id should not be empty!");
01171 return;
01172 }
01173
01174 if(_texts.find(id) != _texts.end())
01175 {
01176 _visualizer->removeText3D(id);
01177 _texts.erase(id);
01178 }
01179 }
01180
01181 void CloudViewer::removeAllTexts()
01182 {
01183 std::set<std::string> texts = _texts;
01184 for(std::set<std::string>::iterator iter = texts.begin(); iter!=texts.end(); ++iter)
01185 {
01186 this->removeText(*iter);
01187 }
01188 UASSERT(_texts.empty());
01189 }
01190
01191 bool CloudViewer::isTrajectoryShown() const
01192 {
01193 return _aShowTrajectory->isChecked();
01194 }
01195
01196 unsigned int CloudViewer::getTrajectorySize() const
01197 {
01198 return _maxTrajectorySize;
01199 }
01200
01201 void CloudViewer::setTrajectoryShown(bool shown)
01202 {
01203 _aShowTrajectory->setChecked(shown);
01204 }
01205
01206 void CloudViewer::setTrajectorySize(unsigned int value)
01207 {
01208 _maxTrajectorySize = value;
01209 }
01210
01211 void CloudViewer::clearTrajectory()
01212 {
01213 _trajectory->clear();
01214 _visualizer->removeShape("trajectory");
01215 this->update();
01216 }
01217
01218 bool CloudViewer::isFrustumShown() const
01219 {
01220 return _aShowFrustum->isChecked();
01221 }
01222
01223 float CloudViewer::getFrustumScale() const
01224 {
01225 return _frustumScale;
01226 }
01227
01228 QColor CloudViewer::getFrustumColor() const
01229 {
01230 return _frustumColor;
01231 }
01232
01233 void CloudViewer::setFrustumShown(bool shown)
01234 {
01235 if(!shown)
01236 {
01237 std::set<std::string> frustumsCopy = _frustums;
01238 for(std::set<std::string>::iterator iter=frustumsCopy.begin(); iter!=frustumsCopy.end(); ++iter)
01239 {
01240 if(uStrContains(*iter, "reference_frustum"))
01241 {
01242 this->removeFrustum(*iter);
01243 }
01244 }
01245 std::set<std::string> linesCopy = _lines;
01246 for(std::set<std::string>::iterator iter=linesCopy.begin(); iter!=linesCopy.end(); ++iter)
01247 {
01248 if(uStrContains(*iter, "reference_frustum_line"))
01249 {
01250 this->removeLine(*iter);
01251 }
01252 }
01253 this->update();
01254 }
01255 _aShowFrustum->setChecked(shown);
01256 }
01257
01258 void CloudViewer::setFrustumScale(float value)
01259 {
01260 _frustumScale = value;
01261 }
01262
01263 void CloudViewer::setFrustumColor(QColor value)
01264 {
01265 if(!value.isValid())
01266 {
01267 value = Qt::gray;
01268 }
01269 for(std::set<std::string>::iterator iter=_frustums.begin(); iter!=_frustums.end(); ++iter)
01270 {
01271 if(uStrContains(*iter, "reference_frustum"))
01272 {
01273 _visualizer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, value.redF(), value.greenF(), value.blueF(), *iter);
01274 }
01275 }
01276 this->update();
01277 _frustumColor = value;
01278 }
01279
01280 void CloudViewer::resetCamera()
01281 {
01282 _lastCameraOrientation= _lastCameraPose = cv::Vec3f(0,0,0);
01283 if((_aFollowCamera->isChecked() || _aLockCamera->isChecked()) && !_lastPose.isNull())
01284 {
01285
01286 if(_aLockViewZ->isChecked())
01287 {
01288 _visualizer->setCameraPosition(
01289 _lastPose.x()-1, _lastPose.y(), _lastPose.z(),
01290 _lastPose.x(), _lastPose.y(), _lastPose.z(),
01291 0, 0, 1);
01292 }
01293 else
01294 {
01295 _visualizer->setCameraPosition(
01296 _lastPose.x()-1, _lastPose.y(), _lastPose.z(),
01297 _lastPose.x(), _lastPose.y(), _lastPose.z(),
01298 _lastPose.r31(), _lastPose.r32(), _lastPose.r33());
01299 }
01300 }
01301 else
01302 {
01303 _visualizer->setCameraPosition(
01304 -1, 0, 0,
01305 0, 0, 0,
01306 0, 0, 1);
01307 }
01308 this->update();
01309 }
01310
01311 void CloudViewer::removeAllClouds()
01312 {
01313 _addedClouds.clear();
01314 _visualizer->removeAllPointClouds();
01315 }
01316
01317
01318 bool CloudViewer::removeCloud(const std::string & id)
01319 {
01320 bool success = _visualizer->removePointCloud(id);
01321 _addedClouds.remove(id);
01322 return success;
01323 }
01324
01325 bool CloudViewer::getPose(const std::string & id, Transform & pose)
01326 {
01327 if(_addedClouds.contains(id))
01328 {
01329 pose = _addedClouds.value(id);
01330 return true;
01331 }
01332 return false;
01333 }
01334
01335 Transform CloudViewer::getTargetPose() const
01336 {
01337 if(_lastPose.isNull())
01338 {
01339 return Transform::getIdentity();
01340 }
01341 return _lastPose;
01342 }
01343
01344 void CloudViewer::setBackfaceCulling(bool enabled, bool frontfaceCulling)
01345 {
01346 _backfaceCulling = enabled;
01347 _frontfaceCulling = frontfaceCulling;
01348 }
01349
01350 void CloudViewer::setRenderingRate(double rate)
01351 {
01352 _renderingRate = rate;
01353 _visualizer->getInteractorStyle()->GetInteractor()->SetDesiredUpdateRate(_renderingRate);
01354 }
01355
01356 void CloudViewer::getCameraPosition(
01357 float & x, float & y, float & z,
01358 float & focalX, float & focalY, float & focalZ,
01359 float & upX, float & upY, float & upZ) const
01360 {
01361 std::vector<pcl::visualization::Camera> cameras;
01362 _visualizer->getCameras(cameras);
01363 if(cameras.size())
01364 {
01365 x = cameras.begin()->pos[0];
01366 y = cameras.begin()->pos[1];
01367 z = cameras.begin()->pos[2];
01368 focalX = cameras.begin()->focal[0];
01369 focalY = cameras.begin()->focal[1];
01370 focalZ = cameras.begin()->focal[2];
01371 upX = cameras.begin()->view[0];
01372 upY = cameras.begin()->view[1];
01373 upZ = cameras.begin()->view[2];
01374 }
01375 else
01376 {
01377 UERROR("No camera set!?");
01378 }
01379 }
01380
01381 void CloudViewer::setCameraPosition(
01382 float x, float y, float z,
01383 float focalX, float focalY, float focalZ,
01384 float upX, float upY, float upZ)
01385 {
01386 _lastCameraOrientation= _lastCameraPose= cv::Vec3f(0,0,0);
01387 _visualizer->setCameraPosition(x,y,z, focalX,focalY,focalX, upX,upY,upZ);
01388 }
01389
01390 void CloudViewer::updateCameraTargetPosition(const Transform & pose)
01391 {
01392 if(!pose.isNull())
01393 {
01394 Eigen::Affine3f m = pose.toEigen3f();
01395 Eigen::Vector3f pos = m.translation();
01396
01397 Eigen::Vector3f lastPos(0,0,0);
01398 if(_trajectory->size())
01399 {
01400 lastPos[0]=_trajectory->back().x;
01401 lastPos[1]=_trajectory->back().y;
01402 lastPos[2]=_trajectory->back().z;
01403 }
01404
01405 _trajectory->push_back(pcl::PointXYZ(pos[0], pos[1], pos[2]));
01406 if(_maxTrajectorySize>0)
01407 {
01408 while(_trajectory->size() > _maxTrajectorySize)
01409 {
01410 _trajectory->erase(_trajectory->begin());
01411 }
01412 }
01413 if(_aShowTrajectory->isChecked())
01414 {
01415 _visualizer->removeShape("trajectory");
01416 pcl::PolygonMesh mesh;
01417 pcl::Vertices vertices;
01418 vertices.vertices.resize(_trajectory->size());
01419 for(unsigned int i=0; i<vertices.vertices.size(); ++i)
01420 {
01421 vertices.vertices[i] = i;
01422 }
01423 pcl::toPCLPointCloud2(*_trajectory, mesh.cloud);
01424 mesh.polygons.push_back(vertices);
01425 _visualizer->addPolylineFromPolygonMesh(mesh, "trajectory");
01426 }
01427
01428 if(pose != _lastPose || _lastPose.isNull())
01429 {
01430 if(_lastPose.isNull())
01431 {
01432 _lastPose.setIdentity();
01433 }
01434
01435 std::vector<pcl::visualization::Camera> cameras;
01436 _visualizer->getCameras(cameras);
01437
01438 if(_aLockCamera->isChecked())
01439 {
01440
01441 Eigen::Vector3f diff = pos - Eigen::Vector3f(_lastPose.x(), _lastPose.y(), _lastPose.z());
01442 cameras.front().pos[0] += diff[0];
01443 cameras.front().pos[1] += diff[1];
01444 cameras.front().pos[2] += diff[2];
01445 cameras.front().focal[0] += diff[0];
01446 cameras.front().focal[1] += diff[1];
01447 cameras.front().focal[2] += diff[2];
01448 }
01449 else if(_aFollowCamera->isChecked())
01450 {
01451 Eigen::Vector3f vPosToFocal = Eigen::Vector3f(cameras.front().focal[0] - cameras.front().pos[0],
01452 cameras.front().focal[1] - cameras.front().pos[1],
01453 cameras.front().focal[2] - cameras.front().pos[2]).normalized();
01454 Eigen::Vector3f zAxis(cameras.front().view[0], cameras.front().view[1], cameras.front().view[2]);
01455 Eigen::Vector3f yAxis = zAxis.cross(vPosToFocal);
01456 Eigen::Vector3f xAxis = yAxis.cross(zAxis);
01457 Transform PR(xAxis[0], xAxis[1], xAxis[2],0,
01458 yAxis[0], yAxis[1], yAxis[2],0,
01459 zAxis[0], zAxis[1], zAxis[2],0);
01460
01461 Transform P(PR[0], PR[1], PR[2], cameras.front().pos[0],
01462 PR[4], PR[5], PR[6], cameras.front().pos[1],
01463 PR[8], PR[9], PR[10], cameras.front().pos[2]);
01464 Transform F(PR[0], PR[1], PR[2], cameras.front().focal[0],
01465 PR[4], PR[5], PR[6], cameras.front().focal[1],
01466 PR[8], PR[9], PR[10], cameras.front().focal[2]);
01467 Transform N = pose;
01468 Transform O = _lastPose;
01469 Transform O2N = O.inverse()*N;
01470 Transform F2O = F.inverse()*O;
01471 Transform T = F2O * O2N * F2O.inverse();
01472 Transform Fp = F * T;
01473 Transform P2F = P.inverse()*F;
01474 Transform Pp = P * P2F * T * P2F.inverse();
01475
01476 cameras.front().pos[0] = Pp.x();
01477 cameras.front().pos[1] = Pp.y();
01478 cameras.front().pos[2] = Pp.z();
01479 cameras.front().focal[0] = Fp.x();
01480 cameras.front().focal[1] = Fp.y();
01481 cameras.front().focal[2] = Fp.z();
01482
01483 cameras.front().view[0] = _aLockViewZ->isChecked()?0:Fp[8];
01484 cameras.front().view[1] = _aLockViewZ->isChecked()?0:Fp[9];
01485 cameras.front().view[2] = _aLockViewZ->isChecked()?1:Fp[10];
01486 }
01487
01488 #if PCL_VERSION_COMPARE(>=, 1, 7, 2)
01489 if(_coordinates.find("reference") != _coordinates.end())
01490 {
01491 this->updateCoordinatePose("reference", pose);
01492 }
01493 else
01494 #endif
01495 {
01496 this->addOrUpdateCoordinate("reference", pose, 0.2);
01497 }
01498
01499 vtkRenderer* renderer = _visualizer->getRendererCollection()->GetFirstRenderer();
01500 vtkSmartPointer<vtkCamera> cam = renderer->GetActiveCamera ();
01501 cam->SetPosition (cameras.front().pos[0], cameras.front().pos[1], cameras.front().pos[2]);
01502 cam->SetFocalPoint (cameras.front().focal[0], cameras.front().focal[1], cameras.front().focal[2]);
01503 cam->SetViewUp (cameras.front().view[0], cameras.front().view[1], cameras.front().view[2]);
01504 renderer->ResetCameraClippingRange();
01505 }
01506 }
01507
01508 _lastPose = pose;
01509 }
01510
01511 void CloudViewer::updateCameraFrustum(const Transform & pose, const StereoCameraModel & model)
01512 {
01513 std::vector<CameraModel> models;
01514 models.push_back(model.left());
01515 updateCameraFrustums(pose, models);
01516 }
01517
01518 void CloudViewer::updateCameraFrustum(const Transform & pose, const CameraModel & model)
01519 {
01520 std::vector<CameraModel> models;
01521 models.push_back(model);
01522 updateCameraFrustums(pose, models);
01523 }
01524
01525 void CloudViewer::updateCameraFrustums(const Transform & pose, const std::vector<CameraModel> & models)
01526 {
01527 if(!pose.isNull())
01528 {
01529
01530
01531
01532
01533
01534 if(_aShowFrustum->isChecked())
01535 {
01536 Transform baseToCamera;
01537 Transform opticalRot(0, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0);
01538
01539 for(unsigned int i=0; i<models.size(); ++i)
01540 {
01541 baseToCamera = Transform::getIdentity();
01542 if(!models[i].localTransform().isNull() && !models[i].localTransform().isIdentity())
01543 {
01544 baseToCamera = models[i].localTransform()*opticalRot.inverse();
01545 }
01546 this->addOrUpdateFrustum(uFormat("reference_frustum_%d", i), pose * baseToCamera, _frustumScale, _frustumColor);
01547 if(!baseToCamera.isIdentity())
01548 {
01549 this->addOrUpdateLine(uFormat("reference_frustum_line_%d", i), pose, pose * baseToCamera, _frustumColor);
01550 }
01551 }
01552 }
01553 }
01554 }
01555
01556 const QColor & CloudViewer::getDefaultBackgroundColor() const
01557 {
01558 return _defaultBgColor;
01559 }
01560
01561 void CloudViewer::setDefaultBackgroundColor(const QColor & color)
01562 {
01563 if(_currentBgColor == _defaultBgColor)
01564 {
01565 setBackgroundColor(color);
01566 }
01567 _defaultBgColor = color;
01568 }
01569
01570 const QColor & CloudViewer::getBackgroundColor() const
01571 {
01572 return _currentBgColor;
01573 }
01574
01575 void CloudViewer::setBackgroundColor(const QColor & color)
01576 {
01577 _currentBgColor = color;
01578 _visualizer->setBackgroundColor(color.redF(), color.greenF(), color.blueF());
01579 }
01580
01581 void CloudViewer::setCloudVisibility(const std::string & id, bool isVisible)
01582 {
01583 pcl::visualization::CloudActorMapPtr cloudActorMap = _visualizer->getCloudActorMap();
01584 pcl::visualization::CloudActorMap::iterator iter = cloudActorMap->find(id);
01585 if(iter != cloudActorMap->end())
01586 {
01587 iter->second.actor->SetVisibility(isVisible?1:0);
01588 }
01589 else
01590 {
01591 UERROR("Cannot find actor named \"%s\".", id.c_str());
01592 }
01593 }
01594
01595 bool CloudViewer::getCloudVisibility(const std::string & id)
01596 {
01597 pcl::visualization::CloudActorMapPtr cloudActorMap = _visualizer->getCloudActorMap();
01598 pcl::visualization::CloudActorMap::iterator iter = cloudActorMap->find(id);
01599 if(iter != cloudActorMap->end())
01600 {
01601 return iter->second.actor->GetVisibility() != 0;
01602 }
01603 else
01604 {
01605 UERROR("Cannot find actor named \"%s\".", id.c_str());
01606 }
01607 return false;
01608 }
01609
01610 void CloudViewer::setCloudOpacity(const std::string & id, double opacity)
01611 {
01612 double lastOpacity;
01613 _visualizer->getPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, lastOpacity, id);
01614 if(lastOpacity != opacity)
01615 {
01616 _visualizer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, opacity, id);
01617 }
01618 }
01619
01620 void CloudViewer::setCloudPointSize(const std::string & id, int size)
01621 {
01622 double lastSize;
01623 _visualizer->getPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, lastSize, id);
01624 if((int)lastSize != size)
01625 {
01626 _visualizer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, (double)size, id);
01627 }
01628 }
01629
01630 void CloudViewer::setCameraTargetLocked(bool enabled)
01631 {
01632 _aLockCamera->setChecked(enabled);
01633 }
01634
01635 void CloudViewer::setCameraTargetFollow(bool enabled)
01636 {
01637 _aFollowCamera->setChecked(enabled);
01638 }
01639
01640 void CloudViewer::setCameraFree()
01641 {
01642 _aLockCamera->setChecked(false);
01643 _aFollowCamera->setChecked(false);
01644 }
01645
01646 void CloudViewer::setCameraLockZ(bool enabled)
01647 {
01648 _lastCameraOrientation= _lastCameraPose = cv::Vec3f(0,0,0);
01649 _aLockViewZ->setChecked(enabled);
01650 }
01651
01652 void CloudViewer::setGridShown(bool shown)
01653 {
01654 _aShowGrid->setChecked(shown);
01655 if(shown)
01656 {
01657 this->addGrid();
01658 }
01659 else
01660 {
01661 this->removeGrid();
01662 }
01663 }
01664
01665 bool CloudViewer::isCameraTargetLocked() const
01666 {
01667 return _aLockCamera->isChecked();
01668 }
01669 bool CloudViewer::isCameraTargetFollow() const
01670 {
01671 return _aFollowCamera->isChecked();
01672 }
01673 bool CloudViewer::isCameraFree() const
01674 {
01675 return !_aFollowCamera->isChecked() && !_aLockCamera->isChecked();
01676 }
01677 bool CloudViewer::isCameraLockZ() const
01678 {
01679 return _aLockViewZ->isChecked();
01680 }
01681 bool CloudViewer::isGridShown() const
01682 {
01683 return _aShowGrid->isChecked();
01684 }
01685 unsigned int CloudViewer::getGridCellCount() const
01686 {
01687 return _gridCellCount;
01688 }
01689 float CloudViewer::getGridCellSize() const
01690 {
01691 return _gridCellSize;
01692 }
01693 double CloudViewer::getRenderingRate() const
01694 {
01695 return _renderingRate;
01696 }
01697
01698 void CloudViewer::setGridCellCount(unsigned int count)
01699 {
01700 if(count > 0)
01701 {
01702 _gridCellCount = count;
01703 if(_aShowGrid->isChecked())
01704 {
01705 this->removeGrid();
01706 this->addGrid();
01707 }
01708 }
01709 else
01710 {
01711 UERROR("Cannot set grid cell count < 1, count=%d", count);
01712 }
01713 }
01714 void CloudViewer::setGridCellSize(float size)
01715 {
01716 if(size > 0)
01717 {
01718 _gridCellSize = size;
01719 if(_aShowGrid->isChecked())
01720 {
01721 this->removeGrid();
01722 this->addGrid();
01723 }
01724 }
01725 else
01726 {
01727 UERROR("Cannot set grid cell size <= 0, value=%f", size);
01728 }
01729 }
01730 void CloudViewer::addGrid()
01731 {
01732 if(_gridLines.empty())
01733 {
01734 float cellSize = _gridCellSize;
01735 int cellCount = _gridCellCount;
01736 double r=0.5;
01737 double g=0.5;
01738 double b=0.5;
01739 int id = 0;
01740 float min = -float(cellCount/2) * cellSize;
01741 float max = float(cellCount/2) * cellSize;
01742 std::string name;
01743 for(float i=min; i<=max; i += cellSize)
01744 {
01745
01746 name = uFormat("line%d", ++id);
01747 _visualizer->addLine(pcl::PointXYZ(i, min, 0.0f), pcl::PointXYZ(i, max, 0.0f), r, g, b, name);
01748 _gridLines.push_back(name);
01749
01750 name = uFormat("line%d", ++id);
01751 _visualizer->addLine(
01752 pcl::PointXYZ(min, i, 0),
01753 pcl::PointXYZ(max, i, 0),
01754 r, g, b, name);
01755 _gridLines.push_back(name);
01756 }
01757 }
01758 }
01759
01760 void CloudViewer::removeGrid()
01761 {
01762 for(std::list<std::string>::iterator iter = _gridLines.begin(); iter!=_gridLines.end(); ++iter)
01763 {
01764 _visualizer->removeShape(*iter);
01765 }
01766 _gridLines.clear();
01767 }
01768
01769 Eigen::Vector3f rotatePointAroundAxe(
01770 const Eigen::Vector3f & point,
01771 const Eigen::Vector3f & axis,
01772 float angle)
01773 {
01774 Eigen::Vector3f direction = point;
01775 Eigen::Vector3f zAxis = axis;
01776 float dotProdZ = zAxis.dot(direction);
01777 Eigen::Vector3f ptOnZaxis = zAxis * dotProdZ;
01778 direction -= ptOnZaxis;
01779 Eigen::Vector3f xAxis = direction.normalized();
01780 Eigen::Vector3f yAxis = zAxis.cross(xAxis);
01781
01782 Eigen::Matrix3f newFrame;
01783 newFrame << xAxis[0], yAxis[0], zAxis[0],
01784 xAxis[1], yAxis[1], zAxis[1],
01785 xAxis[2], yAxis[2], zAxis[2];
01786
01787
01788
01789 Eigen::Vector3f newDirection = newFrame.transpose() * direction;
01790
01791
01792 float cosTheta = cos(angle);
01793 float sinTheta = sin(angle);
01794 float magnitude = newDirection.norm();
01795 newDirection[0] = ( magnitude * cosTheta );
01796 newDirection[1] = ( magnitude * sinTheta );
01797
01798
01799 direction = newFrame * newDirection;
01800
01801 return direction + ptOnZaxis;
01802 }
01803
01804 void CloudViewer::keyReleaseEvent(QKeyEvent * event) {
01805 if(event->key() == Qt::Key_Up ||
01806 event->key() == Qt::Key_Down ||
01807 event->key() == Qt::Key_Left ||
01808 event->key() == Qt::Key_Right)
01809 {
01810 _keysPressed -= (Qt::Key)event->key();
01811 }
01812 else
01813 {
01814 QVTKWidget::keyPressEvent(event);
01815 }
01816 }
01817
01818 void CloudViewer::keyPressEvent(QKeyEvent * event)
01819 {
01820 if(event->key() == Qt::Key_Up ||
01821 event->key() == Qt::Key_Down ||
01822 event->key() == Qt::Key_Left ||
01823 event->key() == Qt::Key_Right)
01824 {
01825 _keysPressed += (Qt::Key)event->key();
01826
01827 std::vector<pcl::visualization::Camera> cameras;
01828 _visualizer->getCameras(cameras);
01829
01830
01831 Eigen::Vector3f pos(cameras.front().pos[0], cameras.front().pos[1], _aLockViewZ->isChecked()?0:cameras.front().pos[2]);
01832 Eigen::Vector3f focal(cameras.front().focal[0], cameras.front().focal[1], _aLockViewZ->isChecked()?0:cameras.front().focal[2]);
01833 Eigen::Vector3f viewUp(cameras.front().view[0], cameras.front().view[1], cameras.front().view[2]);
01834 Eigen::Vector3f cummulatedDir(0,0,0);
01835 Eigen::Vector3f cummulatedFocalDir(0,0,0);
01836 float step = 0.2f;
01837 float stepRot = 0.02f;
01838 if(_keysPressed.contains(Qt::Key_Up))
01839 {
01840 Eigen::Vector3f dir;
01841 if(event->modifiers() & Qt::ShiftModifier)
01842 {
01843 dir = viewUp * step;
01844 }
01845 else
01846 {
01847 dir = (focal-pos).normalized() * step;
01848 }
01849 cummulatedDir += dir;
01850 }
01851 if(_keysPressed.contains(Qt::Key_Down))
01852 {
01853 Eigen::Vector3f dir;
01854 if(event->modifiers() & Qt::ShiftModifier)
01855 {
01856 dir = viewUp * -step;
01857 }
01858 else
01859 {
01860 dir = (focal-pos).normalized() * -step;
01861 }
01862 cummulatedDir += dir;
01863 }
01864 if(_keysPressed.contains(Qt::Key_Right))
01865 {
01866 if(event->modifiers() & Qt::ShiftModifier)
01867 {
01868
01869 Eigen::Vector3f point = (focal-pos);
01870 Eigen::Vector3f newPoint = rotatePointAroundAxe(point, viewUp, -stepRot);
01871 Eigen::Vector3f diff = newPoint - point;
01872 cummulatedFocalDir += diff;
01873 }
01874 else
01875 {
01876 Eigen::Vector3f dir = ((focal-pos).cross(viewUp)).normalized() * step;
01877 cummulatedDir += dir;
01878 }
01879 }
01880 if(_keysPressed.contains(Qt::Key_Left))
01881 {
01882 if(event->modifiers() & Qt::ShiftModifier)
01883 {
01884
01885 Eigen::Vector3f point = (focal-pos);
01886 Eigen::Vector3f newPoint = rotatePointAroundAxe(point, viewUp, stepRot);
01887 Eigen::Vector3f diff = newPoint - point;
01888 cummulatedFocalDir += diff;
01889 }
01890 else
01891 {
01892 Eigen::Vector3f dir = ((focal-pos).cross(viewUp)).normalized() * -step;
01893 cummulatedDir += dir;
01894 }
01895 }
01896
01897 cameras.front().pos[0] += cummulatedDir[0];
01898 cameras.front().pos[1] += cummulatedDir[1];
01899 cameras.front().pos[2] += cummulatedDir[2];
01900 cameras.front().focal[0] += cummulatedDir[0] + cummulatedFocalDir[0];
01901 cameras.front().focal[1] += cummulatedDir[1] + cummulatedFocalDir[1];
01902 cameras.front().focal[2] += cummulatedDir[2] + cummulatedFocalDir[2];
01903 _visualizer->setCameraPosition(
01904 cameras.front().pos[0], cameras.front().pos[1], cameras.front().pos[2],
01905 cameras.front().focal[0], cameras.front().focal[1], cameras.front().focal[2],
01906 cameras.front().view[0], cameras.front().view[1], cameras.front().view[2]);
01907
01908 update();
01909
01910 emit configChanged();
01911 }
01912 else
01913 {
01914 QVTKWidget::keyPressEvent(event);
01915 }
01916 }
01917
01918 void CloudViewer::mousePressEvent(QMouseEvent * event)
01919 {
01920 if(event->button() == Qt::RightButton)
01921 {
01922 event->accept();
01923 }
01924 else
01925 {
01926 QVTKWidget::mousePressEvent(event);
01927 }
01928 }
01929
01930 void CloudViewer::mouseMoveEvent(QMouseEvent * event)
01931 {
01932 QVTKWidget::mouseMoveEvent(event);
01933
01934
01935 if(_aLockViewZ->isChecked())
01936 {
01937 std::vector<pcl::visualization::Camera> cameras;
01938 _visualizer->getCameras(cameras);
01939
01940 cv::Vec3d newCameraOrientation = cv::Vec3d(0,0,1).cross(cv::Vec3d(cameras.front().pos)-cv::Vec3d(cameras.front().focal));
01941
01942 if( _lastCameraOrientation!=cv::Vec3d(0,0,0) &&
01943 _lastCameraPose!=cv::Vec3d(0,0,0) &&
01944 (uSign(_lastCameraOrientation[0]) != uSign(newCameraOrientation[0]) &&
01945 uSign(_lastCameraOrientation[1]) != uSign(newCameraOrientation[1])))
01946 {
01947 cameras.front().pos[0] = _lastCameraPose[0];
01948 cameras.front().pos[1] = _lastCameraPose[1];
01949 cameras.front().pos[2] = _lastCameraPose[2];
01950 }
01951 else if(newCameraOrientation != cv::Vec3d(0,0,0))
01952 {
01953 _lastCameraOrientation = newCameraOrientation;
01954 _lastCameraPose = cv::Vec3d(cameras.front().pos);
01955 }
01956 cameras.front().view[0] = 0;
01957 cameras.front().view[1] = 0;
01958 cameras.front().view[2] = 1;
01959
01960 _visualizer->setCameraPosition(
01961 cameras.front().pos[0], cameras.front().pos[1], cameras.front().pos[2],
01962 cameras.front().focal[0], cameras.front().focal[1], cameras.front().focal[2],
01963 cameras.front().view[0], cameras.front().view[1], cameras.front().view[2]);
01964
01965 }
01966 this->update();
01967
01968 emit configChanged();
01969 }
01970
01971 void CloudViewer::wheelEvent(QWheelEvent * event)
01972 {
01973 QVTKWidget::wheelEvent(event);
01974 if(_aLockViewZ->isChecked())
01975 {
01976 std::vector<pcl::visualization::Camera> cameras;
01977 _visualizer->getCameras(cameras);
01978 _lastCameraPose = cv::Vec3d(cameras.front().pos);
01979 }
01980 emit configChanged();
01981 }
01982
01983 void CloudViewer::contextMenuEvent(QContextMenuEvent * event)
01984 {
01985 QAction * a = _menu->exec(event->globalPos());
01986 if(a)
01987 {
01988 handleAction(a);
01989 emit configChanged();
01990 }
01991 }
01992
01993 void CloudViewer::handleAction(QAction * a)
01994 {
01995 if(a == _aSetTrajectorySize)
01996 {
01997 bool ok;
01998 int value = QInputDialog::getInt(this, tr("Set trajectory size"), tr("Size (0=infinite)"), _maxTrajectorySize, 0, 10000, 10, &ok);
01999 if(ok)
02000 {
02001 _maxTrajectorySize = value;
02002 }
02003 }
02004 else if(a == _aClearTrajectory)
02005 {
02006 this->clearTrajectory();
02007 }
02008 else if(a == _aShowFrustum)
02009 {
02010 this->setFrustumShown(a->isChecked());
02011 }
02012 else if(a == _aSetFrustumScale)
02013 {
02014 bool ok;
02015 double value = QInputDialog::getDouble(this, tr("Set frustum scale"), tr("Scale"), _frustumScale, 0.0, 999.0, 1, &ok);
02016 if(ok)
02017 {
02018 this->setFrustumScale(value);
02019 }
02020 }
02021 else if(a == _aSetFrustumColor)
02022 {
02023 QColor value = QColorDialog::getColor(_frustumColor, this);
02024 if(value.isValid())
02025 {
02026 this->setFrustumColor(value);
02027 }
02028 }
02029 else if(a == _aResetCamera)
02030 {
02031 this->resetCamera();
02032 }
02033 else if(a == _aShowGrid)
02034 {
02035 if(_aShowGrid->isChecked())
02036 {
02037 this->addGrid();
02038 }
02039 else
02040 {
02041 this->removeGrid();
02042 }
02043
02044 this->update();
02045 }
02046 else if(a == _aSetGridCellCount)
02047 {
02048 bool ok;
02049 int value = QInputDialog::getInt(this, tr("Set grid cell count"), tr("Count"), _gridCellCount, 1, 10000, 10, &ok);
02050 if(ok)
02051 {
02052 this->setGridCellCount(value);
02053 }
02054 }
02055 else if(a == _aSetGridCellSize)
02056 {
02057 bool ok;
02058 double value = QInputDialog::getDouble(this, tr("Set grid cell size"), tr("Size (m)"), _gridCellSize, 0.01, 10, 2, &ok);
02059 if(ok)
02060 {
02061 this->setGridCellSize(value);
02062 }
02063 }
02064 else if(a == _aSetBackgroundColor)
02065 {
02066 QColor color = this->getDefaultBackgroundColor();
02067 color = QColorDialog::getColor(color, this);
02068 if(color.isValid())
02069 {
02070 this->setDefaultBackgroundColor(color);
02071 this->update();
02072 }
02073 }
02074 else if(a == _aSetRenderingRate)
02075 {
02076 bool ok;
02077 double value = QInputDialog::getDouble(this, tr("Rendering rate"), tr("Rate (hz)"), _renderingRate, 0, 60, 0, &ok);
02078 if(ok)
02079 {
02080 this->setRenderingRate(value);
02081 }
02082 }
02083 else if(a == _aLockViewZ)
02084 {
02085 if(_aLockViewZ->isChecked())
02086 {
02087 this->update();
02088 }
02089 }
02090 }
02091
02092 }