00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "GraphViewer.h"
00029
00030 #include <QGraphicsView>
00031 #include <QVBoxLayout>
00032 #include <QGraphicsScene>
00033 #include <QGraphicsEllipseItem>
00034 #include <QtGui/QWheelEvent>
00035 #include <QGraphicsSceneHoverEvent>
00036 #include <QMenu>
00037 #include <QtGui/QDesktopServices>
00038 #include <QtGui/QContextMenuEvent>
00039 #include <QColorDialog>
00040 #include <QtSvg/QSvgGenerator>
00041 #include <QInputDialog>
00042
00043 #include <QtCore/QDir>
00044 #include <QtCore/QDateTime>
00045 #include <QtCore/QUrl>
00046
00047 #include <rtabmap/core/util3d.h>
00048 #include <rtabmap/gui/UCv2Qt.h>
00049 #include <rtabmap/utilite/UStl.h>
00050 #include <rtabmap/utilite/ULogger.h>
00051
00052 namespace rtabmap {
00053
00054 class NodeItem: public QGraphicsEllipseItem
00055 {
00056 public:
00057
00058 NodeItem(int id, const Transform & pose, float radius) :
00059 QGraphicsEllipseItem(QRectF(-radius,-radius,radius*2.0f,radius*2.0f)),
00060 _id(id),
00061 _pose(pose)
00062 {
00063 this->setPos(-pose.y(),-pose.x());
00064 this->setBrush(pen().color());
00065 this->setAcceptHoverEvents(true);
00066 }
00067
00068 void setColor(const QColor & color)
00069 {
00070 QPen p = this->pen();
00071 p.setColor(color);
00072 this->setPen(p);
00073 QBrush b = this->brush();
00074 b.setColor(color);
00075 this->setBrush(b);
00076 }
00077
00078 const Transform & pose() const {return _pose;}
00079 void setPose(const Transform & pose) {this->setPos(-pose.y(),-pose.x()); _pose=pose;}
00080
00081 protected:
00082 virtual void hoverEnterEvent ( QGraphicsSceneHoverEvent * event )
00083 {
00084 this->setToolTip(QString("[%1] %2").arg(_id).arg(_pose.prettyPrint().c_str()));
00085 this->setScale(2);
00086 QGraphicsEllipseItem::hoverEnterEvent(event);
00087 }
00088
00089 virtual void hoverLeaveEvent ( QGraphicsSceneHoverEvent * event )
00090 {
00091 this->setScale(1);
00092 QGraphicsEllipseItem::hoverEnterEvent(event);
00093 }
00094
00095 private:
00096 int _id;
00097 Transform _pose;
00098 };
00099
00100 class LinkItem: public QGraphicsLineItem
00101 {
00102 public:
00103
00104 LinkItem(int from, int to, const Transform & poseA, const Transform & poseB, Link::Type type) :
00105 QGraphicsLineItem(-poseA.y(), -poseA.x(), -poseB.y(), -poseB.x()),
00106 _from(from),
00107 _to(to),
00108 _poseA(poseA),
00109 _poseB(poseB),
00110 _type(type)
00111 {
00112 this->setAcceptHoverEvents(true);
00113 }
00114
00115 void setColor(const QColor & color)
00116 {
00117 QPen p = this->pen();
00118 p.setColor(color);
00119 this->setPen(p);
00120 }
00121
00122 void setPoses(const Transform & poseA, const Transform & poseB)
00123 {
00124 this->setLine(-poseA.y(), -poseA.x(), -poseB.y(), -poseB.x());
00125 _poseA = poseA;
00126 _poseB = poseB;
00127 }
00128
00129 Link::Type linkType() const {return _type;}
00130 int from() const {return _from;}
00131 int to() const {return _to;}
00132
00133 protected:
00134 virtual void hoverEnterEvent ( QGraphicsSceneHoverEvent * event )
00135 {
00136 this->setToolTip(QString("%1->%2 %3 m").arg(_from).arg(_to).arg(_poseA.getDistance(_poseB)));
00137 QPen pen = this->pen();
00138 pen.setWidthF(pen.widthF()+0.02);
00139 this->setPen(pen);
00140 QGraphicsLineItem::hoverEnterEvent(event);
00141 }
00142
00143 virtual void hoverLeaveEvent ( QGraphicsSceneHoverEvent * event )
00144 {
00145 QPen pen = this->pen();
00146 pen.setWidthF(pen.widthF()-0.02);
00147 this->setPen(pen);
00148 QGraphicsLineItem::hoverEnterEvent(event);
00149 }
00150
00151 private:
00152 int _from;
00153 int _to;
00154 Transform _poseA;
00155 Transform _poseB;
00156 Link::Type _type;
00157 };
00158
00159 GraphViewer::GraphViewer(QWidget * parent) :
00160 QGraphicsView(parent),
00161 _nodeColor(Qt::blue),
00162 _currentGoalColor(Qt::darkMagenta),
00163 _neighborColor(Qt::blue),
00164 _loopClosureColor(Qt::red),
00165 _loopClosureLocalColor(Qt::yellow),
00166 _loopClosureUserColor(Qt::red),
00167 _loopClosureVirtualColor(Qt::magenta),
00168 _localPathColor(Qt::cyan),
00169 _globalPathColor(Qt::darkMagenta),
00170 _root(0),
00171 _nodeRadius(0.01),
00172 _linkWidth(0),
00173 _gridMap(0),
00174 _referential(0),
00175 _gridCellSize(0.0f),
00176 _localRadius(0)
00177 {
00178 this->setScene(new QGraphicsScene(this));
00179 this->setDragMode(QGraphicsView::ScrollHandDrag);
00180 _workingDirectory = QDir::homePath();
00181
00182 this->scene()->clear();
00183 _root = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
00184
00185
00186 _originReferential = new QGraphicsItemGroup();
00187 this->scene()->addItem(_originReferential);
00188 QGraphicsLineItem * item = this->scene()->addLine(0,0,0,-1, QPen(QBrush(Qt::red), _linkWidth));
00189 item->setZValue(100);
00190 item->setParentItem(_root);
00191 _originReferential->addToGroup(item);
00192 item = this->scene()->addLine(0,0,-1,0, QPen(QBrush(Qt::green), _linkWidth));
00193 item->setZValue(100);
00194 item->setParentItem(_root);
00195 _originReferential->addToGroup(item);
00196
00197
00198 _referential = new QGraphicsItemGroup();
00199 this->scene()->addItem(_referential);
00200 item = this->scene()->addLine(0,0,0,-0.5, QPen(QBrush(Qt::red), _linkWidth));
00201 item->setZValue(100);
00202 item->setParentItem(_root);
00203 _referential->addToGroup(item);
00204 item = this->scene()->addLine(0,0,-0.5,0, QPen(QBrush(Qt::green), _linkWidth));
00205 item->setZValue(100);
00206 item->setParentItem(_root);
00207 _referential->addToGroup(item);
00208
00209 _localRadius = this->scene()->addEllipse(-0.0001,-0.0001,0.0001,0.0001);
00210 _localRadius->setZValue(1);
00211 _localRadius->setParentItem(_root);
00212 _localRadius->setVisible(false);
00213 _localRadius->setPen(QPen(Qt::DashLine));
00214
00215 _gridMap = this->scene()->addPixmap(QPixmap());
00216 _gridMap->setZValue(0);
00217 _gridMap->setParentItem(_root);
00218
00219 this->restoreDefaults();
00220
00221 this->fitInView(this->sceneRect(), Qt::KeepAspectRatio);
00222 }
00223
00224 GraphViewer::~GraphViewer()
00225 {
00226 }
00227
00228 void GraphViewer::updateGraph(const std::map<int, Transform> & poses,
00229 const std::multimap<int, Link> & constraints)
00230 {
00231 bool wasEmpty = _nodeItems.size() == 0 && _linkItems.size() == 0;
00232 UDEBUG("poses=%d constraints=%d", (int)poses.size(), (int)constraints.size());
00233
00234 for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
00235 {
00236 iter.value()->hide();
00237 iter.value()->setColor(_nodeColor);
00238 }
00239 for(QMultiMap<int, LinkItem*>::iterator iter = _linkItems.begin(); iter!=_linkItems.end(); ++iter)
00240 {
00241 iter.value()->hide();
00242 }
00243
00244 for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
00245 {
00246 if(!iter->second.isNull())
00247 {
00248 QMap<int, NodeItem*>::iterator itemIter = _nodeItems.find(iter->first);
00249 if(itemIter != _nodeItems.end())
00250 {
00251 itemIter.value()->setPose(iter->second);
00252 itemIter.value()->show();
00253 }
00254 else
00255 {
00256
00257 const Transform & pose = iter->second;
00258 NodeItem * item = new NodeItem(iter->first, pose, _nodeRadius);
00259 this->scene()->addItem(item);
00260 item->setZValue(20);
00261 item->setColor(_nodeColor);
00262 item->setParentItem(_root);
00263 _nodeItems.insert(iter->first, item);
00264 }
00265 }
00266 }
00267
00268 for(std::multimap<int, Link>::const_iterator iter=constraints.begin(); iter!=constraints.end(); ++iter)
00269 {
00270
00271 int idFrom = iter->first<iter->second.to()?iter->first:iter->second.to();
00272 int idTo = iter->first<iter->second.to()?iter->second.to():iter->first;
00273
00274 std::map<int, Transform>::const_iterator jterA = poses.find(idFrom);
00275 std::map<int, Transform>::const_iterator jterB = poses.find(idTo);
00276 if(jterA != poses.end() && jterB != poses.end() &&
00277 _nodeItems.contains(iter->first) && _nodeItems.contains(idTo))
00278 {
00279 const Transform & poseA = jterA->second;
00280 const Transform & poseB = jterB->second;
00281
00282 bool added = false;
00283 if(_linkItems.contains(idFrom))
00284 {
00285 QMultiMap<int, LinkItem*>::iterator itemIter = _linkItems.find(iter->first);
00286 while(itemIter.key() == idFrom && itemIter != _linkItems.end())
00287 {
00288 if(itemIter.value()->to() == idTo)
00289 {
00290 itemIter.value()->setPoses(poseA, poseB);
00291 itemIter.value()->show();
00292 added = true;
00293
00294 if(iter->second.type() == Link::kNeighbor)
00295 {
00296 itemIter.value()->setColor(_neighborColor);
00297 }
00298 else if(iter->second.type() == Link::kVirtualClosure)
00299 {
00300 itemIter.value()->setColor(_loopClosureVirtualColor);
00301 }
00302 else if(iter->second.type() == Link::kUserClosure)
00303 {
00304 itemIter.value()->setColor(_loopClosureUserColor);
00305 }
00306 else if(iter->second.type() == Link::kLocalSpaceClosure || iter->second.type() == Link::kLocalTimeClosure)
00307 {
00308 itemIter.value()->setColor(_loopClosureLocalColor);
00309 }
00310 else
00311 {
00312 itemIter.value()->setColor(_loopClosureColor);
00313 }
00314 break;
00315 }
00316 ++itemIter;
00317 }
00318 }
00319 if(!added)
00320 {
00321
00322 LinkItem * item = new LinkItem(idFrom, idTo, poseA, poseB, iter->second.type());
00323 QPen p = item->pen();
00324 p.setWidthF(_linkWidth);
00325 item->setPen(p);
00326 if(iter->second.type() == Link::kNeighbor)
00327 {
00328 item->setColor(_neighborColor);
00329 }
00330 else if(iter->second.type() == Link::kVirtualClosure)
00331 {
00332 item->setColor(_loopClosureVirtualColor);
00333 }
00334 else if(iter->second.type() == Link::kUserClosure)
00335 {
00336 item->setColor(_loopClosureUserColor);
00337 }
00338 else if(iter->second.type() == Link::kLocalSpaceClosure || iter->second.type() == Link::kLocalTimeClosure)
00339 {
00340 item->setColor(_loopClosureLocalColor);
00341 }
00342 else
00343 {
00344 item->setColor(_loopClosureColor);
00345 }
00346 this->scene()->addItem(item);
00347 item->setZValue(10);
00348 item->setParentItem(_root);
00349 _linkItems.insert(idFrom, item);
00350 }
00351 }
00352 }
00353
00354
00355 for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end();)
00356 {
00357 if(!iter.value()->isVisible())
00358 {
00359 delete iter.value();
00360 iter = _nodeItems.erase(iter);
00361 }
00362 else
00363 {
00364 ++iter;
00365 }
00366 }
00367 for(QMultiMap<int, LinkItem*>::iterator iter = _linkItems.begin(); iter!=_linkItems.end();)
00368 {
00369 if(!iter.value()->isVisible())
00370 {
00371 delete iter.value();
00372 iter = _linkItems.erase(iter);
00373 }
00374 else
00375 {
00376 ++iter;
00377 }
00378 }
00379
00380 if(_nodeItems.size())
00381 {
00382 (--_nodeItems.end()).value()->setColor(Qt::green);
00383 }
00384
00385 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
00386
00387 if(wasEmpty)
00388 {
00389 this->fitInView(this->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
00390 }
00391 }
00392
00393 void GraphViewer::updateReferentialPosition(const Transform & t)
00394 {
00395 QTransform qt(t.r11(), t.r12(), t.r21(), t.r22(), -t.o24(), -t.o14());
00396 _referential->setTransform(qt);
00397 _localRadius->setTransform(qt);
00398
00399 this->ensureVisible(_referential);
00400 if(_localRadius->isVisible())
00401 {
00402 this->ensureVisible(_localRadius, 0, 0);
00403 }
00404 }
00405
00406 void GraphViewer::updateMap(const cv::Mat & map8U, float resolution, float xMin, float yMin)
00407 {
00408 UASSERT(map8U.empty() || (!map8U.empty() && resolution > 0.0f));
00409 if(!map8U.empty())
00410 {
00411 _gridCellSize = resolution;
00412 QImage image = uCvMat2QImage(map8U, false);
00413 _gridMap->resetTransform();
00414 _gridMap->setTransform(QTransform::fromScale(resolution, -resolution), true);
00415 _gridMap->setRotation(90);
00416 _gridMap->setPixmap(QPixmap::fromImage(image));
00417 _gridMap->setPos(-yMin, -xMin);
00418 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
00419 }
00420 else
00421 {
00422 this->clearMap();
00423 }
00424 }
00425
00426 void GraphViewer::updatePosterior(const std::map<int, float> & posterior)
00427 {
00428
00429 float max = 0.0f;
00430 for(std::map<int, float>::const_iterator iter = posterior.begin(); iter!=posterior.end(); ++iter)
00431 {
00432 if(iter->first > 0 && iter->second>max)
00433 {
00434 max = iter->second;
00435 }
00436 }
00437 if(max > 0.0f)
00438 {
00439 for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
00440 {
00441 std::map<int,float>::const_iterator jter = posterior.find(iter.key());
00442 if(jter != posterior.end())
00443 {
00444 UDEBUG("id=%d max=%f hyp=%f color = %f", iter.key(), max, jter->second, (1-jter->second/max)*240.0f/360.0f);
00445 iter.value()->setColor(QColor::fromHsvF((1-jter->second/max)*240.0f/360.0f, 1, 1, 1));
00446 }
00447 else
00448 {
00449 iter.value()->setColor(QColor::fromHsvF(240.0f/360.0f, 1, 1, 1));
00450 }
00451 }
00452 }
00453 }
00454
00455 void GraphViewer::setGlobalPath(const std::vector<std::pair<int, Transform> > & globalPath)
00456 {
00457 UDEBUG("Set global path size=%d", (int)globalPath.size());
00458 qDeleteAll(_globalPathLinkItems);
00459 _globalPathLinkItems.clear();
00460
00461 if(globalPath.size() >= 2)
00462 {
00463 for(unsigned int i=0; i<globalPath.size()-1; ++i)
00464 {
00465
00466 int idFrom = globalPath[i].first;
00467 int idTo = globalPath[i+1].first;
00468 LinkItem * item = new LinkItem(idFrom, idTo, globalPath[i].second, globalPath[i+1].second, Link::kUndef);
00469 QPen p = item->pen();
00470 p.setWidthF(_linkWidth);
00471 item->setPen(p);
00472 item->setColor(_globalPathColor);
00473 this->scene()->addItem(item);
00474 item->setZValue(15);
00475 item->setParentItem(_root);
00476 _globalPathLinkItems.insert(idFrom, item);
00477 }
00478 }
00479 }
00480
00481 void GraphViewer::setCurrentGoalID(int id)
00482 {
00483 NodeItem * node = _nodeItems.value(id, 0);
00484 if(node)
00485 {
00486 node->setColor(_currentGoalColor);
00487 }
00488 else
00489 {
00490 UWARN("Curent goal %d not found in the graph", id);
00491 }
00492 }
00493
00494 void GraphViewer::setLocalRadius(float radius)
00495 {
00496 _localRadius->setRect(-radius, -radius, radius*2, radius*2);
00497 }
00498
00499 void GraphViewer::updateLocalPath(const std::vector<int> & localPath)
00500 {
00501 for(QMultiMap<int, LinkItem*>::iterator iter = _localPathLinkItems.begin(); iter!=_localPathLinkItems.end(); ++iter)
00502 {
00503 iter.value()->hide();
00504 }
00505
00506 if(localPath.size() > 1)
00507 {
00508 for(unsigned int i=0; i<localPath.size()-1; ++i)
00509 {
00510 int idFrom = localPath[i]<localPath[i+1]?localPath[i]:localPath[i+1];
00511 int idTo = localPath[i]<localPath[i+1]?localPath[i+1]:localPath[i];
00512 if(_nodeItems.contains(idFrom) && _nodeItems.contains(idTo))
00513 {
00514 bool updated = false;
00515 if(_localPathLinkItems.contains(idFrom))
00516 {
00517 QMultiMap<int, LinkItem*>::iterator itemIter = _localPathLinkItems.find(idFrom);
00518 while(itemIter.key() == idFrom && itemIter != _localPathLinkItems.end())
00519 {
00520 if(itemIter.value()->to() == idTo)
00521 {
00522 itemIter.value()->setPoses(_nodeItems.value(idFrom)->pose(), _nodeItems.value(idTo)->pose());
00523 itemIter.value()->show();
00524 updated = true;
00525 break;
00526 }
00527 ++itemIter;
00528 }
00529 }
00530 if(!updated)
00531 {
00532
00533 LinkItem * item = new LinkItem(idFrom, idTo, _nodeItems.value(idFrom)->pose(), _nodeItems.value(idTo)->pose(), Link::kUndef);
00534 QPen p = item->pen();
00535 p.setWidthF(_linkWidth);
00536 item->setPen(p);
00537 item->setColor(_localPathColor);
00538 this->scene()->addItem(item);
00539 item->setZValue(16);
00540 item->setParentItem(_root);
00541 _localPathLinkItems.insert(idFrom, item);
00542 }
00543 }
00544 }
00545 }
00546
00547
00548 for(QMultiMap<int, LinkItem*>::iterator iter = _localPathLinkItems.begin(); iter!=_localPathLinkItems.end();)
00549 {
00550 if(!iter.value()->isVisible())
00551 {
00552 delete iter.value();
00553 iter = _localPathLinkItems.erase(iter);
00554 }
00555 else
00556 {
00557 ++iter;
00558 }
00559 }
00560 }
00561
00562 void GraphViewer::clearGraph()
00563 {
00564 qDeleteAll(_nodeItems);
00565 _nodeItems.clear();
00566 qDeleteAll(_linkItems);
00567 _linkItems.clear();
00568 qDeleteAll(_localPathLinkItems);
00569 _localPathLinkItems.clear();
00570 qDeleteAll(_globalPathLinkItems);
00571 _globalPathLinkItems.clear();
00572
00573 _referential->resetTransform();
00574 _localRadius->resetTransform();
00575 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
00576 }
00577
00578 void GraphViewer::clearMap()
00579 {
00580 _gridMap->setPixmap(QPixmap());
00581 _gridCellSize = 0.0f;
00582 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
00583 }
00584
00585 void GraphViewer::clearPosterior()
00586 {
00587 for(QMap<int, NodeItem*>::iterator iter = _nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
00588 {
00589 iter.value()->setColor(Qt::blue);
00590 }
00591 }
00592
00593 void GraphViewer::clearAll()
00594 {
00595 clearMap();
00596 clearGraph();
00597 }
00598
00599 void GraphViewer::saveSettings(QSettings & settings, const QString & group) const
00600 {
00601 if(!group.isEmpty())
00602 {
00603 settings.beginGroup(group);
00604 }
00605 settings.setValue("node_radius", (double)this->getNodeRadius());
00606 settings.setValue("link_width", (double)this->getLinkWidth());
00607 settings.setValue("node_color", this->getNodeColor());
00608 settings.setValue("current_goal_color", this->getCurrentGoalColor());
00609 settings.setValue("neighbor_color", this->getNeighborColor());
00610 settings.setValue("global_color", this->getGlobalLoopClosureColor());
00611 settings.setValue("local_color", this->getLocalLoopClosureColor());
00612 settings.setValue("user_color", this->getUserLoopClosureColor());
00613 settings.setValue("virtual_color", this->getVirtualLoopClosureColor());
00614 settings.setValue("local_path_color", this->getLocalPathColor());
00615 settings.setValue("global_path_color", this->getGlobalPathColor());
00616 settings.setValue("grid_visible", this->isGridMapVisible());
00617 settings.setValue("origin_visible", this->isOriginVisible());
00618 settings.setValue("referential_visible", this->isReferentialVisible());
00619 settings.setValue("local_radius_visible", this->isLocalRadiusVisible());
00620 if(!group.isEmpty())
00621 {
00622 settings.endGroup();
00623 }
00624 }
00625
00626 void GraphViewer::loadSettings(QSettings & settings, const QString & group)
00627 {
00628 if(!group.isEmpty())
00629 {
00630 settings.beginGroup(group);
00631 }
00632 this->setNodeRadius(settings.value("node_radius", this->getNodeRadius()).toDouble());
00633 this->setLinkWidth(settings.value("link_width", this->getLinkWidth()).toDouble());
00634 this->setNodeColor(settings.value("node_color", this->getNodeColor()).value<QColor>());
00635 this->setCurrentGoalColor(settings.value("current_goal_color", this->getCurrentGoalColor()).value<QColor>());
00636 this->setNeighborColor(settings.value("neighbor_color", this->getNeighborColor()).value<QColor>());
00637 this->setGlobalLoopClosureColor(settings.value("global_color", this->getGlobalLoopClosureColor()).value<QColor>());
00638 this->setLocalLoopClosureColor(settings.value("local_color", this->getLocalLoopClosureColor()).value<QColor>());
00639 this->setUserLoopClosureColor(settings.value("user_color", this->getUserLoopClosureColor()).value<QColor>());
00640 this->setVirtualLoopClosureColor(settings.value("virtual_color", this->getVirtualLoopClosureColor()).value<QColor>());
00641 this->setLocalPathColor(settings.value("local_path_color", this->getLocalPathColor()).value<QColor>());
00642 this->setGlobalPathColor(settings.value("global_path_color", this->getGlobalPathColor()).value<QColor>());
00643 this->setGridMapVisible(settings.value("grid_visible", this->isGridMapVisible()).toBool());
00644 this->setOriginVisible(settings.value("origin_visible", this->isOriginVisible()).toBool());
00645 this->setReferentialVisible(settings.value("referential_visible", this->isReferentialVisible()).toBool());
00646 this->setLocalRadiusVisible(settings.value("local_radius_visible", this->isLocalRadiusVisible()).toBool());
00647 if(!group.isEmpty())
00648 {
00649 settings.endGroup();
00650 }
00651 }
00652
00653 bool GraphViewer::isGridMapVisible() const
00654 {
00655 return _gridMap->isVisible();
00656 }
00657 bool GraphViewer::isOriginVisible() const
00658 {
00659 return _originReferential->isVisible();
00660 }
00661 bool GraphViewer::isReferentialVisible() const
00662 {
00663 return _referential->isVisible();
00664 }
00665 bool GraphViewer::isLocalRadiusVisible() const
00666 {
00667 return _localRadius->isVisible();
00668 }
00669
00670 void GraphViewer::setWorkingDirectory(const QString & path)
00671 {
00672 _workingDirectory = path;
00673 }
00674 void GraphViewer::setNodeRadius(float radius)
00675 {
00676 _nodeRadius = radius;
00677 for(QMap<int, NodeItem*>::iterator iter=_nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
00678 {
00679 iter.value()->setRect(-_nodeRadius, -_nodeRadius, _nodeRadius*2.0f, _nodeRadius*2.0f);
00680 }
00681 }
00682 void GraphViewer::setLinkWidth(float width)
00683 {
00684 _linkWidth = width;
00685 QList<QGraphicsItem*> items = this->scene()->items();
00686 for(int i=0; i<items.size(); ++i)
00687 {
00688 QGraphicsLineItem * line = qgraphicsitem_cast<QGraphicsLineItem *>(items[i]);
00689 if(line)
00690 {
00691 QPen pen = line->pen();
00692 pen.setWidthF(_linkWidth);
00693 line->setPen(pen);
00694 }
00695 }
00696 }
00697 void GraphViewer::setNodeColor(const QColor & color)
00698 {
00699 _nodeColor = color;
00700 for(QMap<int, NodeItem*>::iterator iter=_nodeItems.begin(); iter!=_nodeItems.end(); ++iter)
00701 {
00702 iter.value()->setColor(_nodeColor);
00703 }
00704 }
00705 void GraphViewer::setCurrentGoalColor(const QColor & color)
00706 {
00707 _currentGoalColor = color;
00708 }
00709 void GraphViewer::setNeighborColor(const QColor & color)
00710 {
00711 _neighborColor = color;
00712 for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
00713 {
00714 if(iter.value()->linkType() == Link::kNeighbor)
00715 {
00716 iter.value()->setColor(_neighborColor);
00717 }
00718 }
00719 }
00720 void GraphViewer::setGlobalLoopClosureColor(const QColor & color)
00721 {
00722 _loopClosureColor = color;
00723 for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
00724 {
00725 if(iter.value()->linkType() != Link::kNeighbor &&
00726 iter.value()->linkType() != Link::kLocalSpaceClosure &&
00727 iter.value()->linkType() != Link::kLocalTimeClosure &&
00728 iter.value()->linkType() != Link::kUserClosure &&
00729 iter.value()->linkType() != Link::kVirtualClosure)
00730 {
00731 iter.value()->setColor(_loopClosureColor);
00732 }
00733 }
00734 }
00735 void GraphViewer::setLocalLoopClosureColor(const QColor & color)
00736 {
00737 _loopClosureLocalColor = color;
00738 for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
00739 {
00740 if(iter.value()->linkType() == Link::kLocalSpaceClosure ||
00741 iter.value()->linkType() == Link::kLocalTimeClosure)
00742 {
00743 iter.value()->setColor(_loopClosureLocalColor);
00744 }
00745 }
00746 }
00747 void GraphViewer::setUserLoopClosureColor(const QColor & color)
00748 {
00749 _loopClosureUserColor = color;
00750 for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
00751 {
00752 if(iter.value()->linkType() == Link::kUserClosure)
00753 {
00754 iter.value()->setColor(_loopClosureUserColor);
00755 }
00756 }
00757 }
00758 void GraphViewer::setVirtualLoopClosureColor(const QColor & color)
00759 {
00760 _loopClosureVirtualColor = color;
00761 for(QMultiMap<int, LinkItem*>::iterator iter=_linkItems.begin(); iter!=_linkItems.end(); ++iter)
00762 {
00763 if(iter.value()->linkType() == Link::kVirtualClosure)
00764 {
00765 iter.value()->setColor(_loopClosureVirtualColor);
00766 }
00767 }
00768 }
00769 void GraphViewer::setLocalPathColor(const QColor & color)
00770 {
00771 _localPathColor = color;
00772 }
00773 void GraphViewer::setGlobalPathColor(const QColor & color)
00774 {
00775 _globalPathColor = color;
00776 }
00777 void GraphViewer::setGridMapVisible(bool visible)
00778 {
00779 _gridMap->setVisible(visible);
00780 }
00781 void GraphViewer::setOriginVisible(bool visible)
00782 {
00783 _originReferential->setVisible(visible);
00784 }
00785 void GraphViewer::setReferentialVisible(bool visible)
00786 {
00787 _referential->setVisible(visible);
00788 }
00789 void GraphViewer::setLocalRadiusVisible(bool visible)
00790 {
00791 _localRadius->setVisible(visible);
00792 }
00793
00794 void GraphViewer::restoreDefaults()
00795 {
00796 setNodeRadius(0.01f);
00797 setLinkWidth(0.0f);
00798 setNodeColor(Qt::blue);
00799 setNeighborColor(Qt::blue);
00800 setGlobalLoopClosureColor(Qt::red);
00801 setLocalLoopClosureColor(Qt::yellow);
00802 setUserLoopClosureColor(Qt::red);
00803 setVirtualLoopClosureColor(Qt::magenta);
00804 setGridMapVisible(true);
00805 }
00806
00807
00808 void GraphViewer::wheelEvent ( QWheelEvent * event )
00809 {
00810 if(event->delta() < 0)
00811 {
00812 this->scale(0.95, 0.95);
00813 }
00814 else
00815 {
00816 this->scale(1.05, 1.05);
00817 }
00818 }
00819
00820 QIcon createIcon(const QColor & color)
00821 {
00822 QPixmap pixmap(50, 50);
00823 pixmap.fill(color);
00824 return QIcon(pixmap);
00825 }
00826
00827 void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
00828 {
00829 QMenu menu;
00830 QAction * aScreenShotPNG = menu.addAction(tr("Take a screenshot (PNG)"));
00831 QAction * aScreenShotSVG = menu.addAction(tr("Take a screenshot (SVG)"));
00832 menu.addSeparator();
00833
00834 QAction * aChangeNodeColor = menu.addAction(createIcon(_nodeColor), tr("Set node color..."));
00835 QAction * aChangeCurrentGoalColor = menu.addAction(createIcon(_currentGoalColor), tr("Set current goal color..."));
00836 aChangeNodeColor->setIconVisibleInMenu(true);
00837 aChangeCurrentGoalColor->setIconVisibleInMenu(true);
00838
00839
00840 QMenu * menuLink = menu.addMenu(tr("Set link color..."));
00841 QAction * aChangeNeighborColor = menuLink->addAction(tr("Neighbor"));
00842 QAction * aChangeGlobalLoopColor = menuLink->addAction(tr("Global loop closure"));
00843 QAction * aChangeLocalLoopColor = menuLink->addAction(tr("Local loop closure"));
00844 QAction * aChangeUserLoopColor = menuLink->addAction(tr("User loop closure"));
00845 QAction * aChangeVirtualLoopColor = menuLink->addAction(tr("Virtual loop closure"));
00846 QAction * aChangeLocalPathColor = menuLink->addAction(tr("Local path"));
00847 QAction * aChangeGlobalPathColor = menuLink->addAction(tr("Global path"));
00848 aChangeNeighborColor->setIcon(createIcon(_neighborColor));
00849 aChangeGlobalLoopColor->setIcon(createIcon(_loopClosureColor));
00850 aChangeLocalLoopColor->setIcon(createIcon(_loopClosureLocalColor));
00851 aChangeUserLoopColor->setIcon(createIcon(_loopClosureUserColor));
00852 aChangeVirtualLoopColor->setIcon(createIcon(_loopClosureVirtualColor));
00853 aChangeLocalPathColor->setIcon(createIcon(_localPathColor));
00854 aChangeGlobalPathColor->setIcon(createIcon(_globalPathColor));
00855 aChangeNeighborColor->setIconVisibleInMenu(true);
00856 aChangeGlobalLoopColor->setIconVisibleInMenu(true);
00857 aChangeLocalLoopColor->setIconVisibleInMenu(true);
00858 aChangeUserLoopColor->setIconVisibleInMenu(true);
00859 aChangeVirtualLoopColor->setIconVisibleInMenu(true);
00860 aChangeLocalPathColor->setIconVisibleInMenu(true);
00861 aChangeGlobalPathColor->setIconVisibleInMenu(true);
00862
00863 menu.addSeparator();
00864 QAction * aSetNodeSize = menu.addAction(tr("Set node radius..."));
00865 QAction * aSetLinkSize = menu.addAction(tr("Set link width..."));
00866 menu.addSeparator();
00867 QAction * aShowHideGridMap;
00868 QAction * aShowHideOrigin;
00869 QAction * aShowHideReferential;
00870 QAction * aShowHideLocalRadius;
00871 QAction * aClearGlobalPath;
00872 if(_gridMap->isVisible())
00873 {
00874 aShowHideGridMap = menu.addAction(tr("Hide grid map"));
00875 }
00876 else
00877 {
00878 aShowHideGridMap = menu.addAction(tr("Show grid map"));
00879 }
00880 if(_originReferential->isVisible())
00881 {
00882 aShowHideOrigin = menu.addAction(tr("Hide origin referential"));
00883 }
00884 else
00885 {
00886 aShowHideOrigin = menu.addAction(tr("Show origin referential"));
00887 }
00888 if(_referential->isVisible())
00889 {
00890 aShowHideReferential = menu.addAction(tr("Hide current referential"));
00891 }
00892 else
00893 {
00894 aShowHideReferential = menu.addAction(tr("Show current referential"));
00895 }
00896 if(_localRadius->isVisible())
00897 {
00898 aShowHideLocalRadius = menu.addAction(tr("Hide local radius"));
00899 }
00900 else
00901 {
00902 aShowHideLocalRadius = menu.addAction(tr("Show local radius"));
00903 }
00904 if(_globalPathLinkItems.size() && _globalPathLinkItems.begin().value()->isVisible())
00905 {
00906 aClearGlobalPath = menu.addAction(tr("Hide global path"));
00907 }
00908 else
00909 {
00910 aClearGlobalPath = menu.addAction(tr("Show global path"));
00911 }
00912 aClearGlobalPath->setEnabled(_globalPathLinkItems.size());
00913 menu.addSeparator();
00914 QAction * aRestoreDefaults = menu.addAction(tr("Restore defaults"));
00915
00916 QAction * r = menu.exec(event->globalPos());
00917 if(r == aScreenShotPNG || r == aScreenShotSVG)
00918 {
00919 if(_root)
00920 {
00921 QString targetDir = _workingDirectory + "/ScreensCaptured";
00922 QDir dir;
00923 if(!dir.exists(targetDir))
00924 {
00925 dir.mkdir(targetDir);
00926 }
00927 targetDir += "/";
00928 targetDir += "Graph_view";
00929 if(!dir.exists(targetDir))
00930 {
00931 dir.mkdir(targetDir);
00932 }
00933 targetDir += "/";
00934 bool isPNG = r == aScreenShotPNG;
00935 QString name = (QDateTime::currentDateTime().toString("yyMMddhhmmsszzz") + (isPNG?".png":".svg"));
00936
00937 if(_gridCellSize)
00938 {
00939 _root->setScale(1.0f/_gridCellSize);
00940 }
00941 else
00942 {
00943 _root->setScale(this->transform().m11());
00944 }
00945
00946 this->scene()->clearSelection();
00947 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
00948 QSize sceneSize = this->scene()->sceneRect().size().toSize();
00949
00950 if(isPNG)
00951 {
00952 QImage image(sceneSize, QImage::Format_ARGB32);
00953 image.fill(Qt::transparent);
00954 QPainter painter(&image);
00955
00956 this->scene()->render(&painter);
00957 image.save(targetDir + name);
00958 }
00959 else
00960 {
00961 QSvgGenerator svgGen;
00962
00963 svgGen.setFileName( targetDir + name );
00964 svgGen.setSize(sceneSize);
00965 svgGen.setViewBox(QRect(0, 0, sceneSize.width(), sceneSize.height()));
00966 svgGen.setTitle(tr("RTAB-Map graph"));
00967 svgGen.setDescription(tr("RTAB-Map map and graph"));
00968
00969 QPainter painter( &svgGen );
00970
00971 this->scene()->render(&painter);
00972 }
00973
00974
00975 _root->setScale(1.0f);
00976 this->scene()->setSceneRect(this->scene()->itemsBoundingRect());
00977
00978
00979 QDesktopServices::openUrl(QUrl::fromLocalFile(targetDir + name));
00980 }
00981 return;
00982 }
00983 else if(r == aChangeNodeColor ||
00984 r == aChangeCurrentGoalColor ||
00985 r == aChangeNeighborColor ||
00986 r == aChangeGlobalLoopColor ||
00987 r == aChangeLocalLoopColor ||
00988 r == aChangeUserLoopColor ||
00989 r == aChangeVirtualLoopColor ||
00990 r == aChangeLocalPathColor ||
00991 r == aChangeGlobalPathColor)
00992 {
00993 QColor color;
00994 if(r == aChangeNodeColor)
00995 {
00996 color = _nodeColor;
00997 }
00998 else if(r == aChangeCurrentGoalColor)
00999 {
01000 color = _currentGoalColor;
01001 }
01002 else if(r == aChangeGlobalLoopColor)
01003 {
01004 color = _loopClosureColor;
01005 }
01006 else if(r == aChangeLocalLoopColor)
01007 {
01008 color = _loopClosureLocalColor;
01009 }
01010 else if(r == aChangeUserLoopColor)
01011 {
01012 color = _loopClosureUserColor;
01013 }
01014 else if(r == aChangeVirtualLoopColor)
01015 {
01016 color = _loopClosureVirtualColor;
01017 }
01018 else if(r == aChangeLocalPathColor)
01019 {
01020 color = _localPathColor;
01021 }
01022 else if(r == aChangeGlobalPathColor)
01023 {
01024 color = _globalPathColor;
01025 }
01026 else
01027 {
01028 color = _neighborColor;
01029 }
01030 color = QColorDialog::getColor(color, this);
01031 if(color.isValid())
01032 {
01033
01034 if(r == aChangeNodeColor)
01035 {
01036 this->setNodeColor(color);
01037 }
01038 else if(r == aChangeCurrentGoalColor)
01039 {
01040 this->setCurrentGoalColor(color);
01041 }
01042 else if(r == aChangeGlobalLoopColor)
01043 {
01044 this->setGlobalLoopClosureColor(color);
01045 }
01046 else if(r == aChangeLocalLoopColor)
01047 {
01048 this->setLocalLoopClosureColor(color);
01049 }
01050 else if(r == aChangeUserLoopColor)
01051 {
01052 this->setUserLoopClosureColor(color);
01053 }
01054 else if(r == aChangeVirtualLoopColor)
01055 {
01056 this->setVirtualLoopClosureColor(color);
01057 }
01058 else if(r == aChangeLocalPathColor)
01059 {
01060 this->setLocalPathColor(color);
01061 }
01062 else
01063 {
01064 this->setNeighborColor(color);
01065 }
01066 }
01067 else
01068 {
01069 return;
01070 }
01071 }
01072 else if(r == aSetNodeSize)
01073 {
01074 bool ok;
01075 double value = QInputDialog::getDouble(this, tr("Node radius"), tr("Radius (m)"), _nodeRadius, 0.001, 100, 3, &ok);
01076 if(ok)
01077 {
01078 setNodeRadius(value);
01079 }
01080 }
01081 else if(r == aSetLinkSize)
01082 {
01083 bool ok;
01084 double value = QInputDialog::getDouble(this, tr("Link width"), tr("Width (m)"), _linkWidth, 0, 100, 2, &ok);
01085 if(ok)
01086 {
01087 setLinkWidth(value);
01088 }
01089 }
01090 else if(r == aShowHideGridMap)
01091 {
01092 this->setGridMapVisible(!this->isGridMapVisible());
01093 }
01094 else if(r == aShowHideOrigin)
01095 {
01096 this->setOriginVisible(!this->isOriginVisible());
01097 }
01098 else if(r == aShowHideReferential)
01099 {
01100 this->setReferentialVisible(!this->isReferentialVisible());
01101 }
01102 else if(r == aShowHideLocalRadius)
01103 {
01104 this->setLocalRadiusVisible(!this->isLocalRadiusVisible());
01105 }
01106 else if(r == aRestoreDefaults)
01107 {
01108 this->restoreDefaults();
01109 }
01110 else if(r == aClearGlobalPath)
01111 {
01112 for(QMap<int, LinkItem*>::iterator iter=_globalPathLinkItems.begin(); iter!=_globalPathLinkItems.end(); ++iter)
01113 {
01114 iter.value()->setVisible(!iter.value()->isVisible());
01115 }
01116 }
01117 if(r)
01118 {
01119 emit configChanged();
01120 }
01121 }
01122
01123 }