mirror of
https://github.com/introlab/rtabmap.git
synced 2026-10-05 17:47:49 +08:00
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:
+237
-215
@@ -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 ||
|
||||
|
||||
Reference in New Issue
Block a user