QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgsvectortilebasiclabeling.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectortilebasiclabeling.cpp
3  --------------------------------------
4  Date : April 2020
5  Copyright : (C) 2020 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 
19 #include "qgslogger.h"
20 #include "qgsvectortilelayer.h"
21 #include "qgsvectortilerenderer.h"
22 #include "qgsvectortileutils.h"
23 #include "qgsrendercontext.h"
24 
25 
26 void QgsVectorTileBasicLabelingStyle::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
27 {
28  elem.setAttribute( QStringLiteral( "name" ), mStyleName );
29  elem.setAttribute( QStringLiteral( "layer" ), mLayerName );
30  elem.setAttribute( QStringLiteral( "geometry" ), mGeometryType );
31  elem.setAttribute( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
32  elem.setAttribute( QStringLiteral( "expression" ), mExpression );
33  elem.setAttribute( QStringLiteral( "min-zoom" ), mMinZoomLevel );
34  elem.setAttribute( QStringLiteral( "max-zoom" ), mMaxZoomLevel );
35 
36  QDomDocument doc = elem.ownerDocument();
37  QDomElement elemLabelSettings = mLabelSettings.writeXml( doc, context );
38  elem.appendChild( elemLabelSettings );
39 }
40 
41 void QgsVectorTileBasicLabelingStyle::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
42 {
43  mStyleName = elem.attribute( QStringLiteral( "name" ) );
44  mLayerName = elem.attribute( QStringLiteral( "layer" ) );
45  mGeometryType = static_cast<QgsWkbTypes::GeometryType>( elem.attribute( QStringLiteral( "geometry" ) ).toInt() );
46  mEnabled = elem.attribute( QStringLiteral( "enabled" ) ).toInt();
47  mExpression = elem.attribute( QStringLiteral( "expression" ) );
48  mMinZoomLevel = elem.attribute( QStringLiteral( "min-zoom" ) ).toInt();
49  mMaxZoomLevel = elem.attribute( QStringLiteral( "max-zoom" ) ).toInt();
50 
51  QDomElement elemLabelSettings = elem.firstChildElement( QStringLiteral( "settings" ) );
52  mLabelSettings.readXml( elemLabelSettings, context );
53 }
54 
55 
56 //
57 
58 
60 {
61 }
62 
64 {
65  return QStringLiteral( "basic" );
66 }
67 
69 {
71  l->mStyles = mStyles;
72  return l;
73 }
74 
76 {
77  return new QgsVectorTileBasicLabelProvider( layer, mStyles );
78 }
79 
80 void QgsVectorTileBasicLabeling::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
81 {
82  QDomDocument doc = elem.ownerDocument();
83  QDomElement elemStyles = doc.createElement( QStringLiteral( "styles" ) );
84  for ( const QgsVectorTileBasicLabelingStyle &layerStyle : mStyles )
85  {
86  QDomElement elemStyle = doc.createElement( QStringLiteral( "style" ) );
87  layerStyle.writeXml( elemStyle, context );
88  elemStyles.appendChild( elemStyle );
89  }
90  elem.appendChild( elemStyles );
91 }
92 
93 void QgsVectorTileBasicLabeling::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
94 {
95  mStyles.clear();
96 
97  QDomElement elemStyles = elem.firstChildElement( QStringLiteral( "styles" ) );
98  QDomElement elemStyle = elemStyles.firstChildElement( QStringLiteral( "style" ) );
99  while ( !elemStyle.isNull() )
100  {
102  layerStyle.readXml( elemStyle, context );
103  mStyles.append( layerStyle );
104  elemStyle = elemStyle.nextSiblingElement( QStringLiteral( "style" ) );
105  }
106 }
107 
108 
109 //
110 
111 
112 QgsVectorTileBasicLabelProvider::QgsVectorTileBasicLabelProvider( QgsVectorTileLayer *layer, const QList<QgsVectorTileBasicLabelingStyle> &styles )
113  : QgsVectorTileLabelProvider( layer )
114  , mStyles( styles )
115 {
116 
117  for ( int i = 0; i < mStyles.count(); ++i )
118  {
119  const QgsVectorTileBasicLabelingStyle &style = mStyles[i];
120  //QgsFields fields = QgsVectorTileUtils::makeQgisFields( mRequiredFields[style.layerName()] );
121  QString providerId = QString::number( i );
122  QgsPalLayerSettings labelSettings = style.labelSettings();
123  mSubProviders.append( new QgsVectorLayerLabelProvider( style.geometryType(), QgsFields(), layer->crs(), providerId, &labelSettings, layer ) );
124  }
125 }
126 
127 QMap<QString, QSet<QString> > QgsVectorTileBasicLabelProvider::usedAttributes( const QgsRenderContext &context, int tileZoom ) const
128 {
129  QMap<QString, QSet<QString> > requiredFields;
130  for ( const QgsVectorTileBasicLabelingStyle &layerStyle : std::as_const( mStyles ) )
131  {
132  if ( !layerStyle.isActive( tileZoom ) )
133  continue;
134 
135  if ( !layerStyle.filterExpression().isEmpty() )
136  {
137  QgsExpression expr( layerStyle.filterExpression() );
138  requiredFields[layerStyle.layerName()].unite( expr.referencedColumns() );
139  }
140 
141  requiredFields[layerStyle.layerName()].unite( layerStyle.labelSettings().referencedFields( context ) );
142  }
143  return requiredFields;
144 }
145 
147 {
148  QSet< QString > res;
149  for ( const QgsVectorTileBasicLabelingStyle &layerStyle : std::as_const( mStyles ) )
150  {
151  if ( layerStyle.isActive( tileZoom ) )
152  {
153  res.insert( layerStyle.layerName() );
154  }
155  }
156  return res;
157 }
158 
159 void QgsVectorTileBasicLabelProvider::setFields( const QMap<QString, QgsFields> &perLayerFields )
160 {
161  mPerLayerFields = perLayerFields;
162 }
163 
164 QList<QgsAbstractLabelProvider *> QgsVectorTileBasicLabelProvider::subProviders()
165 {
166  QList<QgsAbstractLabelProvider *> lst;
167  for ( QgsVectorLayerLabelProvider *subprovider : std::as_const( mSubProviders ) )
168  {
169  if ( subprovider ) // sub-providers that failed to initialize are set to null
170  lst << subprovider;
171  }
172  return lst;
173 }
174 
175 bool QgsVectorTileBasicLabelProvider::prepare( QgsRenderContext &context, QSet<QString> &attributeNames )
176 {
177  for ( QgsVectorLayerLabelProvider *provider : std::as_const( mSubProviders ) )
178  provider->setEngine( mEngine );
179 
180  // populate sub-providers
181  for ( int i = 0; i < mSubProviders.count(); ++i )
182  {
183  QgsFields fields = mPerLayerFields[mStyles[i].layerName()];
184 
185  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) ); // will be deleted by popper
186  scope->setFields( fields );
187  QgsExpressionContextScopePopper popper( context.expressionContext(), scope );
188 
189  mSubProviders[i]->setFields( fields );
190  if ( !mSubProviders[i]->prepare( context, attributeNames ) )
191  {
192  QgsDebugMsg( QStringLiteral( "Failed to prepare labeling for style index" ) + QString::number( i ) );
193  mSubProviders[i] = nullptr;
194  }
195  }
196  return true;
197 }
198 
200 {
201  const QgsVectorTileFeatures tileData = tile.features();
202  int zoomLevel = tile.id().zoomLevel();
203 
204  for ( int i = 0; i < mStyles.count(); ++i )
205  {
206  const QgsVectorTileBasicLabelingStyle &layerStyle = mStyles.at( i );
207  if ( !layerStyle.isActive( zoomLevel ) )
208  continue;
209 
210  QgsFields fields = mPerLayerFields[layerStyle.layerName()];
211 
212  QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) ); // will be deleted by popper
213  scope->setFields( fields );
214  QgsExpressionContextScopePopper popper( context.expressionContext(), scope );
215 
216  QgsExpression filterExpression( layerStyle.filterExpression() );
217  filterExpression.prepare( &context.expressionContext() );
218 
219  QgsVectorLayerLabelProvider *subProvider = mSubProviders[i];
220  if ( !subProvider )
221  continue; // sub-providers that failed to initialize are set to null
222 
223  if ( layerStyle.layerName().isEmpty() )
224  {
225  // matching all layers
226  for ( QString layerName : tileData.keys() )
227  {
228  for ( const QgsFeature &f : tileData[layerName] )
229  {
230  scope->setFeature( f );
231  if ( filterExpression.isValid() && !filterExpression.evaluate( &context.expressionContext() ).toBool() )
232  continue;
233 
234  const QgsWkbTypes::GeometryType featureType = QgsWkbTypes::geometryType( f.geometry().wkbType() );
235  if ( featureType == layerStyle.geometryType() )
236  {
237  subProvider->registerFeature( f, context );
238  }
239  else if ( featureType == QgsWkbTypes::PolygonGeometry && layerStyle.geometryType() == QgsWkbTypes::PointGeometry )
240  {
241  // be tolerant and permit labeling polygons with a point layer style, as some style definitions use this approach
242  // to label the polygon center
243  QgsFeature centroid = f;
244  const QgsRectangle boundingBox = f.geometry().boundingBox();
245  centroid.setGeometry( f.geometry().poleOfInaccessibility( std::min( boundingBox.width(), boundingBox.height() ) / 20 ) );
246  subProvider->registerFeature( centroid, context );
247  }
248  }
249  }
250  }
251  else if ( tileData.contains( layerStyle.layerName() ) )
252  {
253  // matching one particular layer
254  for ( const QgsFeature &f : tileData[layerStyle.layerName()] )
255  {
256  scope->setFeature( f );
257  if ( filterExpression.isValid() && !filterExpression.evaluate( &context.expressionContext() ).toBool() )
258  continue;
259 
260  const QgsWkbTypes::GeometryType featureType = QgsWkbTypes::geometryType( f.geometry().wkbType() );
261  if ( featureType == layerStyle.geometryType() )
262  {
263  subProvider->registerFeature( f, context );
264  }
265  else if ( featureType == QgsWkbTypes::PolygonGeometry && layerStyle.geometryType() == QgsWkbTypes::PointGeometry )
266  {
267  // be tolerant and permit labeling polygons with a point layer style, as some style definitions use this approach
268  // to label the polygon center
269  QgsFeature centroid = f;
270  const QgsRectangle boundingBox = f.geometry().boundingBox();
271  centroid.setGeometry( f.geometry().poleOfInaccessibility( std::min( boundingBox.width(), boundingBox.height() ) / 20 ) );
272  subProvider->registerFeature( centroid, context );
273  }
274  }
275  }
276  }
277 }
QgsMapLayer * layer() const
Returns the associated layer, or nullptr if no layer is associated with the provider.
const QgsLabelingEngine * mEngine
Associated labeling engine.
QString providerId() const
Returns provider ID - useful in case there is more than one label provider within a layer (e....
RAII class to pop scope from an expression context on destruction.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the scope.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the scope.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
QVariant evaluate()
Evaluate the feature and return the result.
bool isValid() const
Checks if this expression is valid.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
Container of fields for a vector layer.
Definition: qgsfields.h:45
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
Contains settings for how a map layer will be labeled.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
The class is used as a container of context for various read/write operations on other objects.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
Contains information about the context of a rendering operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
int zoomLevel() const
Returns tile's zoom level (Z)
Definition: qgstiles.h:51
The QgsVectorLayerLabelProvider class implements a label provider for vector layers.
QgsVectorLayerLabelProvider(QgsVectorLayer *layer, const QString &providerId, bool withFeatureLoop, const QgsPalLayerSettings *settings, const QString &layerName=QString())
Convenience constructor to initialize the provider from given vector layer.
virtual QList< QgsLabelFeature * > registerFeature(const QgsFeature &feature, QgsRenderContext &context, const QgsGeometry &obstacleGeometry=QgsGeometry(), const QgsSymbol *symbol=nullptr)
Register a feature for labeling as one or more QgsLabelFeature objects stored into mLabels.
Implementation class for QgsVectorTileBasicLabeling.
QMap< QString, QgsFields > mPerLayerFields
Names of required fields for each sub-layer (only valid between startRender/stopRender calls)
bool prepare(QgsRenderContext &context, QSet< QString > &attributeNames) override
Prepare for registration of features.
void setFields(const QMap< QString, QgsFields > &perLayerFields) override
Sets fields for each sub-layer.
QgsVectorTileBasicLabelProvider(QgsVectorTileLayer *layer, const QList< QgsVectorTileBasicLabelingStyle > &styles)
Constructs a label provider for the given vector tile layer and using styling from QgsVectorTileBasic...
void registerTileFeatures(const QgsVectorTileRendererData &tile, QgsRenderContext &context) override
Registers label features for given tile to the labeling engine.
QMap< QString, QSet< QString > > usedAttributes(const QgsRenderContext &context, int tileZoom) const override
Returns field names for each sub-layer that are required for labeling.
QSet< QString > requiredLayers(QgsRenderContext &context, int tileZoom) const override
Returns a list of the layers required for labeling.
QList< QgsAbstractLabelProvider * > subProviders() override
Returns list of child providers - useful if the provider needs to put labels into more layers with di...
Configuration of a single style within QgsVectorTileBasicLabeling.
QgsPalLayerSettings labelSettings() const
Returns labeling configuration of this style.
QString layerName() const
Returns name of the sub-layer to render (empty layer means that all layers match)
QString filterExpression() const
Returns filter expression (empty filter means that all features match)
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const
Writes object content to given DOM element.
QgsWkbTypes::GeometryType geometryType() const
Returns type of the geometry that will be used (point / line / polygon)
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads object content from given DOM element.
bool isActive(int zoomLevel) const
Returns whether the style is active at given zoom level (also checks "enabled" flag)
Basic labeling configuration for vector tile layers.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads labeling properties from given XML element.
QgsVectorTileLabelProvider * provider(QgsVectorTileLayer *layer) const override SIP_SKIP
Factory for label provider implementation.
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const override
Writes labeling properties to given XML element.
QgsVectorTileLabeling * clone() const override SIP_FACTORY
Returns a new copy of the object.
QString type() const override
Unique type string of the labeling configuration implementation.
Internal base class for implementation of label providers for vector tile labeling.
Base class for labeling configuration classes for vector tile layers.
Implements a map layer that is dedicated to rendering of vector tiles.
Contains decoded features of a single vector tile and any other data necessary for rendering of it.
QgsVectorTileFeatures features() const
Returns features of the tile grouped by sub-layer names.
QgsTileXYZ id() const
Returns coordinates of the tile.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:968
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
CORE_EXPORT QgsMeshVertex centroid(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns the centroid of the face.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QMap< QString, QVector< QgsFeature > > QgsVectorTileFeatures
Features of a vector tile, grouped by sub-layer names (key of the map)