Skip to content
Permalink
Browse files

Zoom and pan to selection from multiple layers

  • Loading branch information
TurboGraphxBeige authored and nyalldawson committed Jan 5, 2021
1 parent f9deb91 commit f3476a567f1f8d54206d57e32c939c81848519a5
@@ -2705,6 +2705,7 @@ void QgisApp::createActions()
// View Menu Items
connect( mActionPan, &QAction::triggered, this, &QgisApp::pan );
connect( mActionPanToSelected, &QAction::triggered, this, &QgisApp::panToSelected );
connect( mActionPanToAllSelected, &QAction::triggered, this, &QgisApp::panToAllSelected );
connect( mActionZoomIn, &QAction::triggered, this, &QgisApp::zoomIn );
connect( mActionZoomOut, &QAction::triggered, this, &QgisApp::zoomOut );
connect( mActionSelectFeatures, &QAction::triggered, this, &QgisApp::selectFeatures );
@@ -2740,6 +2741,7 @@ void QgisApp::createActions()
connect( mActionZoomToLayer, &QAction::triggered, this, &QgisApp::zoomToLayerExtent );
connect( mActionZoomToLayers, &QAction::triggered, this, &QgisApp::zoomToLayerExtent );
connect( mActionZoomToSelected, &QAction::triggered, this, &QgisApp::zoomToSelected );
connect( mActionZoomToAllSelected, &QAction::triggered, this, &QgisApp::zoomToAllSelected );
connect( mActionZoomLast, &QAction::triggered, this, &QgisApp::zoomToPrevious );
connect( mActionZoomNext, &QAction::triggered, this, &QgisApp::zoomToNext );
connect( mActionZoomActualSize, &QAction::triggered, this, &QgisApp::zoomActualSize );
@@ -4095,10 +4097,12 @@ void QgisApp::setTheme( const QString &themeName )
mActionZoomOut->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomOut.svg" ) ) );
mActionZoomFullExtent->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomFullExtent.svg" ) ) );
mActionZoomToSelected->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToSelected.svg" ) ) );
mActionZoomToAllSelected->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToSelected.svg" ) ) );
mActionShowRasterCalculator->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowRasterCalculator.png" ) ) );
mActionShowMeshCalculator->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowMeshCalculator.png" ) ) );
mActionPan->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionPan.svg" ) ) );
mActionPanToSelected->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionPanToSelected.svg" ) ) );
mActionPanToAllSelected->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionPanToSelected.svg" ) ) );
mActionZoomLast->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomLast.svg" ) ) );
mActionZoomNext->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomNext.svg" ) ) );
mActionZoomToLayer->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToLayer.svg" ) ) );
@@ -8191,12 +8195,37 @@ void QgisApp::zoomOut()

void QgisApp::zoomToSelected()
{
mMapCanvas->zoomToSelected();
QList<QgsMapLayer *> layers = mLayerTreeView->selectedLayers();

if ( layers.size() > 1 && !layers.isEmpty() )
mMapCanvas->zoomToAllSelected(&layers);

else
mMapCanvas->zoomToSelected();

}

void QgisApp::zoomToAllSelected()
{
const QList<QgsMapLayer *> layers = mMapCanvas->layers();
mMapCanvas->zoomToAllSelected(&layers);
}

void QgisApp::panToSelected()
{
mMapCanvas->panToSelected();
QList<QgsMapLayer *> layers = mLayerTreeView->selectedLayers();

if ( layers.size() > 1 && !layers.isEmpty() )
mMapCanvas->panToAllSelected(&layers);

else
mMapCanvas->panToSelected();
}

void QgisApp::panToAllSelected()
{
const QList<QgsMapLayer *> layers = mMapCanvas->layers();
mMapCanvas->panToAllSelected(&layers);
}

void QgisApp::pan()
mActionZoomToLayer->setEnabled( isSpatial );
mActionZoomToLayers->setEnabled( isSpatial );
mActionZoomToSelected->setEnabled( isSpatial );
mActionZoomToAllSelected->setEnabled( true );
mActionLabeling->setEnabled( isSpatial );
mActionDiagramProperties->setEnabled( isSpatial );
mActionReverseLine->setEnabled( false );
mActionZoomToLayer->setEnabled( true );
mActionZoomToLayers->setEnabled( true );
mActionZoomToSelected->setEnabled( false );
mActionZoomToAllSelected->setEnabled( true );
mActionOpenTable->setEnabled( false );
mActionSelectAll->setEnabled( false );
mActionReselect->setEnabled( false );
mActionZoomToLayer->setEnabled( true );
mActionZoomToLayers->setEnabled( true );
mActionZoomToSelected->setEnabled( false );
mActionZoomToAllSelected->setEnabled( true );
mActionOpenTable->setEnabled( false );
mActionSelectAll->setEnabled( false );
mActionReselect->setEnabled( false );
mActionZoomToLayer->setEnabled( true );
mActionZoomToLayers->setEnabled( true );
mActionZoomToSelected->setEnabled( false );
mActionZoomToAllSelected->setEnabled( true );
mActionOpenTable->setEnabled( false );
mActionSelectAll->setEnabled( false );
mActionReselect->setEnabled( false );
mActionZoomToLayer->setEnabled( true );
mActionZoomToLayers->setEnabled( true );
mActionZoomToSelected->setEnabled( false );
mActionZoomToAllSelected->setEnabled( true );
mActionOpenTable->setEnabled( false );
mActionSelectAll->setEnabled( false );
mActionReselect->setEnabled( false );
@@ -497,6 +497,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QAction *actionOffsetCurve() { return mActionOffsetCurve; }
QAction *actionPan() { return mActionPan; }
QAction *actionPanToSelected() { return mActionPanToSelected; }
QAction *actionPanToAllSelected() { return mActionPanToAllSelected; }
QAction *actionZoomIn() { return mActionZoomIn; }
QAction *actionZoomOut() { return mActionZoomOut; }
QAction *actionSelect() { return mActionSelectFeatures; }
@@ -512,6 +513,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QAction *actionZoomToLayer() { return mActionZoomToLayer; }
QAction *actionZoomToLayers() { return mActionZoomToLayers; }
QAction *actionZoomToSelected() { return mActionZoomToSelected; }
QAction *actionZoomToAllSelected() { return mActionZoomToAllSelected; }
QAction *actionZoomLast() { return mActionZoomLast; }
QAction *actionZoomNext() { return mActionZoomNext; }
QAction *actionZoomActualSize() { return mActionZoomActualSize; }
@@ -894,8 +896,12 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void zoomToNext();
//! Zoom to selected features
void zoomToSelected();
//! Zoom to selected features from multiple layers
void zoomToAllSelected();
//! Pan map to selected features
void panToSelected();
//! Pan map to selected features from multiple layers
void panToAllSelected();

//! open the properties dialog for the currently selected layer
void layerProperties();
@@ -156,8 +156,28 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
menu->addAction( zoomToLayers );
if ( vlayer )
{
QList<QgsMapLayer *> selectedLayers = mView->selectedLayers();
bool hasSelectedFeature;
for ( int i = 0; i < selectedLayers.size(); ++i )
{
QgsMapLayer *layer = selectedLayers.at( i );
QgsVectorLayer *vLayer;
if (layer->type() == QgsMapLayerType(0) )
{
QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer );

if ( !vLayer->selectedFeatureIds().isEmpty() )
{
hasSelectedFeature = TRUE;
break;
}
else
hasSelectedFeature = FALSE;
}

}
QAction *actionZoomSelected = actions->actionZoomToSelection( mCanvas, menu );
actionZoomSelected->setEnabled( vlayer->isValid() && !vlayer->selectedFeatureIds().isEmpty() );
actionZoomSelected->setEnabled( vlayer->isValid() && hasSelectedFeature );
menu->addAction( actionZoomSelected );
}
menu->addAction( actions->actionShowInOverview( menu ) );
@@ -312,11 +312,19 @@ void QgsLayerTreeViewDefaultActions::zoomToLayers( QgsMapCanvas *canvas )

void QgsLayerTreeViewDefaultActions::zoomToSelection( QgsMapCanvas *canvas )
{
QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mView->currentLayer() );
if ( !layer )
return;
QgsVectorLayer *layer;

if ( mView->currentLayer()->type() == QgsMapLayerType(0) )
layer = qobject_cast<QgsVectorLayer *>( mView->currentLayer() );

QList<QgsMapLayer *> layers = mView->selectedLayers();

if ( layers.size() > 1 && !layers.isEmpty() )
canvas->zoomToAllSelected(&layers);

else if ( layers.size() <= 1 && layer)
canvas->zoomToSelected(layer);

canvas->zoomToSelected( layer );
}

void QgsLayerTreeViewDefaultActions::zoomToGroup( QgsMapCanvas *canvas )
@@ -1349,6 +1349,45 @@ void QgsMapCanvas::zoomToSelected( QgsVectorLayer *layer )
zoomToFeatureExtent( rect );
}

void QgsMapCanvas::zoomToAllSelected(const QList<QgsMapLayer *> *layers) {

QgsVectorLayer *layer;

QgsRectangle rect;
rect.setMinimal();
QgsRectangle selectionExtent;
selectionExtent.setMinimal();

for (int i = 0; i < layers->size(); ++i) {
if ( layers->at(i)->type() == QgsMapLayerType(0) )
layer = qobject_cast<QgsVectorLayer *>(layers->at(i));

if (!layer || !layer->isSpatial() || layer->selectedFeatureCount() == 0)
continue;

rect = layer->boundingBoxOfSelected();

if (rect.isNull())
continue;

rect = mapSettings().layerExtentToOutputExtent(layer, rect);

if (layer->geometryType() == QgsWkbTypes::PointGeometry && rect.isEmpty()) {
rect = optimalExtentForPointLayer(layer, rect.center());
}

selectionExtent.combineExtentWith( rect );
}

if ( selectionExtent.isNull() )
{
emit messageEmitted( tr( "Cannot zoom to selected feature(s)" ), tr( "No extent could be determined." ), Qgis::Warning );
return;
}

zoomToFeatureExtent( selectionExtent );
}

QgsDoubleRange QgsMapCanvas::zRange() const
{
return mSettings.zRange();
@@ -1500,6 +1539,46 @@ void QgsMapCanvas::panToSelected( QgsVectorLayer *layer )
refresh();
}

void QgsMapCanvas::panToAllSelected( const QList<QgsMapLayer *> *layers )
{
QgsVectorLayer *layer;

QgsRectangle rect;
rect.setMinimal();
QgsRectangle selectionExtent;
selectionExtent.setMinimal();

for (int i = 0; i < layers->size(); ++i) {
if ( layers->at(i)->type() == QgsMapLayerType(0) )
layer = qobject_cast<QgsVectorLayer *>(layers->at(i));

if (!layer || !layer->isSpatial() || layer->selectedFeatureCount() == 0)
continue;

rect = layer->boundingBoxOfSelected();

if (rect.isNull())
continue;

rect = mapSettings().layerExtentToOutputExtent(layer, rect);

if (layer->geometryType() == QgsWkbTypes::PointGeometry && rect.isEmpty()) {
rect = optimalExtentForPointLayer(layer, rect.center());
}

selectionExtent.combineExtentWith( rect );
}

if ( selectionExtent.isNull() )
{
emit messageEmitted( tr( "Cannot pan to selected feature(s)" ), tr( "No extent could be determined." ), Qgis::Warning );
return;
}

setCenter( selectionExtent.center() );
refresh();
}

void QgsMapCanvas::flashFeatureIds( QgsVectorLayer *layer, const QgsFeatureIds &ids,
const QColor &color1, const QColor &color2,
int flashes, int duration )
@@ -59,6 +59,7 @@ class QgsHighlight;
class QgsVectorLayer;

class QgsLabelingResults;

class QgsMapRendererCache;
class QgsMapRendererQImageJob;
class QgsMapSettings;
@@ -310,6 +311,12 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! Pan to the selected features of current (vector) layer keeping same extent.
void panToSelected( QgsVectorLayer *layer = nullptr );

/**
* Pan to the combined extent of the selected features of all provided (vector) layers.
* \param layers A list of layers
*/
void panToAllSelected( const QList<QgsMapLayer *> *layers );

/**
* Causes a set of features with matching \a ids from a vector \a layer to flash
* within the canvas.
@@ -865,6 +872,12 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
*/
void zoomToSelected( QgsVectorLayer *layer = nullptr );

/**
* Zoom to the combined extent of the selected features of all provided (vector) layers.
* \param layers A list of layers
*/
void zoomToAllSelected( const QList<QgsMapLayer *> *layers );

/**
* Set a list of resolutions (map units per pixel) to which to "snap to" when zooming the map
* \param resolutions A list of resolutions
@@ -138,6 +138,7 @@
<addaction name="mActionNew3DMapCanvas"/>
<addaction name="mActionPan"/>
<addaction name="mActionPanToSelected"/>
<addaction name="mActionPanToAllSelected"/>
<addaction name="mActionZoomIn"/>
<addaction name="mActionZoomOut"/>
<addaction name="separator"/>
@@ -147,6 +148,7 @@
<addaction name="separator"/>
<addaction name="mActionZoomFullExtent"/>
<addaction name="mActionZoomToSelected"/>
<addaction name="mActionZoomToAllSelected"/>
<addaction name="mActionZoomToLayers"/>
<addaction name="mActionZoomActualSize"/>
<addaction name="mActionZoomLast"/>
@@ -1392,6 +1394,15 @@
<string>Ctrl+J</string>
</property>
</action>
<action name="mActionZoomToAllSelected">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionZoomToSelected.svg</normaloff>:/images/themes/default/mActionZoomToSelected.svg</iconset>
</property>
<property name="text">
<string>Zoom to Selection from All Layers</string>
</property>
</action>
<action name="mActionZoomLast">
<property name="icon">
<iconset resource="../../images/images.qrc">
@@ -2192,6 +2203,15 @@ Acts on all layers.</string>
<string>Pan Map to Selection</string>
</property>
</action>
<action name="mActionPanToAllSelected">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionPanToSelected.svg</normaloff>:/images/themes/default/mActionPanToSelected.svg</iconset>
</property>
<property name="text">
<string>Pan Map to Selection from All Layers</string>
</property>
</action>
<action name="mActionOffsetCurve">
<property name="checkable">
<bool>true</bool>
BIN +0 Bytes (100%) tests/testdata/curved_polys.gpkg
Binary file not shown.

0 comments on commit f3476a5

Please sign in to comment.
You can’t perform that action at this time.