QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsmaplayerutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmaplayerutils.cpp
3 -------------------
4 begin : May 2021
5 copyright : (C) 2021 Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgsmaplayerutils.h"
19#include "qgsrectangle.h"
23#include "qgsprovidermetadata.h"
24#include "qgsproviderregistry.h"
26#include "qgslogger.h"
27#include "qgsmaplayer.h"
29#include <QRegularExpression>
30
31QgsRectangle QgsMapLayerUtils::combinedExtent( const QList<QgsMapLayer *> &layers, const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &transformContext )
32{
33 // We can't use a constructor since QgsRectangle normalizes the rectangle upon construction
34 QgsRectangle fullExtent;
35 fullExtent.setMinimal();
36
37 // iterate through the map layers and test each layers extent
38 // against the current min and max values
39 QgsDebugMsgLevel( QStringLiteral( "Layer count: %1" ).arg( layers.count() ), 5 );
40 for ( const QgsMapLayer *layer : layers )
41 {
42 QgsDebugMsgLevel( "Updating extent using " + layer->name(), 5 );
43 QgsDebugMsgLevel( "Input extent: " + layer->extent().toString(), 5 );
44
45 if ( layer->extent().isNull() )
46 continue;
47
48 // Layer extents are stored in the coordinate system (CS) of the
49 // layer. The extent must be projected to the canvas CS
50 QgsCoordinateTransform ct( layer->crs(), crs, transformContext );
52 try
53 {
54 const QgsRectangle extent = ct.transformBoundingBox( layer->extent() );
55
56 QgsDebugMsgLevel( "Output extent: " + extent.toString(), 5 );
57 fullExtent.combineExtentWith( extent );
58 }
59 catch ( QgsCsException & )
60 {
61 QgsDebugMsg( QStringLiteral( "Could not reproject layer extent" ) );
62 }
63 }
64
65 if ( fullExtent.width() == 0.0 || fullExtent.height() == 0.0 )
66 {
67 // If all of the features are at the one point, buffer the
68 // rectangle a bit. If they are all at zero, do something a bit
69 // more crude.
70
71 if ( fullExtent.xMinimum() == 0.0 && fullExtent.xMaximum() == 0.0 &&
72 fullExtent.yMinimum() == 0.0 && fullExtent.yMaximum() == 0.0 )
73 {
74 fullExtent.set( -1.0, -1.0, 1.0, 1.0 );
75 }
76 else
77 {
78 const double padFactor = 1e-8;
79 const double widthPad = fullExtent.xMinimum() * padFactor;
80 const double heightPad = fullExtent.yMinimum() * padFactor;
81 const double xmin = fullExtent.xMinimum() - widthPad;
82 const double xmax = fullExtent.xMaximum() + widthPad;
83 const double ymin = fullExtent.yMinimum() - heightPad;
84 const double ymax = fullExtent.yMaximum() + heightPad;
85 fullExtent.set( xmin, ymin, xmax, ymax );
86 }
87 }
88
89 QgsDebugMsgLevel( "Full extent: " + fullExtent.toString(), 5 );
90 return fullExtent;
91}
92
94{
95 if ( ! layer || ! layer->dataProvider() )
96 {
97 return nullptr;
98 }
99
100 try
101 {
103 if ( ! providerMetadata )
104 {
105 return nullptr;
106 }
107
108 std::unique_ptr< QgsAbstractDatabaseProviderConnection > conn { static_cast<QgsAbstractDatabaseProviderConnection *>( providerMetadata->createConnection( layer->source(), {} ) ) };
109 return conn.release();
110 }
111 catch ( const QgsProviderConnectionException &ex )
112 {
113 QgsDebugMsg( QStringLiteral( "Error retrieving database connection for layer %1: %2" ).arg( layer->name(), ex.what() ) );
114 return nullptr;
115 }
116}
117
118bool QgsMapLayerUtils::layerSourceMatchesPath( const QgsMapLayer *layer, const QString &path )
119{
120 if ( !layer || path.isEmpty() )
121 return false;
122
123 const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
124 return parts.value( QStringLiteral( "path" ) ).toString() == path;
125}
126
127bool QgsMapLayerUtils::updateLayerSourcePath( QgsMapLayer *layer, const QString &newPath )
128{
129 if ( !layer || newPath.isEmpty() )
130 return false;
131
132 QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
133 if ( !parts.contains( QStringLiteral( "path" ) ) )
134 return false;
135
136 parts.insert( QStringLiteral( "path" ), newPath );
137 const QString newUri = QgsProviderRegistry::instance()->encodeUri( layer->providerType(), parts );
138 layer->setDataSource( newUri, layer->name(), layer->providerType() );
139 return true;
140}
141
142QList<QgsMapLayer *> QgsMapLayerUtils::sortLayersByType( const QList<QgsMapLayer *> &layers, const QList<QgsMapLayerType> &order )
143{
144 QList< QgsMapLayer * > res = layers;
145 std::sort( res.begin(), res.end(), [&order]( const QgsMapLayer * a, const QgsMapLayer * b ) -> bool
146 {
147 for ( QgsMapLayerType type : order )
148 {
149 if ( a->type() == type && b->type() != type )
150 return true;
151 else if ( b->type() == type )
152 return false;
153 }
154 return false;
155 } );
156 return res;
157}
158
159QString QgsMapLayerUtils::launderLayerName( const QString &name )
160{
161 QString laundered = name.toLower();
162 const thread_local QRegularExpression sRxSwapChars( QStringLiteral( "\\s" ) );
163 laundered.replace( sRxSwapChars, QStringLiteral( "_" ) );
164
165 const thread_local QRegularExpression sRxRemoveChars( QStringLiteral( "[^a-zA-Z0-9_]" ) );
166 laundered.replace( sRxRemoveChars, QString() );
167
168 return laundered;
169}
The QgsAbstractDatabaseProviderConnection class provides common functionality for DB based connection...
This class represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
Class for doing transforms between two map coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
virtual QString name() const =0
Returns a provider name.
QString what() const
Definition: qgsexception.h:48
static QList< QgsMapLayer * > sortLayersByType(const QList< QgsMapLayer * > &layers, const QList< QgsMapLayerType > &order)
Sorts a list of map layers by their layer type, respecting the order of types specified.
static bool updateLayerSourcePath(QgsMapLayer *layer, const QString &newPath)
Updates a layer's data source, replacing its data source with a path referring to newPath.
static QgsRectangle combinedExtent(const QList< QgsMapLayer * > &layers, const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &transformContext)
Returns the combined extent of a list of layers.
static QgsAbstractDatabaseProviderConnection * databaseConnection(const QgsMapLayer *layer)
Creates and returns the (possibly nullptr) database connection for a layer.
static QString launderLayerName(const QString &name)
Launders a layer's name, converting it into a format which is general suitable for file names or data...
static bool layerSourceMatchesPath(const QgsMapLayer *layer, const QString &path)
Returns true if the source of the specified layer matches the given path.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
Custom exception class for provider connection related exceptions.
Definition: qgsexception.h:101
Holds data provider key, description, and associated shared library file or function pointer informat...
virtual QgsAbstractProviderConnection * createConnection(const QString &uri, const QVariantMap &configuration) SIP_THROW(QgsProviderConnectionException)
Creates a new connection from uri and configuration, the newly created connection is not automaticall...
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString encodeUri(const QString &providerKey, const QVariantMap &parts)
Reassembles a provider data source URI from its component paths (e.g.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
Definition: qgsrectangle.h:122
void setMinimal() SIP_HOLDGIL
Set a rectangle so that min corner is at max and max corner is at min.
Definition: qgsrectangle.h:172
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
Definition: qgsrectangle.h:391
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
const QgsCoordinateReferenceSystem & crs