QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
QgsExpressionContextScope::setFeature
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the scope.
Definition: qgsexpressioncontext.h:319
qgsexpressioncontextutils.h
qgsvectortilerenderer.h
QgsPalLayerSettings::readXml
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
Definition: qgspallabeling.cpp:953
QgsRectangle::height
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
QgsExpressionContextScopePopper
RAII class to pop scope from an expression context on destruction.
Definition: qgsexpressioncontextutils.h:361
QgsVectorTileLayer
Implements a map layer that is dedicated to rendering of vector tiles. Vector tiles compared to "ordi...
Definition: qgsvectortilelayer.h:84
QgsVectorTileBasicLabelProvider::requiredLayers
QSet< QString > requiredLayers(QgsRenderContext &context, int tileZoom) const override
Returns a list of the layers required for labeling.
Definition: qgsvectortilebasiclabeling.cpp:146
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:625
QgsVectorTileBasicLabelingStyle::isActive
bool isActive(int zoomLevel) const
Returns whether the style is active at given zoom level (also checks "enabled" flag)
Definition: qgsvectortilebasiclabeling.h:76
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
QgsExpression::referencedColumns
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
Definition: qgsexpression.cpp:221
QgsVectorTileBasicLabelProvider::registerTileFeatures
void registerTileFeatures(const QgsVectorTileRendererData &tile, QgsRenderContext &context) override
Registers label features for given tile to the labeling engine.
Definition: qgsvectortilebasiclabeling.cpp:199
QgsPalLayerSettings
Contains settings for how a map layer will be labeled.
Definition: qgspallabeling.h:86
QgsMeshUtils::centroid
CORE_EXPORT QgsMeshVertex centroid(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns the centroid of the face.
Definition: qgstriangularmesh.cpp:955
QgsVectorTileBasicLabeling::QgsVectorTileBasicLabeling
QgsVectorTileBasicLabeling()
Definition: qgsvectortilebasiclabeling.cpp:59
QgsVectorTileBasicLabelingStyle
Configuration of a single style within QgsVectorTileBasicLabeling.
Definition: qgsvectortilebasiclabeling.h:31
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsVectorTileLabelProvider
Internal base class for implementation of label providers for vector tile labeling.
Definition: qgsvectortilelabeling.h:33
QgsExpression::isValid
bool isValid() const
Checks if this expression is valid.
Definition: qgsexpression.cpp:201
QgsVectorTileBasicLabeling::type
QString type() const override
Unique type string of the labeling configuration implementation.
Definition: qgsvectortilebasiclabeling.cpp:63
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsVectorTileBasicLabeling
Basic labeling configuration for vector tile layers. It contains a definition of a list of labeling s...
Definition: qgsvectortilebasiclabeling.h:107
QgsVectorTileBasicLabelingStyle::geometryType
QgsWkbTypes::GeometryType geometryType() const
Returns type of the geometry that will be used (point / line / polygon)
Definition: qgsvectortilebasiclabeling.h:53
QgsVectorTileRendererData
Contains decoded features of a single vector tile and any other data necessary for rendering of it.
Definition: qgsvectortilerenderer.h:39
QgsExpressionContextScope::setFields
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the scope.
Definition: qgsexpressioncontext.cpp:199
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsVectorLayerLabelProvider
The QgsVectorLayerLabelProvider class implements a label provider for vector layers....
Definition: qgsvectorlayerlabelprovider.h:41
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
QgsVectorTileBasicLabelingStyle::filterExpression
QString filterExpression() const
Returns filter expression (empty filter means that all features match)
Definition: qgsvectortilebasiclabeling.h:58
QgsVectorTileRendererData::id
QgsTileXYZ id() const
Returns coordinates of the tile.
Definition: qgsvectortilerenderer.h:48
QgsVectorTileBasicLabelProvider
Implementation class for QgsVectorTileBasicLabeling.
Definition: qgsvectortilebasiclabeling.h:141
qgsvectortilelayer.h
QgsVectorTileBasicLabeling::readXml
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads labeling properties from given XML element.
Definition: qgsvectortilebasiclabeling.cpp:93
QgsVectorTileBasicLabelProvider::subProviders
QList< QgsAbstractLabelProvider * > subProviders() override
Returns list of child providers - useful if the provider needs to put labels into more layers with di...
Definition: qgsvectortilebasiclabeling.cpp:164
QgsVectorTileBasicLabelProvider::QgsVectorTileBasicLabelProvider
QgsVectorTileBasicLabelProvider(QgsVectorTileLayer *layer, const QList< QgsVectorTileBasicLabelingStyle > &styles)
Constructs a label provider for the given vector tile layer and using styling from QgsVectorTileBasic...
Definition: qgsvectortilebasiclabeling.cpp:112
qgsrendercontext.h
QgsVectorTileBasicLabelingStyle::readXml
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads object content from given DOM element.
Definition: qgsvectortilebasiclabeling.cpp:41
QgsVectorTileBasicLabelProvider::setFields
void setFields(const QMap< QString, QgsFields > &perLayerFields) override
Sets fields for each sub-layer.
Definition: qgsvectortilebasiclabeling.cpp:159
QgsExpression::prepare
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
Definition: qgsexpression.cpp:327
QgsTileXYZ::zoomLevel
int zoomLevel() const
Returns tile's zoom level (Z)
Definition: qgstiles.h:51
QgsAbstractLabelProvider::mEngine
const QgsLabelingEngine * mEngine
Associated labeling engine.
Definition: qgslabelingengine.h:178
QgsAbstractLabelProvider::providerId
QString providerId() const
Returns provider ID - useful in case there is more than one label provider within a layer (e....
Definition: qgslabelingengine.h:145
QgsExpression::evaluate
QVariant evaluate()
Evaluate the feature and return the result.
Definition: qgsexpression.cpp:350
QgsVectorTileBasicLabelProvider::mPerLayerFields
QMap< QString, QgsFields > mPerLayerFields
Names of required fields for each sub-layer (only valid between startRender/stopRender calls)
Definition: qgsvectortilebasiclabeling.h:164
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:113
QgsPalLayerSettings::writeXml
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
Definition: qgspallabeling.cpp:1219
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:142
QgsVectorTileBasicLabeling::provider
QgsVectorTileLabelProvider * provider(QgsVectorTileLayer *layer) const override SIP_SKIP
Factory for label provider implementation.
Definition: qgsvectortilebasiclabeling.cpp:75
QgsWkbTypes::GeometryType
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:140
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
QgsVectorTileBasicLabeling::writeXml
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const override
Writes labeling properties to given XML element.
Definition: qgsvectortilebasiclabeling.cpp:80
QgsVectorTileBasicLabelingStyle::writeXml
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const
Writes object content to given DOM element.
Definition: qgsvectortilebasiclabeling.cpp:26
QgsAbstractLabelProvider::layer
QgsMapLayer * layer() const
Returns the associated layer, or nullptr if no layer is associated with the provider.
Definition: qgslabelingengine.h:138
QgsWkbTypes::geometryType
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
QgsVectorLayerLabelProvider::registerFeature
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.
Definition: qgsvectorlayerlabelprovider.cpp:196
QgsVectorTileLabeling
Base class for labeling configuration classes for vector tile layers.
Definition: qgsvectortilelabeling.h:70
QgsVectorTileBasicLabelingStyle::labelSettings
QgsPalLayerSettings labelSettings() const
Returns labeling configuration of this style.
Definition: qgsvectortilebasiclabeling.h:38
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsVectorTileBasicLabelProvider::usedAttributes
QMap< QString, QSet< QString > > usedAttributes(const QgsRenderContext &context, int tileZoom) const override
Returns field names for each sub-layer that are required for labeling.
Definition: qgsvectortilebasiclabeling.cpp:127
QgsVectorTileRendererData::features
QgsVectorTileFeatures features() const
Returns features of the tile grouped by sub-layer names.
Definition: qgsvectortilerenderer.h:63
QgsVectorTileFeatures
QMap< QString, QVector< QgsFeature > > QgsVectorTileFeatures
Features of a vector tile, grouped by sub-layer names (key of the map)
Definition: qgsvectortilerenderer.h:27
qgslogger.h
QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider
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.
Definition: qgsvectorlayerlabelprovider.cpp:49
QgsVectorTileBasicLabeling::clone
QgsVectorTileLabeling * clone() const override SIP_FACTORY
Returns a new copy of the object.
Definition: qgsvectortilebasiclabeling.cpp:68
qgsvectortileutils.h
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
qgsvectortilebasiclabeling.h
QgsVectorTileBasicLabelProvider::prepare
bool prepare(QgsRenderContext &context, QSet< QString > &attributeNames) override
Prepare for registration of features.
Definition: qgsvectortilebasiclabeling.cpp:175
QgsVectorTileBasicLabelingStyle::layerName
QString layerName() const
Returns name of the sub-layer to render (empty layer means that all layers match)
Definition: qgsvectortilebasiclabeling.h:48