qt_gui.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 /* This is the main widget of the application.
00019  * It sets up some not yet useful menus and
00020  * three qlabels in the layout of the central widget
00021  * that can be used to show qimages via the slots
00022  * setDepthImage and setVisualImage.
00023  */
00024 #include <QtGui>
00025 #include <QDir>
00026 #include <QPixmap>
00027 #include <QFont>
00028 #include <QIcon>
00029 #include <QKeySequence>
00030 #include "qt_gui.h"
00031 #include <limits>
00032 #include "glviewer.h"
00033 #include <QList>
00034 #include <QComboBox>
00035 
00037 Graphical_UI::Graphical_UI() : filename("quicksave.pcd"), glviewer(NULL)
00038 {
00039   setup();
00040   setWindowTitle(tr("RGBDSLAM"));
00041 }
00043 Graphical_UI::Graphical_UI(QString title) : filename("quicksave.pcd"), glviewer(NULL)
00044 {
00045   setup();
00046   setWindowTitle(title);
00047 }
00048 
00050 static void formatImageLabel(QLabel* label){
00051     label->setWordWrap(true);//for infotext in rightmost label
00052     label->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
00053     label->setMinimumSize(4,100);
00054     label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
00055 
00056     if(ParameterServer::instance()->get<bool>("scalable_2d_display")) {
00057       label->setScaledContents(true);
00058     }
00059 }
00060 
00061 void Graphical_UI::initTexts(){
00062     infoText = new QString(tr(
00063                 "<p><b>RGBDSLAMv2</b> uses visual features to identify corresponding 3D locations "
00064                 "in RGB-D data. The correspondences are used to reconstruct the camera motion. "
00065                 "The SLAM-backend g2o is used to integrate the transformations between"
00066                 "the RGBD-images and compute a globally consistent 6D trajectory.</p>"
00067                 "<p></p>"));
00068     licenseText = new QString(tr(
00069                  "<p>RGBDSLAMv2 is free software: you can redistribute it and/or modify"
00070                  "it under the terms of the GNU General Public License as published by"
00071                  "the Free Software Foundation, either version 3 of the License, or"
00072                  "(at your option) any later version.</p>"
00073                  "<p>RGBDSLAMv2 is distributed in the hope that it will be useful,"
00074                  "but WITHOUT ANY WARRANTY; without even the implied warranty of"
00075                  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the"
00076                  "GNU General Public License for more details.</p>"
00077                  "<p>You should have received a copy of the GNU General Public License"
00078                  "along with RGBDSLAMv2.  If not, refer to <a href=\"http://www.gnu.org/licenses/\">http://www.gnu.org/licenses</a>.</p>"));
00079     mouseHelpText = new QString(tr(
00080                 "<p><b>3D Viewer Mouse Commands:</b>"
00081                 "<ul><li><i>Left button:</i> Rotate view around x/y.</li>"
00082                 "    <li><i>Ctrl + left button:</i> rotate view around x/z.</li>"
00083                 "    <li><i>Shift + left button:</i> Translate view.</li>"
00084                 "    <li><i>Wheel:</i> zoom view.</li>"
00085                 "    <li><i>Ctrl + Wheel:</i> change 3D point size.</li>"
00086                 "    <li><i>Double click (on background):</i> reset camera position to latest pose.</li>"
00087                 "    <li><i>Ctrl + Double click (on background):</i> reset camera position to first pose (only works if follow mode is off).</li>"
00088                 "    <li><i>Double click on object:</i> set pivot to clicked point (only works if follow mode is off).</li>"
00089                 "<ul></p>")); 
00090 }
00091 
00092 void Graphical_UI::setup(){
00093     initTexts();    
00094 
00095     ParameterServer* ps = ParameterServer::instance();
00096 
00097     // create widgets for image and map display
00098     std::string visual_topic = ps->get<std::string>("topic_image_mono");
00099     QString vl("Waiting for visual image on topic<br/><i>\""); vl += visual_topic.c_str(); vl += "\"</i>";
00100     visual_image_label = new QLabel(vl);
00101     formatImageLabel(visual_image_label);
00102 
00103     std::string depth_topic = ps->get<std::string>("topic_image_depth");
00104     QString dl("Waiting for depth image on topic<br/><i>\""); dl += depth_topic.c_str(); 
00105     dl += "\"</i><br/>";
00106 
00107     depth_image_label = new QLabel(dl);
00108     formatImageLabel(depth_image_label);
00109 
00110     feature_image_label = new QLabel(tr("<i>Waiting for feature image...</i>"));
00111     formatImageLabel(feature_image_label);
00112     
00113     feature_flow_image_label = new QLabel(*mouseHelpText);
00114     formatImageLabel(feature_flow_image_label);
00115 
00116     QSplitter* hsplitter = new QSplitter(Qt::Horizontal);
00117     hsplitter->addWidget(visual_image_label);
00118     hsplitter->addWidget(depth_image_label);
00119     hsplitter->addWidget(feature_image_label);
00120     hsplitter->addWidget(feature_flow_image_label);
00121 
00122     // setup the layout:
00123     // use a splitter as main widget
00124     vsplitter = new QSplitter(Qt::Vertical);
00125     setCentralWidget(vsplitter);
00126 
00127     // add glviewer as top item to splitter
00128     if(ps->get<bool>("use_glwidget")) {
00129       glviewer = new GLViewer(this);//displays the cloud in 3d
00130       vsplitter->addWidget(glviewer);
00131     }
00132 
00133     vsplitter->addWidget(hsplitter);
00134 
00135     createMenus();
00136 
00137     setupStatusbar();
00138 
00139     setMinimumSize(600, 290);
00140     resize(1000, 700);
00141 }
00142 
00143 void Graphical_UI::setupStatusbar(){
00144     tmpLabel = new QLabel();
00145     statusBar()->insertWidget(0,tmpLabel, 0);
00146     QString message = tr("Ready for RGB-D SLAM");
00147     statusBar()->showMessage(message);
00148     infoLabel2 = new QLabel(tr("Empty Map"));
00149     infoLabel2->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
00150     infoLabel2->setAlignment(Qt::AlignRight);
00151     statusBar()->addPermanentWidget(infoLabel2, 0);
00152 
00153     if(ParameterServer::instance()->get<bool>("start_paused")){
00154       infoLabel = new QLabel(tr("<i>Press Enter or Space to Start</i>"));
00155     } else {
00156       infoLabel = new QLabel(tr("<i>No data yet.</i>"));
00157     }
00158     infoLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
00159     infoLabel->setAlignment(Qt::AlignRight);
00160     statusBar()->addPermanentWidget(infoLabel, 0);
00161 
00162 }
00163 
00164 
00165 
00166 
00167 void Graphical_UI::setLabelToImage(QLabel* label, QImage image){
00168   if(label->isVisible()){
00169     label->setMaximumHeight(image.size().height());
00170     label->setMinimumHeight(image.size().height()/2);
00171     //label->setMinimumSize(QSize(image.size().width()/2, image.size().height()/2));
00172     label->setAlignment(Qt::AlignCenter);
00173     label->setPixmap(QPixmap::fromImage(image));
00174     label->repaint();
00175   }
00176 }
00177 
00178 void Graphical_UI::setFeatureImage(QImage qimage){
00179   setLabelToImage(feature_image_label, qimage);
00180 }
00181 
00182 void Graphical_UI::setFeatureFlowImage(QImage qimage){
00183   setLabelToImage(feature_flow_image_label, qimage);
00184 }
00185 
00186 void Graphical_UI::setVisualImage(QImage qimage){
00187   setLabelToImage(visual_image_label, qimage);
00188 }
00189 
00190 void Graphical_UI::setDepthImage(QImage qimage){
00191   setLabelToImage(depth_image_label, qimage);
00192 }
00193 
00194 void Graphical_UI::reloadConfig() {
00195     ParameterServer::instance()->getValues();
00196     QString message = tr("Configuration Reloaded");
00197     statusBar()->showMessage(message);
00198 }
00199 
00200 void Graphical_UI::resetCmd() {
00201     Q_EMIT reset();
00202     if(ParameterServer::instance()->get<bool>("use_glwidget")) glviewer->reset();
00203     QString message = tr("Graph Reset");
00204     statusBar()->showMessage(message);
00205     infoLabel->setText("A fresh new graph is waiting");
00206 }
00207 
00208 void Graphical_UI::setStatus(QString message){
00209     statusBar()->showMessage(message);
00210 }
00211 void Graphical_UI::setInfo2(QString message){
00212     infoLabel2->setText(message);
00213     infoLabel2->repaint();
00214 }
00215 void Graphical_UI::setInfo(QString message){
00216     infoLabel->setText(message);
00217     infoLabel->repaint();
00218 }
00219 
00220 void Graphical_UI::saveG2OGraphDialog() {
00221     QString graph_filename = QFileDialog::getSaveFileName(this, "Save G2O Graph to File", "graph.g2o", tr("G2O (*.g2o)"));
00222     QString message;
00223     if(graph_filename.isEmpty()){
00224       message = tr("Filename empty. Aborting save");
00225     } else {
00226       Q_EMIT saveG2OGraph(graph_filename);
00227       message = tr("Saving Graph");
00228     }
00229     statusBar()->showMessage(message);
00230     //infoLabel->setText(message);
00231 }
00232 
00233 void Graphical_UI::quickSaveAll() {
00234     Q_EMIT saveAllClouds(filename);
00235     QString message = tr("Saving Whole Model to ");
00236     message.append(QDir::currentPath());
00237     message.append(filename);
00238     statusBar()->showMessage(message);
00239     //infoLabel->setText(message);
00240 }
00241 
00242 void Graphical_UI::openBagFileDialog() {
00243     QString filename = QFileDialog::getOpenFileName(this, "Open Bag File", "", tr("BAG (*.bag)"));
00244     QString message;
00245     if(filename.isEmpty()){
00246       message = tr("Filename empty. Aborting.");
00247     } else {
00248       message = tr("Opening Bagfile ");
00249       message += filename;
00250       Q_EMIT openBagFile(filename);
00251     }
00252     statusBar()->showMessage(message);
00253 }
00254 
00255 void Graphical_UI::openPCDFilesDialog() {
00256     QStringList filenamelist = QFileDialog::getOpenFileNames(this, "Open PCD Files", "", tr("PCD (*.pcd)"));
00257     QString message;
00258     if(filenamelist.isEmpty()){
00259       message =  tr("Empty file list. Aborting");
00260     } else {
00261       for(int i=0; i < filenamelist.size(); i++){
00262         std::cout << qPrintable(filenamelist.at(i)) << std::endl;
00263       }
00264       Q_EMIT openPCDFiles(filenamelist);
00265       message =  tr("Opening PCD Files");
00266     }
00267     statusBar()->showMessage(message);
00268 }
00269 void Graphical_UI::saveFeatures() {
00270     filename = QFileDialog::getSaveFileName(this, "Save Features to File", filename, tr("YAML (*.yml);;XML (*.xml)"));
00271     QString message;
00272     if(filename.isEmpty()){
00273       message = tr("Filename empty. Aborting.");
00274     } else {
00275       message = tr("Saving Features to ");
00276       message += filename;
00277       Q_EMIT saveAllFeatures(filename);
00278     }
00279     statusBar()->showMessage(message);
00280 }
00281 
00282 void Graphical_UI::computeOctomap() {
00283   Q_EMIT computeOctomapSig(filename);
00284 }
00285 
00286 void Graphical_UI::saveOctomap() {
00287     filename = QFileDialog::getSaveFileName(this, "Create and Save Octomap to File", filename, tr("OcTree (*.ot)"));
00288     QString message;
00289     if(filename.isEmpty()){
00290       message = tr("Filename empty. Aborting.");
00291     } else {
00292       Q_EMIT saveOctomapSig(filename);
00293       QString message = tr("Creating Octomap");
00294     }
00295     statusBar()->showMessage(message);
00296 }
00297 
00298 void Graphical_UI::saveAll() {
00299     filename = QFileDialog::getSaveFileName(this, "Save Point CLoud to File", filename, tr("PCD (*.pcd);;PLY (*ply)"));
00300     Q_EMIT saveAllClouds(filename);
00301     QString message = tr("Saving Whole Model");
00302     statusBar()->showMessage(message);
00303 }
00304 
00305 void Graphical_UI::showEdgeErrors() {
00306     QString myfilename = QFileDialog::getSaveFileName(this, "Save Current Trajectory Estimate", "trajectory", tr("All Files (*.*)"));
00307     Q_EMIT printEdgeErrors(myfilename);
00308     QString message = tr("Triggering Edge Printing");
00309     statusBar()->showMessage(message);
00310 }
00311 
00312 void Graphical_UI::optimizeGraphTrig() {
00313     Q_EMIT optimizeGraph();
00314     QString message = tr("Triggering Optimizer");
00315     statusBar()->showMessage(message);
00316 }
00317 
00318 void Graphical_UI::saveVectorGraphic() {
00319     QMessageBox::warning(this, tr("Don't render to pdf while point clouds are shown"), tr("This is meant for rendereing the pose graph. Rendering clouds to pdf will generate huge files!"));
00320     QString myfilename = QFileDialog::getSaveFileName(this, "Save Current 3D Display to Vector Graphic", "pose_graph.pdf", tr("All Files (*.*)"));
00321     if(!myfilename.size() == 0){
00322       glviewer->drawToPS(myfilename);
00323       QString message = tr("Drawing current Display");
00324       statusBar()->showMessage(message);
00325     } else {
00326       QString message = tr("Empty Filename");
00327     }
00328 }
00329 void Graphical_UI::toggleScreencast(bool on) {
00330   if(on){
00331     QString myfilename = QFileDialog::getSaveFileName(this, "Path Prefix for Screencast Frames", "rgbdslam_frame_", tr("All Files (*.*)"));
00332     if(myfilename.size() > 0){
00333       ParameterServer::instance()->set("screencast_path_prefix", std::string(qPrintable(myfilename)));
00334       QString message = tr("Saving screencast frames.");
00335       statusBar()->showMessage(message);
00336     }
00337   }
00338   else {
00339     ParameterServer::instance()->set("screencast_path_prefix", std::string());
00340   }
00341 }
00342 void Graphical_UI::saveTrajectoryDialog() {
00343     QString myfilename = QFileDialog::getSaveFileName(this, "Save Current Trajectory Estimate", "trajectory", tr("All Files (*.*)"));
00344     Q_EMIT saveTrajectory(myfilename);
00345     QString message = tr("Saving current trajectory estimate (and possibly ground truth).");
00346     statusBar()->showMessage(message);
00347 }
00348 void Graphical_UI::saveIndividual() {
00349     QString tmpfilename(filename);
00350     tmpfilename.remove(".pcd", Qt::CaseInsensitive);
00351     tmpfilename.remove(".ply", Qt::CaseInsensitive);
00352 
00353     tmpfilename = QFileDialog::getSaveFileName(this, "Save point cloud to one file per node", tmpfilename, tr("PCD (*.pcd)"));
00354     tmpfilename.remove(".pcd", Qt::CaseInsensitive);
00355     Q_EMIT saveIndividualClouds(tmpfilename);
00356     QString message = tr("Saving Model Node-Wise");
00357     statusBar()->showMessage(message);
00358     //infoLabel->setText(message);
00359 }
00360 
00361 void Graphical_UI::saveBagDialog() {
00362     QString filename = QFileDialog::getSaveFileName(this, "Save Clouds to Bag File", "", tr("BAG (*.bag)"));
00363     Q_EMIT saveBagfile(filename);
00364     QString message = tr("Writing Whole Model to Bagfile");
00365     statusBar()->showMessage(message);
00366 }
00367 void Graphical_UI::sendAll() {
00368     Q_EMIT sendAllClouds();
00369     QString message = tr("Sending Whole Model");
00370     statusBar()->showMessage(message);
00371 }
00372 
00373 void Graphical_UI::setRotationGrid() {
00374     bool ok;
00375     double value = QInputDialog::getDouble(this, tr("Set Rotation Stepping in Degree"),
00376                                            tr("Enter Stepping:"), 1.00, -10000000, 10000000, 2, &ok);
00377     if(ok){ glviewer->setRotationGrid(value); }
00378 }
00379 void Graphical_UI::setStereoShift() {
00380     bool ok;
00381     double value = QInputDialog::getDouble(this, tr("Set Stereo Camera shift"),
00382                                            tr("Enter Shift:"), 0.10, -10000000, 10000000, 2, &ok);
00383     if(ok){ glviewer->setStereoShift(value); }
00384 }
00385 
00386 void Graphical_UI::setParam(QString text){
00387     std::map<std::string, boost::any>&  config = ParameterServer::instance()->getConfigData();
00388     std::map<std::string, boost::any>::const_iterator itr;
00389     for (itr = config.begin(); itr != config.end(); ++itr) {
00390       if(itr->first == qPrintable(text)){
00391         bool ok;
00392         if (itr->second.type() == typeid(std::string)) {
00393           QString prev_val = boost::any_cast<std::string>(itr->second).c_str();
00394           QString new_val = QInputDialog::getText(this, text, tr("New Value:"), 
00395                                                   QLineEdit::Normal, prev_val, &ok);
00396           if (ok){
00397             ParameterServer::instance()->set(itr->first, std::string(qPrintable(new_val)));
00398           }
00399         } 
00400         else if (itr->second.type() == typeid(int)) {
00401           int prev_val = boost::any_cast<int>(itr->second);
00402           int new_val = QInputDialog::getInt(this, text, tr("New Value:"), 
00403                                              prev_val, 
00404                                              std::numeric_limits<int>::min(), 
00405                                              std::numeric_limits<int>::max(), 1, &ok);
00406           if (ok){
00407             ParameterServer::instance()->set(itr->first, new_val);
00408           }
00409         } 
00410         else if (itr->second.type() == typeid(double)) {
00411           double prev_val = boost::any_cast<double>(itr->second);
00412           double new_val = QInputDialog::getDouble(this, text, tr("New Value:"), 
00413                                              prev_val,
00414                                              std::numeric_limits<double>::min(), 
00415                                              std::numeric_limits<double>::max(), 3, &ok);
00416           if (ok){
00417             ParameterServer::instance()->set(itr->first, new_val);
00418           }
00419         } 
00420         else if (itr->second.type() == typeid(bool)) {
00421           QStringList truefalse;
00422           truefalse.append("False");//item 0 
00423           truefalse.append("True"); //item 1
00424           //Per definition the cast from bool to int results in 0 or 1
00425           int prev_val = boost::any_cast<bool>(itr->second);
00426           QString new_val = QInputDialog::getItem(this, text, tr("New Value:"), 
00427                                                   truefalse, prev_val, false, &ok);
00428           if (ok){
00429             if(new_val == "False")
00430               ParameterServer::instance()->set(itr->first, false);
00431             else
00432               ParameterServer::instance()->set(itr->first, true);
00433           }
00434         }
00435       }
00436     }
00437 }
00438 
00439 
00440 void Graphical_UI::setParam() {
00441     std::map<std::string, boost::any>&  config = ParameterServer::instance()->getConfigData();
00442     std::map<std::string, boost::any>::const_iterator itr;
00443     QStringList list;
00444     for (itr = config.begin(); itr != config.end(); ++itr) {
00445       QString name(itr->first.c_str());
00446       //QString description(ParameterServer::instance()->getDescription(itr->first).c_str());
00447       list.append(name);
00448     }
00449     bool ok = false;
00450     QString name = QInputDialog::getItem(this, tr("Select Parameter to Change"), 
00451                                          tr("Note: Changing parameters during runtime is not honored for all parameters.\n"
00452                                             "In particular changing parameters used during the initial setup "
00453                                             "(e.g. topic names) will have no effect.\n\n"
00454                                             "Options should be set via launchfiles!\n\n"
00455                                             "This functionality is mostly for quickly trying out the effect of "
00456                                             "individual parameters.\n\nParameter Name"), 
00457                                          list, 0, false, &ok);
00458     if(ok) setParam(name);
00459 }
00460 void Graphical_UI::toggleFullscreen(bool mode){
00461     this->menuBar()->setVisible(!mode);
00462     this->gridlayout->setMargin(mode?0:5);
00463     this->statusBar()->setVisible(!mode);
00464     if(mode){
00465       this->showFullScreen();
00466     } else {
00467       this->showNormal();
00468     }
00469 }
00470 void Graphical_UI::pruneEdgesWithHighError(){
00471     bool ok;
00472     float value = QInputDialog::getDouble(this, tr("Set Max Edge Error"),
00473                                           tr("No Text"), 1.00, -10000000, 10000000, 4, &ok);
00474     if(ok){
00475         Q_EMIT pruneEdgesWithErrorAbove(value);
00476     }
00477 }
00478 void Graphical_UI::sendFinished() {
00479     
00480     QString message = tr("Finished Sending");
00481     statusBar()->showMessage(message);
00482 }
00483 
00484 void Graphical_UI::getOneFrameCmd() {
00485     Q_EMIT getOneFrame();
00486     QString message = tr("Getting a single frame");
00487     statusBar()->showMessage(message);
00488 }
00489 void Graphical_UI::deleteLastFrameCmd() {
00490     Q_EMIT deleteLastFrame();
00491     QString message = tr("Deleting the last node from the graph");
00492     statusBar()->showMessage(message);
00493 }
00494 
00495 void Graphical_UI::toggleMappingPriv(bool mapping_on) {
00496     Q_EMIT toggleMapping(mapping_on);
00497 }
00498 
00499 void Graphical_UI::triggerCloudFiltering() {
00500   Q_EMIT occupancyFilterClouds();
00501 }
00502 void Graphical_UI::setOctoMapResolution() {
00503   this->setParam("octomap_resolution");
00504 }
00505 void Graphical_UI::toggleOnlineVoxelMapping(bool online) {
00506   ParameterServer::instance()->set("octomap_online_creation", online);
00507 }
00508 void Graphical_UI::toggleCloudStorage(bool storage) {
00509   ParameterServer::instance()->set("store_pointclouds", storage);
00510 }
00511 void Graphical_UI::toggleLandmarkOptimization(bool landmarks) {
00512   ParameterServer::instance()->set("optimize_landmarks", landmarks);
00513 }
00514 
00515 void Graphical_UI::pause(bool pause_on) {
00516     Q_EMIT togglePause();
00517     if(pause_on) {
00518         QString message = tr("Processing.");
00519         statusBar()->showMessage(message);
00520     } else {
00521         QString message = tr("Stopped processing.");
00522         statusBar()->showMessage(message);
00523     }
00524 }
00525 
00526 void Graphical_UI::help() {
00527     QMessageBox::about(this, tr("Help Menu"),  *mouseHelpText );
00528 }
00529 void Graphical_UI::about() {
00530     QMessageBox::about(this, tr("About RGBDSLAM"), *infoText + *licenseText);
00531 }
00532 
00533 void Graphical_UI::set2DStream(bool is_on) {
00534     if(is_on){ 
00535         visual_image_label->show();
00536         depth_image_label->show(); 
00537         feature_flow_image_label->show(); 
00538         feature_image_label->show(); 
00539         QList<int> list;
00540         list.append(1);//upper part on
00541         list.append(1);//lower part on
00542         vsplitter->setSizes(list);
00543     } else { 
00544         visual_image_label->hide(); 
00545         depth_image_label->hide(); 
00546         feature_flow_image_label->hide(); 
00547         feature_image_label->hide(); 
00548         QList<int> list;
00549         list.append(1);//upper part on
00550         list.append(0);//lower part off
00551         vsplitter->setSizes(list);
00552     } 
00553 }
00554 
00555 /*
00556 void Graphical_UI::set3DDisplay(bool is_on) {
00557     if(!ParameterServer::instance()->get<bool>("use_glwidget")) return;
00558     if(is_on){ glviewer->show(); } 
00559     else { glviewer->hide(); } 
00560 }
00561 */
00562 QAction* Graphical_UI::newAction(QMenu* menu, const char* title, const char* statustip, QIcon icon){
00563     QAction *new_action = new QAction(tr(title), this);
00564     new_action->setStatusTip(tr(statustip));
00565     new_action->setIcon(icon);
00566     this->addAction(new_action);
00567     menu->addAction(new_action);
00568     return new_action;
00569 }
00570 
00571 QAction* Graphical_UI::newMenuItem(QMenu* menu, const char* title, QObject* receiver, const char* callback, const char* statustip, const char* key_seq_str, QIcon icon){
00572     QAction *new_action = newAction(menu, title, statustip, icon);
00573     new_action->setShortcut(QString(key_seq_str));
00574     connect(new_action, SIGNAL(triggered()), receiver, callback);
00575     return new_action;
00576 }
00577 QAction* Graphical_UI::newMenuItem(QMenu* menu, const char* title, const char* callback_method_of_this_class, const char* statustip, QKeySequence::StandardKey std_key, QIcon icon){
00578     QAction *new_action = newAction(menu, title, statustip, icon);
00579     new_action->setShortcuts(std_key);
00580     connect(new_action, SIGNAL(triggered()), this, callback_method_of_this_class);
00581     return new_action;
00582 }
00583 QAction* Graphical_UI::newMenuItem(QMenu* menu, const char* title, const char* callback_method_of_this_class, const char* statustip, const char* key_seq_str, QIcon icon){
00584     QAction *new_action = newAction(menu, title, statustip, icon);
00585     new_action->setShortcut(QString(key_seq_str));
00586     connect(new_action, SIGNAL(triggered()), this, callback_method_of_this_class);
00587     return new_action;
00588 }
00589 QAction* Graphical_UI::newMenuItem(QMenu* menu, const char* title, QObject* receiver, const char* callback, const char* statustip, bool checked, const char* key_seq_str,QIcon icon){
00590     QAction *new_action = newAction(menu, title, statustip, icon);
00591     new_action->setShortcut(QString(key_seq_str));
00592     new_action->setCheckable(true);
00593     new_action->setChecked(checked);
00594     connect(new_action, SIGNAL(toggled(bool)), receiver, callback);
00595     return new_action;
00596 }
00597 
00598 void Graphical_UI::createLoadMenu() {
00599     QMenu* lm = menuBar()->addMenu(tr("&Load"));
00600     newMenuItem(lm,
00601                 "&Open PCD files", 
00602                 SLOT(openPCDFilesDialog()),
00603                 "Open one or more pcd files to process",
00604                 QKeySequence::Open, 
00605                 QIcon::fromTheme("document-open"));
00606     
00607     newMenuItem(lm,
00608                 "Open ROS &bag file",
00609                 SLOT(openBagFileDialog()),
00610                 "Open a bag file to process",
00611                 "Ctrl+B",
00612                 QIcon::fromTheme("document-open"));
00613 }
00614 
00615 QAction* Graphical_UI::createSaveMenu() {//octomap Menu
00616     QMenu* sm = menuBar()->addMenu(tr("&Save"));
00617     newMenuItem(sm,
00618                 "&Save",                                
00619                 SLOT(quickSaveAll()),
00620                 "Save all stored point clouds with common coordinate frame to a pcd file",
00621                 QKeySequence::Save,
00622                 QIcon::fromTheme("document-save"));
00623     
00624 
00625     newMenuItem(sm,
00626                 "Save &Feature Map...",
00627                 SLOT(saveFeatures()),
00628                 "Save all feature positions and descriptions in a common coordinate frame to a yaml or xml file",
00629                 "Ctrl+F",
00630                 QIcon::fromTheme("document-save"));
00631 
00632     QAction* oa = newMenuItem(sm, "Save Octomap...",
00633                               SLOT(saveOctomap()),
00634                               "Save computed OctoMap",
00635                               "",
00636                               QIcon::fromTheme("document-save-as"));
00637 
00638     newMenuItem(sm, "&Save as Point Cloud ...",
00639                 SLOT(saveAll()),
00640                 "Save all stored point clouds with common coordinate frame",
00641                 QKeySequence::SaveAs,
00642                 QIcon::fromTheme("document-save-as"));
00643 
00644     newMenuItem(sm, "&Save Point Cloud Node-Wise...", 
00645                 SLOT(saveIndividual()),
00646                 "Save stored point clouds in individual files", 
00647                 "Ctrl+N", 
00648                 QIcon::fromTheme("document-save-all"));
00649 
00650     newMenuItem(sm, "Save &G2O Graph...",
00651                 SLOT(saveG2OGraphDialog()),
00652                 "Save G2O graph (e.g. for use with the g2o viewer or external optimization)",
00653                 "",
00654                 QIcon::fromTheme("document-save"));
00655                               
00656     newMenuItem(sm, "Save Clouds to &Bag...",
00657                 SLOT(saveBagDialog()),
00658                 "Save clouds and transforms to bagfile",
00659                 "Ctrl+Shift+B");
00660                 
00661     newMenuItem(sm, "Save Trajectory &Estimate...",
00662                 SLOT(saveTrajectoryDialog()),
00663                 "Save trajectory estimate (and ground truth trajectory if available) for external evaluation.",
00664                 "Ctrl+E");
00665                 
00666     sm->addSeparator();
00667     newMenuItem(sm, "&Send Model",
00668                 SLOT(sendAll()),
00669                 "Send out all stored point clouds with corrected transform",
00670                 "Ctrl+M",
00671                 QIcon::fromTheme("document-send"));
00672 
00673     sm->addSeparator();
00674 
00675     newMenuItem(sm, "Save &3D as PDF File...",
00676                 SLOT(saveVectorGraphic()),
00677                 "Write 3D Scene to a PDF File. Warning: Meant for Pose Graphs not for the clouds or octomaps!",
00678                 "",
00679                 QIcon::fromTheme("application-pdf"));
00680 
00681     newMenuItem(sm, "Save Input &Images to Files...",
00682                 SLOT(saveAllImages()),
00683                 "Write All images shown in the gui to appropriate files",
00684                 "",
00685                 QIcon::fromTheme("image-x-generic"));
00686     
00687     newMenuItem(sm, "Capture Screencast...",
00688                 this,
00689                 SLOT(toggleScreencast(bool)),
00690                 "Dump Screen as Video",
00691                 !ParameterServer::instance()->get<std::string>("screencast_path_prefix").empty());
00692                 
00693     return oa;
00694 }
00695 void Graphical_UI::createProcessingMenu() {
00696     QMenu* pm = menuBar()->addMenu(tr("&Processing"));
00697     newMenuItem(pm, "&Reset",
00698                 SLOT(resetCmd()),
00699                 "Reset the graph, clear all data collected",
00700                 "Ctrl+R",
00701                 QIcon::fromTheme("edit-delete"));
00702 
00703     newMenuItem(pm, "&Process",
00704                 this,
00705                 SLOT(pause(bool)),
00706                 "Start/stop processing of frames",
00707                 !ParameterServer::instance()->get<bool>("start_paused"),
00708                 " ",
00709                 QIcon::fromTheme("media-playback-start"));
00710 
00711     newMenuItem(pm, "Capture One& Frame",
00712                 SLOT(getOneFrameCmd()),
00713                 "Process one frame only",
00714                 QKeySequence::InsertParagraphSeparator);
00715                 
00716                               
00717     /* Crashes
00718     newMenuItem(pm, "&Delete Last Node",
00719                 SLOT(deleteLastFrameCmd()),
00720                 "Remove last node from graph",
00721                 "Backspace",
00722                 QIcon::fromTheme("edit-undo"));
00723                 */
00724     pm->addSeparator();
00725                               
00726     newMenuItem(pm, "Clear Cloud Storage",
00727                 SIGNAL(clearClouds()),
00728                 "Remove Point Clouds from Memory",
00729                 "",
00730                 QIcon::fromTheme("edit-delete"));
00731 
00732     newMenuItem(pm, "Optimize Trajectory &Estimate",
00733                 SLOT(optimizeGraphTrig()),
00734                 "Compute optimized pose graph with g2o",
00735                 "O");
00736                 
00737     pm->addSeparator();
00738 
00739     newMenuItem(pm, "E&xit",
00740                 SLOT(close()),
00741                 "Exit the application",
00742                 "Ctrl+Q",
00743                 QIcon::fromTheme("application-exit"));//doesn't work for gnome
00744 }
00745 
00746 void Graphical_UI::createMenus() {
00747 
00748 
00749     createProcessingMenu();
00750     createLoadMenu();
00751 
00752     QAction* octoMapAction =  createSaveMenu();
00753 
00754     QMenu *om = menuBar()->addMenu(tr("&OctoMap"));
00755     newMenuItem(om, "Point Cloud Occupancy Filter",
00756                 SLOT(triggerCloudFiltering()),
00757                 "Remove points from the cloud that fall into unoccupied voxels of the OctoMap");
00758                 
00759     newMenuItem(om, "Octomap Resolution",
00760                 SLOT(setOctoMapResolution()),
00761                 "Change the octomap resolution. Clears previously created maps on next update.");
00762 
00763     newMenuItem(om, "&Online OctoMapping",
00764                 this,
00765                 SLOT(toggleOnlineVoxelMapping(bool)),
00766                 "Toggle Online/Offline OctoMapping. Make sure to set a low octomap_resolution and/or high cloud_creation_skip_step for online mapping",
00767                 ParameterServer::instance()->get<bool>("octomap_online_creation"));
00768 
00769 
00770 
00771 
00772     /* Separation of computation and saving of octomap not yet Implemented
00773     QAction *computeOctoAct = new QAction(tr("Compute Octomap"), this);
00774     //computeOctoAct->setShortcuts(QKeySequence::SaveAs);
00775     computeOctoAct->setStatusTip(tr("Create OctoMap from stored point clouds"));
00776     connect(computeOctoAct, SIGNAL(triggered()), this, SLOT(computeOctomap()));
00777     octoMapMenu->addAction(computeOctoAct);
00778     this->addAction(computeOctoAct);
00779     */
00780 
00781 
00782 
00783     /*
00784     QAction *showErrorAct = new QAction(tr("Show Edge Errors"), this);
00785     showErrorAct->setShortcut(QString("Ctrl+Shift+E"));
00786     showErrorAct->setStatusTip(tr(""));
00787     connect(showErrorAct, SIGNAL(triggered()), this, SLOT(showEdgeErrors()));
00788     actionMenu->addAction(showErrorAct);
00789     this->addAction(showErrorAct);
00790     */
00791 
00792 
00793     //View Menus ###############################################################
00794     //View Menus ###############################################################
00795 
00796     if(ParameterServer::instance()->get<bool>("use_glwidget"))
00797     {
00798       QMenu* v3 = menuBar()->addMenu(tr("&3D View"));
00799 
00800       newMenuItem(v3, "&Clear 3D Display",
00801                   glviewer,
00802                   SLOT(reset()),
00803                   "Clears 3D viewer cloud data. Point Clouds are still retained, e.g. for mapping purposes.",
00804                   "",
00805                   QIcon::fromTheme("edit-delete"));
00806                                   
00807 
00808       newMenuItem(v3, "Toggle &3D Display",
00809                   glviewer,
00810                   SLOT(setVisible(bool)),
00811                   "Turn off the OpenGL Display",
00812                   true,
00813                   "3");
00814 
00815       newMenuItem(v3, "&Toggle Triangulation",
00816                   glviewer,
00817                   SLOT(toggleTriangulation()),
00818                   "Switch between surface, wireframe and point cloud",
00819                   "T");
00820                   
00821       newMenuItem(v3, "Follow &Camera",
00822                   glviewer,
00823                   SLOT(toggleFollowMode(bool)),
00824                   "Always use viewpoint of last frame (except zoom)",
00825                   true,
00826                   "Shift+F");
00827 
00828       newMenuItem(v3, "Show Grid",
00829                   glviewer,
00830                   SLOT(toggleShowGrid(bool)),
00831                   "Display XY plane grid",
00832                   false);
00833       newMenuItem(v3, "Show Pose TFs",
00834                   glviewer,
00835                   SLOT(toggleShowTFs(bool)),
00836                   "Display pose transformations at axes",
00837                   false);
00838       newMenuItem(v3, "Show Pose IDs",
00839                   glviewer,
00840                   SLOT(toggleShowIDs(bool)),
00841                   "Display pose ids at axes", 
00842                   false,
00843                   "I");
00844 
00845       newMenuItem(v3, "Show &Poses of Graph",
00846                   glviewer,
00847                   SLOT(toggleShowPoses(bool)),
00848                   "Display poses as axes",
00849                   ParameterServer::instance()->get<bool>("show_axis"),
00850                   "P");
00851 
00852       newMenuItem(v3, "Show &Edges of Graph",
00853                   glviewer,
00854                   SLOT(toggleShowEdges(bool)),
00855                   "Display edges of pose graph as lines",
00856                   ParameterServer::instance()->get<bool>("show_axis"),
00857                   "E");
00858 
00859       newMenuItem(v3, "Stere&o View",
00860                   glviewer,
00861                   SLOT(toggleStereo(bool)),
00862                   "Split screen view with slightly shifted Camera",
00863                   false);
00864       newMenuItem(v3, "Show &Feature Locations",
00865                   glviewer,
00866                   SLOT(toggleShowFeatures(bool)),
00867                   "Toggle whether feature locations should be rendered",
00868                   false);
00869       newMenuItem(v3, "Show &Octomap",
00870                   glviewer,
00871                   SLOT(toggleShowOctoMap(bool)),
00872                   "Toggle whether octomap should be displayed",
00873                   true,
00874                   "Ctrl+Shift+O");
00875 
00876       newMenuItem(v3, "Show &Clouds",
00877                   glviewer,
00878                   SLOT(toggleShowClouds(bool)),
00879                   "Toggle whether point clouds should be rendered",
00880                   true,
00881                   "C");
00882 
00883       newMenuItem(v3, "Toggle Background",
00884                   glviewer,
00885                   SLOT(toggleBackgroundColor(bool)),
00886                   "Toggle whether background should be white or black",
00887                   true,
00888                   "B");
00889 
00890       newMenuItem(v3, "Set Rotation &Grid",
00891                   this,
00892                   SLOT(setRotationGrid()),
00893                   "Discretize Rotation in Viewer",
00894                   "G");
00895                   
00896       newMenuItem(v3, "Set Stereo Offset",
00897                   this,
00898                   SLOT(setStereoShift()),
00899                   "Set the distance between the virtual cameras for stereo view",
00900                   "<");
00901                   
00902     }
00903 
00904 
00905 
00906     //2D View Menu ###############################################################
00907     QMenu *v2 = menuBar()->addMenu(tr("&2D View"));
00908 
00909     newMenuItem(v2, "Toggle &2D Stream",
00910                 this,
00911                 SLOT(set2DStream(bool)),
00912                 "Turn the Image Stream on/off", 
00913                 true,
00914                 "2");
00915 
00916     newMenuItem(v2, "Show Visual Image",
00917                 visual_image_label,
00918                 SLOT(setVisible(bool)),
00919                 "Show/Hide visual (color/monochrome) image.", 
00920                 true);
00921 
00922     newMenuItem(v2, "Show Depth Image",
00923                 depth_image_label,
00924                 SLOT(setVisible(bool)),
00925                 "Show/Hide depth image.",
00926                 true);
00927 
00928     newMenuItem(v2, "Show Keypoint Image",
00929                 feature_image_label,
00930                 SLOT(setVisible(bool)),
00931                 "Show/Hide image with keypoints.",
00932                 false);
00933 
00934     newMenuItem(v2, "Show Visual Flow Image",
00935                 feature_flow_image_label,
00936                 SLOT(setVisible(bool)),
00937                 "Show/Hide image with sparse feature flow (arrows).",
00938                 true);
00939 
00940     //Settings Menu
00941     QMenu *st = menuBar()->addMenu(tr("&Settings"));
00942 
00943     newMenuItem(st, "&Reload Config",
00944                 SLOT(reloadConfig()),
00945                 "Reload Configuration from Parameter Server.",
00946                 "",
00947                 QIcon::fromTheme("reload"));
00948 
00949     newMenuItem(st, "&View Current Settings",
00950                 SLOT(showOptions()),
00951                 "Display the currently active options",
00952                 "?");
00953                 
00954     newMenuItem(st, "Set internal &Parameter",
00955                 SLOT(setParam()),
00956                 "Change a parameter (This will also change the value on the ROS Parameter server)");
00957                 
00958     newMenuItem(st, "Set Ma&ximum Edge Error",
00959                 SLOT(pruneEdgesWithHighError()),
00960                 "Set the maximum allowed for edges (reoptimize to see the effect)",
00961                 "Ctrl+X");
00962                 
00963     //Help Menu
00964     QMenu *hm= menuBar()->addMenu(tr("&Help"));
00965 
00966     newMenuItem(hm, "&Usage Help",
00967                 SLOT(help()),
00968                 "Show usage information",
00969                 QKeySequence::HelpContents,
00970                 QIcon::fromTheme("help-contents"));
00971 
00972     newMenuItem(hm, "&About RGBDSLAM",
00973                 SLOT(about()),
00974                 "Show information about RGBDSLAM",
00975                 "Ctrl+A",
00976                 QIcon::fromTheme("help-about"));
00977 
00978 }
00979 
00980 GLViewer* Graphical_UI::getGLViewer() { 
00981   return glviewer; 
00982 }
00983 
00984 void Graphical_UI::showOptions(){
00985   QScrollArea* scrollarea = new QScrollArea();
00986   scrollarea->setMinimumWidth(600);
00987   QWidget* scrollarea_content = new QWidget(scrollarea);
00988   scrollarea_content->setMinimumWidth(500);
00989   QGridLayout *gridLayout = new QGridLayout(scrollarea_content);
00990   //gridLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
00991   //gridLayout->setLabelAlignment(Qt::AlignLeft);
00992   gridLayout->setVerticalSpacing(10);
00993   gridLayout->setContentsMargins(10,10,10,10);
00994   QLabel* intro = new QLabel("<h3>This is an read-only view of the current settings. To modify RGBDSLAM's settings use the ROS parameter server functionality (i.e. set options either in a launch-file or as a command line parameter).</h3>");
00995   intro->setAlignment(Qt::AlignJustify);
00996   intro->setWordWrap(true);
00997   intro->setMinimumWidth(560);
00998   intro->setMinimumHeight(60);
00999   gridLayout->addWidget(intro,0,0,1,-1, Qt::AlignJustify);
01000 
01001   QLabel namevalue_header("Parameter Name and Value");
01002   gridLayout->addWidget(&namevalue_header, 1, 0);
01003   QLabel description_header("Parameter Description");
01004   gridLayout->addWidget(&description_header, 1, 1);
01005 
01006   //Iterate through parameters
01007   std::map<std::string, boost::any>&  config = ParameterServer::instance()->getConfigData();
01008   std::map<std::string, boost::any>::const_iterator itr = config.begin();
01009   for (int row=2; itr != config.end(); ++itr, row+=3) {
01010     //Name and Description
01011     QLabel* name_lbl = new QLabel(QString("<b>") + itr->first.c_str() + QString("</b>"), scrollarea_content);
01012     name_lbl->setTextFormat(Qt::RichText);
01013     name_lbl->setAlignment(Qt::AlignLeft);
01014     gridLayout->addWidget(name_lbl, row, 0);
01015     QLabel* description = new QLabel(ParameterServer::instance()->getDescription(itr->first).c_str());
01016     description->setAlignment(Qt::AlignJustify);
01017     description->setWordWrap(true);
01018     gridLayout->addWidget(description, row+1, 0, 1,-1);
01019 
01020     //Value
01021     QString val_txt;
01022     if (itr->second.type() == typeid(std::string)) {
01023       val_txt = QString::fromStdString(boost::any_cast<std::string>(itr->second));
01024     } else if (itr->second.type() == typeid(int)) {
01025       val_txt = QString::number(boost::any_cast<int>(itr->second));
01026     } else if (itr->second.type() == typeid(double)) {
01027       val_txt = QString::number(boost::any_cast<double>(itr->second));
01028     } else if (itr->second.type() == typeid(bool)) {
01029       val_txt = boost::any_cast<bool>(itr->second)? "True" : "False";
01030     }
01031     QLabel* val_lbl = new QLabel(QString("<tt>") + val_txt + QString("</tt>"), scrollarea_content);
01032     val_lbl->setTextFormat(Qt::RichText);
01033     val_lbl->setLineWidth(1);
01034     val_lbl->setFrameStyle(QFrame::Panel|QFrame::Sunken);
01035     //val_lbl->setAlignment(Qt::AlignTop|Qt::AlignLeft);
01036     gridLayout->addWidget(val_lbl, row, 1);
01037 
01038     //Separator
01039     QFrame* line = new QFrame(scrollarea_content);
01040     line->setGeometry(QRect(500, 150, 118, 3));
01041     line->setFrameShape(QFrame::HLine);
01042     line->setFrameShadow(QFrame::Sunken);
01043     gridLayout->addWidget(line, row+2, 0, 1,-1);
01044   }
01045 
01046 
01047   scrollarea_content->setLayout(gridLayout);
01048   scrollarea->setWidget(scrollarea_content);
01049   scrollarea->show();
01050   scrollarea->raise();
01051   scrollarea->activateWindow();
01052 }
01053 
01054 
01055 void Graphical_UI::showBusy(int id, const char* message, int max){
01056   bool contained = progressbars.contains(id);
01057   QProgressBar* busydialog = NULL;
01058   if(!contained) {
01059     busydialog = new QProgressBar();
01060     busydialog->resize(100, 10);
01061     progressbars[id] = busydialog;
01062     statusBar()->insertPermanentWidget(progressbars.size(), busydialog);
01063   } else {
01064     busydialog = progressbars[id];
01065   }
01066   busydialog->show();
01067   busydialog->setMinimum(0);
01068   busydialog->setMaximum(max);
01069   busydialog->setFormat(QString(message) + " %p%");
01070 }
01071 
01072 void Graphical_UI::setBusy(int id, const char* message, int val){
01073   if(progressbars.contains(id)) {
01074     QProgressBar* busydialog = progressbars[id];
01075     busydialog->show();
01076     if(val > busydialog->maximum()){
01077       statusBar()->removeWidget(busydialog);
01078       busydialog->hide();
01079       statusBar()->showMessage(message);
01080     } else {
01081       busydialog->setValue(val);
01082       busydialog->setFormat(QString(message) + " %p%");
01083       busydialog->update();
01084     }
01085   } else {
01086     statusBar()->showMessage(QString("Error: Set Value for non-existing progressbar ")+QString::number(id));
01087     showBusy(id, message, 0);
01088     setBusy(id, message, val);
01089   }
01090 }
01091 
01092 void Graphical_UI::saveAllImages() {
01093     QString tmp="~";
01094     QString file_basename = QFileDialog::getSaveFileName(this, "Save all images to file", tmp, tr("PNG (*.png)"));
01095     file_basename.remove(".png", Qt::CaseInsensitive);
01096 
01097     QString depth_file =file_basename+"-depth.png";
01098     QString feature_file =file_basename+"-feature.png";
01099     QString flow_file =file_basename+"-flow.png";
01100     QString visual_file =file_basename+"-visual.png";
01101     QString vector_file =file_basename+"-points.ps";
01102     std::cout << visual_file.toStdString() << std::endl;
01103     depth_image_label->pixmap()->save(depth_file);
01104     feature_image_label->pixmap()->save(feature_file);
01105     feature_flow_image_label->pixmap()->save(flow_file);
01106     visual_image_label->pixmap()->save(visual_file);
01107 
01108     //glviewer->drawToPS(vector_file);
01109     QString message = tr("Saving all images.");
01110     statusBar()->showMessage(message);
01111 }


rgbdslam_v2
Author(s): Felix Endres, Juergen Hess, Nikolas Engelhard
autogenerated on Thu Jun 6 2019 21:49:45