QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
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.setNull();
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 QgsDebugError( 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 if ( !ex.what().contains( QLatin1String( "createConnection" ) ) )
113 {
114 QgsDebugError( QStringLiteral( "Error retrieving database connection for layer %1: %2" ).arg( layer->name(), ex.what() ) );
115 }
116 return nullptr;
117 }
118}
119
120bool QgsMapLayerUtils::layerSourceMatchesPath( const QgsMapLayer *layer, const QString &path )
121{
122 if ( !layer || path.isEmpty() )
123 return false;
124
125 const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
126 return parts.value( QStringLiteral( "path" ) ).toString() == path;
127}
128
129bool QgsMapLayerUtils::updateLayerSourcePath( QgsMapLayer *layer, const QString &newPath )
130{
131 if ( !layer || newPath.isEmpty() )
132 return false;
133
134 QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
135 if ( !parts.contains( QStringLiteral( "path" ) ) )
136 return false;
137
138 parts.insert( QStringLiteral( "path" ), newPath );
139 const QString newUri = QgsProviderRegistry::instance()->encodeUri( layer->providerType(), parts );
140 layer->setDataSource( newUri, layer->name(), layer->providerType() );
141 return true;
142}
143
144QList<QgsMapLayer *> QgsMapLayerUtils::sortLayersByType( const QList<QgsMapLayer *> &layers, const QList<Qgis::LayerType> &order )
145{
146 QList< QgsMapLayer * > res = layers;
147 std::sort( res.begin(), res.end(), [&order]( const QgsMapLayer * a, const QgsMapLayer * b ) -> bool
148 {
149 for ( Qgis::LayerType type : order )
150 {
151 if ( a->type() == type && b->type() != type )
152 return true;
153 else if ( b->type() == type )
154 return false;
155 }
156 return false;
157 } );
158 return res;
159}
160
161QString QgsMapLayerUtils::launderLayerName( const QString &name )
162{
163 QString laundered = name.toLower();
164 const thread_local QRegularExpression sRxSwapChars( QStringLiteral( "\\s" ) );
165 laundered.replace( sRxSwapChars, QStringLiteral( "_" ) );
166
167 const thread_local QRegularExpression sRxRemoveChars( QStringLiteral( "[^a-zA-Z0-9_]" ) );
168 laundered.replace( sRxRemoveChars, QString() );
169
170 return laundered;
171}
172
174{
175 if ( layer->providerType() == QLatin1String( "wms" ) )
176 {
177 if ( const QgsProviderMetadata *metadata = layer->providerMetadata() )
178 {
179 QVariantMap details = metadata->decodeUri( layer->source() );
180 QUrl url( details.value( QStringLiteral( "url" ) ).toString() );
181 if ( url.host().endsWith( QLatin1String( ".openstreetmap.org" ) ) || url.host().endsWith( QLatin1String( ".osm.org" ) ) )
182 {
183 return true;
184 }
185 }
186 }
187 return false;
188}
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
Transforms a rectangle from the source CRS to the destination CRS.
Custom exception class for Coordinate Reference System related exceptions.
virtual QString name() const =0
Returns a provider name.
QString what() const
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 isOpenStreetMapLayer(QgsMapLayer *layer)
Returns true if the layer is served by OpenStreetMap server.
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:76
QString name
Definition qgsmaplayer.h:80
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=QString(), const QString &provider=QString(), bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
QgsProviderMetadata * providerMetadata() const
Returns the layer data provider's metadata, it may be nullptr.
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
Custom exception class for provider connection related exceptions.
Holds data provider key, description, and associated shared library file or function pointer informat...
virtual QgsAbstractProviderConnection * createConnection(const QString &uri, const QVariantMap &configuration)
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.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double xMinimum
double yMinimum
double xMaximum
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
double yMaximum
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
void setNull()
Mark a rectangle as being null (holding no spatial information).
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugError(str)
Definition qgslogger.h:38
const QgsCoordinateReferenceSystem & crs