mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-01 17:10:26 +08:00
Integration of the path planner into rtabmap's memory management to actually retrieve nodes on the planned path on the graph.
Added Rtabmap::clearPath(), Rtabmap::computePath(), Rtabmap::getPathGoalId() and Rtabmap::updateGoalIndex() methods. Added virtual links when path retrieval is activated (virtual links are not saved to database and removed when the path goal is reached). New parameters: RGBD/GoalReachedRadius and RGBD/MaxAnticipatedNodes Refactored how loop closure hypotheses are selected (fixed ratio between consecutive hypotheses, not the last loop closure). Updated getNodesInRadius() to use all filtered scans. GUI: window can be saved/loaded maximized GUI: saving Graph View parameters to config.ini
This commit is contained in:
@@ -102,6 +102,7 @@ public:
|
||||
|
||||
QString getWorkingDirectory() const;
|
||||
void setMonitoringState(bool pauseChecked = false); // in monitoring state, only some actions are enabled
|
||||
bool isSavedMaximized() const {return _savedMaximized;}
|
||||
|
||||
public slots:
|
||||
void processStats(const rtabmap::Statistics & stat);
|
||||
@@ -266,6 +267,7 @@ private:
|
||||
bool _emptyNewDatabase;
|
||||
bool _odomImageShow;
|
||||
bool _odomImageDepthShow;
|
||||
bool _savedMaximized;
|
||||
|
||||
QMap<int, Signature> _cachedSignatures;
|
||||
std::map<int, Transform> _currentPosesMap; // <nodeId, pose>
|
||||
|
||||
@@ -100,7 +100,8 @@ public:
|
||||
void saveWindowGeometry(const QWidget * window);
|
||||
void loadWindowGeometry(QWidget * window);
|
||||
void saveMainWindowState(const QMainWindow * mainWindow);
|
||||
void loadMainWindowState(QMainWindow * mainWindow);
|
||||
void loadMainWindowState(QMainWindow * mainWindow, bool & maximized);
|
||||
|
||||
void saveWidgetState(const QWidget * widget);
|
||||
void loadWidgetState(QWidget * widget);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ SET(headers_ui
|
||||
./PostProcessingDialog.h
|
||||
./ExportCloudsDialog.h
|
||||
./MapVisibilityWidget.h
|
||||
./GraphViewer.h
|
||||
)
|
||||
|
||||
SET(uis
|
||||
|
||||
@@ -101,13 +101,13 @@ class LinkItem: public QGraphicsLineItem
|
||||
{
|
||||
public:
|
||||
// in meter
|
||||
LinkItem(int from, int to, const Transform & poseA, const Transform & poseB, bool loopClosure) :
|
||||
LinkItem(int from, int to, const Transform & poseA, const Transform & poseB, Link::Type type) :
|
||||
QGraphicsLineItem(-poseA.y(), -poseA.x(), -poseB.y(), -poseB.x()),
|
||||
_from(from),
|
||||
_to(to),
|
||||
_poseA(poseA),
|
||||
_poseB(poseB),
|
||||
_loopClosure(loopClosure)
|
||||
_type(type)
|
||||
{
|
||||
this->setAcceptHoverEvents(true);
|
||||
}
|
||||
@@ -126,7 +126,7 @@ public:
|
||||
_poseB = poseB;
|
||||
}
|
||||
|
||||
bool isLoopClosure() const {return _loopClosure;}
|
||||
Link::Type linkType() const {return _type;}
|
||||
int from() const {return _from;}
|
||||
int to() const {return _to;}
|
||||
|
||||
@@ -146,7 +146,7 @@ private:
|
||||
int _to;
|
||||
Transform _poseA;
|
||||
Transform _poseB;
|
||||
bool _loopClosure;
|
||||
Link::Type _type;
|
||||
};
|
||||
|
||||
GraphViewer::GraphViewer(QWidget * parent) :
|
||||
@@ -154,6 +154,9 @@ GraphViewer::GraphViewer(QWidget * parent) :
|
||||
_nodeColor(Qt::blue),
|
||||
_neighborColor(Qt::blue),
|
||||
_loopClosureColor(Qt::red),
|
||||
_loopClosureLocalColor(Qt::yellow),
|
||||
_loopClosureUserColor(Qt::red),
|
||||
_loopClosureVirtualColor(Qt::magenta),
|
||||
_root(0),
|
||||
_nodeRadius(0.01),
|
||||
_linkWidth(0),
|
||||
@@ -192,6 +195,8 @@ GraphViewer::GraphViewer(QWidget * parent) :
|
||||
_gridMap = this->scene()->addPixmap(QPixmap());
|
||||
_gridMap->setZValue(0);
|
||||
_gridMap->setParentItem(_root);
|
||||
|
||||
this->restoreDefaults();
|
||||
}
|
||||
|
||||
GraphViewer::~GraphViewer()
|
||||
@@ -286,11 +291,30 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
|
||||
if(!added)
|
||||
{
|
||||
//create a link item
|
||||
LinkItem * item = new LinkItem(iter->first, iter->second.to(), poseA, poseB, loopClosure);
|
||||
LinkItem * item = new LinkItem(iter->first, iter->second.to(), poseA, poseB, iter->second.type());
|
||||
QPen p = item->pen();
|
||||
p.setWidthF(_linkWidth);
|
||||
item->setPen(p);
|
||||
item->setColor(loopClosure?_loopClosureColor:_neighborColor);
|
||||
if(iter->second.type() == Link::kNeighbor)
|
||||
{
|
||||
item->setColor(_neighborColor);
|
||||
}
|
||||
else if(iter->second.type() == Link::kVirtualClosure)
|
||||
{
|
||||
item->setColor(_loopClosureVirtualColor);
|
||||
}
|
||||
else if(iter->second.type() == Link::kUserClosure)
|
||||
{
|
||||
item->setColor(_loopClosureUserColor);
|
||||
}
|
||||
else if(iter->second.type() == Link::kLocalSpaceClosure || iter->second.type() == Link::kLocalTimeClosure)
|
||||
{
|
||||
item->setColor(_loopClosureLocalColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
item->setColor(_loopClosureColor);
|
||||
}
|
||||
this->scene()->addItem(item);
|
||||
item->setZValue(1);
|
||||
item->setParentItem(_root);
|
||||
@@ -438,6 +462,144 @@ void GraphViewer::clearAll()
|
||||
clearGraph();
|
||||
}
|
||||
|
||||
bool GraphViewer::isGridMapVisible() const
|
||||
{
|
||||
return _gridMap->isVisible();
|
||||
}
|
||||
|
||||
void GraphViewer::setWorkingDirectory(const QString & path)
|
||||
{
|
||||
_workingDirectory = path;
|
||||
}
|
||||
void GraphViewer::setNodeRadius(float radius)
|
||||
{
|
||||
_nodeRadius = radius;
|
||||
QList<QGraphicsItem*> items = this->scene()->items();
|
||||
for(int i=0; i<items.size(); ++i)
|
||||
{
|
||||
NodeItem * node = qgraphicsitem_cast<NodeItem *>(items[i]);
|
||||
if(node)
|
||||
{
|
||||
node->setRect(-_nodeRadius, -_nodeRadius, _nodeRadius*2.0f, _nodeRadius*2.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
void GraphViewer::setLinkWidth(float width)
|
||||
{
|
||||
_linkWidth = width;
|
||||
QList<QGraphicsItem*> items = this->scene()->items();
|
||||
for(int i=0; i<items.size(); ++i)
|
||||
{
|
||||
QGraphicsLineItem * line = qgraphicsitem_cast<QGraphicsLineItem *>(items[i]);
|
||||
if(line)
|
||||
{
|
||||
QPen pen = line->pen();
|
||||
pen.setWidthF(_linkWidth);
|
||||
line->setPen(pen);
|
||||
}
|
||||
}
|
||||
}
|
||||
void GraphViewer::setNodeColor(const QColor & color)
|
||||
{
|
||||
_nodeColor = color;
|
||||
QList<QGraphicsItem*> items = this->scene()->items();
|
||||
for(int i=0; i<items.size(); ++i)
|
||||
{
|
||||
NodeItem * node = qgraphicsitem_cast<NodeItem *>(items[i]);
|
||||
if(node)
|
||||
{
|
||||
node->setColor(_nodeColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
void GraphViewer::setNeighborColor(const QColor & color)
|
||||
{
|
||||
_neighborColor = color;
|
||||
QList<QGraphicsItem*> items = this->scene()->items();
|
||||
for(int i=0; i<items.size(); ++i)
|
||||
{
|
||||
LinkItem * link = qgraphicsitem_cast<LinkItem *>(items[i]);
|
||||
if(link && link->linkType() == Link::kNeighbor)
|
||||
{
|
||||
link->setColor(_neighborColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
void GraphViewer::setGlobalLoopClosureColor(const QColor & color)
|
||||
{
|
||||
_loopClosureColor = color;
|
||||
QList<QGraphicsItem*> items = this->scene()->items();
|
||||
for(int i=0; i<items.size(); ++i)
|
||||
{
|
||||
LinkItem * link = qgraphicsitem_cast<LinkItem *>(items[i]);
|
||||
if(link && (link->linkType() != Link::kNeighbor &&
|
||||
link->linkType() != Link::kLocalSpaceClosure &&
|
||||
link->linkType() != Link::kLocalTimeClosure &&
|
||||
link->linkType() != Link::kUserClosure &&
|
||||
link->linkType() != Link::kVirtualClosure))
|
||||
{
|
||||
link->setColor(_loopClosureColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
void GraphViewer::setLocalLoopClosureColor(const QColor & color)
|
||||
{
|
||||
_loopClosureLocalColor = color;
|
||||
QList<QGraphicsItem*> items = this->scene()->items();
|
||||
for(int i=0; i<items.size(); ++i)
|
||||
{
|
||||
LinkItem * link = qgraphicsitem_cast<LinkItem *>(items[i]);
|
||||
if(link && (link->linkType() == Link::kLocalSpaceClosure || link->linkType() == Link::kLocalSpaceClosure))
|
||||
{
|
||||
link->setColor(_loopClosureLocalColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
void GraphViewer::setUserLoopClosureColor(const QColor & color)
|
||||
{
|
||||
_loopClosureUserColor = color;
|
||||
QList<QGraphicsItem*> items = this->scene()->items();
|
||||
for(int i=0; i<items.size(); ++i)
|
||||
{
|
||||
LinkItem * link = qgraphicsitem_cast<LinkItem *>(items[i]);
|
||||
if(link && link->linkType() == Link::kUserClosure)
|
||||
{
|
||||
link->setColor(_loopClosureUserColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
void GraphViewer::setVirtualLoopClosureColor(const QColor & color)
|
||||
{
|
||||
_loopClosureVirtualColor = color;
|
||||
QList<QGraphicsItem*> items = this->scene()->items();
|
||||
for(int i=0; i<items.size(); ++i)
|
||||
{
|
||||
LinkItem * link = qgraphicsitem_cast<LinkItem *>(items[i]);
|
||||
if(link && link->linkType() == Link::kVirtualClosure)
|
||||
{
|
||||
link->setColor(_loopClosureVirtualColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
void GraphViewer::setGridMapVisible(bool visible)
|
||||
{
|
||||
_gridMap->setVisible(visible);
|
||||
}
|
||||
|
||||
void GraphViewer::restoreDefaults()
|
||||
{
|
||||
setNodeRadius(0.01f);
|
||||
setLinkWidth(0.0f);
|
||||
setNodeColor(Qt::blue);
|
||||
setNeighborColor(Qt::blue);
|
||||
setGlobalLoopClosureColor(Qt::red);
|
||||
setLocalLoopClosureColor(Qt::yellow);
|
||||
setUserLoopClosureColor(Qt::red);
|
||||
setVirtualLoopClosureColor(Qt::magenta);
|
||||
setGridMapVisible(true);
|
||||
}
|
||||
|
||||
|
||||
void GraphViewer::wheelEvent ( QWheelEvent * event )
|
||||
{
|
||||
if(event->delta() > 0)
|
||||
@@ -450,15 +612,41 @@ void GraphViewer::wheelEvent ( QWheelEvent * event )
|
||||
}
|
||||
}
|
||||
|
||||
QIcon createIcon(const QColor & color)
|
||||
{
|
||||
QPixmap pixmap(50, 50);
|
||||
pixmap.fill(color);
|
||||
return QIcon(pixmap);
|
||||
}
|
||||
|
||||
void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
{
|
||||
QMenu menu;
|
||||
QAction * aScreenShotPNG = menu.addAction(tr("Take a screenshot (PNG)"));
|
||||
QAction * aScreenShotSVG = menu.addAction(tr("Take a screenshot (SVG)"));
|
||||
menu.addSeparator();
|
||||
QAction * aChangeNodeColor = menu.addAction(tr("Set node color..."));
|
||||
QAction * aChangeNeighborColor = menu.addAction(tr("Set neighbor link color..."));
|
||||
QAction * aChangeLoopColor = menu.addAction(tr("Set loop closure link color..."));
|
||||
|
||||
QAction * aChangeNodeColor = menu.addAction(createIcon(_nodeColor), tr("Set node color..."));
|
||||
aChangeNodeColor->setIconVisibleInMenu(true);
|
||||
|
||||
// Links
|
||||
QMenu * menuLink = menu.addMenu(tr("Set link color..."));
|
||||
QAction * aChangeNeighborColor = menuLink->addAction(tr("Neighbor"));
|
||||
QAction * aChangeGlobalLoopColor = menuLink->addAction(tr("Global loop closure"));
|
||||
QAction * aChangeLocalLoopColor = menuLink->addAction(tr("Local loop closure"));
|
||||
QAction * aChangeUserLoopColor = menuLink->addAction(tr("User loop closure"));
|
||||
QAction * aChangeVirtualLoopColor = menuLink->addAction(tr("Virtual loop closure"));
|
||||
aChangeNeighborColor->setIcon(createIcon(_neighborColor));
|
||||
aChangeGlobalLoopColor->setIcon(createIcon(_loopClosureColor));
|
||||
aChangeLocalLoopColor->setIcon(createIcon(_loopClosureLocalColor));
|
||||
aChangeUserLoopColor->setIcon(createIcon(_loopClosureUserColor));
|
||||
aChangeVirtualLoopColor->setIcon(createIcon(_loopClosureVirtualColor));
|
||||
aChangeNeighborColor->setIconVisibleInMenu(true);
|
||||
aChangeGlobalLoopColor->setIconVisibleInMenu(true);
|
||||
aChangeLocalLoopColor->setIconVisibleInMenu(true);
|
||||
aChangeUserLoopColor->setIconVisibleInMenu(true);
|
||||
aChangeVirtualLoopColor->setIconVisibleInMenu(true);
|
||||
|
||||
menu.addSeparator();
|
||||
QAction * aSetNodeSize = menu.addAction(tr("Set node radius..."));
|
||||
QAction * aSetLinkSize = menu.addAction(tr("Set link width..."));
|
||||
@@ -472,6 +660,8 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
{
|
||||
aShowHideGridMap = menu.addAction(tr("Show grid map"));
|
||||
}
|
||||
menu.addSeparator();
|
||||
QAction * aRestoreDefaults = menu.addAction(tr("Restore defaults"));
|
||||
|
||||
QAction * r = menu.exec(event->globalPos());
|
||||
if(r == aScreenShotPNG || r == aScreenShotSVG)
|
||||
@@ -535,56 +725,72 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(targetDir + name));
|
||||
}
|
||||
return; // without emitting configChanged
|
||||
}
|
||||
else if(r == aChangeNodeColor ||
|
||||
r == aChangeNeighborColor ||
|
||||
r == aChangeLoopColor)
|
||||
r == aChangeGlobalLoopColor ||
|
||||
r == aChangeLocalLoopColor ||
|
||||
r == aChangeUserLoopColor ||
|
||||
r == aChangeVirtualLoopColor)
|
||||
{
|
||||
QColor color;
|
||||
if(r == aChangeNodeColor)
|
||||
{
|
||||
color = _nodeColor;
|
||||
}
|
||||
else if(r == aChangeNeighborColor)
|
||||
{
|
||||
color = _neighborColor;
|
||||
}
|
||||
else if(r == aChangeLoopColor)
|
||||
else if(r == aChangeGlobalLoopColor)
|
||||
{
|
||||
color = _loopClosureColor;
|
||||
}
|
||||
else if(r == aChangeLocalLoopColor)
|
||||
{
|
||||
color = _loopClosureLocalColor;
|
||||
}
|
||||
else if(r == aChangeUserLoopColor)
|
||||
{
|
||||
color = _loopClosureUserColor;
|
||||
}
|
||||
else if(r == aChangeVirtualLoopColor)
|
||||
{
|
||||
color = _loopClosureVirtualColor;
|
||||
}
|
||||
else //if(r == aChangeNeighborColor)
|
||||
{
|
||||
color = _neighborColor;
|
||||
}
|
||||
color = QColorDialog::getColor(color, this);
|
||||
if(color.isValid())
|
||||
{
|
||||
|
||||
if(r == aChangeNodeColor)
|
||||
{
|
||||
_nodeColor = color;
|
||||
}
|
||||
else if(r == aChangeNeighborColor)
|
||||
{
|
||||
_neighborColor = color;
|
||||
}
|
||||
else if(r == aChangeLoopColor)
|
||||
{
|
||||
_loopClosureColor = color;
|
||||
}
|
||||
|
||||
QList<QGraphicsItem*> items = this->scene()->items();
|
||||
for(int i=0; i<items.size(); ++i)
|
||||
{
|
||||
LinkItem * link = qgraphicsitem_cast<LinkItem *>(items[i]);
|
||||
NodeItem * node = qgraphicsitem_cast<NodeItem *>(items[i]);
|
||||
if(r == aChangeNodeColor && node)
|
||||
if(r == aChangeNodeColor)
|
||||
{
|
||||
node->setColor(color);
|
||||
this->setNodeColor(color);
|
||||
}
|
||||
else if(r == aChangeNeighborColor && link && !link->isLoopClosure())
|
||||
else if(r == aChangeGlobalLoopColor)
|
||||
{
|
||||
link->setColor(color);
|
||||
this->setGlobalLoopClosureColor(color);
|
||||
}
|
||||
else if(r == aChangeLoopColor && link && link->isLoopClosure())
|
||||
else if(r == aChangeLocalLoopColor)
|
||||
{
|
||||
link->setColor(color);
|
||||
this->setLocalLoopClosureColor(color);
|
||||
}
|
||||
else if(r == aChangeUserLoopColor)
|
||||
{
|
||||
this->setUserLoopClosureColor(color);
|
||||
}
|
||||
else if(r == aChangeVirtualLoopColor)
|
||||
{
|
||||
this->setVirtualLoopClosureColor(color);
|
||||
}
|
||||
else //if(r == aChangeNeighborColor)
|
||||
{
|
||||
this->setNeighborColor(color);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return; // without emitting configChanged
|
||||
}
|
||||
}
|
||||
else if(r == aSetNodeSize)
|
||||
@@ -593,16 +799,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
double value = QInputDialog::getDouble(this, tr("Node radius"), tr("Radius (m)"), _nodeRadius, 0.01, 100, 2, &ok);
|
||||
if(ok)
|
||||
{
|
||||
_nodeRadius = value;
|
||||
QList<QGraphicsItem*> items = this->scene()->items();
|
||||
for(int i=0; i<items.size(); ++i)
|
||||
{
|
||||
NodeItem * node = qgraphicsitem_cast<NodeItem *>(items[i]);
|
||||
if(node)
|
||||
{
|
||||
node->setRect(-_nodeRadius, -_nodeRadius, _nodeRadius*2.0f, _nodeRadius*2.0f);
|
||||
}
|
||||
}
|
||||
setNodeRadius(value);
|
||||
}
|
||||
}
|
||||
else if(r == aSetLinkSize)
|
||||
@@ -611,23 +808,20 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
double value = QInputDialog::getDouble(this, tr("Link width"), tr("Width (m)"), _linkWidth, 0, 100, 2, &ok);
|
||||
if(ok)
|
||||
{
|
||||
_linkWidth = value;
|
||||
QList<QGraphicsItem*> items = this->scene()->items();
|
||||
for(int i=0; i<items.size(); ++i)
|
||||
{
|
||||
QGraphicsLineItem * line = qgraphicsitem_cast<QGraphicsLineItem *>(items[i]);
|
||||
if(line)
|
||||
{
|
||||
QPen pen = line->pen();
|
||||
pen.setWidthF(_linkWidth);
|
||||
line->setPen(pen);
|
||||
}
|
||||
}
|
||||
setLinkWidth(value);
|
||||
}
|
||||
}
|
||||
else if(r == aShowHideGridMap)
|
||||
{
|
||||
_gridMap->setVisible(!_gridMap->isVisible());
|
||||
this->setGridMapVisible(!this->isGridMapVisible());
|
||||
}
|
||||
else if(r == aRestoreDefaults)
|
||||
{
|
||||
this->restoreDefaults();
|
||||
}
|
||||
if(r)
|
||||
{
|
||||
emit configChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ class NodeItem;
|
||||
class LinkItem;
|
||||
|
||||
class GraphViewer : public QGraphicsView {
|
||||
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
GraphViewer(QWidget * parent = 0);
|
||||
virtual ~GraphViewer();
|
||||
@@ -57,7 +60,35 @@ public:
|
||||
void clearPosterior();
|
||||
void clearAll();
|
||||
|
||||
void setWorkingDirectory(const QString & path) {_workingDirectory = path;}
|
||||
//getters
|
||||
const QString & getWorkingDirectory() const {return _workingDirectory;}
|
||||
float getNodeRadius() const {return _nodeRadius;}
|
||||
float getLinkWidth() const {return _linkWidth;}
|
||||
const QColor & getNodeColor() const {return _nodeColor;}
|
||||
const QColor & getNeighborColor() const {return _neighborColor;}
|
||||
const QColor & getGlobalLoopClosureColor() const {return _loopClosureColor;}
|
||||
const QColor & getLocalLoopClosureColor() const {return _loopClosureLocalColor;}
|
||||
const QColor & getUserLoopClosureColor() const {return _loopClosureUserColor;}
|
||||
const QColor & getVirtualLoopClosureColor() const {return _loopClosureVirtualColor;}
|
||||
bool isGridMapVisible() const;
|
||||
|
||||
// setters
|
||||
void setWorkingDirectory(const QString & path);
|
||||
void setNodeRadius(float radius);
|
||||
void setLinkWidth(float width);
|
||||
void setNodeColor(const QColor & color);
|
||||
void setNeighborColor(const QColor & color);
|
||||
void setGlobalLoopClosureColor(const QColor & color);
|
||||
void setLocalLoopClosureColor(const QColor & color);
|
||||
void setUserLoopClosureColor(const QColor & color);
|
||||
void setVirtualLoopClosureColor(const QColor & color);
|
||||
void setGridMapVisible(bool visible);
|
||||
|
||||
signals:
|
||||
void configChanged();
|
||||
|
||||
public slots:
|
||||
void restoreDefaults();
|
||||
|
||||
protected:
|
||||
virtual void wheelEvent ( QWheelEvent * event );
|
||||
@@ -68,6 +99,9 @@ private:
|
||||
QColor _nodeColor;
|
||||
QColor _neighborColor;
|
||||
QColor _loopClosureColor;
|
||||
QColor _loopClosureLocalColor;
|
||||
QColor _loopClosureUserColor;
|
||||
QColor _loopClosureVirtualColor;
|
||||
QGraphicsItem * _root;
|
||||
QMap<int, NodeItem*> _nodeItems;
|
||||
QMultiMap<int, LinkItem*> _neighborLinkItems;
|
||||
|
||||
@@ -188,7 +188,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
_preferencesDialog->init();
|
||||
|
||||
// Restore window geometry
|
||||
_preferencesDialog->loadMainWindowState(this);
|
||||
_preferencesDialog->loadMainWindowState(this, _savedMaximized);
|
||||
_preferencesDialog->loadWindowGeometry(_preferencesDialog);
|
||||
_preferencesDialog->loadWindowGeometry(_exportDialog);
|
||||
_preferencesDialog->loadWindowGeometry(_postProcessingDialog);
|
||||
@@ -212,6 +212,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
_preferencesDialog->loadWidgetState(_ui->imageView_source);
|
||||
_preferencesDialog->loadWidgetState(_ui->imageView_loopClosure);
|
||||
_preferencesDialog->loadWidgetState(_ui->imageView_odometry);
|
||||
_preferencesDialog->loadWidgetState(_ui->graphicsView_graphView);
|
||||
|
||||
_posteriorCurve = new PdfPlotCurve("Posterior", &_cachedSignatures, this);
|
||||
_ui->posteriorPlot->addCurve(_posteriorCurve, false);
|
||||
@@ -366,6 +367,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent) :
|
||||
connect(_ui->imageView_source, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
|
||||
connect(_ui->imageView_loopClosure, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
|
||||
connect(_ui->imageView_odometry, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
|
||||
connect(_ui->graphicsView_graphView, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
|
||||
connect(_ui->widget_cloudViewer, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
|
||||
connect(_exportDialog, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
|
||||
connect(_postProcessingDialog, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
|
||||
@@ -1369,7 +1371,7 @@ void MainWindow::updateMapCloud(
|
||||
QColor color = Qt::gray;
|
||||
if(iter->first >= 0)
|
||||
{
|
||||
color = (Qt::GlobalColor)(iter->first % 12 + 7 );
|
||||
color = (Qt::GlobalColor)((iter->first+2) % 12 + 7 );
|
||||
}
|
||||
_ui->widget_cloudViewer->addOrUpdateGraph(uFormat("graph_%d", iter->first), iter->second, color);
|
||||
}
|
||||
@@ -2212,6 +2214,7 @@ void MainWindow::configGUIModified()
|
||||
//ACTIONS
|
||||
void MainWindow::saveConfigGUI()
|
||||
{
|
||||
_savedMaximized = this->isMaximized();
|
||||
_preferencesDialog->saveMainWindowState(this);
|
||||
_preferencesDialog->saveWindowGeometry(_preferencesDialog);
|
||||
_preferencesDialog->saveWindowGeometry(_aboutDialog);
|
||||
@@ -2221,6 +2224,7 @@ void MainWindow::saveConfigGUI()
|
||||
_preferencesDialog->saveWidgetState(_ui->imageView_odometry);
|
||||
_preferencesDialog->saveWidgetState(_exportDialog);
|
||||
_preferencesDialog->saveWidgetState(_postProcessingDialog);
|
||||
_preferencesDialog->saveWidgetState(_ui->graphicsView_graphView);
|
||||
this->setWindowModified(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "rtabmap/gui/DataRecorder.h"
|
||||
#include "rtabmap/gui/CloudViewer.h"
|
||||
#include "rtabmap/gui/ImageView.h"
|
||||
#include "GraphViewer.h"
|
||||
#include "ExportCloudsDialog.h"
|
||||
#include "PostProcessingDialog.h"
|
||||
|
||||
@@ -448,6 +449,9 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->globalDetection_toroIgnoreVariance->setObjectName(Parameters::kRGBDToroIgnoreVariance().c_str());
|
||||
_ui->globalDetection_optimizeFromGraphEnd->setObjectName(Parameters::kRGBDOptimizeFromGraphEnd().c_str());
|
||||
|
||||
_ui->graphPlan_goalReachedRadius->setObjectName(Parameters::kRGBDGoalReachedRadius().c_str());
|
||||
_ui->graphPlan_maxAnticipatedNodes->setObjectName(Parameters::kRGBDMaxAnticipatedNodes().c_str());
|
||||
|
||||
_ui->groupBox_localDetection_time->setObjectName(Parameters::kRGBDLocalLoopDetectionTime().c_str());
|
||||
_ui->groupBox_localDetection_space->setObjectName(Parameters::kRGBDLocalLoopDetectionSpace().c_str());
|
||||
_ui->localDetection_radius->setObjectName(Parameters::kRGBDLocalLoopDetectionRadius().c_str());
|
||||
@@ -1629,17 +1633,14 @@ void PreferencesDialog::readSettingsEnd()
|
||||
|
||||
void PreferencesDialog::saveWindowGeometry(const QWidget * window)
|
||||
{
|
||||
if(!window->objectName().isNull())
|
||||
if(!window->objectName().isNull() && !window->isMaximized())
|
||||
{
|
||||
if(!window->isMaximized())
|
||||
{
|
||||
QSettings settings(getIniFilePath(), QSettings::IniFormat);
|
||||
settings.beginGroup("Gui");
|
||||
settings.beginGroup(window->objectName());
|
||||
settings.setValue("geometry", window->saveGeometry());
|
||||
settings.endGroup(); // "windowName"
|
||||
settings.endGroup(); // rtabmap
|
||||
}
|
||||
QSettings settings(getIniFilePath(), QSettings::IniFormat);
|
||||
settings.beginGroup("Gui");
|
||||
settings.beginGroup(window->objectName());
|
||||
settings.setValue("geometry", window->saveGeometry());
|
||||
settings.endGroup(); // "windowName"
|
||||
settings.endGroup(); // rtabmap
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1671,12 +1672,13 @@ void PreferencesDialog::saveMainWindowState(const QMainWindow * mainWindow)
|
||||
settings.beginGroup("Gui");
|
||||
settings.beginGroup(mainWindow->objectName());
|
||||
settings.setValue("state", mainWindow->saveState());
|
||||
settings.setValue("maximized", mainWindow->isMaximized());
|
||||
settings.endGroup(); // "MainWindow"
|
||||
settings.endGroup(); // rtabmap
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::loadMainWindowState(QMainWindow * mainWindow)
|
||||
void PreferencesDialog::loadMainWindowState(QMainWindow * mainWindow, bool & maximized)
|
||||
{
|
||||
if(!mainWindow->objectName().isNull())
|
||||
{
|
||||
@@ -1691,6 +1693,7 @@ void PreferencesDialog::loadMainWindowState(QMainWindow * mainWindow)
|
||||
{
|
||||
mainWindow->restoreState(bytes);
|
||||
}
|
||||
maximized = settings.value("maximized", false).toBool();
|
||||
settings.endGroup(); // "MainWindow"
|
||||
settings.endGroup(); // rtabmap
|
||||
}
|
||||
@@ -1708,6 +1711,7 @@ void PreferencesDialog::saveWidgetState(const QWidget * widget)
|
||||
const ImageView * imageView = qobject_cast<const ImageView*>(widget);
|
||||
const ExportCloudsDialog * exportCloudsDialog = qobject_cast<const ExportCloudsDialog*>(widget);
|
||||
const PostProcessingDialog * postProcessingDialog = qobject_cast<const PostProcessingDialog *>(widget);
|
||||
const GraphViewer * graphViewer = qobject_cast<const GraphViewer *>(widget);
|
||||
|
||||
if(cloudViewer)
|
||||
{
|
||||
@@ -1781,6 +1785,18 @@ void PreferencesDialog::saveWidgetState(const QWidget * widget)
|
||||
settings.setValue("refine_neigbors", postProcessingDialog->isRefineNeighborLinks());
|
||||
settings.setValue("refine_lc", postProcessingDialog->isRefineLoopClosureLinks());
|
||||
}
|
||||
else if(graphViewer)
|
||||
{
|
||||
settings.setValue("node_radius", graphViewer->getNodeRadius());
|
||||
settings.setValue("link_width", graphViewer->getLinkWidth());
|
||||
settings.setValue("node_color", graphViewer->getNodeColor());
|
||||
settings.setValue("neighbor_color", graphViewer->getNeighborColor());
|
||||
settings.setValue("global_color", graphViewer->getGlobalLoopClosureColor());
|
||||
settings.setValue("local_color", graphViewer->getLocalLoopClosureColor());
|
||||
settings.setValue("user_color", graphViewer->getUserLoopClosureColor());
|
||||
settings.setValue("virtual_color", graphViewer->getVirtualLoopClosureColor());
|
||||
settings.setValue("grid_visible", graphViewer->isGridMapVisible());
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Widget \"%s\" cannot be exported in config file.", widget->objectName().toStdString().c_str());
|
||||
@@ -1804,6 +1820,7 @@ void PreferencesDialog::loadWidgetState(QWidget * widget)
|
||||
ImageView * imageView = qobject_cast<ImageView*>(widget);
|
||||
ExportCloudsDialog * exportCloudsDialog = qobject_cast<ExportCloudsDialog*>(widget);
|
||||
PostProcessingDialog * postProcessingDialog = qobject_cast<PostProcessingDialog *>(widget);
|
||||
GraphViewer * graphViewer = qobject_cast<GraphViewer *>(widget);
|
||||
|
||||
if(cloudViewer)
|
||||
{
|
||||
@@ -1865,6 +1882,18 @@ void PreferencesDialog::loadWidgetState(QWidget * widget)
|
||||
postProcessingDialog->setRefineNeighborLinks(settings.value("refine_neigbors", postProcessingDialog->isRefineNeighborLinks()).toBool());
|
||||
postProcessingDialog->setRefineLoopClosureLinks(settings.value("refine_lc", postProcessingDialog->isRefineLoopClosureLinks()).toBool());
|
||||
}
|
||||
else if(graphViewer)
|
||||
{
|
||||
graphViewer->setNodeRadius(settings.value("node_radius", graphViewer->getNodeRadius()).toDouble());
|
||||
graphViewer->setLinkWidth(settings.value("link_width", graphViewer->getLinkWidth()).toDouble());
|
||||
graphViewer->setNodeColor(settings.value("node_color", graphViewer->getNodeColor()).value<QColor>());
|
||||
graphViewer->setNeighborColor(settings.value("neighbor_color", graphViewer->getNeighborColor()).value<QColor>());
|
||||
graphViewer->setGlobalLoopClosureColor(settings.value("global_color", graphViewer->getGlobalLoopClosureColor()).value<QColor>());
|
||||
graphViewer->setLocalLoopClosureColor(settings.value("local_color", graphViewer->getLocalLoopClosureColor()).value<QColor>());
|
||||
graphViewer->setUserLoopClosureColor(settings.value("user_color", graphViewer->getUserLoopClosureColor()).value<QColor>());
|
||||
graphViewer->setVirtualLoopClosureColor(settings.value("virtual_color", graphViewer->getVirtualLoopClosureColor()).value<QColor>());
|
||||
graphViewer->setGridMapVisible(settings.value("grid_visible", graphViewer->isGridMapVisible()).toBool());
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Widget \"%s\" cannot be loaded from config file.", widget->objectName().toStdString().c_str());
|
||||
|
||||
@@ -63,9 +63,9 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<y>-693</y>
|
||||
<width>744</width>
|
||||
<height>1056</height>
|
||||
<height>1378</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
@@ -86,7 +86,7 @@
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>19</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_22">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_29">
|
||||
@@ -4900,7 +4900,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
<property name="title">
|
||||
<string>Map update</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_20">
|
||||
<layout class="QGridLayout" name="gridLayout_47" columnstretch="0,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QDoubleSpinBox" name="rgdb_linearUpdate">
|
||||
<property name="suffix">
|
||||
@@ -4950,16 +4950,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" 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>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QDoubleSpinBox" name="rgdb_newMapOdomChange">
|
||||
<property name="suffix">
|
||||
@@ -4979,10 +4969,10 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_scanMatching">
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_163">
|
||||
<property name="text">
|
||||
<string>Laser scan matching for odometry pose correction. ICP 2D only is used here.</string>
|
||||
<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>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -4996,6 +4986,16 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_scanMatching">
|
||||
<property name="text">
|
||||
<string>Laser scan matching for odometry pose correction. ICP 2D only is used here.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -5054,10 +5054,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_5">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_48" columnstretch="0,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QComboBox" name="globalDetection_icpType">
|
||||
<property name="sizeAdjustPolicy">
|
||||
@@ -5126,7 +5123,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
<property name="title">
|
||||
<string>Graph optimization</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_19">
|
||||
<layout class="QGridLayout" name="gridLayout_49" columnstretch="0,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QSpinBox" name="globalDetection_toroIterations">
|
||||
<property name="minimum">
|
||||
@@ -5147,13 +5144,17 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_151">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="globalDetection_toroIgnoreVariance">
|
||||
<property name="text">
|
||||
<string>Optimize graph from the newest node.
|
||||
-If false, the graph is optimized from the oldest node of the current graph (this adds an overhead computation to detect to oldest mode of the current graph, but it can be useful to preserve the map referential from the oldest node). An odometry correction from frames /map to /odom is computed.
|
||||
-If true, there is no odometry correction computed since it is all previous poses in the map that are corrected, not the last one (which corresponds to latest odometry value).
|
||||
Warning when set to false: when some nodes are transferred, the first referential of the local map may change, resulting in momentary changes in robot/map position (which are annoying in teleoperation).</string>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_141">
|
||||
<property name="text">
|
||||
<string>Ignore constraints' variance. If checked, identity information matrix is used for each constraint in TORO. Otherwise, an information matrix is generated from the variance saved in the links.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -5167,17 +5168,13 @@ Warning when set to false: when some nodes are transferred, the first referentia
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="globalDetection_toroIgnoreVariance">
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_151">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_141">
|
||||
<property name="text">
|
||||
<string>Ignore constraints' variance. If checked, identity information matrix is used for each constraint in TORO. Otherwise, an information matrix is generated from the variance saved in the links.</string>
|
||||
<string>Optimize graph from the newest node.
|
||||
-If false, the graph is optimized from the oldest node of the current graph (this adds an overhead computation to detect to oldest mode of the current graph, but it can be useful to preserve the map referential from the oldest node). An odometry correction from frames /map to /odom is computed.
|
||||
-If true, there is no odometry correction computed since it is all previous poses in the map that are corrected, not the last one (which corresponds to latest odometry value).
|
||||
Warning when set to false: when some nodes are transferred, the first referential of the local map may change, resulting in momentary changes in robot/map position (which are annoying in teleoperation).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -5229,7 +5226,7 @@ Warning when set to false: when some nodes are transferred, the first referentia
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_13">
|
||||
<layout class="QGridLayout" name="gridLayout_50" columnstretch="0,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QDoubleSpinBox" name="localDetection_radius">
|
||||
<property name="suffix">
|
||||
@@ -5267,16 +5264,6 @@ Warning when set to false: when some nodes are transferred, the first referentia
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" 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>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QSpinBox" name="localDetection_maxDiffID">
|
||||
<property name="maximum">
|
||||
@@ -5287,11 +5274,70 @@ Warning when set to false: when some nodes are transferred, the first referentia
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" 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>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_12">
|
||||
<property name="title">
|
||||
<string>Graph planning</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_51" columnstretch="0,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QDoubleSpinBox" name="graphPlan_goalReachedRadius">
|
||||
<property name="suffix">
|
||||
<string> m</string>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_space2_2">
|
||||
<property name="text">
|
||||
<string>Goal reached radius.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QSpinBox" name="graphPlan_maxAnticipatedNodes">
|
||||
<property name="maximum">
|
||||
<number>999999999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_space3_3">
|
||||
<property name="text">
|
||||
<string>Maximum anticipated nodes on the computed path that can be retrieved (the number of nodes actually retrieved at each iteration is limited by "Maximum locations retrieved" from the Memory panel).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
Reference in New Issue
Block a user