mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-01 17:10:26 +08:00
Faster graph zoom by using a snapshot-preview (#1728)
* Faster graph zoom by using a snapshot-preview * Added "Fast Zooming..." menu option --------- Co-authored-by: matlabbe <matlabbe@gmail.com>
This commit is contained in:
@@ -33,6 +33,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <QGraphicsView>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QSettings>
|
||||
#include <QTimer>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <rtabmap/core/Link.h>
|
||||
#include <rtabmap/core/GPS.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
@@ -130,6 +132,7 @@ public:
|
||||
bool isOrientationENU() const;
|
||||
ViewPlane getViewPlane() const;
|
||||
bool isEnsureFrameVisible() const;
|
||||
int getFastZoomMinNodes() const;
|
||||
|
||||
// setters
|
||||
void setWorkingDirectory(const QString & path);
|
||||
@@ -170,6 +173,7 @@ public:
|
||||
void setOrientationENU(bool enabled);
|
||||
void setViewPlane(ViewPlane plane);
|
||||
void setEnsureFrameVisible(bool visible);
|
||||
void setFastZoomMinNodes(int value);
|
||||
|
||||
Q_SIGNALS:
|
||||
void configChanged();
|
||||
@@ -184,11 +188,14 @@ protected:
|
||||
virtual void wheelEvent ( QWheelEvent * event );
|
||||
virtual void mouseMoveEvent(QMouseEvent * event);
|
||||
virtual void mousePressEvent(QMouseEvent * event);
|
||||
virtual void mouseReleaseEvent(QMouseEvent * event);
|
||||
virtual void contextMenuEvent(QContextMenuEvent * event);
|
||||
|
||||
private:
|
||||
void setupGraphicsScene();
|
||||
|
||||
void startZoomOverlay();
|
||||
void updateZoomOverlay();
|
||||
void stopZoomOverlay();
|
||||
private:
|
||||
QString _workingDirectory;
|
||||
QColor _nodeColor;
|
||||
@@ -248,6 +255,11 @@ private:
|
||||
ViewPlane _viewPlane;
|
||||
bool _ensureFrameVisible;
|
||||
QPoint _previousMousePos;
|
||||
QPoint _initialMousePos;
|
||||
QTimer _zoomDebounceTimer;
|
||||
QGraphicsPixmapItem * _zoomOverlayItem;
|
||||
bool _zoomOverlayActive;
|
||||
int _fastZoomMinNodes;
|
||||
};
|
||||
|
||||
} /* namespace rtabmap */
|
||||
|
||||
@@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsEllipseItem>
|
||||
#include <QGraphicsRectItem>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QtGui/QWheelEvent>
|
||||
#include <QGraphicsSceneHoverEvent>
|
||||
#include <QMenu>
|
||||
@@ -341,10 +342,18 @@ GraphViewer::GraphViewer(QWidget * parent) :
|
||||
_orientationENU(false),
|
||||
_mouseTracking(false),
|
||||
_viewPlane(XY),
|
||||
_ensureFrameVisible(true)
|
||||
_ensureFrameVisible(true),
|
||||
_previousMousePos(-1,-1),
|
||||
_initialMousePos(-1,-1),
|
||||
_zoomDebounceTimer(this),
|
||||
_zoomOverlayItem(0),
|
||||
_zoomOverlayActive(false),
|
||||
_fastZoomMinNodes(0)
|
||||
{
|
||||
this->setDragMode(QGraphicsView::ScrollHandDrag);
|
||||
_workingDirectory = QDir::homePath();
|
||||
_zoomDebounceTimer.setSingleShot(true);
|
||||
connect(&_zoomDebounceTimer, &QTimer::timeout, this, &GraphViewer::stopZoomOverlay);
|
||||
|
||||
setupGraphicsScene();
|
||||
|
||||
@@ -355,6 +364,9 @@ GraphViewer::GraphViewer(QWidget * parent) :
|
||||
this->restoreDefaults();
|
||||
|
||||
this->fitInView(this->sceneRect(), Qt::KeepAspectRatio);
|
||||
|
||||
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
|
||||
setResizeAnchor(QGraphicsView::AnchorUnderMouse);
|
||||
}
|
||||
|
||||
GraphViewer::~GraphViewer()
|
||||
@@ -363,11 +375,20 @@ GraphViewer::~GraphViewer()
|
||||
|
||||
void GraphViewer::setupGraphicsScene()
|
||||
{
|
||||
_zoomDebounceTimer.stop();
|
||||
_zoomOverlayActive = false;
|
||||
_zoomOverlayItem = 0;
|
||||
if(this->scene())
|
||||
{
|
||||
delete this->scene();
|
||||
}
|
||||
this->setScene(new QGraphicsScene(this));
|
||||
_zoomOverlayItem = this->scene()->addPixmap(QPixmap());
|
||||
_zoomOverlayItem->setZValue(1000000);
|
||||
_zoomOverlayItem->setVisible(false);
|
||||
_zoomOverlayItem->setAcceptedMouseButtons(Qt::NoButton);
|
||||
_zoomOverlayItem->setAcceptHoverEvents(false);
|
||||
|
||||
_world = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
|
||||
_root = (QGraphicsItem *)this->scene()->addEllipse(QRectF(-0.0001,-0.0001,0.0001,0.0001));
|
||||
_root->setParentItem(_world);
|
||||
@@ -507,6 +528,62 @@ void GraphViewer::setupGraphicsScene()
|
||||
|
||||
}
|
||||
|
||||
void GraphViewer::startZoomOverlay()
|
||||
{
|
||||
if(_fastZoomMinNodes==0 || _nodeItems.size() < _fastZoomMinNodes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(_zoomOverlayActive || !_zoomOverlayItem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const QRect viewportRect = this->viewport()->rect();
|
||||
if(viewportRect.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const QPixmap snapshot = this->viewport()->grab();
|
||||
if(snapshot.isNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const QRectF sourceRect = this->mapToScene(viewportRect).boundingRect();
|
||||
const qreal sx = sourceRect.width() / qreal(snapshot.width());
|
||||
const qreal sy = sourceRect.height() / qreal(snapshot.height());
|
||||
|
||||
_zoomOverlayItem->setPixmap(snapshot);
|
||||
_zoomOverlayItem->setTransform(QTransform::fromScale(sx, sy));
|
||||
_zoomOverlayItem->setPos(sourceRect.topLeft());
|
||||
_zoomOverlayItem->show();
|
||||
_world->setVisible(false);
|
||||
_zoomOverlayActive = true;
|
||||
}
|
||||
|
||||
void GraphViewer::stopZoomOverlay()
|
||||
{
|
||||
_zoomDebounceTimer.stop();
|
||||
if(!_zoomOverlayActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_zoomOverlayActive = false;
|
||||
if(_zoomOverlayItem)
|
||||
{
|
||||
_zoomOverlayItem->hide();
|
||||
}
|
||||
if(_world)
|
||||
{
|
||||
_world->setVisible(true);
|
||||
}
|
||||
this->viewport()->update();
|
||||
}
|
||||
|
||||
void GraphViewer::setWorldMapRotation(const float & theta)
|
||||
{
|
||||
_worldMapRotation = theta;
|
||||
@@ -1432,6 +1509,7 @@ void GraphViewer::clearNodeColorByValue()
|
||||
|
||||
void GraphViewer::clearAll()
|
||||
{
|
||||
stopZoomOverlay();
|
||||
clearMap();
|
||||
clearGraph();
|
||||
|
||||
@@ -1489,6 +1567,7 @@ void GraphViewer::saveSettings(QSettings & settings, const QString & group) cons
|
||||
settings.setValue("orientation_ENU", this->isOrientationENU());
|
||||
settings.setValue("view_plane", (int)this->getViewPlane());
|
||||
settings.setValue("ensure_frame_visible", (int)this->isEnsureFrameVisible());
|
||||
settings.setValue("fast_zoom_min_nodes", this->getFastZoomMinNodes());
|
||||
if(!group.isEmpty())
|
||||
{
|
||||
settings.endGroup();
|
||||
@@ -1540,6 +1619,7 @@ void GraphViewer::loadSettings(QSettings & settings, const QString & group)
|
||||
this->setOrientationENU(settings.value("orientation_ENU", this->isOrientationENU()).toBool());
|
||||
this->setViewPlane((ViewPlane)settings.value("view_plane", (int)this->getViewPlane()).toInt());
|
||||
this->setEnsureFrameVisible(settings.value("ensure_frame_visible", this->isEnsureFrameVisible()).toBool());
|
||||
this->setFastZoomMinNodes(settings.value("fast_zoom_min_nodes", this->getFastZoomMinNodes()).toInt());
|
||||
if(!group.isEmpty())
|
||||
{
|
||||
settings.endGroup();
|
||||
@@ -1602,6 +1682,10 @@ bool GraphViewer::isEnsureFrameVisible() const
|
||||
{
|
||||
return _ensureFrameVisible;
|
||||
}
|
||||
int GraphViewer::getFastZoomMinNodes() const
|
||||
{
|
||||
return _fastZoomMinNodes;
|
||||
}
|
||||
|
||||
void GraphViewer::setWorkingDirectory(const QString & path)
|
||||
{
|
||||
@@ -1967,6 +2051,11 @@ void GraphViewer::setEnsureFrameVisible(bool visible)
|
||||
_ensureFrameVisible = visible;
|
||||
}
|
||||
|
||||
void GraphViewer::setFastZoomMinNodes(int value)
|
||||
{
|
||||
_fastZoomMinNodes = value;
|
||||
}
|
||||
|
||||
|
||||
void GraphViewer::restoreDefaults()
|
||||
{
|
||||
@@ -1997,18 +2086,26 @@ void GraphViewer::restoreDefaults()
|
||||
setGlobalPathVisible(true);
|
||||
setLocalPathVisible(true);
|
||||
setGtGraphVisible(true);
|
||||
setFastZoomMinNodes(0);
|
||||
}
|
||||
|
||||
void GraphViewer::wheelEvent ( QWheelEvent * event )
|
||||
void GraphViewer::wheelEvent(QWheelEvent * event)
|
||||
{
|
||||
if(event->angleDelta().y() < 0)
|
||||
if(event->angleDelta().y() == 0)
|
||||
{
|
||||
this->scale(0.95, 0.95);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->scale(1.05, 1.05);
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
// Start buffering zoom interaction with a raster snapshot.
|
||||
startZoomOverlay();
|
||||
|
||||
const qreal factor = event->angleDelta().y() < 0 ? 0.95 : 1.05;
|
||||
this->scale(factor, factor);
|
||||
|
||||
// When wheel stops for 400 ms, restore the real scene and let it redraw once.
|
||||
_zoomDebounceTimer.start(400);
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void GraphViewer::mouseMoveEvent(QMouseEvent * event)
|
||||
@@ -2029,14 +2126,16 @@ void GraphViewer::mouseMoveEvent(QMouseEvent * event)
|
||||
if (event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier) && event->buttons() & Qt::LeftButton) {
|
||||
// same modifiers than 3D view, change zoom
|
||||
if(_previousMousePos.y()!=0) {
|
||||
if(event->pos().y() - _previousMousePos.y() > 0)
|
||||
{
|
||||
this->scale(0.98, 0.98);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->scale(1.02, 1.02);
|
||||
}
|
||||
qreal factor = (event->pos().y() - _previousMousePos.y() > 0) ? 0.98 : 1.02;
|
||||
|
||||
QGraphicsView::ViewportAnchor oldAnchor = this->transformationAnchor();
|
||||
this->setTransformationAnchor(QGraphicsView::NoAnchor);
|
||||
QPointF scenePointBefore = this->mapToScene(_initialMousePos);
|
||||
this->scale(factor, factor);
|
||||
QPointF scenePointAfter = this->mapToScene(_initialMousePos);
|
||||
QPointF delta = scenePointAfter - scenePointBefore;
|
||||
this->translate(delta.x(), delta.y());
|
||||
this->setTransformationAnchor(oldAnchor);
|
||||
}
|
||||
_previousMousePos = event->pos();
|
||||
return;
|
||||
@@ -2047,11 +2146,21 @@ void GraphViewer::mouseMoveEvent(QMouseEvent * event)
|
||||
|
||||
void GraphViewer::mousePressEvent(QMouseEvent * event)
|
||||
{
|
||||
QGraphicsItem *item = this->scene()->itemAt(mapToScene(event->pos()), QTransform());
|
||||
if((event->button() == Qt::LeftButton) &&
|
||||
(event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier)))
|
||||
{
|
||||
startZoomOverlay();
|
||||
_previousMousePos = event->pos();
|
||||
_initialMousePos = event->pos();
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
QGraphicsItem * item = this->scene()->itemAt(mapToScene(event->pos()), QTransform());
|
||||
if(item)
|
||||
{
|
||||
NodeItem *nodeItem = qgraphicsitem_cast<NodeItem*>(item);
|
||||
LinkItem *linkItem = qgraphicsitem_cast<LinkItem*>(item);
|
||||
NodeItem * nodeItem = qgraphicsitem_cast<NodeItem*>(item);
|
||||
LinkItem * linkItem = qgraphicsitem_cast<LinkItem*>(item);
|
||||
if(nodeItem && nodeItem->parentItem() == _graphRoot && nodeItem->id() != 0)
|
||||
{
|
||||
Q_EMIT nodeSelected(nodeItem->id());
|
||||
@@ -2071,6 +2180,19 @@ void GraphViewer::mousePressEvent(QMouseEvent * event)
|
||||
}
|
||||
}
|
||||
|
||||
void GraphViewer::mouseReleaseEvent(QMouseEvent * event)
|
||||
{
|
||||
_previousMousePos = QPoint(-1, -1);
|
||||
_initialMousePos = QPoint(-1, -1);
|
||||
|
||||
if(_zoomOverlayActive)
|
||||
{
|
||||
stopZoomOverlay();
|
||||
}
|
||||
|
||||
QGraphicsView::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
QIcon createIcon(const QColor & color)
|
||||
{
|
||||
QPixmap pixmap(50, 50);
|
||||
@@ -2167,6 +2289,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
QAction * aShowHideOdomCacheOverlay;
|
||||
QAction * aOrientationENU;
|
||||
QAction * aMouseTracking;
|
||||
QAction * aFastZooming;
|
||||
QAction * aViewPlaneXY;
|
||||
QAction * aViewPlaneXZ;
|
||||
QAction * aViewPlaneYZ;
|
||||
@@ -2269,6 +2392,7 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
aMouseTracking->setCheckable(true);
|
||||
aMouseTracking->setChecked(_mouseTracking);
|
||||
aMouseTracking->setEnabled(_viewPlane == XY);
|
||||
aFastZooming = menu.addAction(tr("Fast Zooming..."));
|
||||
aShowHideGraph->setEnabled(_viewPlane == XY);
|
||||
aShowHideGlobalPath->setEnabled(_globalPathLinkItems.size());
|
||||
aShowHideLocalPath->setEnabled(_localPathLinkItems.size());
|
||||
@@ -2714,6 +2838,15 @@ void GraphViewer::contextMenuEvent(QContextMenuEvent * event)
|
||||
{
|
||||
_mouseTracking = aMouseTracking->isChecked();
|
||||
}
|
||||
else if(r == aFastZooming)
|
||||
{
|
||||
bool ok;
|
||||
double value = QInputDialog::getInt(this, tr("Fast Zooming"), tr("Minimum number of nodes to raster the graph\nwhile zooming (0=disabled):"), _fastZoomMinNodes, 0, 2147483647, 100, &ok);
|
||||
if(ok)
|
||||
{
|
||||
setFastZoomMinNodes(value);
|
||||
}
|
||||
}
|
||||
else if(r == aViewPlaneXY)
|
||||
{
|
||||
this->setViewPlane(XY);
|
||||
|
||||
Reference in New Issue
Block a user