QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgswmslayerinfos.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgswmslayerinfos.cpp
3
4 Layer's information
5 ------------------------------------
6 begin : September 26 , 2022
7 copyright : (C) 2022 by René-Luc D'Hont and David Marteau
8 email : rldhont at 3liz doc com
9 dmarteau at 3liz dot com
10 ***************************************************************************/
11
12/***************************************************************************
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 ***************************************************************************/
20
21#include "qgswmslayerinfos.h"
22
23#include <algorithm>
24
27#include "qgsmessagelog.h"
28#include "qgsproject.h"
29#include "qgsserverinterface.h"
31#include "qgsvectorlayer.h"
32
34 const QgsRectangle &extent,
35 const QgsCoordinateReferenceSystem &source,
36 const QgsCoordinateReferenceSystem &destination,
37 const QgsCoordinateTransformContext &context,
38 const bool &ballparkTransformsAreAppropriate
39)
40{
41 QgsCoordinateTransform transformer { source, destination, context };
42 transformer.setBallparkTransformsAreAppropriate( ballparkTransformsAreAppropriate );
43 // Transform extent and do not catch exception
44 return transformer.transformBoundingBox( extent );
45}
46
48 const QgsRectangle &extent,
49 const QgsCoordinateReferenceSystem &source,
50 const QList<QgsCoordinateReferenceSystem> &destinations,
52)
53{
54 QMap<QString, QgsRectangle> crsExtents;
55 if ( extent.isEmpty() )
56 {
57 return crsExtents;
58 }
59 for ( const QgsCoordinateReferenceSystem &destination : std::as_const( destinations ) )
60 {
61 // Transform extent and do not catch exception
62 QgsCoordinateTransform crsTransform { source, destination, context };
63 crsExtents[destination.authid()] = crsTransform.transformBoundingBox( extent );
64 }
65 return crsExtents;
66}
67
68
70 const QgsProject *project,
71 QgsWmsLayerInfos &pLayer,
72 QgsMapLayer *ml,
73 const QgsRectangle &wmsExtent,
75 const QList<QgsCoordinateReferenceSystem> &outputCrsList
76)
77{
78 QgsRectangle layerExtent = ml->extent();
79 if ( layerExtent.isEmpty() )
80 {
81 // if the extent is empty (not only Null), use the wms extent
82 // defined in the project...
83 if ( wmsExtent.isNull() )
84 {
85 // or the CRS extent otherwise
86 layerExtent = ml->crs().bounds();
87 }
88 else
89 {
90 layerExtent = QgsRectangle( wmsExtent );
91 if ( ml->crs() != project->crs() )
92 {
93 // If CRS is different transform it to layer's CRS
94 try
95 {
96 layerExtent = QgsWmsLayerInfos::transformExtent( wmsExtent, project->crs(), ml->crs(), project->transformContext() );
97 }
98 catch ( QgsCsException &cse )
99 {
100 QgsMessageLog::logMessage( QStringLiteral( "Error transforming extent for layer %1: %2" ).arg( ml->name() ).arg( cse.what() ), QStringLiteral( "Server" ), Qgis::MessageLevel::Warning );
101 return false;
102 }
103 }
104 }
105
106 // Now we have a layer Extent we need the WGS84 bounding rectangle
107 try
108 {
109 pLayer.wgs84BoundingRect = QgsWmsLayerInfos::transformExtent( layerExtent, ml->crs(), wgs84, project->transformContext(), true );
110 }
111 catch ( const QgsCsException &cse )
112 {
113 QgsMessageLog::logMessage( QStringLiteral( "Error transforming extent for layer %1: %2" ).arg( ml->name() ).arg( cse.what() ), QStringLiteral( "Server" ), Qgis::MessageLevel::Warning );
114 return false;
115 }
116 }
117 else
118 {
119 pLayer.wgs84BoundingRect = ml->wgs84Extent();
120 }
121
122 try
123 {
125 layerExtent, ml->crs(), outputCrsList, project->transformContext()
126 );
127 }
128 catch ( QgsCsException &cse )
129 {
130 QgsMessageLog::logMessage( QStringLiteral( "Error transforming extent for layer %1: %2" ).arg( ml->name() ).arg( cse.what() ), QStringLiteral( "Server" ), Qgis::MessageLevel::Warning );
131 return false;
132 }
133
134 return true;
135}
136
137// ===================================
138// Get wms layer infos
139// ===================================
140QMap<QString, QgsWmsLayerInfos> QgsWmsLayerInfos::buildWmsLayerInfos(
141 QgsServerInterface *serverIface,
142 const QgsProject *project,
143 const QList<QgsCoordinateReferenceSystem> &outputCrsList
144)
145{
146 QMap<QString, QgsWmsLayerInfos> wmsLayers;
147#ifdef HAVE_SERVER_PYTHON_PLUGINS
148 QgsAccessControl *accessControl = serverIface->accessControls();
149#else
150 ( void ) serverIface;
151#endif
152
153 bool useLayerIds = QgsServerProjectUtils::wmsUseLayerIds( *project );
154 const QStringList restrictedLayers = QgsServerProjectUtils::wmsRestrictedLayers( *project );
155 const QgsRectangle wmsExtent = QgsServerProjectUtils::wmsExtent( *project );
157
158 for ( QgsMapLayer *ml : project->mapLayers() )
159 {
160 if ( !ml || restrictedLayers.contains( ml->name() ) ) //unpublished layer
161 {
162 continue;
163 }
164
165#ifdef HAVE_SERVER_PYTHON_PLUGINS
166 if ( accessControl && !accessControl->layerReadPermission( ml ) )
167 {
168 continue;
169 }
170#endif
171
172 QgsWmsLayerInfos pLayer;
173 pLayer.id = ml->id();
174
175 // Calculate layer extents for the WMS output CRSes list
176 // First define if the layer has an extent
177 // Vector layer with No Geometry has no extent the other has one
178 bool hasExtent = true;
179 if ( ml->type() == Qgis::LayerType::Vector )
180 {
181 QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( ml );
182 if ( !vLayer || vLayer->wkbType() == Qgis::WkbType::NoGeometry )
183 {
184 hasExtent = false;
185 }
186 }
187
188 // If the layer has an extent and we cannot get CRS bounding boxes, do not keep the layer
189 if ( hasExtent && !setBoundingRect( project, pLayer, ml, wmsExtent, wgs84, outputCrsList ) )
190 continue;
191
192 // layer type
193 pLayer.type = ml->type();
194 // layer wms name
195 pLayer.name = ml->name();
196 if ( useLayerIds )
197 {
198 pLayer.name = ml->id();
199 }
200 else if ( !ml->serverProperties()->shortName().isEmpty() )
201 {
202 pLayer.name = ml->serverProperties()->shortName();
203 }
204 // layer is queryable
205 pLayer.queryable = ml->flags().testFlag( QgsMapLayer::Identifiable );
206 // layer styles
207 pLayer.styles = ml->styleManager()->styles();
208 // layer legend URL
209 pLayer.legendUrl = ml->serverProperties()->legendUrl();
210 // layer legend URL format
211 pLayer.legendUrlFormat = ml->serverProperties()->legendUrlFormat();
212 // layer min/max scales
213 if ( ml->hasScaleBasedVisibility() )
214 {
215 pLayer.hasScaleBasedVisibility = ml->hasScaleBasedVisibility();
216 pLayer.maxScale = ml->maximumScale();
217 pLayer.minScale = ml->minimumScale();
218 }
219
220 wmsLayers[pLayer.id] = pLayer;
221 }
222
223 return wmsLayers;
224}
@ Warning
Warning message.
Definition qgis.h:158
@ Vector
Vector layer.
Definition qgis.h:191
static QString geographicCrsAuthId()
Geographic coordinate system auth:id string for a default geographic CRS (EPSG:4326).
Definition qgis.h:6333
@ NoGeometry
No geometry.
Definition qgis.h:294
A helper class that centralizes restrictions given by all the access control filter plugins.
bool layerReadPermission(const QgsMapLayer *layer) const
Returns the layer read right.
Represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
QgsRectangle bounds() const
Returns the approximate bounds for the region the CRS is usable within.
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
Base class for all map layer types.
Definition qgsmaplayer.h:80
QString name
Definition qgsmaplayer.h:84
QgsRectangle wgs84Extent(bool forceRecalculate=false) const
Returns the WGS84 extent (EPSG:4326) of the layer according to ReadFlag::FlagTrustLayerMetadata.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:87
@ Identifiable
If the layer is identifiable using the identify map tool and as a WMS layer.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:109
QgsCoordinateTransformContext transformContext
Definition qgsproject.h:116
QgsCoordinateReferenceSystem crs
Definition qgsproject.h:115
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
A rectangle specified with double values.
Defines interfaces exposed by QGIS Server and made available to plugins.
virtual QgsAccessControl * accessControls() const =0
Gets the registered access control filters.
static QgsRectangle wmsExtent(const QgsProject &project)
Returns the WMS Extent restriction.
static bool wmsUseLayerIds(const QgsProject &project)
Returns if layer ids are used as name in WMS.
static QStringList wmsRestrictedLayers(const QgsProject &project)
Returns the restricted layer name list.
Represents a vector layer which manages a vector based dataset.
Q_INVOKABLE Qgis::WkbType wkbType() const final
Returns the WKBType or WKBUnknown in case of error.
WMS Layer infos.
QString legendUrlFormat
WMS layer legend URL format.
QStringList styles
WMS layer styles.
QString legendUrl
WMS layer legend URL.
QString id
QGIS layer id.
static QgsRectangle transformExtent(const QgsRectangle &extent, const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination, const QgsCoordinateTransformContext &context, const bool &ballparkTransformsAreAppropriate=false)
Returns a transformed extent.
double maxScale
WMS layer maximum scale (if negative, no maximum scale is defined).
QMap< QString, QgsRectangle > crsExtents
WMS layer CRS extents (can be empty).
static QMap< QString, QgsRectangle > transformExtentToCrsList(const QgsRectangle &extent, const QgsCoordinateReferenceSystem &source, const QList< QgsCoordinateReferenceSystem > &destinations, const QgsCoordinateTransformContext &context)
Returns a map with CRS authid as key and the transformed extent as value.
Qgis::LayerType type
QGIS layer type.
QString name
WMS layer name.
static QMap< QString, QgsWmsLayerInfos > buildWmsLayerInfos(QgsServerInterface *serverIface, const QgsProject *project, const QList< QgsCoordinateReferenceSystem > &outputCrsList)
Returns the WMS layers definition to build WMS capabilities.
bool hasScaleBasedVisibility
WMS layer has scale based visibility.
double minScale
WMS layer minimum scale (if negative, no maximum scale is defined).
bool queryable
WMS layer is queryable.
QgsRectangle wgs84BoundingRect
WMS layer WGS84 bounding rectangle (can be empty).
bool setBoundingRect(const QgsProject *project, QgsWmsLayerInfos &pLayer, QgsMapLayer *ml, const QgsRectangle &wmsExtent, const QgsCoordinateReferenceSystem &wgs84, const QList< QgsCoordinateReferenceSystem > &outputCrsList)