mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 17:40:23 +08:00
Increased database version to 0.8.11 (new Depth.data2d_max_pts column). Updated how local loop closure detection in space is done. Update GraphViewer with local radius ellipse and current goal node color. MainWindow saving/loading figures automatically accordingly to the previous session saved.
This commit is contained in:
@@ -237,6 +237,7 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
|
||||
connect(ui_->checkBox_icp_p2plane, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
|
||||
connect(ui_->spinBox_icp_normalKSearch, SIGNAL(valueChanged(int)), this, SLOT(configModified()));
|
||||
connect(ui_->checkBox_icp_2d, SIGNAL(stateChanged(int)), this, SLOT(configModified()));
|
||||
connect(ui_->doubleSpinBox_icp_minCorrespondenceRatio, SIGNAL(valueChanged(double)), this, SLOT(configModified()));
|
||||
// Visual parameters
|
||||
connect(ui_->groupBox_visual_recomputeFeatures, SIGNAL(clicked(bool)), this, SLOT(configModified()));
|
||||
connect(ui_->comboBox_featureType, SIGNAL(currentIndexChanged(int)), this, SLOT(configModified()));
|
||||
@@ -354,6 +355,7 @@ void DatabaseViewer::readSettings()
|
||||
ui_->checkBox_icp_p2plane->setChecked(settings.value("point2place", ui_->checkBox_icp_p2plane->isChecked()).toBool());
|
||||
ui_->spinBox_icp_normalKSearch->setValue(settings.value("normalKSearch", ui_->spinBox_icp_normalKSearch->value()).toInt());
|
||||
ui_->checkBox_icp_2d->setChecked(settings.value("icp2d", ui_->checkBox_icp_2d->isChecked()).toBool());
|
||||
ui_->doubleSpinBox_icp_minCorrespondenceRatio->setValue(settings.value("icpMinRatio", ui_->doubleSpinBox_icp_minCorrespondenceRatio->value()).toDouble());
|
||||
settings.endGroup();
|
||||
|
||||
// Visual parameters
|
||||
@@ -429,6 +431,7 @@ void DatabaseViewer::writeSettings()
|
||||
settings.setValue("point2place", ui_->checkBox_icp_p2plane->isChecked());
|
||||
settings.setValue("normalKSearch", ui_->spinBox_icp_normalKSearch->value());
|
||||
settings.setValue("icp2d", ui_->checkBox_icp_2d->isChecked());
|
||||
settings.setValue("icpMinRatio", ui_->doubleSpinBox_icp_minCorrespondenceRatio->value());
|
||||
settings.endGroup();
|
||||
|
||||
// save Visual parameters
|
||||
@@ -678,6 +681,8 @@ void DatabaseViewer::exportDatabase()
|
||||
QList<int> ids;
|
||||
|
||||
double previousStamp = 0;
|
||||
std::vector<double> delays(ids_.size());
|
||||
int oi=0;
|
||||
for(int i=0; i<ids_.size(); i+=1+framesIgnored)
|
||||
{
|
||||
Transform odomPose;
|
||||
@@ -697,6 +702,10 @@ void DatabaseViewer::exportDatabase()
|
||||
{
|
||||
ids.push_back(ids_[i]);
|
||||
}
|
||||
if(previousStamp && stamp)
|
||||
{
|
||||
delays[oi++] = stamp - previousStamp;
|
||||
}
|
||||
previousStamp = stamp;
|
||||
}
|
||||
if(sessionExported >= 0 && mapId > sessionExported)
|
||||
@@ -705,11 +714,14 @@ void DatabaseViewer::exportDatabase()
|
||||
}
|
||||
}
|
||||
}
|
||||
delays.resize(oi);
|
||||
|
||||
if(recorder.init(path, false))
|
||||
{
|
||||
rtabmap::DetailedProgressDialog progressDialog(this);
|
||||
progressDialog.setMaximumSteps(ids.size());
|
||||
progressDialog.show();
|
||||
rtabmap::DetailedProgressDialog * progressDialog = new rtabmap::DetailedProgressDialog(this);
|
||||
progressDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
progressDialog->setMaximumSteps(ids.size());
|
||||
progressDialog->show();
|
||||
|
||||
for(int i=0; i<ids.size(); ++i)
|
||||
{
|
||||
@@ -723,12 +735,17 @@ void DatabaseViewer::exportDatabase()
|
||||
}
|
||||
recorder.addData(sensorData);
|
||||
|
||||
progressDialog.appendText(tr("Exported node %1").arg(id));
|
||||
progressDialog.incrementStep();
|
||||
progressDialog->appendText(tr("Exported node %1").arg(id));
|
||||
progressDialog->incrementStep();
|
||||
QApplication::processEvents();
|
||||
}
|
||||
progressDialog.setValue(progressDialog.maximumSteps());
|
||||
progressDialog.appendText("Export finished!");
|
||||
progressDialog->setValue(progressDialog->maximumSteps());
|
||||
if(delays.size())
|
||||
{
|
||||
progressDialog->appendText(tr("Average frame rate=%1 Hz (Min=%2, Max=%3)")
|
||||
.arg(1.0/uMean(delays)).arg(1.0/uMax(delays)).arg(1.0/uMin(delays)));
|
||||
}
|
||||
progressDialog->appendText(tr("Export finished to \"%1\"!").arg(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1261,7 +1278,7 @@ void DatabaseViewer::refineAllNeighborLinks()
|
||||
{
|
||||
int from = neighborLinks_[i].from();
|
||||
int to = neighborLinks_[i].to();
|
||||
this->refineConstraint(neighborLinks_[i].from(), neighborLinks_[i].to(), false);
|
||||
this->refineConstraint(neighborLinks_[i].from(), neighborLinks_[i].to(), true, false);
|
||||
|
||||
progressDialog.appendText(tr("Refined link %1->%2 (%3/%4)").arg(from).arg(to).arg(i+1).arg(neighborLinks_.size()));
|
||||
progressDialog.incrementStep();
|
||||
@@ -1286,7 +1303,7 @@ void DatabaseViewer::refineAllLoopClosureLinks()
|
||||
{
|
||||
int from = loopLinks_[i].from();
|
||||
int to = loopLinks_[i].to();
|
||||
this->refineConstraint(loopLinks_[i].from(), loopLinks_[i].to(), false);
|
||||
this->refineConstraint(loopLinks_[i].from(), loopLinks_[i].to(), true, false);
|
||||
|
||||
progressDialog.appendText(tr("Refined link %1->%2 (%3/%4)").arg(from).arg(to).arg(i+1).arg(loopLinks_.size()));
|
||||
progressDialog.incrementStep();
|
||||
@@ -1311,7 +1328,7 @@ void DatabaseViewer::refineVisuallyAllNeighborLinks()
|
||||
{
|
||||
int from = neighborLinks_[i].from();
|
||||
int to = neighborLinks_[i].to();
|
||||
this->refineConstraintVisually(neighborLinks_[i].from(), neighborLinks_[i].to(), false);
|
||||
this->refineConstraintVisually(neighborLinks_[i].from(), neighborLinks_[i].to(), true, false);
|
||||
|
||||
progressDialog.appendText(tr("Refined link %1->%2 (%3/%4)").arg(from).arg(to).arg(i+1).arg(neighborLinks_.size()));
|
||||
progressDialog.incrementStep();
|
||||
@@ -1336,7 +1353,7 @@ void DatabaseViewer::refineVisuallyAllLoopClosureLinks()
|
||||
{
|
||||
int from = loopLinks_[i].from();
|
||||
int to = loopLinks_[i].to();
|
||||
this->refineConstraintVisually(loopLinks_[i].from(), loopLinks_[i].to(), false);
|
||||
this->refineConstraintVisually(loopLinks_[i].from(), loopLinks_[i].to(), true, false);
|
||||
|
||||
progressDialog.appendText(tr("Refined link %1->%2 (%3/%4)").arg(from).arg(to).arg(i+1).arg(loopLinks_.size()));
|
||||
progressDialog.incrementStep();
|
||||
@@ -1360,7 +1377,9 @@ void DatabaseViewer::sliderAValueChanged(int value)
|
||||
ui_->label_stampA,
|
||||
ui_->graphicsView_A,
|
||||
ui_->widget_cloudA,
|
||||
ui_->label_idA);
|
||||
ui_->label_idA,
|
||||
ui_->label_mapA,
|
||||
true);
|
||||
}
|
||||
|
||||
void DatabaseViewer::sliderBValueChanged(int value)
|
||||
@@ -1374,7 +1393,9 @@ void DatabaseViewer::sliderBValueChanged(int value)
|
||||
ui_->label_stampB,
|
||||
ui_->graphicsView_B,
|
||||
ui_->widget_cloudB,
|
||||
ui_->label_idB);
|
||||
ui_->label_idB,
|
||||
ui_->label_mapB,
|
||||
true);
|
||||
}
|
||||
|
||||
void DatabaseViewer::update(int value,
|
||||
@@ -1387,6 +1408,7 @@ void DatabaseViewer::update(int value,
|
||||
rtabmap::ImageView * view,
|
||||
rtabmap::CloudViewer * view3D,
|
||||
QLabel * labelId,
|
||||
QLabel * labelMapId,
|
||||
bool updateConstraintView)
|
||||
{
|
||||
UTimer timer;
|
||||
@@ -1395,6 +1417,7 @@ void DatabaseViewer::update(int value,
|
||||
labelChildren->clear();
|
||||
weight->clear();
|
||||
label->clear();
|
||||
labelMapId->clear();
|
||||
stamp->clear();
|
||||
QRectF rect;
|
||||
if(value >= 0 && value < ids_.size())
|
||||
@@ -1520,11 +1543,7 @@ void DatabaseViewer::update(int value,
|
||||
|
||||
if(mapId>=0)
|
||||
{
|
||||
labelId->setText(QString("%1 [%2]").arg(id).arg(mapId));
|
||||
}
|
||||
else
|
||||
{
|
||||
labelId->setText(QString::number(id));
|
||||
labelMapId->setText(QString::number(mapId));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1849,16 +1868,19 @@ void DatabaseViewer::sliderLoopValueChanged(int value)
|
||||
// only called when ui_->checkBox_showOptimized state changed
|
||||
void DatabaseViewer::updateConstraintView()
|
||||
{
|
||||
Link link = this->findActiveLink(ui_->horizontalSlider_A->value(), ui_->horizontalSlider_B->value());
|
||||
if(link.isValid())
|
||||
if(ids_.size())
|
||||
{
|
||||
if(link.type() == Link::kNeighbor)
|
||||
Link link = this->findActiveLink(ids_.at(ui_->horizontalSlider_A->value()), ids_.at(ui_->horizontalSlider_B->value()));
|
||||
if(link.isValid())
|
||||
{
|
||||
this->updateConstraintView(neighborLinks_.at(ui_->horizontalSlider_neighbors->value()), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->updateConstraintView(loopLinks_.at(ui_->horizontalSlider_loops->value()), false);
|
||||
if(link.type() == Link::kNeighbor)
|
||||
{
|
||||
this->updateConstraintView(neighborLinks_.at(ui_->horizontalSlider_neighbors->value()), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->updateConstraintView(loopLinks_.at(ui_->horizontalSlider_loops->value()), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1934,6 +1956,7 @@ void DatabaseViewer::updateConstraintView(
|
||||
ui_->graphicsView_A,
|
||||
ui_->widget_cloudA,
|
||||
ui_->label_idA,
|
||||
ui_->label_mapA,
|
||||
false); // don't update constraints view!
|
||||
this->update(idToIndex_.value(link.to()),
|
||||
ui_->label_indexB,
|
||||
@@ -1945,6 +1968,7 @@ void DatabaseViewer::updateConstraintView(
|
||||
ui_->graphicsView_B,
|
||||
ui_->widget_cloudB,
|
||||
ui_->label_idB,
|
||||
ui_->label_mapB,
|
||||
false); // don't update constraints view!
|
||||
}
|
||||
|
||||
@@ -2105,10 +2129,18 @@ void DatabaseViewer::updateConstraintView(
|
||||
{
|
||||
ui_->constraintsViewer->addOrUpdateCloud("scan0", scanA, Transform::getIdentity(), Qt::yellow);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui_->constraintsViewer->removeCloud("scan0");
|
||||
}
|
||||
if(scanB->size())
|
||||
{
|
||||
ui_->constraintsViewer->addOrUpdateCloud("scan1", scanB, Transform::getIdentity(), Qt::magenta);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui_->constraintsViewer->removeCloud("scan1");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2116,10 +2148,18 @@ void DatabaseViewer::updateConstraintView(
|
||||
{
|
||||
ui_->constraintsViewer->addOrUpdateCloud("scan0", scanFrom, Transform::getIdentity(), Qt::yellow);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui_->constraintsViewer->removeCloud("scan0");
|
||||
}
|
||||
if(scanTo->size())
|
||||
{
|
||||
ui_->constraintsViewer->addOrUpdateCloud("scan1", scanTo, Transform::getIdentity(), Qt::magenta);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui_->constraintsViewer->removeCloud("scan1");
|
||||
}
|
||||
}
|
||||
|
||||
//update cordinate
|
||||
@@ -2451,10 +2491,10 @@ void DatabaseViewer::refineConstraint()
|
||||
{
|
||||
int from = ids_.at(ui_->horizontalSlider_A->value());
|
||||
int to = ids_.at(ui_->horizontalSlider_B->value());
|
||||
refineConstraint(from, to, true);
|
||||
refineConstraint(from, to, false, true);
|
||||
}
|
||||
|
||||
void DatabaseViewer::refineConstraint(int from, int to, bool updateGraph)
|
||||
void DatabaseViewer::refineConstraint(int from, int to, bool silent, bool updateGraph)
|
||||
{
|
||||
if(from == to)
|
||||
{
|
||||
@@ -2501,6 +2541,7 @@ void DatabaseViewer::refineConstraint(int from, int to, bool updateGraph)
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudB(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr scanA(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr scanB(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
float correspondenceRatio = 0.0f;
|
||||
if(ui_->checkBox_icp_2d->isChecked())
|
||||
{
|
||||
//2D
|
||||
@@ -2529,6 +2570,18 @@ void DatabaseViewer::refineConstraint(int from, int to, bool updateGraph)
|
||||
&hasConverged,
|
||||
&variance,
|
||||
&correspondences);
|
||||
|
||||
if(!transform.isNull())
|
||||
{
|
||||
if(dataTo.getLaserScanMaxPts())
|
||||
{
|
||||
correspondenceRatio = float(correspondences)/float(dataTo.getLaserScanMaxPts());
|
||||
}
|
||||
else if(ui_->doubleSpinBox_icp_minCorrespondenceRatio->value())
|
||||
{
|
||||
UWARN("Laser scan max pts not set, but correspondence ratio is set!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2639,53 +2692,75 @@ void DatabaseViewer::refineConstraint(int from, int to, bool updateGraph)
|
||||
&hasConverged,
|
||||
&variance,
|
||||
&correspondences);
|
||||
|
||||
correspondenceRatio = float(correspondences)/float(depthB.total());
|
||||
}
|
||||
}
|
||||
|
||||
if(hasConverged && !transform.isNull())
|
||||
{
|
||||
Link newLink(currentLink.from(), currentLink.to(), currentLink.type(), transform*t, variance, variance);
|
||||
|
||||
bool updated = false;
|
||||
std::multimap<int, Link>::iterator iter = linksRefined_.find(currentLink.from());
|
||||
while(iter != linksRefined_.end() && iter->first == currentLink.from())
|
||||
if(correspondenceRatio < ui_->doubleSpinBox_icp_minCorrespondenceRatio->value())
|
||||
{
|
||||
if(iter->second.to() == currentLink.to() &&
|
||||
iter->second.type() == currentLink.type())
|
||||
if(!silent)
|
||||
{
|
||||
iter->second = newLink;
|
||||
updated = true;
|
||||
break;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
if(!updated)
|
||||
{
|
||||
linksRefined_.insert(std::make_pair<int, Link>(newLink.from(), newLink));
|
||||
|
||||
if(updateGraph)
|
||||
{
|
||||
this->updateGraphView();
|
||||
QMessageBox::warning(this,
|
||||
tr("Refine link"),
|
||||
tr("Cannot find a transformation between nodes %1 and %2, correspondence ratio too low (%3).")
|
||||
.arg(from).arg(to).arg(correspondenceRatio));
|
||||
}
|
||||
}
|
||||
|
||||
if(ui_->dockWidget_constraints->isVisible())
|
||||
else
|
||||
{
|
||||
cloudB = util3d::transformPointCloud<pcl::PointXYZ>(cloudB, transform);
|
||||
scanB = util3d::transformPointCloud<pcl::PointXYZ>(scanB, transform);
|
||||
this->updateConstraintView(newLink, true, cloudA, cloudB, scanA, scanB);
|
||||
|
||||
Link newLink(currentLink.from(), currentLink.to(), currentLink.type(), transform*t, variance, variance);
|
||||
|
||||
bool updated = false;
|
||||
std::multimap<int, Link>::iterator iter = linksRefined_.find(currentLink.from());
|
||||
while(iter != linksRefined_.end() && iter->first == currentLink.from())
|
||||
{
|
||||
if(iter->second.to() == currentLink.to() &&
|
||||
iter->second.type() == currentLink.type())
|
||||
{
|
||||
iter->second = newLink;
|
||||
updated = true;
|
||||
break;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
if(!updated)
|
||||
{
|
||||
linksRefined_.insert(std::make_pair<int, Link>(newLink.from(), newLink));
|
||||
|
||||
if(updateGraph)
|
||||
{
|
||||
this->updateGraphView();
|
||||
}
|
||||
}
|
||||
|
||||
if(ui_->dockWidget_constraints->isVisible())
|
||||
{
|
||||
cloudB = util3d::transformPointCloud<pcl::PointXYZ>(cloudB, transform);
|
||||
scanB = util3d::transformPointCloud<pcl::PointXYZ>(scanB, transform);
|
||||
this->updateConstraintView(newLink, true, cloudA, cloudB, scanA, scanB);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!silent)
|
||||
{
|
||||
QMessageBox::warning(this,
|
||||
tr("Refine link"),
|
||||
tr("Cannot find a transformation between nodes %1 and %2").arg(from).arg(to));
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseViewer::refineConstraintVisually()
|
||||
{
|
||||
int from = ids_.at(ui_->horizontalSlider_A->value());
|
||||
int to = ids_.at(ui_->horizontalSlider_B->value());
|
||||
refineConstraintVisually(from, to, true);
|
||||
refineConstraintVisually(from, to, false, true);
|
||||
}
|
||||
|
||||
void DatabaseViewer::refineConstraintVisually(int from, int to, bool updateGraph)
|
||||
void DatabaseViewer::refineConstraintVisually(int from, int to, bool silent, bool updateGraph)
|
||||
{
|
||||
if(from == to)
|
||||
{
|
||||
@@ -2751,6 +2826,14 @@ void DatabaseViewer::refineConstraintVisually(int from, int to, bool updateGraph
|
||||
|
||||
if(!t.isNull())
|
||||
{
|
||||
if(ui_->checkBox_visual_2d->isChecked())
|
||||
{
|
||||
// We are 2D here, make sure the guess has only YAW rotation
|
||||
float x,y,z,r,p,yaw;
|
||||
t.getTranslationAndEulerAngles(x,y,z, r,p,yaw);
|
||||
t = Transform::fromEigen3f(pcl::getTransformation(x,y,0, 0, 0, yaw));
|
||||
}
|
||||
|
||||
Link newLink(currentLink.from(), currentLink.to(), currentLink.type(), t, variance, variance);
|
||||
|
||||
bool updated = false;
|
||||
@@ -2780,6 +2863,12 @@ void DatabaseViewer::refineConstraintVisually(int from, int to, bool updateGraph
|
||||
this->updateConstraintView(newLink);
|
||||
}
|
||||
}
|
||||
else if(!silent)
|
||||
{
|
||||
QMessageBox::warning(this,
|
||||
tr("Add link"),
|
||||
tr("Cannot find a transformation between nodes %1 and %2: %3").arg(from).arg(to).arg(rejectedMsg.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseViewer::addConstraint()
|
||||
@@ -2860,16 +2949,7 @@ bool DatabaseViewer::addConstraint(int from, int to, bool silent, bool updateGra
|
||||
t = memory_->computeVisualTransform(to, from, &rejectedMsg, &inliers, &variance);
|
||||
}
|
||||
|
||||
if(t.isNull())
|
||||
{
|
||||
if(!silent)
|
||||
{
|
||||
QMessageBox::warning(this,
|
||||
tr("Add link"),
|
||||
tr("Cannot find a transformation between nodes %1 and %2: %3").arg(from).arg(to).arg(rejectedMsg.c_str()));
|
||||
}
|
||||
}
|
||||
else
|
||||
if(!t.isNull())
|
||||
{
|
||||
if(ui_->checkBox_visual_2d->isChecked())
|
||||
{
|
||||
@@ -2890,6 +2970,12 @@ bool DatabaseViewer::addConstraint(int from, int to, bool silent, bool updateGra
|
||||
}
|
||||
updateSlider = true;
|
||||
}
|
||||
else if(!silent)
|
||||
{
|
||||
QMessageBox::warning(this,
|
||||
tr("Add link"),
|
||||
tr("Cannot find a transformation between nodes %1 and %2: %3").arg(from).arg(to).arg(rejectedMsg.c_str()));
|
||||
}
|
||||
}
|
||||
else if(containsLink(linksRemoved_, from, to))
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <QCheckBox>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QTime>
|
||||
#include <QScrollBar>
|
||||
#include "rtabmap/utilite/ULogger.h"
|
||||
|
||||
namespace rtabmap {
|
||||
@@ -88,6 +89,7 @@ void DetailedProgressDialog::appendText(const QString & text, const QColor & col
|
||||
QString html = tr("<html><font color=\"#999999\">%1 </font><font color=\"%2\">%3</font></html>").arg(QTime::currentTime().toString("HH:mm:ss")).arg(color.name()).arg(text);
|
||||
_detailedText->append(html);
|
||||
_detailedText->ensureCursorVisible();
|
||||
_detailedText->horizontalScrollBar()->setSliderPosition(0);
|
||||
}
|
||||
void DetailedProgressDialog::setValue(int value)
|
||||
{
|
||||
|
||||
@@ -158,6 +158,7 @@ private:
|
||||
GraphViewer::GraphViewer(QWidget * parent) :
|
||||
QGraphicsView(parent),
|
||||
_nodeColor(Qt::blue),
|
||||
_currentGoalColor(Qt::darkMagenta),
|
||||
_neighborColor(Qt::blue),
|
||||
_loopClosureColor(Qt::red),
|
||||
_loopClosureLocalColor(Qt::yellow),
|
||||
@@ -170,7 +171,8 @@ GraphViewer::GraphViewer(QWidget * parent) :
|
||||
_linkWidth(0),
|
||||
_gridMap(0),
|
||||
_referential(0),
|
||||
_gridCellSize(0.0f)
|
||||
_gridCellSize(0.0f),
|
||||
_localRadius(0)
|
||||
{
|
||||
this->setScene(new QGraphicsScene(this));
|
||||
this->setDragMode(QGraphicsView::ScrollHandDrag);
|
||||
@@ -203,12 +205,19 @@ GraphViewer::GraphViewer(QWidget * parent) :
|
||||
item->setParentItem(_root);
|
||||
_referential->addToGroup(item);
|
||||
|
||||
_localRadius = this->scene()->addEllipse(-0.0001,-0.0001,0.0001,0.0001);
|
||||
_localRadius->setZValue(1);
|
||||
_localRadius->setParentItem(_root);
|
||||
_localRadius->setVisible(false);
|
||||
_localRadius->setPen(QPen(Qt::DashLine));
|
||||
|
||||
_gridMap = this->scene()->addPixmap(QPixmap());
|
||||
_gridMap->setZValue(0);
|
||||
_gridMap->setParentItem(_root);
|
||||
|
||||
this->restoreDefaults();
|
||||
|
||||
this->fitInView(this->sceneRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
GraphViewer::~GraphViewer()
|
||||
@@ -247,7 +256,7 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
|
||||
const Transform & pose = iter->second;
|
||||
NodeItem * item = new NodeItem(iter->first, pose, _nodeRadius);
|
||||
this->scene()->addItem(item);
|
||||
item->setZValue(2);
|
||||
item->setZValue(20);
|
||||
item->setColor(_nodeColor);
|
||||
item->setParentItem(_root);
|
||||
_nodeItems.insert(iter->first, item);
|
||||
@@ -334,7 +343,7 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
|
||||
item->setColor(_loopClosureColor);
|
||||
}
|
||||
this->scene()->addItem(item);
|
||||
item->setZValue(1);
|
||||
item->setZValue(10);
|
||||
item->setParentItem(_root);
|
||||
_linkItems.insert(idFrom, item);
|
||||
}
|
||||
@@ -384,6 +393,7 @@ void GraphViewer::updateReferentialPosition(const Transform & t)
|
||||
{
|
||||
QTransform qt(t.r11(), t.r12(), t.r21(), t.r22(), -t.o24(), -t.o14());
|
||||
_referential->setTransform(qt);
|
||||
_localRadius->setTransform(qt);
|
||||
|
||||
this->ensureVisible(_referential);
|
||||
}
|
||||
@@ -456,13 +466,31 @@ void GraphViewer::setGlobalPath(const std::vector<std::pair<int, Transform> > &
|
||||
item->setPen(p);
|
||||
item->setColor(_globalPathColor);
|
||||
this->scene()->addItem(item);
|
||||
item->setZValue(1);
|
||||
item->setZValue(15);
|
||||
item->setParentItem(_root);
|
||||
_globalPathLinkItems.insert(idFrom, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphViewer::setCurrentGoalID(int id)
|
||||
{
|
||||
NodeItem * node = _nodeItems.value(id, 0);
|
||||
if(node)
|
||||
{
|
||||
node->setColor(_currentGoalColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Curent goal %d not found in the graph", id);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphViewer::setLocalRadius(float radius)
|
||||
{
|
||||
_localRadius->setRect(-radius, -radius, radius*2, radius*2);
|
||||
}
|
||||
|
||||
void GraphViewer::updateLocalPath(const std::vector<int> & localPath)
|
||||
{
|
||||
if(localPath.size() > 1)
|
||||
@@ -497,6 +525,7 @@ void GraphViewer::clearGraph()
|
||||
qDeleteAll(_globalPathLinkItems);
|
||||
_globalPathLinkItems.clear();
|
||||
_referential->resetTransform();
|
||||
_localRadius->resetTransform();
|
||||
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
|
||||
}
|
||||
|
||||
@@ -530,6 +559,7 @@ void GraphViewer::saveSettings(QSettings & settings, const QString & group) cons
|
||||
settings.setValue("node_radius", (double)this->getNodeRadius());
|
||||
settings.setValue("link_width", (double)this->getLinkWidth());
|
||||
settings.setValue("node_color", this->getNodeColor());
|
||||
settings.setValue("current_goal_color", this->getCurrentGoalColor());
|
||||
settings.setValue("neighbor_color", this->getNeighborColor());
|
||||
settings.setValue("global_color", this->getGlobalLoopClosureColor());
|
||||
settings.setValue("local_color", this->getLocalLoopClosureColor());
|
||||
@@ -540,6 +570,7 @@ void GraphViewer::saveSettings(QSettings & settings, const QString & group) cons
|
||||
settings.setValue("grid_visible", this->isGridMapVisible());
|
||||
settings.setValue("origin_visible", this->isOriginVisible());
|
||||
settings.setValue("referential_visible", this->isReferentialVisible());
|
||||
settings.setValue("local_radius_visible", this->isLocalRadiusVisible());
|
||||
if(!group.isEmpty())
|
||||
{
|
||||
settings.endGroup();
|
||||
@@ -555,6 +586,7 @@ void GraphViewer::loadSettings(QSettings & settings, const QString & group)
|
||||
this->setNodeRadius(settings.value("node_radius", this->getNodeRadius()).toDouble());
|
||||
this->setLinkWidth(settings.value("link_width", this->getLinkWidth()).toDouble());
|
||||
this->setNodeColor(settings.value("node_color", this->getNodeColor()).value<QColor>());
|
||||
this->setCurrentGoalColor(settings.value("current_goal_color", this->getCurrentGoalColor()).value<QColor>());
|
||||
this->setNeighborColor(settings.value("neighbor_color", this->getNeighborColor()).value<QColor>());
|
||||
this->setGlobalLoopClosureColor(settings.value("global_color", this->getGlobalLoopClosureColor()).value<QColor>());
|
||||
this->setLocalLoopClosureColor(settings.value("local_color", this->getLocalLoopClosureColor()).value<QColor>());
|
||||
@@ -565,6 +597,7 @@ void GraphViewer::loadSettings(QSettings & settings, const QString & group)
|
||||
this->setGridMapVisible(settings.value("grid_visible", this->isGridMapVisible()).toBool());
|
||||
this->setOriginVisible(settings.value("origin_visible", this->isOriginVisible()).toBool());
|
||||
this->setReferentialVisible(settings.value("referential_visible", this->isReferentialVisible()).toBool());
|
||||
this->setLocalRadiusVisible(settings.value("local_radius_visible", this->isLocalRadiusVisible()).toBool());
|
||||
if(!group.isEmpty())
|
||||
{
|
||||
settings.endGroup();
|
||||
@@ -583,6 +616,10 @@ bool GraphViewer::isReferentialVisible() const
|
||||
{
|
||||
return _referential->isVisible();
|
||||
}
|
||||
bool GraphViewer::isLocalRadiusVisible() const
|
||||
{
|
||||
return _localRadius->isVisible();
|
||||
}
|
||||
|
||||
void GraphViewer::setWorkingDirectory(const QString & path)
|
||||
{
|
||||
@@ -619,6 +656,10 @@ void GraphViewer::setNodeColor(const QColor & color)
|
||||
iter.value()->setColor(_nodeColor);
|
||||
}
|
||||
}
|
||||
void GraphViewer::setCurrentGoalColor(const QColor & color)
|
||||
{
|
||||
_currentGoalColor = color;
|
||||
}
|
||||
void GraphViewer::setNeighborColor(const QColor & color)
|
||||
{
|
||||
_neighborColor = color;
|
||||
@@ -699,6 +740,10 @@ void GraphViewer::setReferentialVisible(bool visible)
|
||||
{
|
||||
_referential->setVisible(visible);
|
||||
}
|
||||
void GraphViewer::setLocalRadiusVisible(bool visible)
|
||||
{
|
||||
_localRadius->setVisible(visible);
|
||||
}
|
||||
|
||||
void GraphViewer::restoreDefaults()
|
||||
{
|
||||
@@ -741,7 +786,9 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
menu.addSeparator();
|
||||
|
||||
QAction * aChangeNodeColor = menu.addAction(createIcon(_nodeColor), tr("Set node color..."));
|
||||
QAction * aChangeCurrentGoalColor = menu.addAction(createIcon(_currentGoalColor), tr("Set current goal color..."));
|
||||
aChangeNodeColor->setIconVisibleInMenu(true);
|
||||
aChangeCurrentGoalColor->setIconVisibleInMenu(true);
|
||||
|
||||
// Links
|
||||
QMenu * menuLink = menu.addMenu(tr("Set link color..."));
|
||||
@@ -774,6 +821,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
QAction * aShowHideGridMap;
|
||||
QAction * aShowHideOrigin;
|
||||
QAction * aShowHideReferential;
|
||||
QAction * aShowHideLocalRadius;
|
||||
if(_gridMap->isVisible())
|
||||
{
|
||||
aShowHideGridMap = menu.addAction(tr("Hide grid map"));
|
||||
@@ -798,6 +846,14 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
{
|
||||
aShowHideReferential = menu.addAction(tr("Show current referential"));
|
||||
}
|
||||
if(_localRadius->isVisible())
|
||||
{
|
||||
aShowHideLocalRadius = menu.addAction(tr("Hide local radius"));
|
||||
}
|
||||
else
|
||||
{
|
||||
aShowHideLocalRadius = menu.addAction(tr("Show local radius"));
|
||||
}
|
||||
menu.addSeparator();
|
||||
QAction * aRestoreDefaults = menu.addAction(tr("Restore defaults"));
|
||||
|
||||
@@ -869,6 +925,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
return; // without emitting configChanged
|
||||
}
|
||||
else if(r == aChangeNodeColor ||
|
||||
r == aChangeCurrentGoalColor ||
|
||||
r == aChangeNeighborColor ||
|
||||
r == aChangeGlobalLoopColor ||
|
||||
r == aChangeLocalLoopColor ||
|
||||
@@ -882,6 +939,10 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
{
|
||||
color = _nodeColor;
|
||||
}
|
||||
else if(r == aChangeCurrentGoalColor)
|
||||
{
|
||||
color = _currentGoalColor;
|
||||
}
|
||||
else if(r == aChangeGlobalLoopColor)
|
||||
{
|
||||
color = _loopClosureColor;
|
||||
@@ -918,6 +979,10 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
{
|
||||
this->setNodeColor(color);
|
||||
}
|
||||
else if(r == aChangeCurrentGoalColor)
|
||||
{
|
||||
this->setCurrentGoalColor(color);
|
||||
}
|
||||
else if(r == aChangeGlobalLoopColor)
|
||||
{
|
||||
this->setGlobalLoopClosureColor(color);
|
||||
@@ -978,6 +1043,10 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
{
|
||||
this->setReferentialVisible(!this->isReferentialVisible());
|
||||
}
|
||||
else if(r == aShowHideLocalRadius)
|
||||
{
|
||||
this->setLocalRadiusVisible(!this->isLocalRadiusVisible());
|
||||
}
|
||||
else if(r == aRestoreDefaults)
|
||||
{
|
||||
this->restoreDefaults();
|
||||
|
||||
@@ -59,6 +59,8 @@ public:
|
||||
void updatePosterior(const std::map<int, float> & posterior);
|
||||
void updateLocalPath(const std::vector<int> & localPath);
|
||||
void setGlobalPath(const std::vector<std::pair<int, Transform> > & globalPath);
|
||||
void setCurrentGoalID(int id);
|
||||
void setLocalRadius(float radius);
|
||||
void clearGraph();
|
||||
void clearMap();
|
||||
void clearPosterior();
|
||||
@@ -72,6 +74,7 @@ public:
|
||||
float getNodeRadius() const {return _nodeRadius;}
|
||||
float getLinkWidth() const {return _linkWidth;}
|
||||
const QColor & getNodeColor() const {return _nodeColor;}
|
||||
const QColor & getCurrentGoalColor() const {return _currentGoalColor;}
|
||||
const QColor & getNeighborColor() const {return _neighborColor;}
|
||||
const QColor & getGlobalLoopClosureColor() const {return _loopClosureColor;}
|
||||
const QColor & getLocalLoopClosureColor() const {return _loopClosureLocalColor;}
|
||||
@@ -82,12 +85,14 @@ public:
|
||||
bool isGridMapVisible() const;
|
||||
bool isOriginVisible() const;
|
||||
bool isReferentialVisible() const;
|
||||
bool isLocalRadiusVisible() const;
|
||||
|
||||
// setters
|
||||
void setWorkingDirectory(const QString & path);
|
||||
void setNodeRadius(float radius);
|
||||
void setLinkWidth(float width);
|
||||
void setNodeColor(const QColor & color);
|
||||
void setCurrentGoalColor(const QColor & color);
|
||||
void setNeighborColor(const QColor & color);
|
||||
void setGlobalLoopClosureColor(const QColor & color);
|
||||
void setLocalLoopClosureColor(const QColor & color);
|
||||
@@ -98,6 +103,7 @@ public:
|
||||
void setGridMapVisible(bool visible);
|
||||
void setOriginVisible(bool visible);
|
||||
void setReferentialVisible(bool visible);
|
||||
void setLocalRadiusVisible(bool visible);
|
||||
|
||||
signals:
|
||||
void configChanged();
|
||||
@@ -112,6 +118,7 @@ protected:
|
||||
private:
|
||||
QString _workingDirectory;
|
||||
QColor _nodeColor;
|
||||
QColor _currentGoalColor;
|
||||
QColor _neighborColor;
|
||||
QColor _loopClosureColor;
|
||||
QColor _loopClosureLocalColor;
|
||||
@@ -129,6 +136,7 @@ private:
|
||||
QGraphicsItemGroup * _referential;
|
||||
QGraphicsItemGroup * _originReferential;
|
||||
float _gridCellSize;
|
||||
QGraphicsEllipseItem * _localRadius;
|
||||
};
|
||||
|
||||
} /* namespace rtabmap */
|
||||
|
||||
@@ -529,22 +529,14 @@ void ImageView::updateOpacity()
|
||||
if(_imageItem->isVisible() && _imageDepthItem->isVisible())
|
||||
{
|
||||
QGraphicsOpacityEffect * effect = new QGraphicsOpacityEffect();
|
||||
QGraphicsOpacityEffect * effect2 = new QGraphicsOpacityEffect();
|
||||
effect->setOpacity(0.5);
|
||||
effect2->setOpacity(0.5);
|
||||
_imageItem->setGraphicsEffect(effect);
|
||||
_imageDepthItem->setGraphicsEffect(effect2);
|
||||
_imageDepthItem->setGraphicsEffect(effect);
|
||||
}
|
||||
else
|
||||
{
|
||||
_imageItem->setGraphicsEffect(0);
|
||||
_imageDepthItem->setGraphicsEffect(0);
|
||||
}
|
||||
}
|
||||
else if(_imageItem)
|
||||
{
|
||||
_imageItem->setGraphicsEffect(0);
|
||||
}
|
||||
else if(_imageDepthItem)
|
||||
{
|
||||
_imageDepthItem->setGraphicsEffect(0);
|
||||
|
||||
@@ -369,9 +369,6 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
_ui->actionStereoFlyCapture2->setEnabled(CameraStereoFlyCapture2::available());
|
||||
this->updateSelectSourceMenu();
|
||||
|
||||
connect(_ui->actionSave_state, SIGNAL(triggered()), this, SLOT(saveFigures()));
|
||||
connect(_ui->actionLoad_state, SIGNAL(triggered()), this, SLOT(loadFigures()));
|
||||
|
||||
connect(_ui->actionPreferences, SIGNAL(triggered()), this, SLOT(openPreferences()));
|
||||
|
||||
QActionGroup * modeGrp = new QActionGroup(this);
|
||||
@@ -461,6 +458,8 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
_ui->statsToolBox->updateStat(QString((*iter).first.c_str()).replace('_', ' '), 0, (*iter).second);
|
||||
}
|
||||
}
|
||||
this->loadFigures();
|
||||
connect(_ui->statsToolBox, SIGNAL(figuresSetupChanged()), this, SLOT(configGUIModified()));
|
||||
|
||||
// update loop closure viewer parameters
|
||||
ParametersMap parameters = _preferencesDialog->getAllParameters();
|
||||
@@ -1201,6 +1200,11 @@ void MainWindow::processStats(const rtabmap::Statistics & stat)
|
||||
// clear the global path if set (goal reached)
|
||||
_ui->graphicsView_graphView->setGlobalPath(std::vector<std::pair<int, Transform> >());
|
||||
}
|
||||
// update current goal id
|
||||
if(stat.currentGoalId() > 0)
|
||||
{
|
||||
_ui->graphicsView_graphView->setCurrentGoalID(stat.currentGoalId());
|
||||
}
|
||||
|
||||
UDEBUG("");
|
||||
}
|
||||
@@ -1986,7 +1990,7 @@ void MainWindow::processRtabmapGlobalPathEvent(const rtabmap::RtabmapGlobalPathE
|
||||
_ui->graphicsView_graphView->setGlobalPath(event.getPoses());
|
||||
_ui->statusbar->showMessage(
|
||||
tr("Global path computed from %1 (%2 poses, %3 m)!").arg(event.getGoal()).arg(event.getPoses().size()).arg(graph::computePathLength(event.getPoses())),
|
||||
5000);
|
||||
10000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2074,6 +2078,11 @@ void MainWindow::applyPrefSettings(PreferencesDialog::PANEL_FLAGS flags)
|
||||
}
|
||||
|
||||
void MainWindow::applyPrefSettings(const rtabmap::ParametersMap & parameters)
|
||||
{
|
||||
applyPrefSettings(parameters, true); //post parameters
|
||||
}
|
||||
|
||||
void MainWindow::applyPrefSettings(const rtabmap::ParametersMap & parameters, bool postParamEvent)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
if(parameters.size())
|
||||
@@ -2098,7 +2107,10 @@ void MainWindow::applyPrefSettings(const rtabmap::ParametersMap & parameters)
|
||||
QMessageBox::information(this, tr("Working memory changed"), tr("The working directory can't be changed while the detector is running. This will be applied when the detector will stop."));
|
||||
}
|
||||
}
|
||||
this->post(new ParamEvent(parametersModified));
|
||||
if(postParamEvent)
|
||||
{
|
||||
this->post(new ParamEvent(parametersModified));
|
||||
}
|
||||
}
|
||||
|
||||
if(_state != kMonitoring && _state != kMonitoringPaused &&
|
||||
@@ -2122,6 +2134,12 @@ void MainWindow::applyPrefSettings(const rtabmap::ParametersMap & parameters)
|
||||
{
|
||||
_ui->widget_loopClosureViewer->setSamples(atoi(parameters.at(Parameters::kLccIcp3Samples()).c_str()));
|
||||
}
|
||||
|
||||
// update graph view parameters
|
||||
if(uContains(parameters, Parameters::kRGBDLocalRadius()))
|
||||
{
|
||||
_ui->graphicsView_graphView->setLocalRadius(uStr2Float(parameters.at(Parameters::kRGBDLocalRadius())));
|
||||
}
|
||||
}
|
||||
|
||||
//update ui
|
||||
@@ -2380,6 +2398,7 @@ void MainWindow::saveConfigGUI()
|
||||
_preferencesDialog->saveWidgetState(_postProcessingDialog);
|
||||
_preferencesDialog->saveWidgetState(_ui->graphicsView_graphView);
|
||||
_preferencesDialog->saveSettings();
|
||||
this->saveFigures();
|
||||
this->setWindowModified(false);
|
||||
}
|
||||
|
||||
@@ -2426,6 +2445,7 @@ void MainWindow::newDatabase()
|
||||
}
|
||||
_newDatabasePath = databasePath.c_str();
|
||||
this->post(new RtabmapEventCmd(RtabmapEventCmd::kCmdInit, databasePath, 0, _preferencesDialog->getAllParameters()));
|
||||
applyPrefSettings(_preferencesDialog->getAllParameters(), false);
|
||||
}
|
||||
|
||||
void MainWindow::openDatabase()
|
||||
@@ -2446,6 +2466,7 @@ void MainWindow::openDatabase()
|
||||
_openedDatabasePath = path;
|
||||
this->post(new RtabmapEventCmd(RtabmapEventCmd::kCmdInit, path.toStdString(), 0, _preferencesDialog->getAllParameters()));
|
||||
}
|
||||
applyPrefSettings(_preferencesDialog->getAllParameters(), false);
|
||||
}
|
||||
|
||||
bool MainWindow::closeDatabase()
|
||||
@@ -3854,20 +3875,6 @@ void MainWindow::saveFigures()
|
||||
QStringList curveNames;
|
||||
_ui->statsToolBox->getFiguresSetup(curvesPerFigure, curveNames);
|
||||
|
||||
if(curvesPerFigure.size() == 0)
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("There is no figure shown.");
|
||||
msgBox.setInformativeText("Do you want to save anyway ? (this will erase the previous saved configuration)");
|
||||
msgBox.setStandardButtons(QFlags<QMessageBox::StandardButton>(QMessageBox::Save | QMessageBox::Cancel));
|
||||
msgBox.setDefaultButton(QMessageBox::Cancel);
|
||||
int ret = msgBox.exec();
|
||||
if(ret == QMessageBox::Cancel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList curvesPerFigureStr;
|
||||
for(int i=0; i<curvesPerFigure.size(); ++i)
|
||||
{
|
||||
@@ -3886,25 +3893,28 @@ void MainWindow::loadFigures()
|
||||
QString curvesPerFigure = _preferencesDialog->loadCustomConfig("Figures", "counts");
|
||||
QString curveNames = _preferencesDialog->loadCustomConfig("Figures", "curves");
|
||||
|
||||
QStringList curvesPerFigureList = curvesPerFigure.split(" ");
|
||||
QStringList curvesNamesList = curveNames.split(" ");
|
||||
|
||||
int j=0;
|
||||
for(int i=0; i<curvesPerFigureList.size(); ++i)
|
||||
if(!curvesPerFigure.isEmpty())
|
||||
{
|
||||
bool ok = false;
|
||||
int count = curvesPerFigureList[i].toInt(&ok);
|
||||
if(!ok)
|
||||
QStringList curvesPerFigureList = curvesPerFigure.split(" ");
|
||||
QStringList curvesNamesList = curveNames.split(" ");
|
||||
|
||||
int j=0;
|
||||
for(int i=0; i<curvesPerFigureList.size(); ++i)
|
||||
{
|
||||
QMessageBox::warning(this, "Loading failed", "Corrupted figures setup...");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ui->statsToolBox->addCurve(curvesNamesList[j++].replace('_', ' '));
|
||||
for(int k=1; k<count && j<curveNames.size(); ++k)
|
||||
bool ok = false;
|
||||
int count = curvesPerFigureList[i].toInt(&ok);
|
||||
if(!ok)
|
||||
{
|
||||
_ui->statsToolBox->addCurve(curvesNamesList[j++].replace('_', ' '), false);
|
||||
QMessageBox::warning(this, "Loading failed", "Corrupted figures setup...");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ui->statsToolBox->addCurve(curvesNamesList[j++].replace('_', ' '));
|
||||
for(int k=1; k<count && j<curveNames.size(); ++k)
|
||||
{
|
||||
_ui->statsToolBox->addCurve(curvesNamesList[j++].replace('_', ' '), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,6 +471,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->general_checkBox_activateRGBD->setObjectName(Parameters::kRGBDEnabled().c_str());
|
||||
_ui->rgdb_linearUpdate->setObjectName(Parameters::kRGBDLinearUpdate().c_str());
|
||||
_ui->rgdb_angularUpdate->setObjectName(Parameters::kRGBDAngularUpdate().c_str());
|
||||
_ui->rgdb_rehearsalWeightIgnoredWhileMoving->setObjectName(Parameters::kMemRehearsalWeightIgnoredWhileMoving().c_str());
|
||||
_ui->rgdb_newMapOdomChange->setObjectName(Parameters::kRGBDNewMapOdomChangeDistance().c_str());
|
||||
_ui->odomScanHistory->setObjectName(Parameters::kRGBDPoseScanMatching().c_str());
|
||||
_ui->spinBox_maxLocalLocationsRetrieved->setObjectName(Parameters::kRGBDMaxLocalRetrieved().c_str());
|
||||
@@ -489,7 +490,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->groupBox_localDetection_time->setObjectName(Parameters::kRGBDLocalLoopDetectionTime().c_str());
|
||||
_ui->groupBox_localDetection_space->setObjectName(Parameters::kRGBDLocalLoopDetectionSpace().c_str());
|
||||
_ui->localDetection_radius->setObjectName(Parameters::kRGBDLocalRadius().c_str());
|
||||
_ui->localDetection_maxDiffID->setObjectName(Parameters::kRGBDLocalLoopDetectionMaxDiffID().c_str());
|
||||
_ui->localDetection_maxDiffID->setObjectName(Parameters::kRGBDLocalLoopDetectionMaxGraphDepth().c_str());
|
||||
_ui->localDetection_pathFilteringRadius->setObjectName(Parameters::kRGBDLocalLoopDetectionPathFilteringRadius().c_str());
|
||||
_ui->checkBox_localSpacePathOdomPosesUsed->setObjectName(Parameters::kRGBDLocalLoopDetectionPathOdomPosesUsed().c_str());
|
||||
|
||||
@@ -2041,16 +2042,15 @@ void PreferencesDialog::selectSourceDatabase(bool user)
|
||||
{
|
||||
dir = getWorkingDirectory();
|
||||
}
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), dir, tr("RTAB-Map database files (*.db)"));
|
||||
QFile file(path);
|
||||
if(!path.isEmpty() && file.exists())
|
||||
QStringList paths = QFileDialog::getOpenFileNames(this, tr("Select file"), dir, tr("RTAB-Map database files (*.db)"));
|
||||
if(paths.size())
|
||||
{
|
||||
int r = QMessageBox::question(this, tr("Odometry in database..."), tr("Use odometry saved in database (if some saved)?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
|
||||
_ui->groupBox_sourceDatabase->setChecked(true);
|
||||
_ui->source_checkBox_ignoreOdometry->setChecked(r != QMessageBox::Yes);
|
||||
_ui->source_checkBox_ignoreGoalDelay->setChecked(false);
|
||||
_ui->source_database_lineEdit_path->setText(path);
|
||||
_ui->source_database_lineEdit_path->setText(paths.size()==1?paths.front():paths.join(";"));
|
||||
_ui->source_spinBox_databaseStartPos->setValue(0);
|
||||
_ui->source_checkBox_useDbStamps->setChecked(false);
|
||||
}
|
||||
|
||||
@@ -313,6 +313,7 @@ void StatsToolBox::plot(const StatItem * stat, const QString & plotName)
|
||||
{
|
||||
ULOGGER_WARN("Already added to the figure");
|
||||
}
|
||||
emit figuresSetupChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -362,6 +363,7 @@ void StatsToolBox::plot(const StatItem * stat, const QString & plotName)
|
||||
delete curve;
|
||||
}
|
||||
figure->show();
|
||||
emit figuresSetupChanged();
|
||||
|
||||
emit menuChanged(_plotMenu);
|
||||
}
|
||||
@@ -386,6 +388,7 @@ void StatsToolBox::figureDeleted(QObject * obj)
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit figuresSetupChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -94,6 +94,7 @@ public slots:
|
||||
|
||||
signals:
|
||||
void menuChanged(const QMenu *);
|
||||
void figuresSetupChanged();
|
||||
|
||||
private slots:
|
||||
void plot(const StatItem * stat, const QString & plotName = QString());
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1183</width>
|
||||
<height>834</height>
|
||||
<height>804</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -50,8 +50,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>159</width>
|
||||
<height>136</height>
|
||||
<width>162</width>
|
||||
<height>150</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
|
||||
@@ -97,14 +97,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_childrenA_6">
|
||||
<property name="text">
|
||||
<string>Stamp</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="label_stampA">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -125,6 +125,20 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_childrenA_10">
|
||||
<property name="text">
|
||||
<string>Map ID</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_mapA">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
@@ -205,8 +219,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>159</width>
|
||||
<height>136</height>
|
||||
<width>162</width>
|
||||
<height>150</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1">
|
||||
@@ -252,14 +266,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_childrenA_7">
|
||||
<property name="text">
|
||||
<string>Stamp</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="label_stampB">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -280,6 +294,20 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_childrenA_11">
|
||||
<property name="text">
|
||||
<string>Map ID</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_mapB">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
@@ -356,7 +384,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1183</width>
|
||||
<height>22</height>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
@@ -679,7 +707,7 @@
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_4" columnstretch="0,1">
|
||||
<item row="4" column="1">
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Iteration</string>
|
||||
@@ -714,21 +742,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Point to plane</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Normal K neighbors</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="8" column="1">
|
||||
<widget class="QLabel" name="label_27">
|
||||
<property name="text">
|
||||
<string>2D icp (laser scans required)</string>
|
||||
@@ -799,7 +827,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_icp_iteration">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
@@ -812,7 +840,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_icp_normalKSearch">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
@@ -825,7 +853,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_icp_p2plane">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -835,7 +863,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="8" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_icp_2d">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -845,6 +873,32 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_46">
|
||||
<property name="text">
|
||||
<string>Min correspondence ratio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_icp_minCorrespondenceRatio">
|
||||
<property name="suffix">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
||||
@@ -195,13 +195,6 @@
|
||||
</property>
|
||||
<addaction name="separator"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuFigures">
|
||||
<property name="title">
|
||||
<string>Figures</string>
|
||||
</property>
|
||||
<addaction name="actionSave_state"/>
|
||||
<addaction name="actionLoad_state"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuAspect_ratio_2">
|
||||
<property name="title">
|
||||
<string>Aspect ratio</string>
|
||||
@@ -217,7 +210,6 @@
|
||||
<addaction name="action240p"/>
|
||||
</widget>
|
||||
<addaction name="menuShow_view"/>
|
||||
<addaction name="menuFigures"/>
|
||||
<addaction name="actionScreenshot"/>
|
||||
<addaction name="actionAuto_screen_capture"/>
|
||||
<addaction name="menuAspect_ratio_2"/>
|
||||
@@ -878,16 +870,6 @@
|
||||
<string>Clear the cache</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_state">
|
||||
<property name="text">
|
||||
<string>Save state</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoad_state">
|
||||
<property name="text">
|
||||
<string>Load state</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAuto_screen_capture">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>760</width>
|
||||
<height>1029</height>
|
||||
<height>1542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
@@ -86,7 +86,7 @@
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>21</number>
|
||||
<number>19</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_22">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_29">
|
||||
@@ -4972,7 +4972,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QDoubleSpinBox" name="rgdb_newMapOdomChange">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
@@ -4991,7 +4991,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_163">
|
||||
<property name="text">
|
||||
<string>Odometry change detected that triggers a new map (0 means whatever the odometry change, the detector will still link the new pose in the current map). Also by default, when an odometry with Identity transformation is detected, a new map is automatically created. </string>
|
||||
@@ -5001,14 +5001,14 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="odomScanHistory">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_scanMatching">
|
||||
<property name="text">
|
||||
<string>Pose scan matching: odometry pose correction using laser scan matching. ICP 2D only is used here.</string>
|
||||
@@ -5018,7 +5018,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="label_scanMatching_3">
|
||||
<property name="text">
|
||||
<string>Maximum local locations retrieved (0=disabled) near the current pose in the local map or on the current planned path (those on the planned path have priority).</string>
|
||||
@@ -5028,10 +5028,10 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_maxLocalLocationsRetrieved"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QDoubleSpinBox" name="localDetection_radius">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
@@ -5041,7 +5041,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="label_space2">
|
||||
<property name="text">
|
||||
<string>Local radius for nodes selection in the local map. This parameter is used in some approaches below.</string>
|
||||
@@ -5051,6 +5051,23 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="rgdb_rehearsalWeightIgnoredWhileMoving">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_165">
|
||||
<property name="text">
|
||||
<string>Ignore weight update when the robot is moving (over linear and angular update values above).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -5207,7 +5224,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_localDetection_space">
|
||||
<property name="title">
|
||||
<string>Local loop closure detection in space (laser scans are required)</string>
|
||||
<string>Local loop closure detection in space</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
@@ -5216,7 +5233,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
<item>
|
||||
<widget class="QLabel" name="label_space1_2">
|
||||
<property name="text">
|
||||
<string>Activate local detection over locations (in Working Memory) near in space. The Bayes filter is not used here, so it may results in more false detections. ICP 2D only is used here. Only nodes in the local radius are used. The laser scans are compared to those inside a radius around the current estimated position of the robot. If the laser scans match, a constraint is added to the graph. Useful when the robot is visiting backward (camera not in the same direction) already visited locations.</string>
|
||||
<string>Activate local detection over locations (in Working Memory) near in space. The locations are compared to those inside the local radius of the current estimated position of the robot (at a maximum distance of the path filtering radius below). If the laser scans are used, local locations are merged together and the current laser scan is compared to them. It is useful when the robot is visiting backward (camera not in the same direction) already visited locations.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -5254,7 +5271,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_space3_2">
|
||||
<property name="text">
|
||||
<string>Maximum ID difference between the current/last loop closure location and the local loop closure hypotheses. Set 0 to ignore.</string>
|
||||
<string>Maximum graph depth between the current/last loop closure location and the local loop closure hypotheses. Set 0 to ignore.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -5281,7 +5298,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_space3_3">
|
||||
<property name="text">
|
||||
<string>Path filtering radius to avoid merging laser scans which are close.</string>
|
||||
<string>Path filtering radius to avoid merging laser scans which are close. 0 to ignore.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -5291,7 +5308,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_scanMatching_4">
|
||||
<property name="text">
|
||||
<string>When comparing to a local path, merge the scan using the odometry poses instead of the ones in the optimized local graph.</string>
|
||||
<string>When comparing to a local path, merge the laser scans using the odometry poses instead of the ones in the optimized local graph.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
||||
Reference in New Issue
Block a user