QGIS API Documentation  3.21.0-Master (5b68dc587e)
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 "qgsreferencedgeometry.h"
26 #include "qgslogger.h"
27 #include "qgsmaplayer.h"
28 #include "qgscoordinatetransform.h"
29 
30 QgsRectangle 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 
117 bool 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 
126 bool 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 }
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 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