-
-
Notifications
You must be signed in to change notification settings - Fork 3k
/
qgsmaplayerutils.cpp
138 lines (120 loc) · 5.3 KB
/
qgsmaplayerutils.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/***************************************************************************
qgsmaplayerutils.cpp
-------------------
begin : May 2021
copyright : (C) 2021 Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsmaplayerutils.h"
#include "qgsrectangle.h"
#include "qgscoordinatereferencesystem.h"
#include "qgscoordinatetransformcontext.h"
#include "qgsabstractdatabaseproviderconnection.h"
#include "qgsprovidermetadata.h"
#include "qgsproviderregistry.h"
#include "qgsreferencedgeometry.h"
#include "qgslogger.h"
#include "qgsmaplayer.h"
QgsRectangle QgsMapLayerUtils::combinedExtent( const QList<QgsMapLayer *> &layers, const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &transformContext )
{
// We can't use a constructor since QgsRectangle normalizes the rectangle upon construction
QgsRectangle fullExtent;
fullExtent.setMinimal();
// iterate through the map layers and test each layers extent
// against the current min and max values
QgsDebugMsgLevel( QStringLiteral( "Layer count: %1" ).arg( layers.count() ), 5 );
for ( const QgsMapLayer *layer : layers )
{
QgsDebugMsgLevel( "Updating extent using " + layer->name(), 5 );
QgsDebugMsgLevel( "Input extent: " + layer->extent().toString(), 5 );
if ( layer->extent().isNull() )
continue;
// Layer extents are stored in the coordinate system (CS) of the
// layer. The extent must be projected to the canvas CS
QgsCoordinateTransform ct( layer->crs(), crs, transformContext );
ct.setBallparkTransformsAreAppropriate( true );
try
{
const QgsRectangle extent = ct.transformBoundingBox( layer->extent() );
QgsDebugMsgLevel( "Output extent: " + extent.toString(), 5 );
fullExtent.combineExtentWith( extent );
}
catch ( QgsCsException & )
{
QgsDebugMsg( QStringLiteral( "Could not reproject layer extent" ) );
}
}
if ( fullExtent.width() == 0.0 || fullExtent.height() == 0.0 )
{
// If all of the features are at the one point, buffer the
// rectangle a bit. If they are all at zero, do something a bit
// more crude.
if ( fullExtent.xMinimum() == 0.0 && fullExtent.xMaximum() == 0.0 &&
fullExtent.yMinimum() == 0.0 && fullExtent.yMaximum() == 0.0 )
{
fullExtent.set( -1.0, -1.0, 1.0, 1.0 );
}
else
{
const double padFactor = 1e-8;
const double widthPad = fullExtent.xMinimum() * padFactor;
const double heightPad = fullExtent.yMinimum() * padFactor;
const double xmin = fullExtent.xMinimum() - widthPad;
const double xmax = fullExtent.xMaximum() + widthPad;
const double ymin = fullExtent.yMinimum() - heightPad;
const double ymax = fullExtent.yMaximum() + heightPad;
fullExtent.set( xmin, ymin, xmax, ymax );
}
}
QgsDebugMsgLevel( "Full extent: " + fullExtent.toString(), 5 );
return fullExtent;
}
QgsAbstractDatabaseProviderConnection *QgsMapLayerUtils::databaseConnection( const QgsMapLayer *layer )
{
if ( ! layer || ! layer->dataProvider() )
{
return nullptr;
}
try
{
QgsProviderMetadata *providerMetadata = QgsProviderRegistry::instance()->providerMetadata( layer->dataProvider()->name() );
if ( ! providerMetadata )
{
return nullptr;
}
std::unique_ptr< QgsAbstractDatabaseProviderConnection > conn { static_cast<QgsAbstractDatabaseProviderConnection *>( providerMetadata->createConnection( layer->source(), {} ) ) };
return conn.release();
}
catch ( const QgsProviderConnectionException &ex )
{
QgsDebugMsg( QStringLiteral( "Error retrieving database connection for layer %1: %2" ).arg( layer->name(), ex.what() ) );
return nullptr;
}
}
bool QgsMapLayerUtils::layerSourceMatchesPath( const QgsMapLayer *layer, const QString &path )
{
if ( !layer || path.isEmpty() )
return false;
const QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
return parts.value( QStringLiteral( "path" ) ).toString() == path;
}
bool QgsMapLayerUtils::updateLayerSourcePath( QgsMapLayer *layer, const QString &newPath )
{
if ( !layer || newPath.isEmpty() )
return false;
QVariantMap parts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
if ( !parts.contains( QStringLiteral( "path" ) ) )
return false;
parts.insert( QStringLiteral( "path" ), newPath );
const QString newUri = QgsProviderRegistry::instance()->encodeUri( layer->providerType(), parts );
layer->setDataSource( newUri, layer->name(), layer->providerType() );
return true;
}