Graph viewer optimizations (#1616)

* DbViewer: coloring graph based on env sensor value (e.g., wifi signal strength)

* GraphViewer optimizations

* Fixed link memory allocation

* refactor

* more optimizations

* mainwindow keypoints optimization

* MainWindow optimizations

* Shrink graphics scene on clearAll
This commit is contained in:
matlabbe
2025-11-16 18:56:55 -08:00
committed by GitHub
parent 82fb7ff5d2
commit e75baec73e
5 changed files with 579 additions and 490 deletions
+237 -215
View File
@@ -337,17 +337,37 @@ GraphViewer::GraphViewer(QWidget * parent) :
_gridCellSize(0.0f),
_localRadius(0),
_loopClosureOutlierThr(0),
_maxLinkLength(0.02f),
_minLinkLength(0.02f),
_orientationENU(false),
_mouseTracking(false),
_viewPlane(XY),
_ensureFrameVisible(true)
{
this->setScene(new QGraphicsScene(this));
this->setDragMode(QGraphicsView::ScrollHandDrag);
_workingDirectory = QDir::homePath();
this->scene()->clear();
setupGraphicsScene();
// Match by default scan colors from DatabaseViewer
_highlightedNodes.push_back(QPair<QColor, NodeItem*>(Qt::yellow, nullptr));
_highlightedNodes.push_back(QPair<QColor, NodeItem*>(Qt::magenta, nullptr));
this->restoreDefaults();
this->fitInView(this->sceneRect(), Qt::KeepAspectRatio);
}
GraphViewer::~GraphViewer()
{
}
void GraphViewer::setupGraphicsScene()
{
if(this->scene())
{
delete this->scene();
}
this->setScene(new QGraphicsScene(this));
_world = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
_root = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
_root->setParentItem(_world);
@@ -485,17 +505,6 @@ GraphViewer::GraphViewer(QWidget * parent) :
_odomCacheOverlay->setBrush(QBrush(QColor(255, 255, 255, 150)));
_odomCacheOverlay->setPen(QPen(Qt::NoPen));
// Match by default scan colors from DatabaseViewer
_highlightedNodes.push_back(QPair<QColor, NodeItem*>(Qt::yellow, nullptr));
_highlightedNodes.push_back(QPair<QColor, NodeItem*>(Qt::magenta, nullptr));
this->restoreDefaults();
this->fitInView(this->sceneRect(), Qt::KeepAspectRatio);
}
GraphViewer::~GraphViewer()
{
}
void GraphViewer::setWorldMapRotation(const float & theta)
@@ -510,18 +519,48 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
const std::map<int, int> & weights,
const std::set<int> & odomCacheIds)
{
UTimer timer;
bool wasVisible = _graphRoot->isVisible();
_graphRoot->show();
bool wasEmpty = _nodeItems.size() == 0 && _linkItems.size() == 0;
UDEBUG("poses=%d constraints=%d", (int)poses.size(), (int)constraints.size());
//Hide nodes and links
for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
if(!_graphRoot->isVisible())
{
UDEBUG("Ignoring updating graph, the graph root is not visible.");
return;
}
UTimer timer;
bool wasEmpty = _nodeItems.size() == 0 && _linkItems.size() == 0 && _gridMap->pixmap().isNull();
UDEBUG("poses=%ld constraints=%ld mapIds=%ld weights=%ld", poses.size(), constraints.size(), mapIds.size(), weights.size());
for(QMultiMap<int, LinkItem*>::iterator iter = _linkItems.begin(); iter!=_linkItems.end(); ++iter)
{
iter.value()->hide();
}
UDEBUG("hidden %d links", _linkItems.size());
int created = 0;
int reused = 0;
int removed = 0;
QMap<int, NodeItem*>::iterator nter = _nodeItems.begin();
std::map<int, Transform>::const_iterator iter=_nodeVisible?poses.begin():poses.end();
while(nter!=_nodeItems.end() || iter!=poses.end())
{
if(nter!=_nodeItems.end() && (iter==poses.end() || nter.key() < iter->first || iter->second.isNull()))
{
// NodeItem is not in poses anymore, increase only _nodeItems iterator
for(int i=0; i<_highlightedNodes.size(); ++i)
{
if(_highlightedNodes[i].second && _highlightedNodes[i].second == nter.value())
{
_highlightedNodes[i].second = nullptr;
}
}
delete nter.value();
nter = _nodeItems.erase(nter);
++removed;
continue;
}
QColor color = _nodeColor;
bool isOdomCache = odomCacheIds.find(iter.key()) != odomCacheIds.end();
if(iter.key()<0)
bool isOdomCache = odomCacheIds.find(iter->first) != odomCacheIds.end();
if(iter->first<0)
{
color = QColor(255-color.red(), 255-color.green(), 255-color.blue());
}
@@ -529,51 +568,50 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
{
color = _nodeOdomCacheColor;
}
iter.value()->hide();
iter.value()->setColor(color); // reset color
iter.value()->setToolTipInfo(QString());
iter.value()->setZValue(iter.key()<0?21:20);
}
for(QMultiMap<int, LinkItem*>::iterator iter = _linkItems.begin(); iter!=_linkItems.end(); ++iter)
{
iter.value()->hide();
}
for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
{
if(!iter->second.isNull())
UASSERT(iter!=poses.end());
if(nter == _nodeItems.end() || nter.key() > iter->first)
{
QMap<int, NodeItem*>::iterator itemIter = _nodeItems.find(iter->first);
if(itemIter != _nodeItems.end())
{
itemIter.value()->setPose(iter->second, _viewPlane);
itemIter.value()->show();
}
else
{
// create node item
QColor color = _nodeColor;
bool isOdomCache = odomCacheIds.find(iter->first) != odomCacheIds.end();
if(iter->first<0)
{
color = QColor(255-color.red(), 255-color.green(), 255-color.blue());
}
else if(isOdomCache)
{
color = _nodeOdomCacheColor;
}
const Transform & pose = iter->second;
NodeItem * item = new NodeItem(iter->first, uContains(mapIds, iter->first)?mapIds.at(iter->first):-1, pose, _nodeRadius, uContains(weights, iter->first)?weights.at(iter->first):-1, _viewPlane, _linkWidth);
this->scene()->addItem(item);
item->setZValue(iter->first<0?21:20);
item->setColor(color);
item->setParentItem(_graphRoot);
item->show();
_nodeItems.insert(iter->first, item);
}
// NodeItem is not in poses, create a new one and increase poses iterator
const Transform & pose = iter->second;
NodeItem * item = new NodeItem(
iter->first,
uValue(mapIds, iter->first, -1),
pose,
_nodeRadius,
uValue(weights, iter->first, -1),
_viewPlane,
_linkWidth);
this->scene()->addItem(item);
item->setZValue(iter->first<0?21:20);
item->setColor(color);
item->setParentItem(_graphRoot);
item->show();
_nodeItems.insert(iter->first, item);
++iter;
++created;
}
else
{
// NodeItem exists for the pose, copy data and increase both iterators
UASSERT(iter->first == nter.key());
nter.value()->setColor(color); // reset color
nter.value()->setToolTipInfo(QString());
nter.value()->setZValue(iter->first<0?21:20);
nter.value()->setPose(iter->second, _viewPlane);
nter.value()->show();
++nter;
++iter;
++reused;
}
}
UDEBUG("Nodes created=%d, reused=%d removed=%d", created, reused, removed);
created = 0;
reused = 0;
removed = 0;
int removedSmallLinks = 0;
int ignoredSmallLinks = 0;
for(std::multimap<int, Link>::const_iterator iter=constraints.begin(); iter!=constraints.end(); ++iter)
{
// make the first id the smallest one
@@ -587,30 +625,28 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
std::map<int, Transform>::const_iterator jterA = poses.find(idFrom);
std::map<int, Transform>::const_iterator jterB = poses.find(idTo);
LinkItem * linkItem = 0;
if(jterA != poses.end() && jterB != poses.end() &&
_nodeItems.contains(idFrom) && _nodeItems.contains(idTo))
if(jterA != poses.end() && jterB != poses.end())
{
const Transform & poseA = jterA->second;
const Transform & poseB = jterB->second;
QMultiMap<int, LinkItem*>::iterator itemIter = _linkItems.end();
if(_linkItems.contains(idFrom))
QMultiMap<int, LinkItem*>::iterator itemIter = _linkItems.find(idFrom);
bool alreadyAdded = false;
while(itemIter != _linkItems.end() && itemIter.key() == idFrom)
{
itemIter = _linkItems.find(idFrom);
bool alreadyAdded = false;
while(itemIter != _linkItems.end() && itemIter.key() == idFrom)
if(itemIter.value()->to() == idTo)
{
if(itemIter.value()->to() == idTo && itemIter.value()->isVisible())
{
if(itemIter.value()->isVisible()) {
alreadyAdded = true;
break;
} else {
linkItem = itemIter.value();
}
++itemIter;
}
if(alreadyAdded){
continue;
break;
}
++itemIter;
}
if(alreadyAdded){
continue;
}
bool interSessionClosure = false;
@@ -625,11 +661,15 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
if(isLinkedToOdomCachePoses)
{
_nodeItems.value(idFrom)->setZValue(odomCacheIds.find(idFrom)!=odomCacheIds.end()?24:23);
_nodeItems.value(idTo)->setZValue(odomCacheIds.find(idTo)!=odomCacheIds.end()?24:23);
if(_nodeItems.contains(idFrom)) {
_nodeItems.value(idFrom)->setZValue(odomCacheIds.find(idFrom)!=odomCacheIds.end()?24:23);
}
if(_nodeItems.contains(idTo)) {
_nodeItems.value(idTo)->setZValue(odomCacheIds.find(idTo)!=odomCacheIds.end()?24:23);
}
}
if(poseA.getDistance(poseB) > _maxLinkLength)
if(poseA.getDistance(poseB) > _minLinkLength)
{
if(linkItem == 0)
{
@@ -642,14 +682,24 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
this->scene()->addItem(linkItem);
linkItem->setParentItem(_graphRoot);
_linkItems.insert(idFrom, linkItem);
++created;
}
else {
linkItem->setPoses(poseA, poseB, _viewPlane);
linkItem->show();
++reused;
}
}
else if(linkItem && itemIter != _linkItems.end())
else if(linkItem)
{
// erase small links
_linkItems.erase(itemIter);
delete linkItem;
linkItem = 0;
++removedSmallLinks;
}
else {
++ignoredSmallLinks;
}
if(linkItem)
@@ -730,71 +780,48 @@ void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
}
}
}
UDEBUG("Links created=%d, reused=%d, small links: removed=%d ignored=%d", created, reused, removedSmallLinks, ignoredSmallLinks);
//remove not used nodes and links
for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end();)
{
if(!iter.value()->isVisible())
{
for(int i=0; i<_highlightedNodes.size(); ++i)
{
if(_highlightedNodes[i].second && _highlightedNodes[i].second == iter.value())
{
_highlightedNodes[i].second = nullptr;
}
}
delete iter.value();
iter = _nodeItems.erase(iter);
}
else
{
iter.value()->setVisible(_nodeVisible);
++iter;
}
}
removed = 0;
int visible = 0;
for(QMultiMap<int, LinkItem*>::iterator iter = _linkItems.begin(); iter!=_linkItems.end();)
{
if(!iter.value()->isVisible())
{
delete iter.value();
iter = _linkItems.erase(iter);
++removed;
}
else
{
++iter;
++visible;
}
}
UDEBUG("Links removed=%d, visible=%d", removed, visible);
if(_nodeItems.size())
{
(--_nodeItems.end()).value()->setColor(_nodeOdomCacheColor);
}
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
if(!odomCacheIds.empty())
_odomCacheOverlay->setRect(this->scene()->itemsBoundingRect());
else
_odomCacheOverlay->setRect(0, 0, 0, 0);
if(wasEmpty)
{
QRectF rect = this->scene()->itemsBoundingRect();
QRectF rect = this->scene()->sceneRect();
this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
}
_graphRoot->setVisible(wasVisible);
UDEBUG("_nodeItems=%d, _linkItems=%d, timer=%fs", _nodeItems.size(), _linkItems.size(), timer.ticks());
}
void GraphViewer::updateGTGraph(const std::map<int, Transform> & poses)
{
if(!_gtGraphRoot->isVisible())
{
UDEBUG("Ignoring updating gt graph, the graph root is not visible.");
return;
}
UTimer timer;
bool wasVisible = _gtGraphRoot->isVisible();
_gtGraphRoot->show();
bool wasEmpty = _gtNodeItems.size() == 0 && _gtLinkItems.size() == 0;
UDEBUG("poses=%d", (int)poses.size());
//Hide nodes and links
for(QMap<int, NodeItem*>::iterator iter = _gtNodeItems.begin(); iter!=_gtNodeItems.end(); ++iter)
@@ -811,23 +838,26 @@ void GraphViewer::updateGTGraph(const std::map<int, Transform> & poses)
{
if(!iter->second.isNull())
{
QMap<int, NodeItem*>::iterator itemIter = _gtNodeItems.find(iter->first);
if(itemIter != _gtNodeItems.end())
if(_nodeVisible)
{
itemIter.value()->setPose(iter->second, _viewPlane);
itemIter.value()->show();
}
else
{
// create node item
const Transform & pose = iter->second;
NodeItem * item = new NodeItem(iter->first, -1, pose, _nodeRadius, -1, _viewPlane, _linkWidth);
this->scene()->addItem(item);
item->setZValue(20);
item->setColor(_gtPathColor);
item->setParentItem(_gtGraphRoot);
item->setVisible(_nodeVisible);
_gtNodeItems.insert(iter->first, item);
QMap<int, NodeItem*>::iterator itemIter = _gtNodeItems.find(iter->first);
if(itemIter != _gtNodeItems.end())
{
itemIter.value()->setPose(iter->second, _viewPlane);
itemIter.value()->show();
}
else
{
// create node item
const Transform & pose = iter->second;
NodeItem * item = new NodeItem(iter->first, -1, pose, _nodeRadius, -1, _viewPlane, _linkWidth);
this->scene()->addItem(item);
item->setZValue(20);
item->setColor(_gtPathColor);
item->setParentItem(_gtGraphRoot);
item->setVisible(_nodeVisible);
_gtNodeItems.insert(iter->first, item);
}
}
if(iter!=poses.begin())
@@ -913,20 +943,6 @@ void GraphViewer::updateGTGraph(const std::map<int, Transform> & poses)
++iter;
}
}
if(_gtNodeItems.size() || _gtLinkItems.size())
{
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
if(wasEmpty)
{
QRectF rect = this->scene()->itemsBoundingRect();
this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
}
}
_gtGraphRoot->setVisible(wasVisible);
UDEBUG("_gtNodeItems=%d, _gtLinkItems=%d timer=%fs", _gtNodeItems.size(), _gtLinkItems.size(), timer.ticks());
}
@@ -934,10 +950,11 @@ void GraphViewer::updateGPSGraph(
const std::map<int, Transform> & poses,
const std::map<int, GPS> & gpsValues)
{
if(!_gpsGraphRoot->isVisible()) {
UDEBUG("Ignoring updating gps graph, the graph root is not visible.");
return;
}
UTimer timer;
bool wasVisible = _gpsGraphRoot->isVisible();
_gpsGraphRoot->show();
bool wasEmpty = _gpsNodeItems.size() == 0 && _gpsNodeItems.size() == 0;
UDEBUG("poses=%d", (int)poses.size());
//Hide nodes and links
for(QMap<int, NodeItem*>::iterator iter = _gpsNodeItems.begin(); iter!=_gpsNodeItems.end(); ++iter)
@@ -954,24 +971,27 @@ void GraphViewer::updateGPSGraph(
{
if(!iter->second.isNull())
{
QMap<int, NodeItem*>::iterator itemIter = _gpsNodeItems.find(iter->first);
if(itemIter != _gpsNodeItems.end())
if(_nodeVisible)
{
itemIter.value()->setPose(iter->second, _viewPlane);
itemIter.value()->show();
}
else
{
// create node item
const Transform & pose = iter->second;
UASSERT(gpsValues.find(iter->first) != gpsValues.end());
NodeItem * item = new NodeGPSItem(iter->first, -1, pose, _nodeRadius, gpsValues.at(iter->first), _viewPlane, _linkWidth);
this->scene()->addItem(item);
item->setZValue(20);
item->setColor(_gpsPathColor);
item->setParentItem(_gpsGraphRoot);
item->setVisible(_nodeVisible);
_gpsNodeItems.insert(iter->first, item);
QMap<int, NodeItem*>::iterator itemIter = _gpsNodeItems.find(iter->first);
if(itemIter != _gpsNodeItems.end())
{
itemIter.value()->setPose(iter->second, _viewPlane);
itemIter.value()->show();
}
else
{
// create node item
const Transform & pose = iter->second;
UASSERT(gpsValues.find(iter->first) != gpsValues.end());
NodeItem * item = new NodeGPSItem(iter->first, -1, pose, _nodeRadius, gpsValues.at(iter->first), _viewPlane, _linkWidth);
this->scene()->addItem(item);
item->setZValue(20);
item->setColor(_gpsPathColor);
item->setParentItem(_gpsGraphRoot);
item->setVisible(_nodeVisible);
_gpsNodeItems.insert(iter->first, item);
}
}
if(iter!=poses.begin())
@@ -1043,20 +1063,6 @@ void GraphViewer::updateGPSGraph(
++iter;
}
}
if(_gpsNodeItems.size() || _gpsLinkItems.size())
{
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
if(wasEmpty)
{
QRectF rect = this->scene()->itemsBoundingRect();
this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
}
}
_gpsGraphRoot->setVisible(wasVisible);
UDEBUG("_gpsNodeItems=%d, _gpsLinkItems=%d timer=%fs", _gpsNodeItems.size(), _gpsLinkItems.size(), timer.ticks());
}
@@ -1085,6 +1091,7 @@ void GraphViewer::updateMap(const cv::Mat & map8U, float resolution, float xMin,
UASSERT(map8U.empty() || (!map8U.empty() && resolution > 0.0f));
if(!map8U.empty())
{
bool wasEmpty = _nodeItems.size() <= 1 && _linkItems.size() == 0 && _gridMap->pixmap().isNull();
_gridCellSize = resolution;
QImage image = uCvMat2QImage(map8U, false);
_gridMap->resetTransform();
@@ -1092,8 +1099,11 @@ void GraphViewer::updateMap(const cv::Mat & map8U, float resolution, float xMin,
_gridMap->setRotation(90);
_gridMap->setPixmap(QPixmap::fromImage(image));
_gridMap->setPos(-yMin*100.0f, -xMin*100.0f);
// Re-shrink the scene to it's bounding contents
this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
if(wasEmpty)
{
this->fitInView(this->scene()->sceneRect(), Qt::KeepAspectRatio);
}
}
else
{
@@ -1186,10 +1196,10 @@ void GraphViewer::updateNodeColorByValue(
}
}
}
else if(min < max) {
else if(min >= max) {
UWARN("min (%f) is not less than max (%f), cannot change color of the graph.", min, max);
}
else if(hueMin < hueMax) {
else if(hueMin >= hueMax) {
UWARN("Hue min (%d) is not less than hue max (%d), cannot change color of the graph. The hue values should be set between 0 (red) and 360(pink).", (int)hueMin, (int)hueMax);
}
}
@@ -1260,6 +1270,11 @@ void GraphViewer::setNodeInfo(int id, const QString & info)
void GraphViewer::setLocalRadius(float radius)
{
_localRadius->setRect(-radius*100, -radius*100, radius*200, radius*200);
if(_nodeItems.empty() && _linkItems.empty() && _gridMap->pixmap().isNull())
{
QRectF rect = this->scene()->sceneRect();
this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
}
}
void GraphViewer::updateLocalPath(const std::vector<int> & localPath)
@@ -1384,14 +1399,17 @@ void GraphViewer::clearGraph()
_worldMapRotation = 0.0f;
_referential->resetTransform();
_localRadius->resetTransform();
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
}
void GraphViewer::clearMap()
{
_gridMap->setPixmap(QPixmap());
_gridCellSize = 0.0f;
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
if(_gridMap->pixmap().isNull())
{
// there is no grid map, just return
return;
}
_gridMap->setPixmap(QPixmap());
}
void GraphViewer::clearPosterior()
@@ -1411,6 +1429,14 @@ void GraphViewer::clearAll()
{
clearMap();
clearGraph();
// The only way to re-shrink the dynamic scene rect is to re-create the QGraphicsScene.
QSettings tmp;
saveSettings(tmp);
QRectF localRadiusRectF = _localRadius->rect();
setupGraphicsScene();
loadSettings(tmp); // restore previous state
_localRadius->setRect(localRadiusRectF);
}
void GraphViewer::saveSettings(QSettings & settings, const QString & group) const
@@ -1447,8 +1473,9 @@ void GraphViewer::saveSettings(QSettings & settings, const QString & group) cons
settings.setValue("referential_visible", this->isReferentialVisible());
settings.setValue("local_radius_visible", this->isLocalRadiusVisible());
settings.setValue("loop_closure_outlier_thr", this->getLoopClosureOutlierThr());
settings.setValue("max_link_length", this->getMaxLinkLength());
settings.setValue("min_link_length", this->getMinLinkLength());
settings.setValue("graph_visible", this->isGraphVisible());
settings.setValue("node_visible", this->isNodeVisible());
settings.setValue("global_path_visible", this->isGlobalPathVisible());
settings.setValue("local_path_visible", this->isLocalPathVisible());
settings.setValue("gt_graph_visible", this->isGtGraphVisible());
@@ -1497,8 +1524,9 @@ void GraphViewer::loadSettings(QSettings & settings, const QString & group)
this->setLocalRadiusVisible(settings.value("local_radius_visible", this->isLocalRadiusVisible()).toBool());
this->setIntraInterSessionColorsEnabled(settings.value("intra_inter_session_colors_enabled", this->isIntraInterSessionColorsEnabled()).toBool());
this->setLoopClosureOutlierThr(settings.value("loop_closure_outlier_thr", this->getLoopClosureOutlierThr()).toDouble());
this->setMaxLinkLength(settings.value("max_link_length", this->getMaxLinkLength()).toDouble());
this->setMinLinkLength(settings.value("min_link_length", this->getMinLinkLength()).toDouble());
this->setGraphVisible(settings.value("graph_visible", this->isGraphVisible()).toBool());
this->setNodeVisible(settings.value("node_visible", this->isNodeVisible()).toBool());
this->setGlobalPathVisible(settings.value("global_path_visible", this->isGlobalPathVisible()).toBool());
this->setLocalPathVisible(settings.value("local_path_visible", this->isLocalPathVisible()).toBool());
this->setGtGraphVisible(settings.value("gt_graph_visible", this->isGtGraphVisible()).toBool());
@@ -1533,6 +1561,10 @@ bool GraphViewer::isGraphVisible() const
{
return _graphRoot->isVisible();
}
bool GraphViewer::isNodeVisible() const
{
return _nodeVisible;
}
bool GraphViewer::isGlobalPathVisible() const
{
return _globalPathRoot->isVisible();
@@ -1855,9 +1887,9 @@ void GraphViewer::setLoopClosureOutlierThr(float value)
{
_loopClosureOutlierThr = value;
}
void GraphViewer::setMaxLinkLength(float value)
void GraphViewer::setMinLinkLength(float value)
{
_maxLinkLength = value;
_minLinkLength = value;
}
void GraphViewer::setGraphVisible(bool visible)
{
@@ -1898,10 +1930,6 @@ void GraphViewer::setOrientationENU(bool enabled)
QTransform t;
t.rotateRadians(_worldMapRotation);
_root->setTransform(t);
if(_nodeItems.size() || _linkItems.size())
{
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
}
}
void GraphViewer::setViewPlane(ViewPlane plane)
@@ -1928,11 +1956,6 @@ void GraphViewer::setViewPlane(ViewPlane plane)
_referentialXY->setVisible(plane==XY);
_referentialXZ->setVisible(plane==XZ);
_referentialYZ->setVisible(plane==YZ);
if(_nodeItems.size() || _linkItems.size())
{
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
}
}
void GraphViewer::setEnsureFrameVisible(bool visible)
{
@@ -2123,7 +2146,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
menu.addSeparator();
QAction * aSetNodeSize = menu.addAction(tr("Set node radius..."));
QAction * aSetLinkSize = menu.addAction(tr("Set link width..."));
QAction * aChangeMaxLinkLength = menu.addAction(tr("Set maximum link length..."));
QAction * aChangeMinLinkLength = menu.addAction(tr("Set minimum link length..."));
menu.addSeparator();
QAction * aEnsureFrameVisible;
QAction * aShowHideGridMap;
@@ -2241,12 +2264,12 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
aMouseTracking->setCheckable(true);
aMouseTracking->setChecked(_mouseTracking);
aMouseTracking->setEnabled(_viewPlane == XY);
aShowHideGraph->setEnabled(_nodeItems.size() && _viewPlane == XY);
aShowHideGraphNodes->setEnabled(_nodeItems.size() && _graphRoot->isVisible());
aShowHideGraph->setEnabled(_viewPlane == XY);
aShowHideGraphNodes->setEnabled(_graphRoot->isVisible());
aShowHideGlobalPath->setEnabled(_globalPathLinkItems.size());
aShowHideLocalPath->setEnabled(_localPathLinkItems.size());
aShowHideGtGraph->setEnabled(_gtNodeItems.size());
aShowHideGPSGraph->setEnabled(_gpsNodeItems.size());
aShowHideGtGraph->setEnabled(_gtGraphRoot->isVisible());
aShowHideGPSGraph->setEnabled(_gpsGraphRoot->isVisible());
aShowHideOdomCacheOverlay->setEnabled(_odomCacheOverlay->rect().width()>0);
QMenu * viewPlaneMenu = menu.addMenu("View Plane...");
@@ -2363,8 +2386,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
//reset scale
_root->setScale(1.0f);
this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
this->scene()->setSceneRect(QRectF());
QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
}
@@ -2426,13 +2448,13 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
setLoopClosureOutlierThr(value);
}
}
else if(r == aChangeMaxLinkLength)
else if(r == aChangeMinLinkLength)
{
bool ok;
double value = QInputDialog::getDouble(this, tr("Maximum link length to be shown"), tr("Value (m)"), _maxLinkLength, 0.0, 1000.0, 3, &ok);
double value = QInputDialog::getDouble(this, tr("Minimum link length to be shown"), tr("Value (m)"), _minLinkLength, 0.0, 1000.0, 3, &ok);
if(ok)
{
setMaxLinkLength(value);
setMinLinkLength(value);
}
}
else if(r == aChangeNodeColor ||