36 #define _MAXRANGE_URG 5.1
37 #define _MAXRANGE_SICK 50.0
42 : QMainWindow(parent), m_scanGraph(NULL),
43 m_trajectoryDrawer(NULL), m_pointcloudDrawer(NULL),
44 m_cameraFollowMode(NULL),
45 m_octreeResolution(0.1), m_laserMaxRange(-1.), m_occupancyThresh(0.5),
46 m_max_tree_depth(initDepth > 0 && initDepth <= 16 ? initDepth : 16),
47 m_laserType(LASERTYPE_SICK),
48 m_cameraStored(false),
59 QDockWidget* settingsDock =
new QDockWidget(
"Octree / Scan graph settings",
this);
60 settingsDock->setWidget(settingsPanel);
61 this->addDockWidget(Qt::RightDockWidgetArea, settingsDock);
62 ui.menuShow->addAction(settingsDock->toggleViewAction());
66 QDockWidget *settingsCameraDock =
new QDockWidget(
"Camera settings",
this);
67 settingsCameraDock->setWidget(settingsCameraPanel);
68 this->addDockWidget(Qt::RightDockWidgetArea, settingsCameraDock);
69 this->tabifyDockWidget(settingsDock, settingsCameraDock);
70 settingsDock->raise();
71 ui.menuShow->addAction(settingsCameraDock->toggleViewAction());
86 connect(
this, SIGNAL(
updateStatusBar(QString,
int)), statusBar(), SLOT(showMessage(QString,
int)));
88 connect(settingsPanel, SIGNAL(treeDepthChanged(
int)),
this, SLOT(
changeTreeDepth(
int)));
92 connect(settingsCameraPanel, SIGNAL(jumpToFrame(
unsigned)),
m_cameraFollowMode, SLOT(jumpToFrame(
unsigned)));
95 connect(settingsCameraPanel, SIGNAL(clearCameraPath()),
m_cameraFollowMode, SLOT(clearCameraPath()));
96 connect(settingsCameraPanel, SIGNAL(saveToCameraPath()),
m_cameraFollowMode, SLOT(saveToCameraPath()));
97 connect(settingsCameraPanel, SIGNAL(removeFromCameraPath()),
m_cameraFollowMode, SLOT(removeFromCameraPath()));
98 connect(settingsCameraPanel, SIGNAL(addToCameraPath()),
m_cameraFollowMode, SLOT(addToCameraPath()));
99 connect(settingsCameraPanel, SIGNAL(followCameraPath()),
m_cameraFollowMode, SLOT(followCameraPath()));
100 connect(settingsCameraPanel, SIGNAL(followRobotPath()),
m_cameraFollowMode, SLOT(followRobotPath()));
102 connect(
m_cameraFollowMode, SIGNAL(changeNumberOfFrames(
unsigned)), settingsCameraPanel, SLOT(setNumberOfFrames(
unsigned)));
103 connect(
m_cameraFollowMode, SIGNAL(frameChanged(
unsigned)), settingsCameraPanel, SLOT(setCurrentFrame(
unsigned)));
104 connect(
m_cameraFollowMode, SIGNAL(stopped()), settingsCameraPanel, SLOT(setStopped()));
105 connect(
m_cameraFollowMode, SIGNAL(scanGraphAvailable(
bool)), settingsCameraPanel, SLOT(setRobotTrajectoryAvailable(
bool)));
119 connect(
this, SIGNAL(
changeNumberOfScans(
unsigned)), settingsPanel, SLOT(setNumberOfScans(
unsigned)));
120 connect(
this, SIGNAL(
changeCurrentScan(
unsigned)), settingsPanel, SLOT(setCurrentScan(
unsigned)));
121 connect(
this, SIGNAL(
changeResolution(
double)), settingsPanel, SLOT(setResolution(
double)));
123 connect(settingsCameraPanel, SIGNAL(
changeCamPosition(
double,
double,
double,
double,
double,
double)),
124 m_glwidget, SLOT(setCamPosition(
double,
double,
double,
double,
double,
double)));
128 connect(
ui.actionReset_view, SIGNAL(triggered()),
m_glwidget, SLOT(resetView()));
150 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin(); it !=
m_octrees.end(); ++it) {
152 delete (it->second.octree_drawer);
153 delete (it->second.octree);
168 std::cerr <<
string.toLocal8Bit().data();
169 if (newline) std::cerr << std::endl;
170 else std::cerr << std::flush;
178 std::map<int, OcTreeRecord>::iterator it =
m_octrees.find(
id);
195 if (
dynamic_cast<OcTree*
>(tree)) {
219 if (
dynamic_cast<OcTree*
>(tree)) {
243 double minX, minY, minZ, maxX, maxY, maxZ;
244 minX = minY = minZ = -10;
245 maxX = maxY = maxZ = 10;
246 double sizeX, sizeY, sizeZ;
247 sizeX = sizeY = sizeZ = 0.;
248 size_t memoryUsage = 0;
249 size_t num_nodes = 0;
250 size_t memorySingleNode = 0;
253 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin(); it !=
m_octrees.end(); ++it) {
255 double lminX, lminY, lminZ, lmaxX, lmaxY, lmaxZ;
256 it->second.octree->getMetricMin(lminX, lminY, lminZ);
257 it->second.octree->getMetricMax(lmaxX, lmaxY, lmaxZ);
261 pmin = it->second.origin.transform(pmin);
262 pmax = it->second.origin.transform(pmax);
263 lminX = pmin.
x(); lminY = pmin.
y(); lminZ = pmin.
z();
264 lmaxX = pmax.
x(); lmaxY = pmax.
y(); lmaxZ = pmax.
z();
266 if (lminX < minX) minX = lminX;
267 if (lminY < minY) minY = lminY;
268 if (lminZ < minZ) minZ = lminZ;
269 if (lmaxX > maxX) maxX = lmaxX;
270 if (lmaxY > maxY) maxY = lmaxY;
271 if (lmaxZ > maxZ) maxZ = lmaxZ;
272 double lsizeX, lsizeY, lsizeZ;
274 it->second.octree->getMetricSize(lsizeX, lsizeY, lsizeZ);
275 if (lsizeX > sizeX) sizeX = lsizeX;
276 if (lsizeY > sizeY) sizeY = lsizeY;
277 if (lsizeZ > sizeZ) sizeZ = lsizeZ;
278 memoryUsage += it->second.octree->memoryUsage();
279 num_nodes += it->second.octree->size();
280 memorySingleNode = std::max(memorySingleNode, it->second.octree->memoryUsageNode());
286 QString size = QString(
"%L1 x %L2 x %L3 m^3; %L4 nodes").arg(sizeX).arg(sizeY).arg(sizeZ).arg(
unsigned(num_nodes));
287 QString memory = QString(
"Single node: %L1 B; ").arg(memorySingleNode)
288 + QString (
"Octree: %L1 B (%L2 MB)").arg(memoryUsage).arg((
double) memoryUsage/(1024.*1024.), 0,
'f', 3);
299 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin(); it !=
m_octrees.end(); ++it) {
301 it->second.octree_drawer->setOcTree(*it->second.octree, it->second.origin, it->second.id);
314 QApplication::setOverrideCursor(Qt::WaitCursor);
317 std::cerr << std::endl;
324 unsigned currentScan = 1;
327 fprintf(stderr,
"generateOctree:: inserting scan node with %d points, origin: %.2f ,%.2f , %.2f.\n",
328 (
unsigned int) (*it)->scan->size(), (*it)->pose.x(), (*it)->pose.y(), (*it)->pose.z() );
330 std::cout <<
" S ("<<currentScan<<
"/"<<numScans<<
") " << std::flush;
338 QApplication::restoreOverrideCursor();
341 std::cerr <<
"generateOctree called but no ScanGraph present!\n";
350 showInfo(
"Inserting first scan node into tree... ",
true);
351 QApplication::setOverrideCursor(Qt::WaitCursor);
362 QApplication::restoreOverrideCursor();
370 showInfo(
"Inserting next scan node into tree... ",
true);
372 QApplication::setOverrideCursor(Qt::WaitCursor);
376 fprintf(stderr,
"ERROR: OctreeRecord for id %d not found!\n",
DEFAULT_OCTREE_ID);
384 QApplication::restoreOverrideCursor();
392 for (
unsigned i = 0; i < scans; ++i){
405 QFileInfo fileinfo(temp);
406 this->setWindowTitle(fileinfo.fileName());
407 if (fileinfo.suffix() ==
"graph"){
409 }
else if (fileinfo.suffix() ==
"bt"){
412 else if (fileinfo.suffix() ==
"ot")
416 else if (fileinfo.suffix() ==
"hot"){
419 else if (fileinfo.suffix() ==
"dat"){
423 QMessageBox::warning(
this,
"Unknown file",
"Cannot open file, unknown extension: "+fileinfo.suffix(), QMessageBox::Ok);
431 QApplication::setOverrideCursor(Qt::WaitCursor);
444 QApplication::setOverrideCursor(Qt::WaitCursor);
456 std::cout <<
"ERROR: could not read " <<
m_filename << std::endl;
462 pose6d laser_pose(0,0,0,0,0,0);
471 ui.actionPointcloud->setChecked(
false);
472 ui.actionPointcloud->setEnabled(
false);
473 ui.actionOctree_cells->setChecked(
true);
474 ui.actionOctree_cells->setEnabled(
true);
475 ui.actionFree->setChecked(
false);
476 ui.actionFree->setEnabled(
true);
477 ui.actionOctree_structure->setEnabled(
true);
478 ui.actionOctree_structure->setChecked(
false);
479 ui.actionTrajectory->setEnabled(
false);
480 ui.actionConvert_ml_tree->setEnabled(
true);
481 ui.actionReload_Octree->setEnabled(
true);
482 ui.actionSettings->setEnabled(
false);
483 ui.actionSelected->setChecked(
true);
484 ui.actionSelected->setEnabled(
true);
514 ui.actionHeight_map->setText (
"Map color");
516 ui.actionHeight_map->setChecked(
true);
520 QMessageBox::warning(
this,
"File error",
"Cannot open OcTree file", QMessageBox::Ok);
530 std::ifstream infile(
m_filename.c_str(), std::ios_base::in |std::ios_base::binary);
531 if (!infile.is_open()) {
532 QMessageBox::warning(
this,
"File error",
"Cannot open OcTree file", QMessageBox::Ok);
540 it != collection.
end(); ++it) {
541 OCTOMAP_DEBUG(
"Adding hierarchy node %s\n", (*it)->getId().c_str());
542 OcTree* tree = (*it)->getMap();
544 OCTOMAP_ERROR(
"Error while reading node %s\n", (*it)->getId().c_str());
548 pose6d origin = (*it)->getOrigin();
560 ui.actionSettings->setEnabled(
true);
561 ui.actionPointcloud->setEnabled(
true);
562 ui.actionPointcloud->setChecked(
false);
563 ui.actionTrajectory->setEnabled(
true);
564 ui.actionOctree_cells->setEnabled(
true);
565 ui.actionOctree_cells->setChecked(
true);
566 ui.actionOctree_structure->setEnabled(
true);
567 ui.actionOctree_structure->setChecked(
false);
568 ui.actionFree->setChecked(
false);
569 ui.actionFree->setEnabled(
true);
570 ui.actionReload_Octree->setEnabled(
true);
571 ui.actionConvert_ml_tree->setEnabled(
true);
574 unsigned currentScan;
577 fprintf(stderr,
"loadGraph:: generating octree from complete graph.\n" );
580 currentScan = graphSize;
596 QApplication::restoreOverrideCursor();
600 showInfo(
"Done (" +QString::number(currentScan)+
" of "+ QString::number(graphSize)+
" nodes)",
true);
614 if (
ui.actionTrajectory->isChecked())
617 if (
ui.actionPointcloud->isChecked())
623 if (depth < 1 || depth > 16)
661 bool maxRangeChanged = (std::abs(oldLaserMaxRange -
m_laserMaxRange) > 1e-5);
663 if (resolutionChanged)
668 }
else if (resolutionChanged || maxRangeChanged){
676 QString filename = QFileDialog::getOpenFileName(
this,
677 tr(
"Open data file"),
"",
678 "All supported files (*.graph *.bt *.ot *.dat);;OcTree file (*.ot);;Bonsai tree file (*.bt);;Binary scan graph (*.graph);;Pointcloud (*.dat);;All files (*)");
679 if (!filename.isEmpty()){
681 m_filename = std::string(filename.toLocal8Bit().data());
691 QString filename = QFileDialog::getOpenFileName(
this,
692 tr(
"Open graph file incrementally (at start)"),
"",
693 "Binary scan graph (*.graph)");
694 if (!filename.isEmpty()){
698 m_filename = std::string(filename.toLocal8Bit().data());
711 fprintf(stderr,
"ERROR: OctreeRecord for id %d not found!\n",
DEFAULT_OCTREE_ID);
712 QMessageBox::warning(
this, tr(
"3D Mapping Viewer"),
713 "Error: No OcTree present.",
718 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save octree file"),
719 "", tr(
"Full OcTree (*.ot);;Bonsai Tree file (*.bt);;"), 0, QFileDialog::DontUseNativeDialog);
722 QApplication::setOverrideCursor(Qt::WaitCursor);
723 showInfo(
"Writing file... ",
false);
725 QFileInfo fileinfo(filename);
726 std::string std_filename;
728 std_filename = filename.toLocal8Bit().data();
730 std_filename = filename.toStdString();
735 if (fileinfo.suffix() ==
"bt") {
740 QMessageBox::warning(
this,
"Unknown tree type",
741 "Could not convert to occupancy tree for writing .bt file",
745 else if (fileinfo.suffix() ==
"ot"){
749 QMessageBox::warning(
this,
"Unknown file",
750 "Cannot write file, unknown extension: "+fileinfo.suffix(),
754 QApplication::restoreOverrideCursor();
814 for (std::map<int, OcTreeRecord>::iterator t_it =
m_octrees.begin(); t_it !=
m_octrees.end(); ++t_it) {
815 OcTree* octree =
dynamic_cast<OcTree*
>(t_it->second.octree);
820 octree->
deleteNode(it.getKey(), it.getDepth());
823 QMessageBox::warning(
this,
"Not implemented",
"Functionality not yet implemented for this octree type",
837 for (std::map<int, OcTreeRecord>::iterator t_it =
m_octrees.begin(); t_it !=
m_octrees.end(); ++t_it) {
838 OcTree* octree =
dynamic_cast<OcTree*
>(t_it->second.octree);
847 for(OcTree::leaf_iterator it = octree->
begin_leafs(),
848 end=octree->
end_leafs(); it!= end; ++it){
851 if (k[0] < minKey[0] || k[1] < minKey[1] || k[2] < minKey[2]
852 || k[0] > maxKey[0] || k[1] > maxKey[1] || k[2] > maxKey[2])
858 QMessageBox::warning(
this,
"Not implemented",
"Functionality not yet implemented for this octree type",
866 for (std::map<int, OcTreeRecord>::iterator t_it =
m_octrees.begin(); t_it !=
m_octrees.end(); ++t_it) {
867 OcTree* octree =
dynamic_cast<OcTree*
>(t_it->second.octree);
887 QMessageBox::warning(
this,
"Not implemented",
"Functionality not yet implemented for this octree type",
897 for (std::map<int, OcTreeRecord>::iterator t_it =
m_octrees.begin(); t_it !=
m_octrees.end(); ++t_it) {
898 OcTree* octree =
dynamic_cast<OcTree*
>(t_it->second.octree);
910 for (k[0] = minKey[0]; k[0] < maxKey[0]; ++k[0]){
911 for (k[1] = minKey[1]; k[1] < maxKey[1]; ++k[1]){
912 for (k[2] = minKey[2]; k[2] < maxKey[2]; ++k[2]){
925 for (std::map<int, OcTreeRecord>::iterator t_it =
m_octrees.begin(); t_it !=
m_octrees.end(); ++t_it) {
926 OcTree* octree =
dynamic_cast<OcTree*
>(t_it->second.octree);
938 for (k[0] = minKey[0]; k[0] < maxKey[0]; ++k[0]){
939 for (k[1] = minKey[1]; k[1] < maxKey[1]; ++k[1]){
940 for (k[2] = minKey[2]; k[2] < maxKey[2]; ++k[2]){
966 ui.actionExport_sequence->setChecked(
false);
975 ui.actionHeight_map->setChecked(
false);
976 ui.actionSemanticColoring->setChecked(
false);
984 ui.menuDelete_nodes->setEnabled(checked);
985 ui.menuFill_selection->setEnabled(checked);
986 ui.menuChange_nodes_in_selection->setEnabled(checked);
997 ui.actionPrintout_mode->setChecked(
false);
998 ui.actionSemanticColoring->setChecked(
false);
1005 ui.actionHeight_map->setChecked(
false);
1006 ui.actionPrintout_mode->setChecked(
false);
1017 ui.actionRestore_camera->setEnabled(
true);
1045 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin();
1047 it->second.octree_drawer->enableAxes(checked);
1062 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin(); it !=
m_octrees.end(); ++it) {
1064 it->second.octree_drawer->setAlternativeDrawing(checked);
1069 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin();
1072 delete (it->second.octree_drawer);
1073 delete (it->second.octree);
1080 QPoint pixel_coord = e->pos();
1084 const point3d origin3d{(float)origin.
x,(
float)origin.
y,(float)origin.
z};
1085 const point3d direction3d{(float)direction.
x,(
float)direction.
y,(float)direction.
z};
1087 QString message = QString(
"--, --, -- m");
1088 std::list<octomap::OcTreeVolume> selection;
1090 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin(); it !=
m_octrees.end(); ++it)
1093 bool ray_hit =
false;
1094 if (
OcTree* occupancytree =
dynamic_cast<OcTree*
>(tree))
1096 ray_hit = occupancytree->castRay(origin3d, direction3d, end3d,
true);
1100 ray_hit = occupancytree->castRay(origin3d, direction3d, end3d,
true);
1109 message = QString(
"%L1, %L2, %L3 m").arg(end3d.
x()).arg(end3d.
y()).arg(end3d.
z());
1111 selection.push_back(voxel);
1112 it->second.octree_drawer->setOcTreeSelection(selection);
1114 else it->second.octree_drawer->clearOcTreeSelection();
1133 QApplication::setOverrideCursor(Qt::WaitCursor);
1135 showInfo(
"Converting OcTree to maximum Likelihood map... ");
1136 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin();
1139 if (
dynamic_cast<OcTree*
>(t)) {
1140 ((
OcTree*) t)->toMaxLikelihood();
1142 else if (
dynamic_cast<OcTree*
>(t)) {
1148 QApplication::restoreOverrideCursor();
1154 QApplication::setOverrideCursor(Qt::WaitCursor);
1157 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin();
1159 it->second.octree->prune();
1164 QApplication::restoreOverrideCursor();
1170 QApplication::setOverrideCursor(Qt::WaitCursor);
1175 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin();
1177 it->second.octree->expand();
1183 QApplication::restoreOverrideCursor();
1188 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin();
1190 it->second.octree_drawer->enableOcTreeCells(enabled);
1196 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin();
1198 it->second.octree_drawer->enableOcTree(enabled);
1204 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin();
1206 it->second.octree_drawer->enableFreespace(enabled);
1213 for (std::map<int, OcTreeRecord>::iterator it =
m_octrees.begin();
1215 if(it->second.octree_drawer)
1216 it->second.octree_drawer->enableSelection(enabled);
1234 QString filename = QFileDialog::getSaveFileName(
this,
"Save Viewer State",
"camera.xml",
"Camera/State file (*.xml)");
1235 if (!filename.isEmpty()) {
1236 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
1238 #else // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
1240 #endif // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
1245 QString filename = QFileDialog::getOpenFileName(
this,
"Load Viewer State",
"camera.xml",
"Camera/State file (*.xml)");
1246 if (!filename.isEmpty()) {
1247 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
1249 #else // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
1251 #endif // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)