QGIS API Documentation 4.1.0-Master (467af3bbe65)
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
24#include "qgslogger.h"
25#include "qgsmaplayer.h"
26#include "qgsprovidermetadata.h"
27#include "qgsproviderregistry.h"
28#include "qgsrectangle.h"
31#include "qgsvectorlayer.h"
32
33#include <QRegularExpression>
34#include <QString>
35
36using namespace Qt::StringLiterals;
37
38QgsRectangle QgsMapLayerUtils::combinedExtent( const QList<QgsMapLayer *> &layers, const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &transformContext )
39{
40 // We can't use a constructor since QgsRectangle normalizes the rectangle upon construction
41 QgsRectangle fullExtent;
42 fullExtent.setNull();
43
44 // iterate through the map layers and test each layers extent
45 // against the current min and max values
46 QgsDebugMsgLevel( u"Layer count: %1"_s.arg( layers.count() ), 5 );
47 for ( const QgsMapLayer *layer : layers )
48 {
49 QgsDebugMsgLevel( "Updating extent using " + layer->name(), 5 );
50 QgsDebugMsgLevel( "Input extent: " + layer->extent().toString(), 5 );
51
52 if ( layer->extent().isNull() )
53 continue;
54
55 // Layer extents are stored in the coordinate system (CS) of the
56 // layer. The extent must be projected to the canvas CS
57 QgsCoordinateTransform ct( layer->crs(), crs, transformContext );
59 try
60 {
61 const QgsRectangle extent = ct.transformBoundingBox( layer->extent() );
62
63 QgsDebugMsgLevel( "Output extent: " + extent.toString(), 5 );
64 fullExtent.combineExtentWith( extent );
65 }
66 catch ( QgsCsException & )
67 {
68 QgsDebugError( u"Could not reproject layer extent"_s );
69 }
70 }
71
72 if ( fullExtent.width() == 0.0 || fullExtent.height() == 0.0 )
73 {
74 // If all of the features are at the one point, buffer the
75 // rectangle a bit. If they are all at zero, do something a bit
76 // more crude.
77
78 if ( fullExtent.xMinimum() == 0.0 && fullExtent.xMaximum() == 0.0 && fullExtent.yMinimum() == 0.0 && fullExtent.yMaximum() == 0.0 )
79 {
80 fullExtent.set( -1.0, -1.0, 1.0, 1.0 );
81 }
82 else
83 {
84 const double padFactor = 1e-8;
85 const double widthPad = fullExtent.xMinimum() * padFactor;
86 const double heightPad = fullExtent.yMinimum() * padFactor;
87 const double xmin = fullExtent.xMinimum() - widthPad;
88 const double xmax = fullExtent.xMaximum() + widthPad;
89 const double ymin = fullExtent.yMinimum() - heightPad;
90 const double ymax = fullExtent.yMaximum() + heightPad;
91 fullExtent.set( xmin, ymin, xmax, ymax );
92 }
93 }
94
95 QgsDebugMsgLevel( "Full extent: " + fullExtent.toString(), 5 );
96 return fullExtent;
97}
98
100{
101 if ( !layer )
102 {
103 return nullptr;
104 }
105
106 try
107 {
109 if ( !providerMetadata )
110 {
111 return nullptr;
112 }
113
114 std::unique_ptr< QgsAbstractDatabaseProviderConnection > conn { static_cast<QgsAbstractDatabaseProviderConnection *>( providerMetadata->createConnection( layer->source(), {} ) ) };
115 return conn.release();
116 }
117 catch ( const QgsProviderConnectionException &ex )
118 {
119 if ( !ex.what().contains( "createConnection"_L1 ) )
120 {
121 QgsDebugError( u"Error retrieving database connection for layer %1: %2"_s.arg( layer->name(), ex.what() ) );
122 }
123 return nullptr;
124 }
125}
126
127bool QgsMapLayerUtils::layerSourceMatchesPath( const QgsMapLayer *layer, const QString &path )
128{
129 if ( !layer || path.isEmpty() )
130 return false;
131
132 const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
133 return parts.value( u"path"_s ).toString() == path;
134}
135
136bool QgsMapLayerUtils::layerRefersToUri( const QgsMapLayer *layer, const QString &uri, Qgis::SourceHierarchyLevel level )
137{
138 if ( !layer )
139 return false;
140
142 if ( !metadata )
143 {
144 throw QgsNotSupportedException( u"Could not retrieve metadata for %1 provider"_s.arg( layer->providerType() ) );
145 }
146
148 {
149 throw QgsNotSupportedException( u"%1 provider does not support UrisReferToSame capability"_s.arg( layer->providerType() ) );
150 }
151
152 return metadata->urisReferToSame( layer->source(), uri, level );
153}
154
155bool QgsMapLayerUtils::updateLayerSourcePath( QgsMapLayer *layer, const QString &newPath )
156{
157 if ( !layer || newPath.isEmpty() )
158 return false;
159
160 QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
161 if ( !parts.contains( u"path"_s ) )
162 return false;
163
164 parts.insert( u"path"_s, newPath );
165 const QString newUri = QgsProviderRegistry::instance()->encodeUri( layer->providerType(), parts );
166 layer->setDataSource( newUri, layer->name(), layer->providerType() );
167 return true;
168}
169
170QList<QgsMapLayer *> QgsMapLayerUtils::sortLayersByType( const QList<QgsMapLayer *> &layers, const QList<Qgis::LayerType> &order )
171{
172 QList< QgsMapLayer * > res = layers;
173 std::sort( res.begin(), res.end(), [&order]( const QgsMapLayer *a, const QgsMapLayer *b ) -> bool {
174 for ( Qgis::LayerType type : order )
175 {
176 if ( a->type() == type && b->type() != type )
177 return true;
178 else if ( b->type() == type )
179 return false;
180 }
181 return false;
182 } );
183 return res;
184}
185
186QString QgsMapLayerUtils::launderLayerName( const QString &name )
187{
188 QString laundered = name.toLower();
189 const thread_local QRegularExpression sRxSwapChars( u"\\s"_s );
190 laundered.replace( sRxSwapChars, u"_"_s );
191
192 const thread_local QRegularExpression sRxRemoveChars( u"[^a-zA-Z0-9_]"_s );
193 laundered.replace( sRxRemoveChars, QString() );
194
195 return laundered;
196}
197
199{
200 if ( !layer )
201 {
202 return false;
203 }
204
205 return QgsMapLayerUtils::isOpenStreetMapUri( layer->source(), layer->providerType() );
206}
207
208bool QgsMapLayerUtils::isOpenStreetMapUri( const QString &uri, const QString &providerType )
209{
210 QUrl url;
211 if ( providerType == "wms"_L1 )
212 {
213 if ( const QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( providerType ) )
214 {
215 QVariantMap details = metadata->decodeUri( uri );
216 url = QUrl( details.value( u"url"_s ).toString() );
217 }
218 }
219 else if ( providerType == "xyzvectortiles"_L1 )
220 {
221 if ( const QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( providerType ) )
222 {
223 QVariantMap details = metadata->decodeUri( uri );
224 url = QUrl( details.value( u"url"_s ).toString() );
225 }
226 }
227 return !url.isEmpty() && ( url.host().endsWith( ".openstreetmap.org"_L1 ) || url.host().endsWith( ".osm.org"_L1 ) );
228}
229
231{
232 switch ( type )
233 {
235 return QObject::tr( "Vector" );
237 return QObject::tr( "Raster" );
239 return QObject::tr( "Mesh" );
241 return QObject::tr( "Point Cloud" );
243 return QObject::tr( "Annotation" );
245 return QObject::tr( "Vector Tile" );
247 return QObject::tr( "Plugin" );
249 return QObject::tr( "Group" );
251 return QObject::tr( "Tiled Scene" );
252 }
253 Q_ASSERT( false );
254 return QString();
255}
256
258{
259 if ( layer )
260 {
261 QStringList parts;
262 QString title = !layer->metadata().title().isEmpty() ? layer->metadata().title()
263 : ( layer->serverProperties()->title().isEmpty() ? layer->serverProperties()->shortName() : layer->serverProperties()->title() );
264 if ( title.isEmpty() )
265 title = layer->name();
266 title = "<b>" + title + "</b>";
267 if ( layer->isSpatial() && layer->crs().isValid() )
268 {
269 QString layerCrs = layer->crs().authid();
270 if ( !std::isnan( layer->crs().coordinateEpoch() ) )
271 {
272 layerCrs += u" @ %1"_s.arg( qgsDoubleToString( layer->crs().coordinateEpoch(), 3 ) );
273 }
274 if ( const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( layer ) )
275 title = QObject::tr( "%1 (%2 - %3)" ).arg( title, QgsWkbTypes::displayString( vl->wkbType() ), layerCrs );
276 else
277 title = QObject::tr( "%1 (%2)" ).arg( title, layerCrs );
278 }
279 parts << title;
280
281 QString abstract = !layer->metadata().abstract().isEmpty() ? layer->metadata().abstract() : layer->serverProperties()->abstract();
282 if ( !abstract.isEmpty() )
283 parts << "<br/>" + abstract.replace( "\n"_L1, "<br/>"_L1 );
284 parts << "<i>" + layer->publicSource() + "</i>";
286 {
287 parts << QObject::tr( "ID: %1" ).arg( layer->id() );
288 }
289 return parts.join( "<br/>"_L1 );
290 }
291 return QString();
292}
LayerType
Types of layers that can be added to a map.
Definition qgis.h:206
@ Group
Composite group layer. Added in QGIS 3.24.
Definition qgis.h:214
@ Plugin
Plugin based layer.
Definition qgis.h:209
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
Definition qgis.h:215
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
Definition qgis.h:212
@ Vector
Vector layer.
Definition qgis.h:207
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
Definition qgis.h:211
@ Mesh
Mesh layer. Added in QGIS 3.2.
Definition qgis.h:210
@ Raster
Raster layer.
Definition qgis.h:208
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
Definition qgis.h:213
SourceHierarchyLevel
Defines the structural levels within a data source hierarchy.
Definition qgis.h:1496
Provides common functionality for database based connections.
QString abstract() const
Returns a free-form description of the resource.
QString title() const
Returns the human readable name of the resource, typically displayed in search results.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
double coordinateEpoch() const
Returns the coordinate epoch, as a decimal year.
Contains information about the context in which a coordinate transform is executed.
Handles coordinate transforms between two 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.
QString what() const
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
QString abstract() const
Returns the abstract of the layerused by QGIS Server in GetCapabilities request.
static QString layerToolTip(const QgsMapLayer *layer)
Returns the consistent tooltip for the given layer.
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 bool layerRefersToUri(const QgsMapLayer *layer, const QString &uri, Qgis::SourceHierarchyLevel level=Qgis::SourceHierarchyLevel::Object)
Returns true if a layer and uri point to the same resource at the specified hierarchy level.
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 layerTypeToString(Qgis::LayerType type)
Returns the translated name of the type for a given layer type.
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.
static bool isOpenStreetMapUri(const QString &uri, const QString &providerType)
Returns true if the uri for a given provider is served by OpenStreetMap server.
Base class for all map layer types.
Definition qgsmaplayer.h:83
QString name
Definition qgsmaplayer.h:87
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:90
QgsMapLayerServerProperties * serverProperties()
Returns QGIS Server Properties for the map layer.
void setDataSource(const QString &dataSource, const QString &baseName=QString(), const QString &provider=QString(), bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
QString id
Definition qgsmaplayer.h:86
QgsLayerMetadata metadata
Definition qgsmaplayer.h:89
QString publicSource(bool hidePassword=false) const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
Custom exception class which is raised when an operation is not supported.
Custom exception class for provider connection related exceptions.
Holds data provider key, description, and associated shared library file or function pointer informat...
virtual bool urisReferToSame(const QString &uri1, const QString &uri2, Qgis::SourceHierarchyLevel level=Qgis::SourceHierarchyLevel::Object) const
Returns true if the URI uri1 and uri2 point to the same resource at the specified hierarchy level.
virtual QgsAbstractProviderConnection * createConnection(const QString &uri, const QVariantMap &configuration)
Creates a new connection from uri and configuration, the newly created connection is not automaticall...
@ UrisReferToSame
Indicates that the metadata can check whether layer URIs refer to the same object.
virtual QgsProviderMetadata::ProviderMetadataCapabilities capabilities() const
Returns the provider metadata capabilities.
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 rounded to the spec...
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).
static const QgsSettingsEntryBool * settingsLayerTreeShowIdInLayerTooltips
Settings entry for hidden ID in layer tooltips.
Represents a vector layer which manages a vector based dataset.
static Q_INVOKABLE QString displayString(Qgis::WkbType type)
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6995
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59