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);
95 void setColor(
const QColor & color,
const QString & valueName = QString(),
float value = 0.0f)
100 QBrush
b = this->brush();
104 QPen pen =
_line->pen();
105 pen.setColor(QColor(255-color.red(), 255-color.green(), 255-color.blue()));
117 this->setRect(-radius, -radius, radius*2.0
f, radius*2.0
f);
128 this->setPos(
pose.
x()*100.0f,-
pose.
z()*100.0f);
131 this->setPos(
pose.
y()*100.0f,-
pose.
z()*100.0f);
134 this->setPos(-
pose.
y()*100.0f,-
pose.
x()*100.0f);
142 float radius = this->rect().width()/2.0f;
164 this->setToolTip(
msg);
167 QGraphicsEllipseItem::hoverEnterEvent(event);
173 QGraphicsEllipseItem::hoverEnterEvent(event);
198 this->setToolTip(QString(
"%1 [%2] %3\n"
199 "longitude=%4 latitude=%5 altitude=%6m error=%7m bearing=%8deg")
203 QGraphicsEllipseItem::hoverEnterEvent(event);
222 this->setAcceptHoverEvents(
true);
228 QPen
p = this->pen();
238 this->setLine(poseA.
x()*100.0f, -poseA.
z()*100.0f, poseB.
x()*100.0f, -poseB.
z()*100.0f);
241 this->setLine(poseA.
y()*100.0f, -poseA.
z()*100.0f, poseB.
y()*100.0f, -poseB.
z()*100.0f);
244 this->setLine(-poseA.
y()*100.0f, -poseA.
x()*100.0f, -poseB.
y()*100.0f, -poseB.
x()*100.0f);
273 this->setToolTip(
str);
274 QPen pen = this->pen();
275 pen.setWidthF(pen.widthF()+2);
277 QGraphicsLineItem::hoverEnterEvent(event);
282 QPen pen = this->pen();
283 pen.setWidthF(pen.widthF()-2);
285 QGraphicsLineItem::hoverEnterEvent(event);
298 QGraphicsView(parent),
299 _nodeColor(Qt::blue),
300 _nodeOdomCacheColor(Qt::darkGreen),
301 _currentGoalColor(Qt::darkMagenta),
302 _neighborColor(Qt::blue),
303 _loopClosureColor(Qt::red),
304 _loopClosureLocalColor(Qt::yellow),
305 _loopClosureUserColor(Qt::red),
306 _loopClosureVirtualColor(Qt::magenta),
307 _neighborMergedColor(QColor(255,170,0)),
308 _landmarkColor(Qt::darkGreen),
309 _loopClosureRejectedColor(Qt::black),
310 _localPathColor(Qt::cyan),
311 _globalPathColor(Qt::darkMagenta),
312 _gtPathColor(Qt::gray),
313 _gpsPathColor(Qt::darkCyan),
314 _loopIntraSessionColor(Qt::red),
315 _loopInterSessionColor(Qt::green),
316 _intraInterSessionColors(
false),
317 _worldMapRotation(0.0
f),
327 _originReferential(0),
330 _loopClosureOutlierThr(0),
331 _maxLinkLength(0.02
f),
332 _orientationENU(
false),
333 _mouseTracking(
false),
335 _ensureFrameVisible(
true)
337 this->setScene(
new QGraphicsScene(
this));
338 this->setDragMode(QGraphicsView::ScrollHandDrag);
341 this->scene()->clear();
342 _world = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
343 _root = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
347 QGraphicsLineItem * item;
354 item = this->scene()->addLine(0,0,0,-100, QPen(QBrush(Qt::red),
_linkWidth));
356 item->setParentItem(
_root);
358 item = this->scene()->addLine(0,0,-100,0, QPen(QBrush(Qt::green),
_linkWidth));
360 item->setParentItem(
_root);
367 item = this->scene()->addLine(0,0,100,0, QPen(QBrush(Qt::red),
_linkWidth));
369 item->setParentItem(
_root);
371 item = this->scene()->addLine(0,0,0,-100, QPen(QBrush(Qt::blue),
_linkWidth));
373 item->setParentItem(
_root);
381 item = this->scene()->addLine(0,0,100,0, QPen(QBrush(Qt::green),
_linkWidth));
383 item->setParentItem(
_root);
385 item = this->scene()->addLine(0,0,0,-100, QPen(QBrush(Qt::blue),
_linkWidth));
387 item->setParentItem(
_root);
402 item = this->scene()->addLine(0,0,0,-50, QPen(QBrush(Qt::red),
_linkWidth));
403 item->setZValue(100);
404 item->setParentItem(
_root);
406 item = this->scene()->addLine(0,0,-50,0, QPen(QBrush(Qt::green),
_linkWidth));
407 item->setZValue(100);
408 item->setParentItem(
_root);
415 item = this->scene()->addLine(0,0,50,0, QPen(QBrush(Qt::red),
_linkWidth));
416 item->setZValue(100);
417 item->setParentItem(
_root);
419 item = this->scene()->addLine(0,0,0,-50, QPen(QBrush(Qt::blue),
_linkWidth));
420 item->setZValue(100);
421 item->setParentItem(
_root);
429 item = this->scene()->addLine(0,0,50,0, QPen(QBrush(Qt::green),
_linkWidth));
430 item->setZValue(100);
431 item->setParentItem(
_root);
433 item = this->scene()->addLine(0,0,0,-50, QPen(QBrush(Qt::blue),
_linkWidth));
434 item->setZValue(100);
435 item->setParentItem(
_root);
443 _localRadius = this->scene()->addEllipse(-0.0001,-0.0001,0.0001,0.0001);
449 _gridMap = this->scene()->addPixmap(QPixmap());
453 _graphRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
457 _globalPathRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
461 _localPathRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
465 _gtGraphRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
469 _gpsGraphRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
485 this->fitInView(this->sceneRect(), Qt::KeepAspectRatio);
499 const std::multimap<int, Link> & constraints,
500 const std::map<int, int> & mapIds,
501 const std::map<int, int> & weights,
502 const std::set<int> & odomCacheIds)
509 UDEBUG(
"poses=%d constraints=%d", (
int)poses.size(), (
int)constraints.size());
514 bool isOdomCache = odomCacheIds.find(
iter.key()) != odomCacheIds.end();
517 color = QColor(255-color.red(), 255-color.green(), 255-color.blue());
532 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
534 if(!
iter->second.isNull())
536 QMap<int, NodeItem*>::iterator itemIter =
_nodeItems.find(
iter->first);
540 itemIter.value()->show();
546 bool isOdomCache = odomCacheIds.find(
iter->first) != odomCacheIds.end();
549 color = QColor(255-color.red(), 255-color.green(), 255-color.blue());
557 this->scene()->addItem(item);
558 item->setZValue(
iter->first<0?21:20);
567 for(std::multimap<int, Link>::const_iterator
iter=constraints.begin();
iter!=constraints.end(); ++
iter)
573 std::map<int, Transform>::const_iterator jterA = poses.find(idFrom);
574 std::map<int, Transform>::const_iterator jterB = poses.find(idTo);
576 if(jterA != poses.end() && jterB != poses.end() &&
582 QMultiMap<int, LinkItem*>::iterator itemIter =
_linkItems.end();
586 while(itemIter.key() == idFrom && itemIter !=
_linkItems.end())
588 if(itemIter.value()->to() == idTo && itemIter.value()->type() ==
iter->second.type())
590 itemIter.value()->setPoses(poseA, poseB,
_viewPlane);
591 itemIter.value()->show();
592 linkItem = itemIter.value();
599 bool interSessionClosure =
false;
602 interSessionClosure = mapIds.at(jterA->first) != mapIds.at(jterB->first);
605 bool isLinkedToOdomCachePoses =
606 odomCacheIds.find(idFrom)!=odomCacheIds.end() ||
607 odomCacheIds.find(idTo)!=odomCacheIds.end();
609 if(isLinkedToOdomCachePoses)
611 _nodeItems.value(idFrom)->setZValue(odomCacheIds.find(idFrom)!=odomCacheIds.end()?24:23);
612 _nodeItems.value(idTo)->setZValue(odomCacheIds.find(idTo)!=odomCacheIds.end()?24:23);
621 QPen
p = linkItem->pen();
624 linkItem->setZValue(isLinkedToOdomCachePoses?22:10);
625 this->scene()->addItem(linkItem);
630 else if(linkItem && itemIter !=
_linkItems.end())
673 linkItem->setZValue(isLinkedToOdomCachePoses?22:interSessionClosure?6:7);
678 linkItem->setZValue(isLinkedToOdomCachePoses?22:7);
686 linkItem->setZValue(isLinkedToOdomCachePoses?22:interSessionClosure?8:9);
691 linkItem->setZValue(isLinkedToOdomCachePoses?22:9);
699 if(
iter->second.to() != idTo)
706 float linearError =
fabs(
iter->second.transform().getNorm() -
t.getNorm());
756 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
758 if(!odomCacheIds.empty())
765 QRectF rect = this->scene()->itemsBoundingRect();
766 this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
780 UDEBUG(
"poses=%d", (
int)poses.size());
792 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
794 if(!
iter->second.isNull())
800 itemIter.value()->show();
807 this->scene()->addItem(item);
815 if(
iter!=poses.begin())
817 std::map<int, Transform>::const_iterator iterPrevious =
iter;
819 Transform previousPose = iterPrevious->second;
823 QMultiMap<int, LinkItem*>::iterator linkIter =
_gtLinkItems.end();
827 while(linkIter.key() == iterPrevious->first && linkIter !=
_gtLinkItems.end())
829 if(linkIter.value()->to() ==
iter->first)
831 linkIter.value()->setPoses(previousPose, currentPose,
_viewPlane);
832 linkIter.value()->show();
833 linkItem = linkIter.value();
841 bool linkFound =
iter->first - iterPrevious->first == 1;
842 for(QMultiMap<int, LinkItem*>::iterator kter =
_linkItems.find(iterPrevious->first);
843 kter!=
_linkItems.end() && kter.key()==iterPrevious->first && !linkFound;
846 if(kter.value()->from() == iterPrevious->first && kter.value()->to() ==
iter->first)
856 QPen
p = linkItem->pen();
859 linkItem->setZValue(10);
860 this->scene()->addItem(linkItem);
901 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
905 QRectF rect = this->scene()->itemsBoundingRect();
906 this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
916 const std::map<int, Transform> & poses,
917 const std::map<int, GPS> & gpsValues)
923 UDEBUG(
"poses=%d", (
int)poses.size());
935 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
937 if(!
iter->second.isNull())
943 itemIter.value()->show();
949 UASSERT(gpsValues.find(
iter->first) != gpsValues.end());
951 this->scene()->addItem(item);
959 if(
iter!=poses.begin())
961 std::map<int, Transform>::const_iterator iterPrevious =
iter;
963 Transform previousPose = iterPrevious->second;
967 QMultiMap<int, LinkItem*>::iterator linkIter =
_gpsLinkItems.end();
971 while(linkIter.key() == iterPrevious->first && linkIter !=
_gpsLinkItems.end())
973 if(linkIter.value()->to() ==
iter->first)
975 linkIter.value()->setPoses(previousPose, currentPose,
_viewPlane);
976 linkIter.value()->show();
977 linkItem = linkIter.value();
987 QPen
p = linkItem->pen();
990 linkItem->setZValue(10);
991 this->scene()->addItem(linkItem);
1031 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1035 QRectF rect = this->scene()->itemsBoundingRect();
1036 this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
1048 qt.translate(-
t.o24()*100.0f, -
t.o14()*100.0f);
1050 qt.rotateRadians(-
t.theta());
1067 UASSERT(map8U.empty() || (!map8U.empty() && resolution > 0.0f));
1073 _gridMap->setTransform(QTransform::fromScale(resolution*100.0
f, -resolution*100.0
f),
true);
1075 _gridMap->setPixmap(QPixmap::fromImage(image));
1076 _gridMap->setPos(-yMin*100.0
f, -xMin*100.0
f);
1078 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1108 std::map<int,float>::const_iterator jter =
values.
find(
iter.key());
1111 float v = jter->second>
max?
max:jter->second;
1112 iter.
value()->setColor(QColor::fromHsvF(( invertedColorScale ?
v/
max : 1-
v/
max )*240.0
f/360.0
f, 1, 1, 1), valueName.c_str(), jter->second);
1121 UDEBUG(
"Set global path size=%d", (
int)globalPath.size());
1125 if(globalPath.size() >= 2)
1127 for(
unsigned int i=0;
i<globalPath.size()-1; ++
i)
1130 int idFrom = globalPath[
i].first;
1131 int idTo = globalPath[
i+1].first;
1133 QPen
p = item->pen();
1137 this->scene()->addItem(item);
1138 item->setZValue(15);
1154 UWARN(
"Current goal %d not found in the graph",
id);
1171 _localRadius->setRect(-radius*100, -radius*100, radius*200, radius*200);
1184 if(localPath.size() > 1)
1186 for(
unsigned int i=0;
i<localPath.size()-1; ++
i)
1188 int idFrom = localPath[
i]<localPath[
i+1]?localPath[
i]:localPath[
i+1];
1189 int idTo = localPath[
i]<localPath[
i+1]?localPath[
i+1]:localPath[
i];
1198 if(itemIter.value()->to() == idTo)
1201 itemIter.value()->show();
1212 QPen
p = item->pen();
1216 this->scene()->addItem(item);
1217 item->setZValue(16);
1246 UERROR(
"Unsupported highlight color index %d", highlightIndex);
1292 _root->resetTransform();
1296 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1303 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1327 if(!group.isEmpty())
1329 settings.beginGroup(group);
1331 settings.setValue(
"node_radius", (
double)this->
getNodeRadius());
1332 settings.setValue(
"link_width", (
double)this->
getLinkWidth());
1349 settings.setValue(
"gt_color", this->
getGTColor());
1350 settings.setValue(
"gps_color", this->
getGPSColor());
1367 settings.setValue(
"view_plane", (
int)this->
getViewPlane());
1369 if(!group.isEmpty())
1371 settings.endGroup();
1377 if(!group.isEmpty())
1379 settings.beginGroup(group);
1381 this->
setNodeRadius(settings.value(
"node_radius",
this->getNodeRadius()).toDouble());
1382 this->
setLinkWidth(settings.value(
"link_width",
this->getLinkWidth()).toDouble());
1383 this->
setNodeColor(settings.value(
"node_color",
this->getNodeColor()).value<QColor>());
1390 this->
setNeighborColor(settings.value(
"neighbor_color",
this->getNeighborColor()).value<QColor>());
1397 this->
setLocalPathColor(settings.value(
"local_path_color",
this->getLocalPathColor()).value<QColor>());
1398 this->
setGlobalPathColor(settings.value(
"global_path_color",
this->getGlobalPathColor()).value<QColor>());
1399 this->
setGTColor(settings.value(
"gt_color",
this->getGTColor()).value<QColor>());
1400 this->
setGPSColor(settings.value(
"gps_color",
this->getGPSColor()).value<QColor>());
1409 this->
setMaxLinkLength(settings.value(
"max_link_length",
this->getMaxLinkLength()).toDouble());
1419 if(!group.isEmpty())
1421 settings.endGroup();
1517 QList<QGraphicsItem*> items = this->scene()->items();
1518 for(
int i=0;
i<items.size(); ++
i)
1520 QGraphicsLineItem * line = qgraphicsitem_cast<QGraphicsLineItem *>(items[
i]);
1523 QPen pen = line->pen();
1678 UERROR(
"Unsupported highlight color index %d", index);
1747 UWARN(
"Grid map can be shown only with view plane is XY.");
1799 UWARN(
"ENU orientation can be set only with view plane is XY.");
1812 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1843 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
1885 if(event->angleDelta().y() < 0)
1887 this->
scale(0.95, 0.95);
1891 this->
scale(1.05, 1.05);
1897 QPointF scenePoint = mapToScene(event->pos());
1900 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1901 QToolTip::showText(event->globalPosition().toPoint(), QString(
"%1m %2m").
arg(-scenePoint.y()/100.0).
arg(-scenePoint.x()/100.0));
1903 QToolTip::showText(event->globalPos(), QString(
"%1m %2m").
arg(-scenePoint.y()/100.0).
arg(-scenePoint.x()/100.0));
1908 QToolTip::hideText();
1910 if (event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier) && event->buttons() & Qt::LeftButton) {
1915 this->
scale(0.98, 0.98);
1919 this->
scale(1.02, 1.02);
1926 QGraphicsView::mouseMoveEvent(event);
1931 QGraphicsItem *item = this->scene()->itemAt(mapToScene(event->pos()), QTransform());
1934 NodeItem *nodeItem = qgraphicsitem_cast<NodeItem*>(item);
1935 LinkItem *linkItem = qgraphicsitem_cast<LinkItem*>(item);
1936 if(nodeItem && nodeItem->parentItem() ==
_graphRoot && nodeItem->
id() != 0)
1940 else if(linkItem && linkItem->parentItem() ==
_graphRoot && linkItem->
from() != 0 && linkItem->
to() != 0)
1946 QGraphicsView::mousePressEvent(event);
1951 QGraphicsView::mousePressEvent(event);
1957 QPixmap pixmap(50, 50);
1959 return QIcon(pixmap);
1965 QAction * aScreenShot = menu.addAction(tr(
"Take a screenshot..."));
1966 QAction * aExportGridMap = menu.addAction(tr(
"Export grid map..."));
1967 aExportGridMap->setEnabled(!
_gridMap->pixmap().isNull());
1968 menu.addSeparator();
1973 QMenu * menuChangeHighlightingColors = menu.addMenu(tr(
"Set node highlighting colors..."));
1977 aChangeHighlightingColors[
i]->setIconVisibleInMenu(
true);
1979 aChangeNodeColor->setIconVisibleInMenu(
true);
1980 aChangeNodeOdomCacheColor->setIconVisibleInMenu(
true);
1981 aChangeCurrentGoalColor->setIconVisibleInMenu(
true);
1984 QMenu * menuLink = menu.addMenu(tr(
"Set link color..."));
1985 QAction * aChangeNeighborColor = menuLink->addAction(tr(
"Neighbor"));
1986 QAction * aChangeGlobalLoopColor = menuLink->addAction(tr(
"Global loop closure"));
1987 QAction * aChangeLocalLoopColor = menuLink->addAction(tr(
"Local loop closure"));
1988 QAction * aChangeUserLoopColor = menuLink->addAction(tr(
"User loop closure"));
1989 QAction * aChangeVirtualLoopColor = menuLink->addAction(tr(
"Virtual loop closure"));
1990 QAction * aChangeNeighborMergedColor = menuLink->addAction(tr(
"Neighbor merged"));
1991 QAction * aChangeLandmarkColor = menuLink->addAction(tr(
"Landmark"));
1992 QAction * aChangeRejectedLoopColor = menuLink->addAction(tr(
"Outlier loop closure"));
1993 QAction * aChangeRejectedLoopThr = menuLink->addAction(tr(
"Set outlier threshold..."));
1994 QAction * aChangeLocalPathColor = menuLink->addAction(tr(
"Local path"));
1995 QAction * aChangeGlobalPathColor = menuLink->addAction(tr(
"Global path"));
1996 QAction * aChangeGTColor = menuLink->addAction(tr(
"Ground truth"));
1997 QAction * aChangeGPSColor = menuLink->addAction(tr(
"GPS"));
1998 menuLink->addSeparator();
1999 QAction * aSetIntraInterSessionColors = menuLink->addAction(tr(
"Enable intra/inter-session colors"));
2000 QAction * aChangeIntraSessionLoopColor = menuLink->addAction(tr(
"Intra-session loop closure"));
2001 QAction * aChangeInterSessionLoopColor = menuLink->addAction(tr(
"Inter-session loop closure"));
2016 aChangeNeighborColor->setIconVisibleInMenu(
true);
2017 aChangeGlobalLoopColor->setIconVisibleInMenu(
true);
2018 aChangeLocalLoopColor->setIconVisibleInMenu(
true);
2019 aChangeUserLoopColor->setIconVisibleInMenu(
true);
2020 aChangeVirtualLoopColor->setIconVisibleInMenu(
true);
2021 aChangeNeighborMergedColor->setIconVisibleInMenu(
true);
2022 aChangeRejectedLoopColor->setIconVisibleInMenu(
true);
2023 aChangeLocalPathColor->setIconVisibleInMenu(
true);
2024 aChangeGlobalPathColor->setIconVisibleInMenu(
true);
2025 aChangeGTColor->setIconVisibleInMenu(
true);
2026 aChangeGPSColor->setIconVisibleInMenu(
true);
2027 aChangeIntraSessionLoopColor->setIconVisibleInMenu(
true);
2028 aChangeInterSessionLoopColor->setIconVisibleInMenu(
true);
2029 aSetIntraInterSessionColors->setCheckable(
true);
2032 menu.addSeparator();
2033 QAction * aSetNodeSize = menu.addAction(tr(
"Set node radius..."));
2034 QAction * aSetLinkSize = menu.addAction(tr(
"Set link width..."));
2035 QAction * aChangeMaxLinkLength = menu.addAction(tr(
"Set maximum link length..."));
2036 menu.addSeparator();
2037 QAction * aEnsureFrameVisible;
2038 QAction * aShowHideGridMap;
2039 QAction * aShowHideGraph;
2040 QAction * aShowHideGraphNodes;
2041 QAction * aShowHideOrigin;
2042 QAction * aShowHideReferential;
2043 QAction * aShowHideLocalRadius;
2044 QAction * aShowHideGlobalPath;
2045 QAction * aShowHideLocalPath;
2046 QAction * aShowHideGtGraph;
2047 QAction * aShowHideGPSGraph;
2048 QAction * aShowHideOdomCacheOverlay;
2049 QAction * aOrientationENU;
2050 QAction * aMouseTracking;
2051 QAction * aViewPlaneXY;
2052 QAction * aViewPlaneXZ;
2053 QAction * aViewPlaneYZ;
2054 aEnsureFrameVisible = menu.addAction(tr(
"Ensure Frame Visible"));
2055 aEnsureFrameVisible->setCheckable(
true);
2059 aShowHideGridMap = menu.addAction(tr(
"Hide grid map"));
2063 aShowHideGridMap = menu.addAction(tr(
"Show grid map"));
2068 aShowHideOrigin = menu.addAction(tr(
"Hide origin referential"));
2072 aShowHideOrigin = menu.addAction(tr(
"Show origin referential"));
2076 aShowHideReferential = menu.addAction(tr(
"Hide current referential"));
2080 aShowHideReferential = menu.addAction(tr(
"Show current referential"));
2084 aShowHideLocalRadius = menu.addAction(tr(
"Hide local radius"));
2088 aShowHideLocalRadius = menu.addAction(tr(
"Show local radius"));
2092 aShowHideGraph = menu.addAction(tr(
"Hide graph"));
2096 aShowHideGraph = menu.addAction(tr(
"Show graph"));
2100 aShowHideGraphNodes = menu.addAction(tr(
"Hide graph nodes"));
2104 aShowHideGraphNodes = menu.addAction(tr(
"Show graph nodes"));
2108 aShowHideGlobalPath = menu.addAction(tr(
"Hide global path"));
2112 aShowHideGlobalPath = menu.addAction(tr(
"Show global path"));
2116 aShowHideLocalPath = menu.addAction(tr(
"Hide local path"));
2120 aShowHideLocalPath = menu.addAction(tr(
"Show local path"));
2124 aShowHideGtGraph = menu.addAction(tr(
"Hide ground truth graph"));
2128 aShowHideGtGraph = menu.addAction(tr(
"Show ground truth graph"));
2132 aShowHideGPSGraph = menu.addAction(tr(
"Hide GPS graph"));
2136 aShowHideGPSGraph = menu.addAction(tr(
"Show GPS graph"));
2140 aShowHideOdomCacheOverlay = menu.addAction(tr(
"Hide odom cache overlay"));
2144 aShowHideOdomCacheOverlay = menu.addAction(tr(
"Show odom cache overlay"));
2146 aOrientationENU = menu.addAction(tr(
"ENU Orientation"));
2147 aOrientationENU->setCheckable(
true);
2149 aMouseTracking = menu.addAction(tr(
"Show mouse cursor position (m)"));
2150 aMouseTracking->setCheckable(
true);
2161 QMenu * viewPlaneMenu = menu.addMenu(
"View Plane...");
2162 aViewPlaneXY = viewPlaneMenu->addAction(
"XY");
2163 aViewPlaneXY->setCheckable(
true);
2165 aViewPlaneXZ = viewPlaneMenu->addAction(
"XZ");
2166 aViewPlaneXZ->setCheckable(
true);
2168 aViewPlaneYZ = viewPlaneMenu->addAction(
"YZ");
2169 aViewPlaneYZ->setCheckable(
true);
2172 menu.addSeparator();
2173 QAction * aRestoreDefaults = menu.addAction(tr(
"Restore defaults"));
2175 QAction * r = menu.exec(event->globalPos());
2176 int aChangeHighlightingColorIndex = 0;
2177 for(
int i=1;
i<aChangeHighlightingColors.size(); ++
i)
2179 if(r == aChangeHighlightingColors[
i]) {
2180 aChangeHighlightingColorIndex =
i;
2183 if(r == aScreenShot)
2188 #if QT_VERSION >= 0x050000
2189 filePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
2192 if(!dir.exists(filePath))
2194 filePath = QDir::homePath();
2196 filePath +=
"/graph.png";
2199 filePath = QFileDialog::getSaveFileName(
this, tr(
"Save figure to ..."), filePath,
"*.png *.xpm *.jpg *.pdf *.svg");
2201 filePath = QFileDialog::getSaveFileName(
this, tr(
"Save figure to ..."), filePath,
"*.png *.xpm *.jpg *.pdf");
2203 if(!filePath.isEmpty())
2205 if(QFileInfo(filePath).suffix() ==
"")
2220 this->scene()->clearSelection();
2221 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
2222 QSize sceneSize = this->scene()->sceneRect().size().toSize();
2224 if(QFileInfo(filePath).suffix().
compare(
"pdf") == 0)
2226 QPrinter printer(QPrinter::HighResolution);
2227 printer.setPageOrientation(QPageLayout::Portrait);
2228 printer.setOutputFileName( filePath );
2229 QPainter
p(&printer);
2230 scene()->render(&
p);
2233 else if(QFileInfo(filePath).suffix().
compare(
"svg") == 0)
2236 QSvgGenerator svgGen;
2238 svgGen.setFileName( filePath );
2239 svgGen.setSize(sceneSize);
2241 int borderH = sceneSize.width()/100;
2242 int borderV = sceneSize.height()/100;
2243 svgGen.setViewBox(QRect(-borderH, -borderV, sceneSize.width()+borderH*2, sceneSize.height()+borderV*2));
2244 svgGen.setTitle(tr(
"RTAB-Map graph"));
2245 svgGen.setDescription(tr(
"RTAB-Map map and graph"));
2247 QPainter painter( &svgGen );
2249 this->scene()->render(&painter);
2251 UERROR(
"RTAB-MAp is not built with Qt's SVG library, cannot save picture in svg format.");
2256 QImage image(sceneSize, QImage::Format_ARGB32);
2257 image.fill(Qt::transparent);
2258 QPainter painter(&image);
2260 this->scene()->render(&painter);
2263 image.save(filePath);
2267 QMessageBox::warning(
this,
2269 tr(
"Could not export in PNG (the scene may be too large %1x%2), try saving in SVG.").
arg(sceneSize.width()).
arg(sceneSize.height()));
2275 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
2278 QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
2283 else if(r == aExportGridMap)
2285 float xMin, yMin, cellSize;
2291 QString
path = QFileDialog::getSaveFileName(
2299 if(QFileInfo(
path).suffix() ==
"")
2306 QString yaml =
info.absolutePath() +
"/" +
info.baseName() +
".yaml";
2308 float occupancyThr = Parameters::defaultGridGlobalOccupancyThr();
2311 file.open (yaml.toStdString());
2312 file <<
"image: " <<
info.baseName().toStdString() <<
".pgm" << std::endl;
2313 file <<
"resolution: " << cellSize << std::endl;
2314 file <<
"origin: [" << xMin <<
", " << yMin <<
", 0.0]" << std::endl;
2315 file <<
"negate: 0" << std::endl;
2316 file <<
"occupied_thresh: " << occupancyThr << std::endl;
2317 file <<
"free_thresh: 0.196" << std::endl;
2322 QMessageBox::information(
this, tr(
"Export 2D map"), tr(
"Exported %1 and %2!").
arg(
path).
arg(yaml));
2325 else if(r == aSetIntraInterSessionColors)
2329 else if(r == aChangeRejectedLoopThr)
2332 double value = QInputDialog::getDouble(
this, tr(
"Loop closure outlier threshold"), tr(
"Value (m)"),
_loopClosureOutlierThr, 0.0, 1000.0, 2, &ok);
2338 else if(r == aChangeMaxLinkLength)
2341 double value = QInputDialog::getDouble(
this, tr(
"Maximum link length to be shown"), tr(
"Value (m)"),
_maxLinkLength, 0.0, 1000.0, 3, &ok);
2347 else if(r == aChangeNodeColor ||
2348 r == aChangeNodeOdomCacheColor ||
2349 r == aChangeCurrentGoalColor ||
2350 r == aChangeHighlightingColors[aChangeHighlightingColorIndex] ||
2351 r == aChangeNeighborColor ||
2352 r == aChangeGlobalLoopColor ||
2353 r == aChangeLocalLoopColor ||
2354 r == aChangeUserLoopColor ||
2355 r == aChangeVirtualLoopColor ||
2356 r == aChangeNeighborMergedColor ||
2357 r == aChangeRejectedLoopColor ||
2358 r == aChangeLocalPathColor ||
2359 r == aChangeGlobalPathColor ||
2360 r == aChangeGTColor ||
2361 r == aChangeGPSColor ||
2362 r == aChangeIntraSessionLoopColor ||
2363 r == aChangeInterSessionLoopColor)
2366 if(r == aChangeNodeColor)
2370 else if(r == aChangeNodeOdomCacheColor)
2374 else if(r == aChangeCurrentGoalColor)
2378 else if(r == aChangeHighlightingColors[aChangeHighlightingColorIndex])
2382 else if(r == aChangeGlobalLoopColor)
2386 else if(r == aChangeLocalLoopColor)
2390 else if(r == aChangeUserLoopColor)
2394 else if(r == aChangeVirtualLoopColor)
2398 else if(r == aChangeNeighborMergedColor)
2402 else if(r == aChangeLandmarkColor)
2406 else if(r == aChangeRejectedLoopColor)
2410 else if(r == aChangeLocalPathColor)
2414 else if(r == aChangeGlobalPathColor)
2418 else if(r == aChangeGTColor)
2422 else if(r == aChangeGPSColor)
2426 else if(r == aChangeIntraSessionLoopColor)
2430 else if(r == aChangeInterSessionLoopColor)
2438 color = QColorDialog::getColor(color,
this);
2442 if(r == aChangeNodeColor)
2446 else if(r == aChangeNodeOdomCacheColor)
2450 else if(r == aChangeCurrentGoalColor)
2454 else if(r == aChangeHighlightingColors[aChangeHighlightingColorIndex])
2458 else if(r == aChangeGlobalLoopColor)
2462 else if(r == aChangeLocalLoopColor)
2466 else if(r == aChangeUserLoopColor)
2470 else if(r == aChangeVirtualLoopColor)
2474 else if(r == aChangeNeighborMergedColor)
2478 else if(r == aChangeLandmarkColor)
2482 else if(r == aChangeRejectedLoopColor)
2486 else if(r == aChangeLocalPathColor)
2490 else if(r == aChangeGlobalPathColor)
2494 else if(r == aChangeGTColor)
2498 else if(r == aChangeGPSColor)
2502 else if(r == aChangeIntraSessionLoopColor)
2506 else if(r == aChangeInterSessionLoopColor)
2520 else if(r == aSetNodeSize)
2523 double value = QInputDialog::getDouble(
this, tr(
"Node radius"), tr(
"Radius (m)"),
_nodeRadius, 0.001, 100, 3, &ok);
2529 else if(r == aSetLinkSize)
2532 double value = QInputDialog::getDouble(
this, tr(
"Link width"), tr(
"Width (m)"),
_linkWidth, 0, 100, 2, &ok);
2538 else if(r == aEnsureFrameVisible)
2542 else if(r == aShowHideGridMap)
2550 else if(r == aShowHideOrigin)
2554 else if(r == aShowHideReferential)
2558 else if(r == aShowHideLocalRadius)
2562 else if(r == aRestoreDefaults)
2566 else if(r == aShowHideGraph)
2570 else if(r == aShowHideGraphNodes)
2574 else if(r == aShowHideGlobalPath)
2578 else if(r == aShowHideLocalPath)
2582 else if(r == aShowHideGtGraph)
2586 else if(r == aShowHideGPSGraph)
2590 else if(r == aShowHideOdomCacheOverlay)
2594 else if(r == aOrientationENU)
2598 else if(r == aMouseTracking)
2602 else if(r == aViewPlaneXY)
2606 else if(r == aViewPlaneXZ)
2610 else if(r == aViewPlaneYZ)