30 #include <QGraphicsView>
31 #include <QVBoxLayout>
32 #include <QGraphicsScene>
33 #include <QGraphicsEllipseItem>
34 #include <QGraphicsRectItem>
35 #include <QtGui/QWheelEvent>
36 #include <QGraphicsSceneHoverEvent>
38 #include <QtGui/QDesktopServices>
39 #include <QtGui/QContextMenuEvent>
40 #include <QColorDialog>
42 #include <QFileDialog>
44 #include <QtSvg/QSvgGenerator>
46 #include <QInputDialog>
47 #include <QMessageBox>
50 #include <QtCore/QDir>
51 #include <QtCore/QDateTime>
52 #include <QtCore/QUrl>
62 #if QT_VERSION >= 0x050000
63 #include <QStandardPaths>
75 QGraphicsEllipseItem(QRectF(-radius*100.0
f,-radius*100.0
f,radius*100.0
f*2.0
f,radius*100.0
f*2.0
f)),
83 this->setBrush(pen().color());
84 this->setAcceptHoverEvents(
true);
89 QPen pen =
_line->pen();
90 pen.setWidth(linkWidth*100.0
f);
100 QBrush
b = this->brush();
104 QPen pen =
_line->pen();
105 pen.setColor(QColor(255-color.red(), 255-color.green(), 255-color.blue()));
114 this->setRect(-radius, -radius, radius*2.0
f, radius*2.0
f);
125 this->setPos(
pose.
x()*100.0f,-
pose.
z()*100.0f);
128 this->setPos(
pose.
y()*100.0f,-
pose.
z()*100.0f);
131 this->setPos(-
pose.
y()*100.0f,-
pose.
x()*100.0f);
139 float radius = this->rect().width()/2.0f;
156 QGraphicsEllipseItem::hoverEnterEvent(event);
162 QGraphicsEllipseItem::hoverEnterEvent(event);
185 this->setToolTip(QString(
"%1 [%2] %3\n"
186 "longitude=%4 latitude=%5 altitude=%6m error=%7m bearing=%8deg")
190 QGraphicsEllipseItem::hoverEnterEvent(event);
209 this->setAcceptHoverEvents(
true);
215 QPen
p = this->pen();
225 this->setLine(poseA.
x()*100.0f, -poseA.
z()*100.0f, poseB.
x()*100.0f, -poseB.
z()*100.0f);
228 this->setLine(poseA.
y()*100.0f, -poseA.
z()*100.0f, poseB.
y()*100.0f, -poseB.
z()*100.0f);
231 this->setLine(-poseA.
y()*100.0f, -poseA.
x()*100.0f, -poseB.
y()*100.0f, -poseB.
x()*100.0f);
260 this->setToolTip(
str);
261 QPen pen = this->pen();
262 pen.setWidthF(pen.widthF()+2);
264 QGraphicsLineItem::hoverEnterEvent(event);
269 QPen pen = this->pen();
270 pen.setWidthF(pen.widthF()-2);
272 QGraphicsLineItem::hoverEnterEvent(event);
285 QGraphicsView(parent),
286 _nodeColor(Qt::blue),
287 _nodeOdomCacheColor(Qt::darkGreen),
288 _currentGoalColor(Qt::darkMagenta),
289 _neighborColor(Qt::blue),
290 _loopClosureColor(Qt::red),
291 _loopClosureLocalColor(Qt::yellow),
292 _loopClosureUserColor(Qt::red),
293 _loopClosureVirtualColor(Qt::magenta),
294 _neighborMergedColor(QColor(255,170,0)),
295 _landmarkColor(Qt::darkGreen),
296 _loopClosureRejectedColor(Qt::black),
297 _localPathColor(Qt::cyan),
298 _globalPathColor(Qt::darkMagenta),
299 _gtPathColor(Qt::gray),
300 _gpsPathColor(Qt::darkCyan),
301 _loopIntraSessionColor(Qt::red),
302 _loopInterSessionColor(Qt::green),
303 _intraInterSessionColors(
false),
304 _worldMapRotation(0.0
f),
314 _originReferential(0),
317 _loopClosureOutlierThr(0),
318 _maxLinkLength(0.02
f),
319 _orientationENU(
false),
320 _mouseTracking(
false),
322 _ensureFrameVisible(
true)
324 this->setScene(
new QGraphicsScene(
this));
325 this->setDragMode(QGraphicsView::ScrollHandDrag);
328 this->scene()->clear();
329 _world = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
330 _root = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
334 QGraphicsLineItem * item;
341 item = this->scene()->addLine(0,0,0,-100, QPen(QBrush(Qt::red),
_linkWidth));
343 item->setParentItem(
_root);
345 item = this->scene()->addLine(0,0,-100,0, QPen(QBrush(Qt::green),
_linkWidth));
347 item->setParentItem(
_root);
354 item = this->scene()->addLine(0,0,100,0, QPen(QBrush(Qt::red),
_linkWidth));
356 item->setParentItem(
_root);
358 item = this->scene()->addLine(0,0,0,-100, QPen(QBrush(Qt::blue),
_linkWidth));
360 item->setParentItem(
_root);
368 item = this->scene()->addLine(0,0,100,0, QPen(QBrush(Qt::green),
_linkWidth));
370 item->setParentItem(
_root);
372 item = this->scene()->addLine(0,0,0,-100, QPen(QBrush(Qt::blue),
_linkWidth));
374 item->setParentItem(
_root);
389 item = this->scene()->addLine(0,0,0,-50, QPen(QBrush(Qt::red),
_linkWidth));
390 item->setZValue(100);
391 item->setParentItem(
_root);
393 item = this->scene()->addLine(0,0,-50,0, QPen(QBrush(Qt::green),
_linkWidth));
394 item->setZValue(100);
395 item->setParentItem(
_root);
402 item = this->scene()->addLine(0,0,50,0, QPen(QBrush(Qt::red),
_linkWidth));
403 item->setZValue(100);
404 item->setParentItem(
_root);
406 item = this->scene()->addLine(0,0,0,-50, QPen(QBrush(Qt::blue),
_linkWidth));
407 item->setZValue(100);
408 item->setParentItem(
_root);
416 item = this->scene()->addLine(0,0,50,0, QPen(QBrush(Qt::green),
_linkWidth));
417 item->setZValue(100);
418 item->setParentItem(
_root);
420 item = this->scene()->addLine(0,0,0,-50, QPen(QBrush(Qt::blue),
_linkWidth));
421 item->setZValue(100);
422 item->setParentItem(
_root);
430 _localRadius = this->scene()->addEllipse(-0.0001,-0.0001,0.0001,0.0001);
436 _gridMap = this->scene()->addPixmap(QPixmap());
440 _graphRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
444 _globalPathRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
448 _localPathRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
452 _gtGraphRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
456 _gpsGraphRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
471 this->fitInView(this->sceneRect(), Qt::KeepAspectRatio);
485 const std::multimap<int, Link> & constraints,
486 const std::map<int, int> & mapIds,
487 const std::map<int, int> & weights,
488 const std::set<int> & odomCacheIds)
495 UDEBUG(
"poses=%d constraints=%d", (
int)poses.size(), (
int)constraints.size());
500 bool isOdomCache = odomCacheIds.find(
iter.key()) != odomCacheIds.end();
503 color = QColor(255-color.red(), 255-color.green(), 255-color.blue());
518 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
520 if(!
iter->second.isNull())
522 QMap<int, NodeItem*>::iterator itemIter =
_nodeItems.find(
iter->first);
526 itemIter.value()->show();
532 bool isOdomCache = odomCacheIds.find(
iter->first) != odomCacheIds.end();
535 color = QColor(255-color.red(), 255-color.green(), 255-color.blue());
543 this->scene()->addItem(item);
544 item->setZValue(
iter->first<0?21:20);
553 for(std::multimap<int, Link>::const_iterator
iter=constraints.begin();
iter!=constraints.end(); ++
iter)
559 std::map<int, Transform>::const_iterator jterA = poses.find(idFrom);
560 std::map<int, Transform>::const_iterator jterB = poses.find(idTo);
562 if(jterA != poses.end() && jterB != poses.end() &&
568 QMultiMap<int, LinkItem*>::iterator itemIter =
_linkItems.end();
572 while(itemIter.key() == idFrom && itemIter !=
_linkItems.end())
574 if(itemIter.value()->to() == idTo && itemIter.value()->type() ==
iter->second.type())
576 itemIter.value()->setPoses(poseA, poseB,
_viewPlane);
577 itemIter.value()->show();
578 linkItem = itemIter.value();
585 bool interSessionClosure =
false;
588 interSessionClosure = mapIds.at(jterA->first) != mapIds.at(jterB->first);
591 bool isLinkedToOdomCachePoses =
592 odomCacheIds.find(idFrom)!=odomCacheIds.end() ||
593 odomCacheIds.find(idTo)!=odomCacheIds.end();
595 if(isLinkedToOdomCachePoses)
597 _nodeItems.value(idFrom)->setZValue(odomCacheIds.find(idFrom)!=odomCacheIds.end()?24:23);
598 _nodeItems.value(idTo)->setZValue(odomCacheIds.find(idTo)!=odomCacheIds.end()?24:23);
607 QPen
p = linkItem->pen();
610 linkItem->setZValue(isLinkedToOdomCachePoses?22:10);
611 this->scene()->addItem(linkItem);
616 else if(linkItem && itemIter !=
_linkItems.end())
659 linkItem->setZValue(isLinkedToOdomCachePoses?22:interSessionClosure?6:7);
664 linkItem->setZValue(isLinkedToOdomCachePoses?22:7);
672 linkItem->setZValue(isLinkedToOdomCachePoses?22:interSessionClosure?8:9);
677 linkItem->setZValue(isLinkedToOdomCachePoses?22:9);
685 if(
iter->second.to() != idTo)
692 float linearError =
fabs(
iter->second.transform().getNorm() -
t.getNorm());
742 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
744 if(!odomCacheIds.empty())
751 QRectF rect = this->scene()->itemsBoundingRect();
752 this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
766 UDEBUG(
"poses=%d", (
int)poses.size());
778 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
780 if(!
iter->second.isNull())
786 itemIter.value()->show();
793 this->scene()->addItem(item);
801 if(
iter!=poses.begin())
803 std::map<int, Transform>::const_iterator iterPrevious =
iter;
805 Transform previousPose = iterPrevious->second;
809 QMultiMap<int, LinkItem*>::iterator linkIter =
_gtLinkItems.end();
813 while(linkIter.key() == iterPrevious->first && linkIter !=
_gtLinkItems.end())
815 if(linkIter.value()->to() ==
iter->first)
817 linkIter.value()->setPoses(previousPose, currentPose,
_viewPlane);
818 linkIter.value()->show();
819 linkItem = linkIter.value();
827 bool linkFound =
iter->first - iterPrevious->first == 1;
828 for(QMultiMap<int, LinkItem*>::iterator kter =
_linkItems.find(iterPrevious->first);
829 kter!=
_linkItems.end() && kter.key()==iterPrevious->first && !linkFound;
832 if(kter.value()->from() == iterPrevious->first && kter.value()->to() ==
iter->first)
842 QPen
p = linkItem->pen();
845 linkItem->setZValue(10);
846 this->scene()->addItem(linkItem);
887 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
891 QRectF rect = this->scene()->itemsBoundingRect();
892 this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
902 const std::map<int, Transform> & poses,
903 const std::map<int, GPS> & gpsValues)
909 UDEBUG(
"poses=%d", (
int)poses.size());
921 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
923 if(!
iter->second.isNull())
929 itemIter.value()->show();
935 UASSERT(gpsValues.find(
iter->first) != gpsValues.end());
937 this->scene()->addItem(item);
945 if(
iter!=poses.begin())
947 std::map<int, Transform>::const_iterator iterPrevious =
iter;
949 Transform previousPose = iterPrevious->second;
953 QMultiMap<int, LinkItem*>::iterator linkIter =
_gpsLinkItems.end();
957 while(linkIter.key() == iterPrevious->first && linkIter !=
_gpsLinkItems.end())
959 if(linkIter.value()->to() ==
iter->first)
961 linkIter.value()->setPoses(previousPose, currentPose,
_viewPlane);
962 linkIter.value()->show();
963 linkItem = linkIter.value();
973 QPen
p = linkItem->pen();
976 linkItem->setZValue(10);
977 this->scene()->addItem(linkItem);
1017 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1021 QRectF rect = this->scene()->itemsBoundingRect();
1022 this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
1034 qt.translate(-
t.o24()*100.0f, -
t.o14()*100.0f);
1036 qt.rotateRadians(-
t.theta());
1053 UASSERT(map8U.empty() || (!map8U.empty() && resolution > 0.0f));
1059 _gridMap->setTransform(QTransform::fromScale(resolution*100.0
f, -resolution*100.0
f),
true);
1061 _gridMap->setPixmap(QPixmap::fromImage(image));
1062 _gridMap->setPos(-yMin*100.0
f, -xMin*100.0
f);
1064 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1077 for(std::map<int, float>::const_iterator
iter = posterior.begin();
iter!=posterior.end(); ++
iter)
1089 std::map<int,float>::const_iterator jter = posterior.find(
iter.key());
1090 if(jter != posterior.end())
1092 float v = jter->second>
max?
max:jter->second;
1093 iter.
value()->setColor(QColor::fromHsvF((1-
v/
max)*240.0
f/360.0
f, 1, 1, 1));
1102 UDEBUG(
"Set global path size=%d", (
int)globalPath.size());
1106 if(globalPath.size() >= 2)
1108 for(
unsigned int i=0;
i<globalPath.size()-1; ++
i)
1111 int idFrom = globalPath[
i].first;
1112 int idTo = globalPath[
i+1].first;
1114 QPen
p = item->pen();
1118 this->scene()->addItem(item);
1119 item->setZValue(15);
1135 UWARN(
"Current goal %d not found in the graph",
id);
1152 _localRadius->setRect(-radius*100, -radius*100, radius*200, radius*200);
1165 if(localPath.size() > 1)
1167 for(
unsigned int i=0;
i<localPath.size()-1; ++
i)
1169 int idFrom = localPath[
i]<localPath[
i+1]?localPath[
i]:localPath[
i+1];
1170 int idTo = localPath[
i]<localPath[
i+1]?localPath[
i+1]:localPath[
i];
1179 if(itemIter.value()->to() == idTo)
1182 itemIter.value()->show();
1193 QPen
p = item->pen();
1197 this->scene()->addItem(item);
1198 item->setZValue(16);
1227 UERROR(
"Unsupported highlight color index %d", highlightIndex);
1273 _root->resetTransform();
1277 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1284 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1303 if(!group.isEmpty())
1305 settings.beginGroup(group);
1307 settings.setValue(
"node_radius", (
double)this->
getNodeRadius());
1308 settings.setValue(
"link_width", (
double)this->
getLinkWidth());
1325 settings.setValue(
"gt_color", this->
getGTColor());
1326 settings.setValue(
"gps_color", this->
getGPSColor());
1343 settings.setValue(
"view_plane", (
int)this->
getViewPlane());
1345 if(!group.isEmpty())
1347 settings.endGroup();
1353 if(!group.isEmpty())
1355 settings.beginGroup(group);
1357 this->
setNodeRadius(settings.value(
"node_radius",
this->getNodeRadius()).toDouble());
1358 this->
setLinkWidth(settings.value(
"link_width",
this->getLinkWidth()).toDouble());
1359 this->
setNodeColor(settings.value(
"node_color",
this->getNodeColor()).value<QColor>());
1366 this->
setNeighborColor(settings.value(
"neighbor_color",
this->getNeighborColor()).value<QColor>());
1373 this->
setLocalPathColor(settings.value(
"local_path_color",
this->getLocalPathColor()).value<QColor>());
1374 this->
setGlobalPathColor(settings.value(
"global_path_color",
this->getGlobalPathColor()).value<QColor>());
1375 this->
setGTColor(settings.value(
"gt_color",
this->getGTColor()).value<QColor>());
1376 this->
setGPSColor(settings.value(
"gps_color",
this->getGPSColor()).value<QColor>());
1385 this->
setMaxLinkLength(settings.value(
"max_link_length",
this->getMaxLinkLength()).toDouble());
1395 if(!group.isEmpty())
1397 settings.endGroup();
1493 QList<QGraphicsItem*> items = this->scene()->items();
1494 for(
int i=0;
i<items.size(); ++
i)
1496 QGraphicsLineItem * line = qgraphicsitem_cast<QGraphicsLineItem *>(items[
i]);
1499 QPen pen = line->pen();
1654 UERROR(
"Unsupported highlight color index %d", index);
1723 UWARN(
"Grid map can be shown only with view plane is XY.");
1775 UWARN(
"ENU orientation can be set only with view plane is XY.");
1788 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1819 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1861 if(event->angleDelta().y() < 0)
1863 this->
scale(0.95, 0.95);
1867 this->
scale(1.05, 1.05);
1873 QPointF scenePoint = mapToScene(event->pos());
1876 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1877 QToolTip::showText(event->globalPosition().toPoint(), QString(
"%1m %2m").
arg(-scenePoint.y()/100.0).
arg(-scenePoint.x()/100.0));
1879 QToolTip::showText(event->globalPos(), QString(
"%1m %2m").
arg(-scenePoint.y()/100.0).
arg(-scenePoint.x()/100.0));
1884 QToolTip::hideText();
1886 QGraphicsView::mouseMoveEvent(event);
1891 QGraphicsItem *item = this->scene()->itemAt(mapToScene(event->pos()), QTransform());
1894 NodeItem *nodeItem = qgraphicsitem_cast<NodeItem*>(item);
1895 LinkItem *linkItem = qgraphicsitem_cast<LinkItem*>(item);
1896 if(nodeItem && nodeItem->parentItem() ==
_graphRoot && nodeItem->
id() != 0)
1900 else if(linkItem && linkItem->parentItem() ==
_graphRoot && linkItem->
from() != 0 && linkItem->
to() != 0)
1906 QGraphicsView::mousePressEvent(event);
1911 QGraphicsView::mousePressEvent(event);
1917 QPixmap pixmap(50, 50);
1919 return QIcon(pixmap);
1925 QAction * aScreenShot = menu.addAction(tr(
"Take a screenshot..."));
1926 QAction * aExportGridMap = menu.addAction(tr(
"Export grid map..."));
1927 aExportGridMap->setEnabled(!
_gridMap->pixmap().isNull());
1928 menu.addSeparator();
1933 QMenu * menuChangeHighlightingColors = menu.addMenu(tr(
"Set node highlighting colors..."));
1937 aChangeHighlightingColors[
i]->setIconVisibleInMenu(
true);
1939 aChangeNodeColor->setIconVisibleInMenu(
true);
1940 aChangeNodeOdomCacheColor->setIconVisibleInMenu(
true);
1941 aChangeCurrentGoalColor->setIconVisibleInMenu(
true);
1944 QMenu * menuLink = menu.addMenu(tr(
"Set link color..."));
1945 QAction * aChangeNeighborColor = menuLink->addAction(tr(
"Neighbor"));
1946 QAction * aChangeGlobalLoopColor = menuLink->addAction(tr(
"Global loop closure"));
1947 QAction * aChangeLocalLoopColor = menuLink->addAction(tr(
"Local loop closure"));
1948 QAction * aChangeUserLoopColor = menuLink->addAction(tr(
"User loop closure"));
1949 QAction * aChangeVirtualLoopColor = menuLink->addAction(tr(
"Virtual loop closure"));
1950 QAction * aChangeNeighborMergedColor = menuLink->addAction(tr(
"Neighbor merged"));
1951 QAction * aChangeLandmarkColor = menuLink->addAction(tr(
"Landmark"));
1952 QAction * aChangeRejectedLoopColor = menuLink->addAction(tr(
"Outlier loop closure"));
1953 QAction * aChangeRejectedLoopThr = menuLink->addAction(tr(
"Set outlier threshold..."));
1954 QAction * aChangeLocalPathColor = menuLink->addAction(tr(
"Local path"));
1955 QAction * aChangeGlobalPathColor = menuLink->addAction(tr(
"Global path"));
1956 QAction * aChangeGTColor = menuLink->addAction(tr(
"Ground truth"));
1957 QAction * aChangeGPSColor = menuLink->addAction(tr(
"GPS"));
1958 menuLink->addSeparator();
1959 QAction * aSetIntraInterSessionColors = menuLink->addAction(tr(
"Enable intra/inter-session colors"));
1960 QAction * aChangeIntraSessionLoopColor = menuLink->addAction(tr(
"Intra-session loop closure"));
1961 QAction * aChangeInterSessionLoopColor = menuLink->addAction(tr(
"Inter-session loop closure"));
1976 aChangeNeighborColor->setIconVisibleInMenu(
true);
1977 aChangeGlobalLoopColor->setIconVisibleInMenu(
true);
1978 aChangeLocalLoopColor->setIconVisibleInMenu(
true);
1979 aChangeUserLoopColor->setIconVisibleInMenu(
true);
1980 aChangeVirtualLoopColor->setIconVisibleInMenu(
true);
1981 aChangeNeighborMergedColor->setIconVisibleInMenu(
true);
1982 aChangeRejectedLoopColor->setIconVisibleInMenu(
true);
1983 aChangeLocalPathColor->setIconVisibleInMenu(
true);
1984 aChangeGlobalPathColor->setIconVisibleInMenu(
true);
1985 aChangeGTColor->setIconVisibleInMenu(
true);
1986 aChangeGPSColor->setIconVisibleInMenu(
true);
1987 aChangeIntraSessionLoopColor->setIconVisibleInMenu(
true);
1988 aChangeInterSessionLoopColor->setIconVisibleInMenu(
true);
1989 aSetIntraInterSessionColors->setCheckable(
true);
1992 menu.addSeparator();
1993 QAction * aSetNodeSize = menu.addAction(tr(
"Set node radius..."));
1994 QAction * aSetLinkSize = menu.addAction(tr(
"Set link width..."));
1995 QAction * aChangeMaxLinkLength = menu.addAction(tr(
"Set maximum link length..."));
1996 menu.addSeparator();
1997 QAction * aEnsureFrameVisible;
1998 QAction * aShowHideGridMap;
1999 QAction * aShowHideGraph;
2000 QAction * aShowHideGraphNodes;
2001 QAction * aShowHideOrigin;
2002 QAction * aShowHideReferential;
2003 QAction * aShowHideLocalRadius;
2004 QAction * aShowHideGlobalPath;
2005 QAction * aShowHideLocalPath;
2006 QAction * aShowHideGtGraph;
2007 QAction * aShowHideGPSGraph;
2008 QAction * aShowHideOdomCacheOverlay;
2009 QAction * aOrientationENU;
2010 QAction * aMouseTracking;
2011 QAction * aViewPlaneXY;
2012 QAction * aViewPlaneXZ;
2013 QAction * aViewPlaneYZ;
2014 aEnsureFrameVisible = menu.addAction(tr(
"Ensure Frame Visible"));
2015 aEnsureFrameVisible->setCheckable(
true);
2019 aShowHideGridMap = menu.addAction(tr(
"Hide grid map"));
2023 aShowHideGridMap = menu.addAction(tr(
"Show grid map"));
2028 aShowHideOrigin = menu.addAction(tr(
"Hide origin referential"));
2032 aShowHideOrigin = menu.addAction(tr(
"Show origin referential"));
2036 aShowHideReferential = menu.addAction(tr(
"Hide current referential"));
2040 aShowHideReferential = menu.addAction(tr(
"Show current referential"));
2044 aShowHideLocalRadius = menu.addAction(tr(
"Hide local radius"));
2048 aShowHideLocalRadius = menu.addAction(tr(
"Show local radius"));
2052 aShowHideGraph = menu.addAction(tr(
"Hide graph"));
2056 aShowHideGraph = menu.addAction(tr(
"Show graph"));
2060 aShowHideGraphNodes = menu.addAction(tr(
"Hide graph nodes"));
2064 aShowHideGraphNodes = menu.addAction(tr(
"Show graph nodes"));
2068 aShowHideGlobalPath = menu.addAction(tr(
"Hide global path"));
2072 aShowHideGlobalPath = menu.addAction(tr(
"Show global path"));
2076 aShowHideLocalPath = menu.addAction(tr(
"Hide local path"));
2080 aShowHideLocalPath = menu.addAction(tr(
"Show local path"));
2084 aShowHideGtGraph = menu.addAction(tr(
"Hide ground truth graph"));
2088 aShowHideGtGraph = menu.addAction(tr(
"Show ground truth graph"));
2092 aShowHideGPSGraph = menu.addAction(tr(
"Hide GPS graph"));
2096 aShowHideGPSGraph = menu.addAction(tr(
"Show GPS graph"));
2100 aShowHideOdomCacheOverlay = menu.addAction(tr(
"Hide odom cache overlay"));
2104 aShowHideOdomCacheOverlay = menu.addAction(tr(
"Show odom cache overlay"));
2106 aOrientationENU = menu.addAction(tr(
"ENU Orientation"));
2107 aOrientationENU->setCheckable(
true);
2109 aMouseTracking = menu.addAction(tr(
"Show mouse cursor position (m)"));
2110 aMouseTracking->setCheckable(
true);
2121 QMenu * viewPlaneMenu = menu.addMenu(
"View Plane...");
2122 aViewPlaneXY = viewPlaneMenu->addAction(
"XY");
2123 aViewPlaneXY->setCheckable(
true);
2125 aViewPlaneXZ = viewPlaneMenu->addAction(
"XZ");
2126 aViewPlaneXZ->setCheckable(
true);
2128 aViewPlaneYZ = viewPlaneMenu->addAction(
"YZ");
2129 aViewPlaneYZ->setCheckable(
true);
2132 menu.addSeparator();
2133 QAction * aRestoreDefaults = menu.addAction(tr(
"Restore defaults"));
2135 QAction * r = menu.exec(event->globalPos());
2136 int aChangeHighlightingColorIndex = 0;
2137 for(
int i=1;
i<aChangeHighlightingColors.size(); ++
i)
2139 if(r == aChangeHighlightingColors[
i]) {
2140 aChangeHighlightingColorIndex =
i;
2143 if(r == aScreenShot)
2148 #if QT_VERSION >= 0x050000
2149 filePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
2152 if(!dir.exists(filePath))
2154 filePath = QDir::homePath();
2156 filePath +=
"/graph.png";
2159 filePath = QFileDialog::getSaveFileName(
this, tr(
"Save figure to ..."), filePath,
"*.png *.xpm *.jpg *.pdf *.svg");
2161 filePath = QFileDialog::getSaveFileName(
this, tr(
"Save figure to ..."), filePath,
"*.png *.xpm *.jpg *.pdf");
2163 if(!filePath.isEmpty())
2165 if(QFileInfo(filePath).suffix() ==
"")
2180 this->scene()->clearSelection();
2181 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
2182 QSize sceneSize = this->scene()->sceneRect().size().toSize();
2184 if(QFileInfo(filePath).suffix().
compare(
"pdf") == 0)
2186 QPrinter printer(QPrinter::HighResolution);
2187 printer.setPageOrientation(QPageLayout::Portrait);
2188 printer.setOutputFileName( filePath );
2189 QPainter
p(&printer);
2190 scene()->render(&
p);
2193 else if(QFileInfo(filePath).suffix().
compare(
"svg") == 0)
2196 QSvgGenerator svgGen;
2198 svgGen.setFileName( filePath );
2199 svgGen.setSize(sceneSize);
2201 int borderH = sceneSize.width()/100;
2202 int borderV = sceneSize.height()/100;
2203 svgGen.setViewBox(QRect(-borderH, -borderV, sceneSize.width()+borderH*2, sceneSize.height()+borderV*2));
2204 svgGen.setTitle(tr(
"RTAB-Map graph"));
2205 svgGen.setDescription(tr(
"RTAB-Map map and graph"));
2207 QPainter painter( &svgGen );
2209 this->scene()->render(&painter);
2211 UERROR(
"RTAB-MAp is not built with Qt's SVG library, cannot save picture in svg format.");
2216 QImage image(sceneSize, QImage::Format_ARGB32);
2217 image.fill(Qt::transparent);
2218 QPainter painter(&image);
2220 this->scene()->render(&painter);
2223 image.save(filePath);
2227 QMessageBox::warning(
this,
2229 tr(
"Could not export in PNG (the scene may be too large %1x%2), try saving in SVG.").
arg(sceneSize.width()).
arg(sceneSize.height()));
2235 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
2238 QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
2243 else if(r == aExportGridMap)
2245 float xMin, yMin, cellSize;
2251 QString
path = QFileDialog::getSaveFileName(
2259 if(QFileInfo(
path).suffix() ==
"")
2266 QString yaml =
info.absolutePath() +
"/" +
info.baseName() +
".yaml";
2268 float occupancyThr = Parameters::defaultGridGlobalOccupancyThr();
2271 file.open (yaml.toStdString());
2272 file <<
"image: " <<
info.baseName().toStdString() <<
".pgm" << std::endl;
2273 file <<
"resolution: " << cellSize << std::endl;
2274 file <<
"origin: [" << xMin <<
", " << yMin <<
", 0.0]" << std::endl;
2275 file <<
"negate: 0" << std::endl;
2276 file <<
"occupied_thresh: " << occupancyThr << std::endl;
2277 file <<
"free_thresh: 0.196" << std::endl;
2282 QMessageBox::information(
this, tr(
"Export 2D map"), tr(
"Exported %1 and %2!").
arg(
path).
arg(yaml));
2285 else if(r == aSetIntraInterSessionColors)
2289 else if(r == aChangeRejectedLoopThr)
2292 double value = QInputDialog::getDouble(
this, tr(
"Loop closure outlier threshold"), tr(
"Value (m)"),
_loopClosureOutlierThr, 0.0, 1000.0, 2, &ok);
2298 else if(r == aChangeMaxLinkLength)
2301 double value = QInputDialog::getDouble(
this, tr(
"Maximum link length to be shown"), tr(
"Value (m)"),
_maxLinkLength, 0.0, 1000.0, 3, &ok);
2307 else if(r == aChangeNodeColor ||
2308 r == aChangeNodeOdomCacheColor ||
2309 r == aChangeCurrentGoalColor ||
2310 r == aChangeHighlightingColors[aChangeHighlightingColorIndex] ||
2311 r == aChangeNeighborColor ||
2312 r == aChangeGlobalLoopColor ||
2313 r == aChangeLocalLoopColor ||
2314 r == aChangeUserLoopColor ||
2315 r == aChangeVirtualLoopColor ||
2316 r == aChangeNeighborMergedColor ||
2317 r == aChangeRejectedLoopColor ||
2318 r == aChangeLocalPathColor ||
2319 r == aChangeGlobalPathColor ||
2320 r == aChangeGTColor ||
2321 r == aChangeGPSColor ||
2322 r == aChangeIntraSessionLoopColor ||
2323 r == aChangeInterSessionLoopColor)
2326 if(r == aChangeNodeColor)
2330 else if(r == aChangeNodeOdomCacheColor)
2334 else if(r == aChangeCurrentGoalColor)
2338 else if(r == aChangeHighlightingColors[aChangeHighlightingColorIndex])
2342 else if(r == aChangeGlobalLoopColor)
2346 else if(r == aChangeLocalLoopColor)
2350 else if(r == aChangeUserLoopColor)
2354 else if(r == aChangeVirtualLoopColor)
2358 else if(r == aChangeNeighborMergedColor)
2362 else if(r == aChangeLandmarkColor)
2366 else if(r == aChangeRejectedLoopColor)
2370 else if(r == aChangeLocalPathColor)
2374 else if(r == aChangeGlobalPathColor)
2378 else if(r == aChangeGTColor)
2382 else if(r == aChangeGPSColor)
2386 else if(r == aChangeIntraSessionLoopColor)
2390 else if(r == aChangeInterSessionLoopColor)
2398 color = QColorDialog::getColor(color,
this);
2402 if(r == aChangeNodeColor)
2406 else if(r == aChangeNodeOdomCacheColor)
2410 else if(r == aChangeCurrentGoalColor)
2414 else if(r == aChangeHighlightingColors[aChangeHighlightingColorIndex])
2418 else if(r == aChangeGlobalLoopColor)
2422 else if(r == aChangeLocalLoopColor)
2426 else if(r == aChangeUserLoopColor)
2430 else if(r == aChangeVirtualLoopColor)
2434 else if(r == aChangeNeighborMergedColor)
2438 else if(r == aChangeLandmarkColor)
2442 else if(r == aChangeRejectedLoopColor)
2446 else if(r == aChangeLocalPathColor)
2450 else if(r == aChangeGlobalPathColor)
2454 else if(r == aChangeGTColor)
2458 else if(r == aChangeGPSColor)
2462 else if(r == aChangeIntraSessionLoopColor)
2466 else if(r == aChangeInterSessionLoopColor)
2480 else if(r == aSetNodeSize)
2483 double value = QInputDialog::getDouble(
this, tr(
"Node radius"), tr(
"Radius (m)"),
_nodeRadius, 0.001, 100, 3, &ok);
2489 else if(r == aSetLinkSize)
2492 double value = QInputDialog::getDouble(
this, tr(
"Link width"), tr(
"Width (m)"),
_linkWidth, 0, 100, 2, &ok);
2498 else if(r == aEnsureFrameVisible)
2502 else if(r == aShowHideGridMap)
2510 else if(r == aShowHideOrigin)
2514 else if(r == aShowHideReferential)
2518 else if(r == aShowHideLocalRadius)
2522 else if(r == aRestoreDefaults)
2526 else if(r == aShowHideGraph)
2530 else if(r == aShowHideGraphNodes)
2534 else if(r == aShowHideGlobalPath)
2538 else if(r == aShowHideLocalPath)
2542 else if(r == aShowHideGtGraph)
2546 else if(r == aShowHideGPSGraph)
2550 else if(r == aShowHideOdomCacheOverlay)
2554 else if(r == aOrientationENU)
2558 else if(r == aMouseTracking)
2562 else if(r == aViewPlaneXY)
2566 else if(r == aViewPlaneXZ)
2570 else if(r == aViewPlaneYZ)