QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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"
25#include "qgslogger.h"
26#include "qgsmaplayer.h"
28#include <QRegularExpression>
29
30QgsRectangle QgsMapLayerUtils::combinedExtent( const QList<QgsMapLayer *> &layers, const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &transformContext )
31{
32 // We can't use a constructor since QgsRectangle normalizes the rectangle upon construction
33 QgsRectangle fullExtent;
34 fullExtent.setMinimal();
35
36 // iterate through the map layers and test each layers extent
37 // against the current min and max values
38 QgsDebugMsgLevel( QStringLiteral( "Layer count: %1" ).arg( layers.count() ), 5 );
39 for ( const QgsMapLayer *layer : layers )
40 {
41 QgsDebugMsgLevel( "Updating extent using " + layer->name(), 5 );
42 QgsDebugMsgLevel( "Input extent: " + layer->extent().toString(), 5 );
43
44 if ( layer->extent().isNull() )
45 continue;
46
47 // Layer extents are stored in the coordinate system (CS) of the
48 // layer. The extent must be projected to the canvas CS
49 QgsCoordinateTransform ct( layer->crs(), crs, transformContext );
51 try
52 {
53 const QgsRectangle extent = ct.transformBoundingBox( layer->extent() );
54
55 QgsDebugMsgLevel( "Output extent: " + extent.toString(), 5 );
56 fullExtent.combineExtentWith( extent );
57 }
58 catch ( QgsCsException & )
59 {
60 QgsDebugMsg( QStringLiteral( "Could not reproject layer extent" ) );
61 }
62 }
63
64 if ( fullExtent.width() == 0.0 || fullExtent.height() == 0.0 )
65 {
66 // If all of the features are at the one point, buffer the
67 // rectangle a bit. If they are all at zero, do something a bit
68 // more crude.
69
70 if ( fullExtent.xMinimum() == 0.0 && fullExtent.xMaximum() == 0.0 &&
71 fullExtent.yMinimum() == 0.0 && fullExtent.yMaximum() == 0.0 )
72 {
73 fullExtent.set( -1.0, -1.0, 1.0, 1.0 );
74 }
75 else
76 {
77 const double padFactor = 1e-8;
78 const double widthPad = fullExtent.xMinimum() * padFactor;
79 const double heightPad = fullExtent.yMinimum() * padFactor;
80 const double xmin = fullExtent.xMinimum() - widthPad;
81 const double xmax = fullExtent.xMaximum() + widthPad;
82 const double ymin = fullExtent.yMinimum() - heightPad;
83 const double ymax = fullExtent.yMaximum() + heightPad;
84 fullExtent.set( xmin, ymin, xmax, ymax );
85 }
86 }
87
88 QgsDebugMsgLevel( "Full extent: " + fullExtent.toString(), 5 );
89 return fullExtent;
90}
91
93{
94 if ( ! layer || ! layer->dataProvider() )
95 {
96 return nullptr;
97 }
98
99 try
100 {
102 if ( ! providerMetadata )
103 {
104 return nullptr;
105 }
106
107 std::unique_ptr< QgsAbstractDatabaseProviderConnection > conn { static_cast<QgsAbstractDatabaseProviderConnection *>( providerMetadata->createConnection( layer->source(), {} ) ) };
108 return conn.release();
109 }
110 catch ( const QgsProviderConnectionException &ex )
111 {
112 QgsDebugMsg( QStringLiteral( "Error retrieving database connection for layer %1: %2" ).arg( layer->name(), ex.what() ) );
113 return nullptr;
114 }
115}
116
117bool QgsMapLayerUtils::layerSourceMatchesPath( const QgsMapLayer *layer, const QString &path )
118{
119 if ( !layer || path.isEmpty() )
120 return false;
121
122 const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
123 return parts.value( QStringLiteral( "path" ) ).toString() == path;
124}
125
126bool QgsMapLayerUtils::updateLayerSourcePath( QgsMapLayer *layer, const QString &newPath )
127{
128 if ( !layer || newPath.isEmpty() )
129 return false;
130
131 QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
132 if ( !parts.contains( QStringLiteral( "path" ) ) )
133 return false;
134
135 parts.insert( QStringLiteral( "path" ), newPath );
136 const QString newUri = QgsProviderRegistry::instance()->encodeUri( layer->providerType(), parts );
137 layer->setDataSource( newUri, layer->name(), layer->providerType() );
138 return true;
139}
140
141QList<QgsMapLayer *> QgsMapLayerUtils::sortLayersByType( const QList<QgsMapLayer *> &layers, const QList<Qgis::LayerType> &order )
142{
143 QList< QgsMapLayer * > res = layers;
144 std::sort( res.begin(), res.end(), [&order]( const QgsMapLayer * a, const QgsMapLayer * b ) -> bool
145 {
146 for ( Qgis::LayerType type : order )
147 {
148 if ( a->type() == type && b->type() != type )
149 return true;
150 else if ( b->type() == type )
151 return false;
152 }
153 return false;
154 } );
155 return res;
156}
157
158QString QgsMapLayerUtils::launderLayerName( const QString &name )
159{
160 QString laundered = name.toLower();
161 const thread_local QRegularExpression sRxSwapChars( QStringLiteral( "\\s" ) );
162 laundered.replace( sRxSwapChars, QStringLiteral( "_" ) );
163
164 const thread_local QRegularExpression sRxRemoveChars( QStringLiteral( "[^a-zA-Z0-9_]" ) );
165 laundered.replace( sRxRemoveChars, QString() );
166
167 return laundered;
168}
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 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 QList< QgsMapLayer * > sortLayersByType(const QList< QgsMapLayer * > &layers, const QList< Qgis::LayerType > &order)
Sorts a list of map layers by their layer type, respecting the order of types specified.
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