GraphViewer.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of the Universite de Sherbrooke nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
29 
30 #include <QGraphicsView>
31 #include <QVBoxLayout>
32 #include <QGraphicsScene>
33 #include <QGraphicsEllipseItem>
34 #include <QtGui/QWheelEvent>
35 #include <QGraphicsSceneHoverEvent>
36 #include <QMenu>
37 #include <QtGui/QDesktopServices>
38 #include <QtGui/QContextMenuEvent>
39 #include <QColorDialog>
40 #ifdef QT_SVG_LIB
41 #include <QtSvg/QSvgGenerator>
42 #endif
43 #include <QInputDialog>
44 #include <QMessageBox>
45 
46 #include <QtCore/QDir>
47 #include <QtCore/QDateTime>
48 #include <QtCore/QUrl>
49 
50 #include <rtabmap/core/util3d.h>
52 #include <rtabmap/utilite/UCv2Qt.h>
53 #include <rtabmap/utilite/UStl.h>
55 #include <rtabmap/utilite/UTimer.h>
56 
57 namespace rtabmap {
58 
59 class NodeItem: public QGraphicsEllipseItem
60 {
61 public:
62  // in meter
63  NodeItem(int id, int mapId, const Transform & pose, float radius) :
64  QGraphicsEllipseItem(QRectF(-radius*100.0f,-radius*100.0f,radius*100.0f*2.0f,radius*100.0f*2.0f)),
65  _id(id),
66  _mapId(mapId),
67  _pose(pose),
68  _line(0)
69  {
70  this->setPos(-pose.y()*100.0f,-pose.x()*100.0f);
71  this->setBrush(pen().color());
72  this->setAcceptHoverEvents(true);
73  float r,p,yaw;
74  pose.getEulerAngles(r, p, yaw);
75  radius*=100.0f;
76  _line = new QGraphicsLineItem(0,0,-radius*sin(yaw),-radius*cos(yaw), this);
77  }
78  virtual ~NodeItem() {}
79 
80  void setColor(const QColor & color)
81  {
82  QPen p = this->pen();
83  p.setColor(color);
84  this->setPen(p);
85  QBrush b = this->brush();
86  b.setColor(color);
87  this->setBrush(b);
88 
89  _line->setPen(QPen(QColor(255-color.red(), 255-color.green(), 255-color.blue())));
90  }
91 
92  void setRadius(float radius)
93  {
94  float r,p,yaw;
95  _pose.getEulerAngles(r, p, yaw);
96  radius*=100.0f;
97  this->setRect(-radius, -radius, radius*2.0f, radius*2.0f);
98  _line->setLine(0,0,-radius*sin(yaw),-radius*cos(yaw));
99  }
100 
101  int id() const {return _id;};
102  int mapId() const {return _mapId;}
103  const Transform & pose() const {return _pose;}
104  void setPose(const Transform & pose) {this->setPos(-pose.y()*100.0f,-pose.x()*100.0f); _pose=pose;}
105 
106 protected:
107  virtual void hoverEnterEvent ( QGraphicsSceneHoverEvent * event )
108  {
109  this->setToolTip(QString("%1 [%2] %3").arg(_id).arg(_mapId).arg(_pose.prettyPrint().c_str()));
110  this->setScale(2);
111  QGraphicsEllipseItem::hoverEnterEvent(event);
112  }
113 
114  virtual void hoverLeaveEvent ( QGraphicsSceneHoverEvent * event )
115  {
116  this->setScale(1);
117  QGraphicsEllipseItem::hoverEnterEvent(event);
118  }
119 
120 private:
121  int _id;
122  int _mapId;
124  QGraphicsLineItem * _line;
125 };
126 
127 class NodeGPSItem: public NodeItem
128 {
129 public:
130  NodeGPSItem(int id, int mapId, const Transform & pose, float radius, const GPS & gps) :
131  NodeItem(id, mapId, pose, radius),
132  _gps(gps)
133  {
134  }
135  virtual ~NodeGPSItem() {}
136 protected:
137  virtual void hoverEnterEvent ( QGraphicsSceneHoverEvent * event )
138  {
139  this->setToolTip(QString("%1 [%2] %3\n"
140  "longitude=%4 latitude=%5 altitude=%6m error=%7m bearing=%8deg")
141  .arg(id()).arg(mapId()).arg(pose().prettyPrint().c_str())
142  .arg(_gps.longitude()).arg(_gps.latitude()).arg(_gps.altitude()).arg(_gps.error()).arg(_gps.bearing()));
143  this->setScale(2);
144  QGraphicsEllipseItem::hoverEnterEvent(event);
145  }
146 private:
148 };
149 
150 class LinkItem: public QGraphicsLineItem
151 {
152 public:
153  // in meter
154  LinkItem(int from, int to, const Transform & poseA, const Transform & poseB, const Link & link, bool interSessionClosure) :
155  QGraphicsLineItem(-poseA.y()*100.0f, -poseA.x()*100.0f, -poseB.y()*100.0f, -poseB.x()*100.0f),
156  _from(from),
157  _to(to),
158  _poseA(poseA),
159  _poseB(poseB),
160  _link(link),
161  _interSession(interSessionClosure)
162  {
163  this->setAcceptHoverEvents(true);
164  }
165  virtual ~LinkItem() {}
166 
167  void setColor(const QColor & color)
168  {
169  QPen p = this->pen();
170  p.setColor(color);
171  this->setPen(p);
172  }
173 
174  void setPoses(const Transform & poseA, const Transform & poseB)
175  {
176  this->setLine(-poseA.y()*100.0f, -poseA.x()*100.0f, -poseB.y()*100.0f, -poseB.x()*100.0f);
177  _poseA = poseA;
178  _poseB = poseB;
179  }
180 
181  const Transform & getPoseA() const
182  {
183  return _poseA;
184  }
185  const Transform & getPoseB() const
186  {
187  return _poseB;
188  }
189 
190  Link::Type linkType() const {return _link.type();}
191  bool isInterSession() const {return _interSession;}
192  int from() const {return _from;}
193  int to() const {return _to;}
194 
195 protected:
196  virtual void hoverEnterEvent ( QGraphicsSceneHoverEvent * event )
197  {
198  QString str = QString("%1->%2 (%3 m)").arg(_from).arg(_to).arg(_poseA.getDistance(_poseB));
199  if(!_link.transform().isNull())
200  {
201  str.append(QString("\n%1\n%2 %3").arg(_link.transform().prettyPrint().c_str()).arg(_link.transVariance()).arg(_link.rotVariance()));
202  }
203  this->setToolTip(str);
204  QPen pen = this->pen();
205  pen.setWidthF(pen.widthF()+2);
206  this->setPen(pen);
207  QGraphicsLineItem::hoverEnterEvent(event);
208  }
209 
210  virtual void hoverLeaveEvent ( QGraphicsSceneHoverEvent * event )
211  {
212  QPen pen = this->pen();
213  pen.setWidthF(pen.widthF()-2);
214  this->setPen(pen);
215  QGraphicsLineItem::hoverEnterEvent(event);
216  }
217 
218 private:
219  int _from;
220  int _to;
225 };
226 
227 GraphViewer::GraphViewer(QWidget * parent) :
228  QGraphicsView(parent),
229  _nodeColor(Qt::blue),
230  _currentGoalColor(Qt::darkMagenta),
231  _neighborColor(Qt::blue),
232  _loopClosureColor(Qt::red),
233  _loopClosureLocalColor(Qt::yellow),
234  _loopClosureUserColor(Qt::red),
235  _loopClosureVirtualColor(Qt::magenta),
236  _neighborMergedColor(QColor(255,170,0)),
237  _loopClosureRejectedColor(Qt::black),
238  _localPathColor(Qt::cyan),
239  _globalPathColor(Qt::darkMagenta),
240  _gtPathColor(Qt::gray),
241  _gpsPathColor(Qt::darkCyan),
242  _loopIntraSessionColor(Qt::red),
243  _loopInterSessionColor(Qt::green),
244  _intraInterSessionColors(false),
245  _root(0),
246  _graphRoot(0),
247  _globalPathRoot(0),
248  _nodeVisible(true),
249  _nodeRadius(0.01f),
250  _linkWidth(0),
251  _gridMap(0),
252  _referential(0),
253  _originReferential(0),
254  _gridCellSize(0.0f),
255  _localRadius(0),
256  _loopClosureOutlierThr(0),
257  _maxLinkLength(0.02f),
258  _orientationENU(false)
259 {
260  this->setScene(new QGraphicsScene(this));
261  this->setDragMode(QGraphicsView::ScrollHandDrag);
262  _workingDirectory = QDir::homePath();
263 
264  this->scene()->clear();
265  _root = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
266 
267  // add referential
268  _originReferential = new QGraphicsItemGroup();
269  this->scene()->addItem(_originReferential); // ownership transfered
270  QGraphicsLineItem * item = this->scene()->addLine(0,0,0,-100, QPen(QBrush(Qt::red), _linkWidth));
271  item->setZValue(100);
272  item->setParentItem(_root);
273  _originReferential->addToGroup(item);
274  item = this->scene()->addLine(0,0,-100,0, QPen(QBrush(Qt::green), _linkWidth));
275  item->setZValue(100);
276  item->setParentItem(_root);
277  _originReferential->addToGroup(item);
278 
279  // current pose
280  _referential = new QGraphicsItemGroup();
281  this->scene()->addItem(_referential); // ownership transfered
282  item = this->scene()->addLine(0,0,0,-50, QPen(QBrush(Qt::red), _linkWidth));
283  item->setZValue(100);
284  item->setParentItem(_root);
285  _referential->addToGroup(item);
286  item = this->scene()->addLine(0,0,-50,0, QPen(QBrush(Qt::green), _linkWidth));
287  item->setZValue(100);
288  item->setParentItem(_root);
289  _referential->addToGroup(item);
290 
291  _localRadius = this->scene()->addEllipse(-0.0001,-0.0001,0.0001,0.0001);
292  _localRadius->setZValue(1);
293  _localRadius->setParentItem(_root);
294  _localRadius->setVisible(false);
295  _localRadius->setPen(QPen(Qt::DashLine));
296 
297  _gridMap = this->scene()->addPixmap(QPixmap());
298  _gridMap->setZValue(0);
299  _gridMap->setParentItem(_root);
300 
301  _graphRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
302  _graphRoot->setZValue(4);
303  _graphRoot->setParentItem(_root);
304 
305  _globalPathRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
306  _globalPathRoot->setZValue(8);
307  _globalPathRoot->setParentItem(_root);
308 
309  _localPathRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
310  _localPathRoot->setZValue(9);
311  _localPathRoot->setParentItem(_root);
312 
313  _gtGraphRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
314  _gtGraphRoot->setZValue(2);
315  _gtGraphRoot->setParentItem(_root);
316 
317  _gpsGraphRoot = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
318  _gpsGraphRoot->setZValue(3);
319  _gpsGraphRoot->setParentItem(_root);
320 
321  this->restoreDefaults();
322 
323  this->fitInView(this->sceneRect(), Qt::KeepAspectRatio);
324 }
325 
327 {
328 }
329 
330 void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
331  const std::multimap<int, Link> & constraints,
332  const std::map<int, int> & mapIds)
333 {
334  UTimer timer;
335  bool wasVisible = _graphRoot->isVisible();
336  _graphRoot->show();
337 
338  bool wasEmpty = _nodeItems.size() == 0 && _linkItems.size() == 0;
339  UDEBUG("poses=%d constraints=%d", (int)poses.size(), (int)constraints.size());
340  //Hide nodes and links
341  for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
342  {
343  iter.value()->hide();
344  iter.value()->setColor(_nodeColor); // reset color
345  }
346  for(QMultiMap<int, LinkItem*>::iterator iter = _linkItems.begin(); iter!=_linkItems.end(); ++iter)
347  {
348  iter.value()->hide();
349  }
350 
351  for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
352  {
353  if(!iter->second.isNull())
354  {
355  QMap<int, NodeItem*>::iterator itemIter = _nodeItems.find(iter->first);
356  if(itemIter != _nodeItems.end())
357  {
358  itemIter.value()->setPose(iter->second);
359  itemIter.value()->show();
360  }
361  else
362  {
363  // create node item
364  const Transform & pose = iter->second;
365  NodeItem * item = new NodeItem(iter->first, uContains(mapIds, iter->first)?mapIds.at(iter->first):-1, pose, _nodeRadius);
366  this->scene()->addItem(item);
367  item->setZValue(20);
368  item->setColor(_nodeColor);
369  item->setParentItem(_graphRoot);
370  item->setVisible(_nodeVisible);
371  _nodeItems.insert(iter->first, item);
372  }
373  }
374  }
375 
376  for(std::multimap<int, Link>::const_iterator iter=constraints.begin(); iter!=constraints.end(); ++iter)
377  {
378  // make the first id the smallest one
379  int idFrom = iter->first<iter->second.to()?iter->first:iter->second.to();
380  int idTo = iter->first<iter->second.to()?iter->second.to():iter->first;
381 
382  std::map<int, Transform>::const_iterator jterA = poses.find(idFrom);
383  std::map<int, Transform>::const_iterator jterB = poses.find(idTo);
384  LinkItem * linkItem = 0;
385  if(jterA != poses.end() && jterB != poses.end() &&
386  _nodeItems.contains(iter->first) && _nodeItems.contains(idTo))
387  {
388  const Transform & poseA = jterA->second;
389  const Transform & poseB = jterB->second;
390 
391  QMultiMap<int, LinkItem*>::iterator itemIter = _linkItems.end();
392  if(_linkItems.contains(idFrom))
393  {
394  itemIter = _linkItems.find(iter->first);
395  while(itemIter.key() == idFrom && itemIter != _linkItems.end())
396  {
397  if(itemIter.value()->to() == idTo)
398  {
399  itemIter.value()->setPoses(poseA, poseB);
400  itemIter.value()->show();
401  linkItem = itemIter.value();
402  break;
403  }
404  ++itemIter;
405  }
406  }
407 
408  bool interSessionClosure = false;
409  if(uContains(mapIds, jterA->first) && uContains(mapIds, jterB->first))
410  {
411  interSessionClosure = mapIds.at(jterA->first) != mapIds.at(jterB->first);
412  }
413 
414  if(poseA.getDistance(poseB) > _maxLinkLength)
415  {
416  if(linkItem == 0)
417  {
418  //create a link item
419  linkItem = new LinkItem(idFrom, idTo, poseA, poseB, iter->second, interSessionClosure);
420  QPen p = linkItem->pen();
421  p.setWidthF(_linkWidth*100.0f);
422  linkItem->setPen(p);
423  linkItem->setZValue(10);
424  this->scene()->addItem(linkItem);
425  linkItem->setParentItem(_graphRoot);
426  _linkItems.insert(idFrom, linkItem);
427  }
428  }
429  else if(linkItem && itemIter != _linkItems.end())
430  {
431  // erase small links
432  _linkItems.erase(itemIter);
433  delete linkItem;
434  linkItem = 0;
435  }
436 
437  if(linkItem)
438  {
439  //update color
440  if(iter->second.type() == Link::kNeighbor)
441  {
442  linkItem->setColor(_neighborColor);
443  }
444  else if(iter->second.type() == Link::kVirtualClosure)
445  {
447  }
448  else if(iter->second.type() == Link::kNeighborMerged)
449  {
450  linkItem->setColor(_neighborMergedColor);
451  }
452  else if(iter->second.type() == Link::kUserClosure)
453  {
454  linkItem->setColor(_loopClosureUserColor);
455  }
456  else if(iter->second.type() == Link::kLocalSpaceClosure || iter->second.type() == Link::kLocalTimeClosure)
457  {
459  {
460  linkItem->setColor(interSessionClosure?_loopInterSessionColor:_loopIntraSessionColor);
461  linkItem->setZValue(interSessionClosure?6:7);
462  }
463  else
464  {
465  linkItem->setColor(_loopClosureLocalColor);
466  linkItem->setZValue(7);
467  }
468  }
469  else
470  {
472  {
473  linkItem->setColor(interSessionClosure?_loopInterSessionColor:_loopIntraSessionColor);
474  linkItem->setZValue(interSessionClosure?8:9);
475  }
476  else
477  {
478  linkItem->setColor(_loopClosureColor);
479  linkItem->setZValue(9);
480  }
481  }
482 
483  //rejected loop closures
484  if(_loopClosureOutlierThr > 0.0f)
485  {
486  Transform t = poseA.inverse()*poseB;
487  if(iter->second.to() != idTo)
488  {
489  t = t.inverse();
490  }
491  if(iter->second.type() != Link::kNeighbor &&
492  iter->second.type() != Link::kNeighborMerged)
493  {
494  float linearError = uMax3(
495  fabs(iter->second.transform().x() - t.x()),
496  fabs(iter->second.transform().y() - t.y()),
497  fabs(iter->second.transform().z() - t.z()));
498  if(linearError > _loopClosureOutlierThr)
499  {
501  }
502  }
503  }
504  }
505  }
506  }
507 
508  //remove not used nodes and links
509  for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end();)
510  {
511  if(!iter.value()->isVisible())
512  {
513  delete iter.value();
514  iter = _nodeItems.erase(iter);
515  }
516  else
517  {
518  ++iter;
519  }
520  }
521  for(QMultiMap<int, LinkItem*>::iterator iter = _linkItems.begin(); iter!=_linkItems.end();)
522  {
523  if(!iter.value()->isVisible())
524  {
525  delete iter.value();
526  iter = _linkItems.erase(iter);
527  }
528  else
529  {
530  ++iter;
531  }
532  }
533 
534  if(_nodeItems.size())
535  {
536  (--_nodeItems.end()).value()->setColor(Qt::green);
537  }
538 
539  this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
540 
541  if(wasEmpty)
542  {
543  QRectF rect = this->scene()->itemsBoundingRect();
544  this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
545  }
546 
547  _graphRoot->setVisible(wasVisible);
548 
549  UDEBUG("_nodeItems=%d, _linkItems=%d, timer=%fs", _nodeItems.size(), _linkItems.size(), timer.ticks());
550 }
551 
552 void GraphViewer::updateGTGraph(const std::map<int, Transform> & poses)
553 {
554  UTimer timer;
555  bool wasVisible = _gtGraphRoot->isVisible();
556  _gtGraphRoot->show();
557  bool wasEmpty = _gtNodeItems.size() == 0 && _gtLinkItems.size() == 0;
558  UDEBUG("poses=%d", (int)poses.size());
559  //Hide nodes and links
560  for(QMap<int, NodeItem*>::iterator iter = _gtNodeItems.begin(); iter!=_gtNodeItems.end(); ++iter)
561  {
562  iter.value()->hide();
563  iter.value()->setColor(_gtPathColor); // reset color
564  }
565  for(QMultiMap<int, LinkItem*>::iterator iter = _gtLinkItems.begin(); iter!=_gtLinkItems.end(); ++iter)
566  {
567  iter.value()->hide();
568  }
569 
570  for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
571  {
572  if(!iter->second.isNull())
573  {
574  QMap<int, NodeItem*>::iterator itemIter = _gtNodeItems.find(iter->first);
575  if(itemIter != _gtNodeItems.end())
576  {
577  itemIter.value()->setPose(iter->second);
578  itemIter.value()->show();
579  }
580  else
581  {
582  // create node item
583  const Transform & pose = iter->second;
584  NodeItem * item = new NodeItem(iter->first, -1, pose, _nodeRadius);
585  this->scene()->addItem(item);
586  item->setZValue(20);
587  item->setColor(_gtPathColor);
588  item->setParentItem(_gtGraphRoot);
589  item->setVisible(_nodeVisible);
590  _gtNodeItems.insert(iter->first, item);
591  }
592 
593  if(iter!=poses.begin())
594  {
595  std::map<int, Transform>::const_iterator iterPrevious = iter;
596  --iterPrevious;
597  Transform previousPose = iterPrevious->second;
598  Transform currentPose = iter->second;
599 
600  LinkItem * linkItem = 0;
601  QMultiMap<int, LinkItem*>::iterator linkIter = _gtLinkItems.end();
602  if(_gtLinkItems.contains(iterPrevious->first))
603  {
604  linkIter = _gtLinkItems.find(iter->first);
605  while(linkIter.key() == iterPrevious->first && linkIter != _gtLinkItems.end())
606  {
607  if(linkIter.value()->to() == iter->first)
608  {
609  linkIter.value()->setPoses(previousPose, currentPose);
610  linkIter.value()->show();
611  linkItem = linkIter.value();
612  break;
613  }
614  ++linkIter;
615  }
616  }
617  if(linkItem == 0)
618  {
619  //create a link item
620  linkItem = new LinkItem(iterPrevious->first, iter->first, previousPose, currentPose, Link(), 1);
621  QPen p = linkItem->pen();
622  p.setWidthF(_linkWidth*100.0f);
623  linkItem->setPen(p);
624  linkItem->setZValue(10);
625  this->scene()->addItem(linkItem);
626  linkItem->setParentItem(_gtGraphRoot);
627  _gtLinkItems.insert(iterPrevious->first, linkItem);
628  }
629  if(linkItem)
630  {
631  linkItem->setColor(_gtPathColor);
632  }
633  }
634  }
635  }
636 
637  //remove not used nodes and links
638  for(QMap<int, NodeItem*>::iterator iter = _gtNodeItems.begin(); iter!=_gtNodeItems.end();)
639  {
640  if(!iter.value()->isVisible())
641  {
642  delete iter.value();
643  iter = _gtNodeItems.erase(iter);
644  }
645  else
646  {
647  ++iter;
648  }
649  }
650  for(QMultiMap<int, LinkItem*>::iterator iter = _gtLinkItems.begin(); iter!=_gtLinkItems.end();)
651  {
652  if(!iter.value()->isVisible())
653  {
654  delete iter.value();
655  iter = _gtLinkItems.erase(iter);
656  }
657  else
658  {
659  ++iter;
660  }
661  }
662 
663  if(_gtNodeItems.size() || _gtLinkItems.size())
664  {
665  this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
666 
667  if(wasEmpty)
668  {
669  QRectF rect = this->scene()->itemsBoundingRect();
670  this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
671  }
672  }
673 
674  _gtGraphRoot->setVisible(wasVisible);
675 
676  UDEBUG("_gtNodeItems=%d, _gtLinkItems=%d timer=%fs", _gtNodeItems.size(), _gtLinkItems.size(), timer.ticks());
677 }
678 
680  const std::map<int, Transform> & poses,
681  const std::map<int, GPS> & gpsValues)
682 {
683  UTimer timer;
684  bool wasVisible = _gpsGraphRoot->isVisible();
685  _gpsGraphRoot->show();
686  bool wasEmpty = _gpsNodeItems.size() == 0 && _gpsNodeItems.size() == 0;
687  UDEBUG("poses=%d", (int)poses.size());
688  //Hide nodes and links
689  for(QMap<int, NodeItem*>::iterator iter = _gpsNodeItems.begin(); iter!=_gpsNodeItems.end(); ++iter)
690  {
691  iter.value()->hide();
692  iter.value()->setColor(_gpsPathColor); // reset color
693  }
694  for(QMultiMap<int, LinkItem*>::iterator iter = _gpsLinkItems.begin(); iter!=_gpsLinkItems.end(); ++iter)
695  {
696  iter.value()->hide();
697  }
698 
699  for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
700  {
701  if(!iter->second.isNull())
702  {
703  QMap<int, NodeItem*>::iterator itemIter = _gpsNodeItems.find(iter->first);
704  if(itemIter != _gpsNodeItems.end())
705  {
706  itemIter.value()->setPose(iter->second);
707  itemIter.value()->show();
708  }
709  else
710  {
711  // create node item
712  const Transform & pose = iter->second;
713  UASSERT(gpsValues.find(iter->first) != gpsValues.end());
714  NodeItem * item = new NodeGPSItem(iter->first, -1, pose, _nodeRadius, gpsValues.at(iter->first));
715  this->scene()->addItem(item);
716  item->setZValue(20);
717  item->setColor(_gpsPathColor);
718  item->setParentItem(_gpsGraphRoot);
719  item->setVisible(_nodeVisible);
720  _gpsNodeItems.insert(iter->first, item);
721  }
722 
723  if(iter!=poses.begin())
724  {
725  std::map<int, Transform>::const_iterator iterPrevious = iter;
726  --iterPrevious;
727  Transform previousPose = iterPrevious->second;
728  Transform currentPose = iter->second;
729 
730  LinkItem * linkItem = 0;
731  QMultiMap<int, LinkItem*>::iterator linkIter = _gpsLinkItems.end();
732  if(_gpsLinkItems.contains(iterPrevious->first))
733  {
734  linkIter = _gpsLinkItems.find(iter->first);
735  while(linkIter.key() == iterPrevious->first && linkIter != _gpsLinkItems.end())
736  {
737  if(linkIter.value()->to() == iter->first)
738  {
739  linkIter.value()->setPoses(previousPose, currentPose);
740  linkIter.value()->show();
741  linkItem = linkIter.value();
742  break;
743  }
744  ++linkIter;
745  }
746  }
747  if(linkItem == 0)
748  {
749  //create a link item
750  linkItem = new LinkItem(iterPrevious->first, iter->first, previousPose, currentPose, Link(), 1);
751  QPen p = linkItem->pen();
752  p.setWidthF(_linkWidth*100.0f);
753  linkItem->setPen(p);
754  linkItem->setZValue(10);
755  this->scene()->addItem(linkItem);
756  linkItem->setParentItem(_gpsGraphRoot);
757  _gpsLinkItems.insert(iterPrevious->first, linkItem);
758  }
759  if(linkItem)
760  {
761  linkItem->setColor(_gpsPathColor);
762  }
763  }
764  }
765  }
766 
767  //remove not used nodes and links
768  for(QMap<int, NodeItem*>::iterator iter = _gpsNodeItems.begin(); iter!=_gpsNodeItems.end();)
769  {
770  if(!iter.value()->isVisible())
771  {
772  delete iter.value();
773  iter = _gpsNodeItems.erase(iter);
774  }
775  else
776  {
777  ++iter;
778  }
779  }
780  for(QMultiMap<int, LinkItem*>::iterator iter = _gpsLinkItems.begin(); iter!=_gpsLinkItems.end();)
781  {
782  if(!iter.value()->isVisible())
783  {
784  delete iter.value();
785  iter = _gpsLinkItems.erase(iter);
786  }
787  else
788  {
789  ++iter;
790  }
791  }
792 
793  if(_gpsNodeItems.size() || _gpsLinkItems.size())
794  {
795  this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
796 
797  if(wasEmpty)
798  {
799  QRectF rect = this->scene()->itemsBoundingRect();
800  this->fitInView(rect.adjusted(-rect.width()/2.0f, -rect.height()/2.0f, rect.width()/2.0f, rect.height()/2.0f), Qt::KeepAspectRatio);
801  }
802  }
803 
804  _gpsGraphRoot->setVisible(wasVisible);
805 
806  UDEBUG("_gpsNodeItems=%d, _gpsLinkItems=%d timer=%fs", _gpsNodeItems.size(), _gpsLinkItems.size(), timer.ticks());
807 }
808 
810 {
811  QTransform qt(t.r11(), t.r12(), t.r21(), t.r22(), -t.o24()*100.0f, -t.o14()*100.0f);
812  _referential->setTransform(qt);
813  _localRadius->setTransform(qt);
814 
815  this->ensureVisible(_referential);
816  if(_localRadius->isVisible())
817  {
818  this->ensureVisible(_localRadius, 0, 0);
819  }
820 }
821 
822 void GraphViewer::updateMap(const cv::Mat & map8U, float resolution, float xMin, float yMin)
823 {
824  UASSERT(map8U.empty() || (!map8U.empty() && resolution > 0.0f));
825  if(!map8U.empty())
826  {
827  _gridCellSize = resolution;
828  QImage image = uCvMat2QImage(map8U, false);
829  _gridMap->resetTransform();
830  _gridMap->setTransform(QTransform::fromScale(resolution*100.0f, -resolution*100.0f), true);
831  _gridMap->setRotation(90);
832  _gridMap->setPixmap(QPixmap::fromImage(image));
833  _gridMap->setPos(-yMin*100.0f, -xMin*100.0f);
834  this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
835  }
836  else
837  {
838  this->clearMap();
839  }
840 }
841 
842 void GraphViewer::updatePosterior(const std::map<int, float> & posterior, float max)
843 {
844  //find max
845  if(max <= 0.0f)
846  {
847  for(std::map<int, float>::const_iterator iter = posterior.begin(); iter!=posterior.end(); ++iter)
848  {
849  if(iter->first > 0 && iter->second>max)
850  {
851  max = iter->second;
852  }
853  }
854  }
855  if(max > 0.0f)
856  {
857  for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
858  {
859  std::map<int,float>::const_iterator jter = posterior.find(iter.key());
860  if(jter != posterior.end())
861  {
862  float v = jter->second>max?max:jter->second;
863  iter.value()->setColor(QColor::fromHsvF((1-v/max)*240.0f/360.0f, 1, 1, 1)); //0=red 240=blue
864  }
865  else
866  {
867  iter.value()->setColor(QColor::fromHsvF(240.0f/360.0f, 1, 1, 1)); // blue
868  }
869  }
870  }
871 }
872 
873 void GraphViewer::setGlobalPath(const std::vector<std::pair<int, Transform> > & globalPath)
874 {
875  UDEBUG("Set global path size=%d", (int)globalPath.size());
876  qDeleteAll(_globalPathLinkItems);
877  _globalPathLinkItems.clear();
878 
879  if(globalPath.size() >= 2)
880  {
881  for(unsigned int i=0; i<globalPath.size()-1; ++i)
882  {
883  //create a link item
884  int idFrom = globalPath[i].first;
885  int idTo = globalPath[i+1].first;
886  LinkItem * item = new LinkItem(idFrom, idTo, globalPath[i].second, globalPath[i+1].second, Link(), false);
887  QPen p = item->pen();
888  p.setWidthF(_linkWidth*100.0f);
889  item->setPen(p);
890  item->setColor(_globalPathColor);
891  this->scene()->addItem(item);
892  item->setZValue(15);
893  item->setParentItem(_globalPathRoot);
894  _globalPathLinkItems.insert(idFrom, item);
895  }
896  }
897 }
898 
899 void GraphViewer::setCurrentGoalID(int id, const Transform & pose)
900 {
901  NodeItem * node = _nodeItems.value(id, 0);
902  if(node)
903  {
905  }
906  else
907  {
908  UWARN("Current goal %d not found in the graph", id);
909  }
910 
911  if(!pose.isNull() && _globalPathLinkItems.size() && _globalPathLinkItems.contains(id))
912  {
913  // transform the global path in the goal referential
914  const LinkItem * oldPose = _globalPathLinkItems.value(id);
915  Transform t = pose * oldPose->getPoseA().inverse();
916  for(QMultiMap<int, LinkItem*>::iterator iter=_globalPathLinkItems.begin(); iter!=_globalPathLinkItems.end(); ++iter)
917  {
918  iter.value()->setPoses(t*iter.value()->getPoseA(), t*iter.value()->getPoseB());
919  }
920  }
921 }
922 
923 void GraphViewer::setLocalRadius(float radius)
924 {
925  _localRadius->setRect(-radius, -radius, radius*2, radius*2);
926 }
927 
928 void GraphViewer::updateLocalPath(const std::vector<int> & localPath)
929 {
930  bool wasVisible = _localPathRoot->isVisible();
931  _localPathRoot->show();
932 
933  for(QMultiMap<int, LinkItem*>::iterator iter = _localPathLinkItems.begin(); iter!=_localPathLinkItems.end(); ++iter)
934  {
935  iter.value()->hide();
936  }
937 
938  if(localPath.size() > 1)
939  {
940  for(unsigned int i=0; i<localPath.size()-1; ++i)
941  {
942  int idFrom = localPath[i]<localPath[i+1]?localPath[i]:localPath[i+1];
943  int idTo = localPath[i]<localPath[i+1]?localPath[i+1]:localPath[i];
944  if(_nodeItems.contains(idFrom) && _nodeItems.contains(idTo))
945  {
946  bool updated = false;
947  if(_localPathLinkItems.contains(idFrom))
948  {
949  QMultiMap<int, LinkItem*>::iterator itemIter = _localPathLinkItems.find(idFrom);
950  while(itemIter.key() == idFrom && itemIter != _localPathLinkItems.end())
951  {
952  if(itemIter.value()->to() == idTo)
953  {
954  itemIter.value()->setPoses(_nodeItems.value(idFrom)->pose(), _nodeItems.value(idTo)->pose());
955  itemIter.value()->show();
956  updated = true;
957  break;
958  }
959  ++itemIter;
960  }
961  }
962  if(!updated)
963  {
964  //create a link item
965  LinkItem * item = new LinkItem(idFrom, idTo, _nodeItems.value(idFrom)->pose(), _nodeItems.value(idTo)->pose(), Link(), false);
966  QPen p = item->pen();
967  p.setWidthF(_linkWidth*100.0f);
968  item->setPen(p);
969  item->setColor(_localPathColor);
970  this->scene()->addItem(item);
971  item->setZValue(16); // just over the global path
972  item->setParentItem(_localPathRoot);
973  _localPathLinkItems.insert(idFrom, item);
974  }
975  }
976  }
977  }
978 
979  // remove not used links
980  for(QMultiMap<int, LinkItem*>::iterator iter = _localPathLinkItems.begin(); iter!=_localPathLinkItems.end();)
981  {
982  if(!iter.value()->isVisible())
983  {
984  delete iter.value();
985  iter = _localPathLinkItems.erase(iter);
986  }
987  else
988  {
989  ++iter;
990  }
991  }
992  _localPathRoot->setVisible(wasVisible);
993 }
994 
996 {
997  qDeleteAll(_nodeItems);
998  _nodeItems.clear();
999  qDeleteAll(_linkItems);
1000  _linkItems.clear();
1001  qDeleteAll(_localPathLinkItems);
1002  _localPathLinkItems.clear();
1003  qDeleteAll(_globalPathLinkItems);
1004  _globalPathLinkItems.clear();
1005  qDeleteAll(_gtNodeItems);
1006  _gtNodeItems.clear();
1007  qDeleteAll(_gtLinkItems);
1008  _gtLinkItems.clear();
1009  qDeleteAll(_gpsNodeItems);
1010  _gpsNodeItems.clear();
1011  qDeleteAll(_gpsLinkItems);
1012  _gpsLinkItems.clear();
1013 
1014  _referential->resetTransform();
1015  _localRadius->resetTransform();
1016  this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
1017 }
1018 
1020 {
1021  _gridMap->setPixmap(QPixmap());
1022  _gridCellSize = 0.0f;
1023  this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
1024 }
1025 
1027 {
1028  for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
1029  {
1030  iter.value()->setColor(Qt::blue); // blue
1031  }
1032 }
1033 
1035 {
1036  clearMap();
1037  clearGraph();
1038 }
1039 
1040 void GraphViewer::saveSettings(QSettings & settings, const QString & group) const
1041 {
1042  if(!group.isEmpty())
1043  {
1044  settings.beginGroup(group);
1045  }
1046  settings.setValue("node_radius", (double)this->getNodeRadius());
1047  settings.setValue("link_width", (double)this->getLinkWidth());
1048  settings.setValue("node_color", this->getNodeColor());
1049  settings.setValue("current_goal_color", this->getCurrentGoalColor());
1050  settings.setValue("neighbor_color", this->getNeighborColor());
1051  settings.setValue("global_color", this->getGlobalLoopClosureColor());
1052  settings.setValue("local_color", this->getLocalLoopClosureColor());
1053  settings.setValue("user_color", this->getUserLoopClosureColor());
1054  settings.setValue("virtual_color", this->getVirtualLoopClosureColor());
1055  settings.setValue("neighbor_merged_color", this->getNeighborMergedColor());
1056  settings.setValue("rejected_color", this->getRejectedLoopClosureColor());
1057  settings.setValue("local_path_color", this->getLocalPathColor());
1058  settings.setValue("global_path_color", this->getGlobalPathColor());
1059  settings.setValue("gt_color", this->getGTColor());
1060  settings.setValue("gps_color", this->getGPSColor());
1061  settings.setValue("intra_session_color", this->getIntraSessionLoopColor());
1062  settings.setValue("inter_session_color", this->getInterSessionLoopColor());
1063  settings.setValue("intra_inter_session_colors_enabled", this->isIntraInterSessionColorsEnabled());
1064  settings.setValue("grid_visible", this->isGridMapVisible());
1065  settings.setValue("origin_visible", this->isOriginVisible());
1066  settings.setValue("referential_visible", this->isReferentialVisible());
1067  settings.setValue("local_radius_visible", this->isLocalRadiusVisible());
1068  settings.setValue("loop_closure_outlier_thr", this->getLoopClosureOutlierThr());
1069  settings.setValue("max_link_length", this->getMaxLinkLength());
1070  settings.setValue("graph_visible", this->isGraphVisible());
1071  settings.setValue("global_path_visible", this->isGlobalPathVisible());
1072  settings.setValue("local_path_visible", this->isLocalPathVisible());
1073  settings.setValue("gt_graph_visible", this->isGtGraphVisible());
1074  settings.setValue("gps_graph_visible", this->isGPSGraphVisible());
1075  settings.setValue("orientation_ENU", this->isOrientationENU());
1076  if(!group.isEmpty())
1077  {
1078  settings.endGroup();
1079  }
1080 }
1081 
1082 void GraphViewer::loadSettings(QSettings & settings, const QString & group)
1083 {
1084  if(!group.isEmpty())
1085  {
1086  settings.beginGroup(group);
1087  }
1088  this->setNodeRadius(settings.value("node_radius", this->getNodeRadius()).toDouble());
1089  this->setLinkWidth(settings.value("link_width", this->getLinkWidth()).toDouble());
1090  this->setNodeColor(settings.value("node_color", this->getNodeColor()).value<QColor>());
1091  this->setCurrentGoalColor(settings.value("current_goal_color", this->getCurrentGoalColor()).value<QColor>());
1092  this->setNeighborColor(settings.value("neighbor_color", this->getNeighborColor()).value<QColor>());
1093  this->setGlobalLoopClosureColor(settings.value("global_color", this->getGlobalLoopClosureColor()).value<QColor>());
1094  this->setLocalLoopClosureColor(settings.value("local_color", this->getLocalLoopClosureColor()).value<QColor>());
1095  this->setUserLoopClosureColor(settings.value("user_color", this->getUserLoopClosureColor()).value<QColor>());
1096  this->setVirtualLoopClosureColor(settings.value("virtual_color", this->getVirtualLoopClosureColor()).value<QColor>());
1097  this->setNeighborMergedColor(settings.value("neighbor_merged_color", this->getNeighborMergedColor()).value<QColor>());
1098  this->setRejectedLoopClosureColor(settings.value("rejected_color", this->getRejectedLoopClosureColor()).value<QColor>());
1099  this->setLocalPathColor(settings.value("local_path_color", this->getLocalPathColor()).value<QColor>());
1100  this->setGlobalPathColor(settings.value("global_path_color", this->getGlobalPathColor()).value<QColor>());
1101  this->setGTColor(settings.value("gt_color", this->getGTColor()).value<QColor>());
1102  this->setGPSColor(settings.value("gps_color", this->getGPSColor()).value<QColor>());
1103  this->setIntraSessionLoopColor(settings.value("intra_session_color", this->getIntraSessionLoopColor()).value<QColor>());
1104  this->setInterSessionLoopColor(settings.value("inter_session_color", this->getInterSessionLoopColor()).value<QColor>());
1105  this->setGridMapVisible(settings.value("grid_visible", this->isGridMapVisible()).toBool());
1106  this->setOriginVisible(settings.value("origin_visible", this->isOriginVisible()).toBool());
1107  this->setReferentialVisible(settings.value("referential_visible", this->isReferentialVisible()).toBool());
1108  this->setLocalRadiusVisible(settings.value("local_radius_visible", this->isLocalRadiusVisible()).toBool());
1109  this->setIntraInterSessionColorsEnabled(settings.value("intra_inter_session_colors_enabled", this->isIntraInterSessionColorsEnabled()).toBool());
1110  this->setLoopClosureOutlierThr(settings.value("loop_closure_outlier_thr", this->getLoopClosureOutlierThr()).toDouble());
1111  this->setMaxLinkLength(settings.value("max_link_length", this->getMaxLinkLength()).toDouble());
1112  this->setGraphVisible(settings.value("graph_visible", this->isGraphVisible()).toBool());
1113  this->setGlobalPathVisible(settings.value("global_path_visible", this->isGlobalPathVisible()).toBool());
1114  this->setLocalPathVisible(settings.value("local_path_visible", this->isLocalPathVisible()).toBool());
1115  this->setGtGraphVisible(settings.value("gt_graph_visible", this->isGtGraphVisible()).toBool());
1116  this->setGPSGraphVisible(settings.value("gps_graph_visible", this->isGPSGraphVisible()).toBool());
1117  this->setOrientationENU(settings.value("orientation_ENU", this->isOrientationENU()).toBool());
1118  if(!group.isEmpty())
1119  {
1120  settings.endGroup();
1121  }
1122 }
1123 
1125 {
1126  return _gridMap->isVisible();
1127 }
1129 {
1130  return _originReferential->isVisible();
1131 }
1133 {
1134  return _referential->isVisible();
1135 }
1137 {
1138  return _localRadius->isVisible();
1139 }
1141 {
1142  return _graphRoot->isVisible();
1143 }
1145 {
1146  return _globalPathRoot->isVisible();
1147 }
1149 {
1150  return _localPathRoot->isVisible();
1151 }
1153 {
1154  return _gtGraphRoot->isVisible();
1155 }
1157 {
1158  return _gpsGraphRoot->isVisible();
1159 }
1161 {
1162  return _orientationENU;
1163 }
1164 
1165 void GraphViewer::setWorkingDirectory(const QString & path)
1166 {
1167  _workingDirectory = path;
1168 }
1170 {
1171  _nodeVisible = visible;
1172  for(QMap<int, NodeItem*>::iterator iter=_nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
1173  {
1174  iter.value()->setVisible(_nodeVisible);
1175  }
1176  for(QMap<int, NodeItem*>::iterator iter=_gtNodeItems.begin(); iter!=_gtNodeItems.end(); ++iter)
1177  {
1178  iter.value()->setVisible(_nodeVisible);
1179  }
1180  for(QMap<int, NodeItem*>::iterator iter=_gpsNodeItems.begin(); iter!=_gpsNodeItems.end(); ++iter)
1181  {
1182  iter.value()->setVisible(_nodeVisible);
1183  }
1184 }
1185 void GraphViewer::setNodeRadius(float radius)
1186 {
1187  _nodeRadius = radius;
1188  for(QMap<int, NodeItem*>::iterator iter=_nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
1189  {
1190  iter.value()->setRadius(_nodeRadius);
1191  }
1192  for(QMap<int, NodeItem*>::iterator iter=_gtNodeItems.begin(); iter!=_gtNodeItems.end(); ++iter)
1193  {
1194  iter.value()->setRadius(_nodeRadius);
1195  }
1196  for(QMap<int, NodeItem*>::iterator iter=_gpsNodeItems.begin(); iter!=_gpsNodeItems.end(); ++iter)
1197  {
1198  iter.value()->setRadius(_nodeRadius);
1199  }
1200 }
1201 void GraphViewer::setLinkWidth(float width)
1202 {
1203  _linkWidth = width;
1204  QList<QGraphicsItem*> items = this->scene()->items();
1205  for(int i=0; i<items.size(); ++i)
1206  {
1207  QGraphicsLineItem * line = qgraphicsitem_cast<QGraphicsLineItem *>(items[i]);
1208  if(line)
1209  {
1210  QPen pen = line->pen();
1211  pen.setWidthF(_linkWidth*100.0f);
1212  line->setPen(pen);
1213  }
1214  }
1215 }
1216 void GraphViewer::setNodeColor(const QColor & color)
1217 {
1218  _nodeColor = color;
1219  for(QMap<int, NodeItem*>::iterator iter=_nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
1220  {
1221  iter.value()->setColor(_nodeColor);
1222  }
1223 }
1224 void GraphViewer::setCurrentGoalColor(const QColor & color)
1225 {
1226  _currentGoalColor = color;
1227 }
1228 void GraphViewer::setNeighborColor(const QColor & color)
1229 {
1230  _neighborColor = color;
1231  for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
1232  {
1233  if(iter.value()->linkType() == Link::kNeighbor)
1234  {
1235  iter.value()->setColor(_neighborColor);
1236  }
1237  }
1238 }
1239 void GraphViewer::setGlobalLoopClosureColor(const QColor & color)
1240 {
1241  _loopClosureColor = color;
1243  {
1244  for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
1245  {
1246  if(iter.value()->linkType() == Link::kGlobalClosure)
1247  {
1248  iter.value()->setColor(_loopClosureColor);
1249  iter.value()->setZValue(10);
1250  }
1251  }
1252  }
1253 }
1254 void GraphViewer::setLocalLoopClosureColor(const QColor & color)
1255 {
1256  _loopClosureLocalColor = color;
1258  {
1259  for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
1260  {
1261  if(iter.value()->linkType() == Link::kLocalSpaceClosure ||
1262  iter.value()->linkType() == Link::kLocalTimeClosure)
1263  {
1264  iter.value()->setColor(_loopClosureLocalColor);
1265  iter.value()->setZValue(10);
1266  }
1267  }
1268  }
1269 }
1270 void GraphViewer::setUserLoopClosureColor(const QColor & color)
1271 {
1272  _loopClosureUserColor = color;
1273  for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
1274  {
1275  if(iter.value()->linkType() == Link::kUserClosure)
1276  {
1277  iter.value()->setColor(_loopClosureUserColor);
1278  }
1279  }
1280 }
1282 {
1283  _loopClosureVirtualColor = color;
1284  for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
1285  {
1286  if(iter.value()->linkType() == Link::kVirtualClosure)
1287  {
1288  iter.value()->setColor(_loopClosureVirtualColor);
1289  }
1290  }
1291 }
1292 void GraphViewer::setNeighborMergedColor(const QColor & color)
1293 {
1294  _neighborMergedColor = color;
1295  for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
1296  {
1297  if(iter.value()->linkType() == Link::kNeighborMerged)
1298  {
1299  iter.value()->setColor(_neighborMergedColor);
1300  }
1301  }
1302 }
1304 {
1305  _loopClosureRejectedColor = color;
1306 }
1307 void GraphViewer::setLocalPathColor(const QColor & color)
1308 {
1309  _localPathColor = color;
1310 }
1311 void GraphViewer::setGlobalPathColor(const QColor & color)
1312 {
1313  _globalPathColor = color;
1314 }
1315 void GraphViewer::setGTColor(const QColor & color)
1316 {
1317  _gtPathColor = color;
1318  for(QMap<int, NodeItem*>::iterator iter=_gtNodeItems.begin(); iter!=_gtNodeItems.end(); ++iter)
1319  {
1320  iter.value()->setColor(_gtPathColor);
1321  }
1322  for(QMultiMap<int, LinkItem*>::iterator iter=_gtLinkItems.begin(); iter!=_gtLinkItems.end(); ++iter)
1323  {
1324  iter.value()->setColor(_gtPathColor);
1325  }
1326 }
1327 void GraphViewer::setGPSColor(const QColor & color)
1328 {
1329  _gpsPathColor = color;
1330  for(QMap<int, NodeItem*>::iterator iter=_gpsNodeItems.begin(); iter!=_gpsNodeItems.end(); ++iter)
1331  {
1332  iter.value()->setColor(_gpsPathColor);
1333  }
1334  for(QMultiMap<int, LinkItem*>::iterator iter=_gpsLinkItems.begin(); iter!=_gpsLinkItems.end(); ++iter)
1335  {
1336  iter.value()->setColor(_gpsPathColor);
1337  }
1338 }
1339 void GraphViewer::setIntraSessionLoopColor(const QColor & color)
1340 {
1341  _loopIntraSessionColor = color;
1343  {
1344  for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
1345  {
1346  if((iter.value()->linkType() == Link::kGlobalClosure ||
1347  iter.value()->linkType() == Link::kLocalSpaceClosure ||
1348  iter.value()->linkType() == Link::kLocalTimeClosure) &&
1349  !iter.value()->isInterSession())
1350  {
1351  iter.value()->setColor(_loopIntraSessionColor);
1352  iter.value()->setZValue(9);
1353  }
1354  }
1355  }
1356 }
1357 void GraphViewer::setInterSessionLoopColor(const QColor & color)
1358 {
1359  _loopInterSessionColor = color;
1361  {
1362  for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
1363  {
1364  if((iter.value()->linkType() == Link::kGlobalClosure ||
1365  iter.value()->linkType() == Link::kLocalSpaceClosure ||
1366  iter.value()->linkType() == Link::kLocalTimeClosure) &&
1367  iter.value()->isInterSession())
1368  {
1369  iter.value()->setColor(_loopInterSessionColor);
1370  iter.value()->setZValue(8);
1371  }
1372  }
1373  }
1374 }
1375 
1377 {
1378  _intraInterSessionColors = enabled;
1380  {
1383  }
1384  else
1385  {
1388  }
1389 }
1390 
1392 {
1393  _gridMap->setVisible(visible);
1394 }
1396 {
1397  _originReferential->setVisible(visible);
1398 }
1400 {
1401  _referential->setVisible(visible);
1402 }
1404 {
1405  _localRadius->setVisible(visible);
1406 }
1408 {
1409  _loopClosureOutlierThr = value;
1410 }
1412 {
1413  _maxLinkLength = value;
1414 }
1416 {
1417  _graphRoot->setVisible(visible);
1418 }
1420 {
1421  _globalPathRoot->setVisible(visible);
1422 }
1424 {
1425  _localPathRoot->setVisible(visible);
1426 }
1428 {
1429  _gtGraphRoot->setVisible(visible);
1430 }
1432 {
1433  _gpsGraphRoot->setVisible(visible);
1434 }
1436 {
1437  if(_orientationENU!=enabled)
1438  {
1439  _orientationENU = enabled;
1440  this->rotate(_orientationENU?90:270);
1441  }
1442 }
1443 
1445 {
1446  setNodeRadius(0.01f);
1447  setLinkWidth(0.0f);
1448  setNodeColor(Qt::blue);
1449  setNeighborColor(Qt::blue);
1450  setGlobalLoopClosureColor(Qt::red);
1451  setLocalLoopClosureColor(Qt::yellow);
1452  setUserLoopClosureColor(Qt::red);
1453  setVirtualLoopClosureColor(Qt::magenta);
1454  setNeighborMergedColor(QColor(255,170,0));
1455  setGridMapVisible(true);
1456  setGraphVisible(true);
1457  setGlobalPathVisible(true);
1458  setLocalPathVisible(true);
1459  setGtGraphVisible(true);
1460 }
1461 
1462 void GraphViewer::wheelEvent ( QWheelEvent * event )
1463 {
1464  if(event->delta() < 0)
1465  {
1466  this->scale(0.95, 0.95);
1467  }
1468  else
1469  {
1470  this->scale(1.05, 1.05);
1471  }
1472 }
1473 
1474 QIcon createIcon(const QColor & color)
1475 {
1476  QPixmap pixmap(50, 50);
1477  pixmap.fill(color);
1478  return QIcon(pixmap);
1479 }
1480 
1481 void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
1482 {
1483  QMenu menu;
1484  QAction * aScreenShotPNG = menu.addAction(tr("Take a screenshot (PNG)"));
1485  QAction * aScreenShotSVG = menu.addAction(tr("Take a screenshot (SVG)"));
1486 #ifndef QT_SVG_LIB
1487  aScreenShotSVG->setEnabled(false);
1488 #endif
1489  menu.addSeparator();
1490 
1491  QAction * aChangeNodeColor = menu.addAction(createIcon(_nodeColor), tr("Set node color..."));
1492  QAction * aChangeCurrentGoalColor = menu.addAction(createIcon(_currentGoalColor), tr("Set current goal color..."));
1493  aChangeNodeColor->setIconVisibleInMenu(true);
1494  aChangeCurrentGoalColor->setIconVisibleInMenu(true);
1495 
1496  // Links
1497  QMenu * menuLink = menu.addMenu(tr("Set link color..."));
1498  QAction * aChangeNeighborColor = menuLink->addAction(tr("Neighbor"));
1499  QAction * aChangeGlobalLoopColor = menuLink->addAction(tr("Global loop closure"));
1500  QAction * aChangeLocalLoopColor = menuLink->addAction(tr("Local loop closure"));
1501  QAction * aChangeUserLoopColor = menuLink->addAction(tr("User loop closure"));
1502  QAction * aChangeVirtualLoopColor = menuLink->addAction(tr("Virtual loop closure"));
1503  QAction * aChangeNeighborMergedColor = menuLink->addAction(tr("Neighbor merged"));
1504  QAction * aChangeRejectedLoopColor = menuLink->addAction(tr("Outlier loop closure"));
1505  QAction * aChangeRejectedLoopThr = menuLink->addAction(tr("Set outlier threshold..."));
1506  QAction * aChangeLocalPathColor = menuLink->addAction(tr("Local path"));
1507  QAction * aChangeGlobalPathColor = menuLink->addAction(tr("Global path"));
1508  QAction * aChangeGTColor = menuLink->addAction(tr("Ground truth"));
1509  QAction * aChangeGPSColor = menuLink->addAction(tr("GPS"));
1510  menuLink->addSeparator();
1511  QAction * aSetIntraInterSessionColors = menuLink->addAction(tr("Enable intra/inter-session colors"));
1512  QAction * aChangeIntraSessionLoopColor = menuLink->addAction(tr("Intra-session loop closure"));
1513  QAction * aChangeInterSessionLoopColor = menuLink->addAction(tr("Inter-session loop closure"));
1514  aChangeNeighborColor->setIcon(createIcon(_neighborColor));
1515  aChangeGlobalLoopColor->setIcon(createIcon(_loopClosureColor));
1516  aChangeLocalLoopColor->setIcon(createIcon(_loopClosureLocalColor));
1517  aChangeUserLoopColor->setIcon(createIcon(_loopClosureUserColor));
1518  aChangeVirtualLoopColor->setIcon(createIcon(_loopClosureVirtualColor));
1519  aChangeNeighborMergedColor->setIcon(createIcon(_neighborMergedColor));
1520  aChangeRejectedLoopColor->setIcon(createIcon(_loopClosureRejectedColor));
1521  aChangeLocalPathColor->setIcon(createIcon(_localPathColor));
1522  aChangeGlobalPathColor->setIcon(createIcon(_globalPathColor));
1523  aChangeGTColor->setIcon(createIcon(_gtPathColor));
1524  aChangeGPSColor->setIcon(createIcon(_gpsPathColor));
1525  aChangeIntraSessionLoopColor->setIcon(createIcon(_loopIntraSessionColor));
1526  aChangeInterSessionLoopColor->setIcon(createIcon(_loopInterSessionColor));
1527  aChangeNeighborColor->setIconVisibleInMenu(true);
1528  aChangeGlobalLoopColor->setIconVisibleInMenu(true);
1529  aChangeLocalLoopColor->setIconVisibleInMenu(true);
1530  aChangeUserLoopColor->setIconVisibleInMenu(true);
1531  aChangeVirtualLoopColor->setIconVisibleInMenu(true);
1532  aChangeNeighborMergedColor->setIconVisibleInMenu(true);
1533  aChangeRejectedLoopColor->setIconVisibleInMenu(true);
1534  aChangeLocalPathColor->setIconVisibleInMenu(true);
1535  aChangeGlobalPathColor->setIconVisibleInMenu(true);
1536  aChangeGTColor->setIconVisibleInMenu(true);
1537  aChangeGPSColor->setIconVisibleInMenu(true);
1538  aChangeIntraSessionLoopColor->setIconVisibleInMenu(true);
1539  aChangeInterSessionLoopColor->setIconVisibleInMenu(true);
1540  aSetIntraInterSessionColors->setCheckable(true);
1541  aSetIntraInterSessionColors->setChecked(_intraInterSessionColors);
1542 
1543  menu.addSeparator();
1544  QAction * aSetNodeSize = menu.addAction(tr("Set node radius..."));
1545  QAction * aSetLinkSize = menu.addAction(tr("Set link width..."));
1546  QAction * aChangeMaxLinkLength = menu.addAction(tr("Set maximum link length..."));
1547  menu.addSeparator();
1548  QAction * aShowHideGridMap;
1549  QAction * aShowHideGraph;
1550  QAction * aShowHideGraphNodes;
1551  QAction * aShowHideOrigin;
1552  QAction * aShowHideReferential;
1553  QAction * aShowHideLocalRadius;
1554  QAction * aShowHideGlobalPath;
1555  QAction * aShowHideLocalPath;
1556  QAction * aShowHideGtGraph;
1557  QAction * aShowHideGPSGraph;
1558  QAction * aOrientationENU;
1559  if(_gridMap->isVisible())
1560  {
1561  aShowHideGridMap = menu.addAction(tr("Hide grid map"));
1562  }
1563  else
1564  {
1565  aShowHideGridMap = menu.addAction(tr("Show grid map"));
1566  }
1567  if(_originReferential->isVisible())
1568  {
1569  aShowHideOrigin = menu.addAction(tr("Hide origin referential"));
1570  }
1571  else
1572  {
1573  aShowHideOrigin = menu.addAction(tr("Show origin referential"));
1574  }
1575  if(_referential->isVisible())
1576  {
1577  aShowHideReferential = menu.addAction(tr("Hide current referential"));
1578  }
1579  else
1580  {
1581  aShowHideReferential = menu.addAction(tr("Show current referential"));
1582  }
1583  if(_localRadius->isVisible())
1584  {
1585  aShowHideLocalRadius = menu.addAction(tr("Hide local radius"));
1586  }
1587  else
1588  {
1589  aShowHideLocalRadius = menu.addAction(tr("Show local radius"));
1590  }
1591  if(_graphRoot->isVisible())
1592  {
1593  aShowHideGraph = menu.addAction(tr("Hide graph"));
1594  }
1595  else
1596  {
1597  aShowHideGraph = menu.addAction(tr("Show graph"));
1598  }
1599  if(_nodeVisible)
1600  {
1601  aShowHideGraphNodes = menu.addAction(tr("Hide graph nodes"));
1602  }
1603  else
1604  {
1605  aShowHideGraphNodes = menu.addAction(tr("Show graph nodes"));
1606  }
1607  if(_globalPathRoot->isVisible())
1608  {
1609  aShowHideGlobalPath = menu.addAction(tr("Hide global path"));
1610  }
1611  else
1612  {
1613  aShowHideGlobalPath = menu.addAction(tr("Show global path"));
1614  }
1615  if(_localPathRoot->isVisible())
1616  {
1617  aShowHideLocalPath = menu.addAction(tr("Hide local path"));
1618  }
1619  else
1620  {
1621  aShowHideLocalPath = menu.addAction(tr("Show local path"));
1622  }
1623  if(_gtGraphRoot->isVisible())
1624  {
1625  aShowHideGtGraph = menu.addAction(tr("Hide ground truth graph"));
1626  }
1627  else
1628  {
1629  aShowHideGtGraph = menu.addAction(tr("Show ground truth graph"));
1630  }
1631  if(_gpsGraphRoot->isVisible())
1632  {
1633  aShowHideGPSGraph = menu.addAction(tr("Hide GPS graph"));
1634  }
1635  else
1636  {
1637  aShowHideGPSGraph = menu.addAction(tr("Show GPS graph"));
1638  }
1639  aOrientationENU = menu.addAction(tr("ENU Orientation"));
1640  aOrientationENU->setCheckable(true);
1641  aOrientationENU->setChecked(_orientationENU);
1642  aShowHideGraph->setEnabled(_nodeItems.size());
1643  aShowHideGraphNodes->setEnabled(_nodeItems.size() && _graphRoot->isVisible());
1644  aShowHideGlobalPath->setEnabled(_globalPathLinkItems.size());
1645  aShowHideLocalPath->setEnabled(_localPathLinkItems.size());
1646  aShowHideGtGraph->setEnabled(_gtNodeItems.size());
1647  aShowHideGPSGraph->setEnabled(_gpsNodeItems.size());
1648  menu.addSeparator();
1649  QAction * aRestoreDefaults = menu.addAction(tr("Restore defaults"));
1650 
1651  QAction * r = menu.exec(event->globalPos());
1652  if(r == aScreenShotPNG || r == aScreenShotSVG)
1653  {
1654  if(_root)
1655  {
1656  QString targetDir = _workingDirectory + "/ScreensCaptured";
1657  QDir dir;
1658  if(!dir.exists(targetDir))
1659  {
1660  dir.mkdir(targetDir);
1661  }
1662  targetDir += "/";
1663  targetDir += "Graph_view";
1664  if(!dir.exists(targetDir))
1665  {
1666  dir.mkdir(targetDir);
1667  }
1668  targetDir += "/";
1669  bool isPNG = r == aScreenShotPNG;
1670  QString name = (QDateTime::currentDateTime().toString("yyMMddhhmmsszzz") + (isPNG?".png":".svg"));
1671 
1672  if(_gridCellSize)
1673  {
1674  _root->setScale(1.0f/(_gridCellSize*100.0f)); // grid map precision (for 5cm grid cell, x20 to have 1pix/5cm)
1675  }
1676  else
1677  {
1678  _root->setScale(this->transform().m11()); // current view
1679  }
1680 
1681  this->scene()->clearSelection(); // Selections would also render to the file
1682  this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
1683  QSize sceneSize = this->scene()->sceneRect().size().toSize();
1684 
1685  if(isPNG)
1686  {
1687  QImage image(sceneSize, QImage::Format_ARGB32); // Create the image with the exact size of the shrunk scene
1688  image.fill(Qt::transparent); // Start all pixels transparent
1689  QPainter painter(&image);
1690 
1691  this->scene()->render(&painter);
1692  if(!image.isNull())
1693  {
1694  image.save(targetDir + name);
1695  }
1696  else
1697  {
1698  QMessageBox::warning(this,
1699  tr("Save PNG"),
1700  tr("Could not export in PNG (the scene may be too large %1x%2), try saving in SVG.").arg(sceneSize.width()).arg(sceneSize.height()));
1701  }
1702  }
1703  else
1704  {
1705 #ifdef QT_SVG_LIB
1706  QSvgGenerator svgGen;
1707 
1708  svgGen.setFileName( targetDir + name );
1709  svgGen.setSize(sceneSize);
1710  // add 1% border to make sure values are not cropped
1711  int borderH = sceneSize.width()/100;
1712  int borderV = sceneSize.height()/100;
1713  svgGen.setViewBox(QRect(-borderH, -borderV, sceneSize.width()+borderH*2, sceneSize.height()+borderV*2));
1714  svgGen.setTitle(tr("RTAB-Map graph"));
1715  svgGen.setDescription(tr("RTAB-Map map and graph"));
1716 
1717  QPainter painter( &svgGen );
1718 
1719  this->scene()->render(&painter);
1720 #else
1721  UERROR("RTAB-MAp is not built with Qt's SVG library, cannot save picture in svg format.");
1722 #endif
1723  }
1724 
1725  //reset scale
1726  _root->setScale(1.0f);
1727  this->scene()->setSceneRect(this->scene()->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
1728 
1729 
1730  QDesktopServices::openUrl(QUrl::fromLocalFile(targetDir + name));
1731  }
1732  return; // without emitting configChanged
1733  }
1734  else if(r == aSetIntraInterSessionColors)
1735  {
1736  setIntraInterSessionColorsEnabled(aSetIntraInterSessionColors->isChecked());
1737  }
1738  else if(r == aChangeRejectedLoopThr)
1739  {
1740  bool ok;
1741  double value = QInputDialog::getDouble(this, tr("Loop closure outlier threshold"), tr("Value (m)"), _loopClosureOutlierThr, 0.0, 1000.0, 2, &ok);
1742  if(ok)
1743  {
1744  setLoopClosureOutlierThr(value);
1745  }
1746  }
1747  else if(r == aChangeMaxLinkLength)
1748  {
1749  bool ok;
1750  double value = QInputDialog::getDouble(this, tr("Maximum link length to be shown"), tr("Value (m)"), _maxLinkLength, 0.0, 1000.0, 3, &ok);
1751  if(ok)
1752  {
1753  setMaxLinkLength(value);
1754  }
1755  }
1756  else if(r == aChangeNodeColor ||
1757  r == aChangeCurrentGoalColor ||
1758  r == aChangeNeighborColor ||
1759  r == aChangeGlobalLoopColor ||
1760  r == aChangeLocalLoopColor ||
1761  r == aChangeUserLoopColor ||
1762  r == aChangeVirtualLoopColor ||
1763  r == aChangeNeighborMergedColor ||
1764  r == aChangeRejectedLoopColor ||
1765  r == aChangeLocalPathColor ||
1766  r == aChangeGlobalPathColor ||
1767  r == aChangeGTColor ||
1768  r == aChangeGPSColor ||
1769  r == aChangeIntraSessionLoopColor ||
1770  r == aChangeInterSessionLoopColor)
1771  {
1772  QColor color;
1773  if(r == aChangeNodeColor)
1774  {
1775  color = _nodeColor;
1776  }
1777  else if(r == aChangeCurrentGoalColor)
1778  {
1779  color = _currentGoalColor;
1780  }
1781  else if(r == aChangeGlobalLoopColor)
1782  {
1783  color = _loopClosureColor;
1784  }
1785  else if(r == aChangeLocalLoopColor)
1786  {
1787  color = _loopClosureLocalColor;
1788  }
1789  else if(r == aChangeUserLoopColor)
1790  {
1791  color = _loopClosureUserColor;
1792  }
1793  else if(r == aChangeVirtualLoopColor)
1794  {
1795  color = _loopClosureVirtualColor;
1796  }
1797  else if(r == aChangeNeighborMergedColor)
1798  {
1799  color = _neighborMergedColor;
1800  }
1801  else if(r == aChangeRejectedLoopColor)
1802  {
1803  color = _loopClosureRejectedColor;
1804  }
1805  else if(r == aChangeLocalPathColor)
1806  {
1807  color = _localPathColor;
1808  }
1809  else if(r == aChangeGlobalPathColor)
1810  {
1811  color = _globalPathColor;
1812  }
1813  else if(r == aChangeGTColor)
1814  {
1815  color = _gtPathColor;
1816  }
1817  else if(r == aChangeGPSColor)
1818  {
1819  color = _gpsPathColor;
1820  }
1821  else if(r == aChangeIntraSessionLoopColor)
1822  {
1823  color = _loopIntraSessionColor;
1824  }
1825  else if(r == aChangeInterSessionLoopColor)
1826  {
1827  color = _loopInterSessionColor;
1828  }
1829  else //if(r == aChangeNeighborColor)
1830  {
1831  color = _neighborColor;
1832  }
1833  color = QColorDialog::getColor(color, this);
1834  if(color.isValid())
1835  {
1836 
1837  if(r == aChangeNodeColor)
1838  {
1839  this->setNodeColor(color);
1840  }
1841  else if(r == aChangeCurrentGoalColor)
1842  {
1843  this->setCurrentGoalColor(color);
1844  }
1845  else if(r == aChangeGlobalLoopColor)
1846  {
1847  this->setGlobalLoopClosureColor(color);
1848  }
1849  else if(r == aChangeLocalLoopColor)
1850  {
1851  this->setLocalLoopClosureColor(color);
1852  }
1853  else if(r == aChangeUserLoopColor)
1854  {
1855  this->setUserLoopClosureColor(color);
1856  }
1857  else if(r == aChangeVirtualLoopColor)
1858  {
1859  this->setVirtualLoopClosureColor(color);
1860  }
1861  else if(r == aChangeNeighborMergedColor)
1862  {
1863  this->setNeighborMergedColor(color);
1864  }
1865  else if(r == aChangeRejectedLoopColor)
1866  {
1867  this->setRejectedLoopClosureColor(color);
1868  }
1869  else if(r == aChangeLocalPathColor)
1870  {
1871  this->setLocalPathColor(color);
1872  }
1873  else if(r == aChangeGlobalPathColor)
1874  {
1875  this->setGlobalPathColor(color);
1876  }
1877  else if(r == aChangeGTColor)
1878  {
1879  this->setGTColor(color);
1880  }
1881  else if(r == aChangeGPSColor)
1882  {
1883  this->setGPSColor(color);
1884  }
1885  else if(r == aChangeIntraSessionLoopColor)
1886  {
1887  this->setIntraSessionLoopColor(color);
1888  }
1889  else if(r == aChangeInterSessionLoopColor)
1890  {
1891  this->setInterSessionLoopColor(color);
1892  }
1893  else //if(r == aChangeNeighborColor)
1894  {
1895  this->setNeighborColor(color);
1896  }
1897  }
1898  else
1899  {
1900  return; // without emitting configChanged
1901  }
1902  }
1903  else if(r == aSetNodeSize)
1904  {
1905  bool ok;
1906  double value = QInputDialog::getDouble(this, tr("Node radius"), tr("Radius (m)"), _nodeRadius, 0.001, 100, 3, &ok);
1907  if(ok)
1908  {
1909  setNodeRadius(value);
1910  }
1911  }
1912  else if(r == aSetLinkSize)
1913  {
1914  bool ok;
1915  double value = QInputDialog::getDouble(this, tr("Link width"), tr("Width (m)"), _linkWidth, 0, 100, 2, &ok);
1916  if(ok)
1917  {
1918  setLinkWidth(value);
1919  }
1920  }
1921  else if(r == aShowHideGridMap)
1922  {
1923  this->setGridMapVisible(!this->isGridMapVisible());
1924  if(_gridMap->isVisible())
1925  {
1927  }
1928  }
1929  else if(r == aShowHideOrigin)
1930  {
1931  this->setOriginVisible(!this->isOriginVisible());
1932  }
1933  else if(r == aShowHideReferential)
1934  {
1936  }
1937  else if(r == aShowHideLocalRadius)
1938  {
1940  }
1941  else if(r == aRestoreDefaults)
1942  {
1943  this->restoreDefaults();
1944  }
1945  else if(r == aShowHideGraph)
1946  {
1947  this->setGraphVisible(!this->isGraphVisible());
1948  }
1949  else if(r == aShowHideGraphNodes)
1950  {
1951  this->setNodeVisible(!_nodeVisible);
1952  }
1953  else if(r == aShowHideGlobalPath)
1954  {
1955  this->setGlobalPathVisible(!this->isGlobalPathVisible());
1956  }
1957  else if(r == aShowHideLocalPath)
1958  {
1959  this->setLocalPathVisible(!this->isLocalPathVisible());
1960  }
1961  else if(r == aShowHideGtGraph)
1962  {
1963  this->setGtGraphVisible(!this->isGtGraphVisible());
1964  }
1965  else if(r == aShowHideGPSGraph)
1966  {
1967  this->setGPSGraphVisible(!this->isGPSGraphVisible());
1968  }
1969  else if(r == aOrientationENU)
1970  {
1971  this->setOrientationENU(!this->isOrientationENU());
1972  }
1973 
1974  if(r)
1975  {
1976  Q_EMIT configChanged();
1977  }
1978 }
1979 
1980 } /* namespace rtabmap */
void setPoses(const Transform &poseA, const Transform &poseB)
void setLoopClosureOutlierThr(float value)
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
QGraphicsItem * _gpsGraphRoot
Definition: GraphViewer.h:182
QColor _loopClosureLocalColor
Definition: GraphViewer.h:165
int to() const
QColor _loopClosureVirtualColor
Definition: GraphViewer.h:167
Definition: UTimer.h:46
void setGlobalPathColor(const QColor &color)
const QColor & getVirtualLoopClosureColor() const
Definition: GraphViewer.h:91
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
float getLinkWidth() const
Definition: GraphViewer.h:84
QGraphicsItem * _localPathRoot
Definition: GraphViewer.h:180
void setCurrentGoalID(int id, const Transform &pose=Transform())
std::string prettyPrint() const
Definition: Transform.cpp:274
void setGridMapVisible(bool visible)
const QColor & getInterSessionLoopColor() const
Definition: GraphViewer.h:99
void setMaxLinkLength(float value)
QGraphicsEllipseItem * _localRadius
Definition: GraphViewer.h:198
const Transform & pose() const
QGraphicsItemGroup * _referential
Definition: GraphViewer.h:195
void updatePosterior(const std::map< int, float > &posterior, float fixedMax=0.0f)
const Transform & getPoseA() const
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
f
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
void setRadius(float radius)
Definition: GraphViewer.cpp:92
void setWorkingDirectory(const QString &path)
NodeGPSItem(int id, int mapId, const Transform &pose, float radius, const GPS &gps)
void setColor(const QColor &color)
void setIntraInterSessionColorsEnabled(bool enabled)
void saveSettings(QSettings &settings, const QString &group="") const
void updateReferentialPosition(const Transform &t)
void setGlobalPathVisible(bool visible)
void setNeighborColor(const QColor &color)
GLM_FUNC_DECL detail::tmat4x4< T, P > scale(detail::tmat4x4< T, P > const &m, detail::tvec3< T, P > const &v)
const QColor & getGPSColor() const
Definition: GraphViewer.h:97
const QColor & getRejectedLoopClosureColor() const
Definition: GraphViewer.h:93
float getNodeRadius() const
Definition: GraphViewer.h:83
bool isInterSession() const
virtual ~NodeItem()
Definition: GraphViewer.cpp:78
bool isGlobalPathVisible() const
virtual void wheelEvent(QWheelEvent *event)
QGraphicsPixmapItem * _gridMap
Definition: GraphViewer.h:194
void updateLocalPath(const std::vector< int > &localPath)
void setGPSGraphVisible(bool visible)
void setReferentialVisible(bool visible)
void setGPSColor(const QColor &color)
void setGlobalPath(const std::vector< std::pair< int, Transform > > &globalPath)
QMultiMap< int, LinkItem * > _gpsLinkItems
Definition: GraphViewer.h:188
QGraphicsItem * _graphRoot
Definition: GraphViewer.h:178
QGraphicsItem * _root
Definition: GraphViewer.h:177
const QColor & getGlobalLoopClosureColor() const
Definition: GraphViewer.h:88
bool isGPSGraphVisible() const
int id() const
bool isGraphVisible() const
QColor _loopInterSessionColor
Definition: GraphViewer.h:175
const QColor & getGlobalPathColor() const
Definition: GraphViewer.h:95
#define UASSERT(condition)
GLM_FUNC_DECL genType cos(genType const &angle)
Wrappers of STL for convenient functions.
const QColor & getLocalPathColor() const
Definition: GraphViewer.h:94
QColor _loopClosureRejectedColor
Definition: GraphViewer.h:169
GLM_FUNC_DECL genType sin(genType const &angle)
void setGtGraphVisible(bool visible)
float getLoopClosureOutlierThr() const
Definition: GraphViewer.h:105
void setColor(const QColor &color)
Definition: GraphViewer.cpp:80
QColor _loopIntraSessionColor
Definition: GraphViewer.h:174
#define true
Definition: ConvertUTF.c:57
T uMax3(const T &a, const T &b, const T &c)
Definition: UMath.h:80
QMultiMap< int, LinkItem * > _globalPathLinkItems
Definition: GraphViewer.h:190
bool isNull() const
Definition: Transform.cpp:107
void updateGraph(const std::map< int, Transform > &poses, const std::multimap< int, Link > &constraints, const std::map< int, int > &mapIds)
void setPose(const Transform &pose)
float o14() const
Definition: Transform.h:71
void setNeighborMergedColor(const QColor &color)
QImage uCvMat2QImage(const cv::Mat &image, bool isBgr=true, uCvQtDepthColorMap colorMap=uCvQtDepthWhiteToBlack)
Definition: UCv2Qt.h:44
QGraphicsItemGroup * _originReferential
Definition: GraphViewer.h:196
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
const QColor & getNodeColor() const
Definition: GraphViewer.h:85
void getEulerAngles(float &roll, float &pitch, float &yaw) const
Definition: Transform.cpp:211
float getMaxLinkLength() const
Definition: GraphViewer.h:106
bool isOrientationENU() const
int from() const
float r12() const
Definition: Transform.h:62
Link::Type linkType() const
void setLocalLoopClosureColor(const QColor &color)
QMultiMap< int, LinkItem * > _gtLinkItems
Definition: GraphViewer.h:187
const QColor & getIntraSessionLoopColor() const
Definition: GraphViewer.h:98
QGraphicsItem * _gtGraphRoot
Definition: GraphViewer.h:181
GraphViewer(QWidget *parent=0)
bool isGtGraphVisible() const
void setInterSessionLoopColor(const QColor &color)
NodeItem(int id, int mapId, const Transform &pose, float radius)
Definition: GraphViewer.cpp:63
void setUserLoopClosureColor(const QColor &color)
float r21() const
Definition: Transform.h:64
void setOrientationENU(bool enabled)
void updateMap(const cv::Mat &map8U, float resolution, float xMin, float yMin)
bool uContains(const std::list< V > &list, const V &value)
Definition: UStl.h:409
void setGlobalLoopClosureColor(const QColor &color)
bool isLocalRadiusVisible() const
const QColor & getLocalLoopClosureColor() const
Definition: GraphViewer.h:89
const QColor & getCurrentGoalColor() const
Definition: GraphViewer.h:86
void setLocalPathColor(const QColor &color)
#define false
Definition: ConvertUTF.c:56
LinkItem(int from, int to, const Transform &poseA, const Transform &poseB, const Link &link, bool interSessionClosure)
bool isGridMapVisible() const
QMultiMap< int, LinkItem * > _localPathLinkItems
Definition: GraphViewer.h:189
bool isIntraInterSessionColorsEnabled() const
Definition: GraphViewer.h:100
bool isReferentialVisible() const
QGraphicsItem * _globalPathRoot
Definition: GraphViewer.h:179
float getDistance(const Transform &t) const
Definition: Transform.cpp:241
QMap< int, NodeItem * > _gpsNodeItems
Definition: GraphViewer.h:186
void setVirtualLoopClosureColor(const QColor &color)
#define UDEBUG(...)
GLM_FUNC_DECL genType max(genType const &x, genType const &y)
void setIntraSessionLoopColor(const QColor &color)
void setNodeRadius(float radius)
QIcon createIcon(const QColor &color)
QColor _loopClosureUserColor
Definition: GraphViewer.h:166
float r22() const
Definition: Transform.h:65
void updateGTGraph(const std::map< int, Transform > &poses)
void setGTColor(const QColor &color)
bool isOriginVisible() const
#define UERROR(...)
void setGraphVisible(bool visible)
const Transform & getPoseB() const
void setNodeColor(const QColor &color)
const QColor & getUserLoopClosureColor() const
Definition: GraphViewer.h:90
void setNodeVisible(bool visible)
ULogger class and convenient macros.
#define UWARN(...)
QMultiMap< int, LinkItem * > _linkItems
Definition: GraphViewer.h:184
double ticks()
Definition: UTimer.cpp:110
bool isLocalPathVisible() const
GLM_FUNC_DECL T yaw(detail::tquat< T, P > const &x)
const QColor & getNeighborMergedColor() const
Definition: GraphViewer.h:92
void updateGPSGraph(const std::map< int, Transform > &gpsMapPoses, const std::map< int, GPS > &gpsValues)
void loadSettings(QSettings &settings, const QString &group="")
Transform inverse() const
Definition: Transform.cpp:169
void setLocalRadius(float radius)
const QColor & getGTColor() const
Definition: GraphViewer.h:96
virtual void contextMenuEvent(QContextMenuEvent *event)
QMap< int, NodeItem * > _nodeItems
Definition: GraphViewer.h:183
QGraphicsLineItem * _line
QMap< int, NodeItem * > _gtNodeItems
Definition: GraphViewer.h:185
float r11() const
Definition: Transform.h:61
const QColor & getNeighborColor() const
Definition: GraphViewer.h:87
float o24() const
Definition: Transform.h:72
void setLocalPathVisible(bool visible)
int mapId() const
void setOriginVisible(bool visible)
void setCurrentGoalColor(const QColor &color)
void setLocalRadiusVisible(bool visible)
void setRejectedLoopClosureColor(const QColor &color)
void setLinkWidth(float width)
GLM_FUNC_DECL detail::tmat4x4< T, P > rotate(detail::tmat4x4< T, P > const &m, T const &angle, detail::tvec3< T, P > const &axis)


rtabmap
Author(s): Mathieu Labbe
autogenerated on Wed Jun 5 2019 22:41:31