Branch data Line data Source code
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 : : 16 : : #include "qgsvectortilebasiclabeling.h" 17 : : 18 : : #include "qgsexpressioncontextutils.h" 19 : : #include "qgslogger.h" 20 : : #include "qgsvectortilelayer.h" 21 : : #include "qgsvectortilerenderer.h" 22 : : #include "qgsvectortileutils.h" 23 : : 24 : : 25 : : 26 : 0 : void QgsVectorTileBasicLabelingStyle::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const 27 : : { 28 : 0 : elem.setAttribute( QStringLiteral( "name" ), mStyleName ); 29 : 0 : elem.setAttribute( QStringLiteral( "layer" ), mLayerName ); 30 : 0 : elem.setAttribute( QStringLiteral( "geometry" ), mGeometryType ); 31 : 0 : elem.setAttribute( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ); 32 : 0 : elem.setAttribute( QStringLiteral( "expression" ), mExpression ); 33 : 0 : elem.setAttribute( QStringLiteral( "min-zoom" ), mMinZoomLevel ); 34 : 0 : elem.setAttribute( QStringLiteral( "max-zoom" ), mMaxZoomLevel ); 35 : : 36 : 0 : QDomDocument doc = elem.ownerDocument(); 37 : 0 : QDomElement elemLabelSettings = mLabelSettings.writeXml( doc, context ); 38 : 0 : elem.appendChild( elemLabelSettings ); 39 : 0 : } 40 : : 41 : 0 : void QgsVectorTileBasicLabelingStyle::readXml( const QDomElement &elem, const QgsReadWriteContext &context ) 42 : : { 43 : 0 : mStyleName = elem.attribute( QStringLiteral( "name" ) ); 44 : 0 : mLayerName = elem.attribute( QStringLiteral( "layer" ) ); 45 : 0 : mGeometryType = static_cast<QgsWkbTypes::GeometryType>( elem.attribute( QStringLiteral( "geometry" ) ).toInt() ); 46 : 0 : mEnabled = elem.attribute( QStringLiteral( "enabled" ) ).toInt(); 47 : 0 : mExpression = elem.attribute( QStringLiteral( "expression" ) ); 48 : 0 : mMinZoomLevel = elem.attribute( QStringLiteral( "min-zoom" ) ).toInt(); 49 : 0 : mMaxZoomLevel = elem.attribute( QStringLiteral( "max-zoom" ) ).toInt(); 50 : : 51 : 0 : QDomElement elemLabelSettings = elem.firstChildElement( QStringLiteral( "settings" ) ); 52 : 0 : mLabelSettings.readXml( elemLabelSettings, context ); 53 : 0 : } 54 : : 55 : : 56 : : // 57 : : 58 : : 59 : 0 : QgsVectorTileBasicLabeling::QgsVectorTileBasicLabeling() 60 : 0 : { 61 : 0 : } 62 : : 63 : 0 : QString QgsVectorTileBasicLabeling::type() const 64 : : { 65 : 0 : return QStringLiteral( "basic" ); 66 : : } 67 : : 68 : 0 : QgsVectorTileLabeling *QgsVectorTileBasicLabeling::clone() const 69 : : { 70 : 0 : QgsVectorTileBasicLabeling *l = new QgsVectorTileBasicLabeling; 71 : 0 : l->mStyles = mStyles; 72 : 0 : return l; 73 : 0 : } 74 : : 75 : 0 : QgsVectorTileLabelProvider *QgsVectorTileBasicLabeling::provider( QgsVectorTileLayer *layer ) const 76 : : { 77 : 0 : return new QgsVectorTileBasicLabelProvider( layer, mStyles ); 78 : 0 : } 79 : : 80 : 0 : void QgsVectorTileBasicLabeling::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const 81 : : { 82 : 0 : QDomDocument doc = elem.ownerDocument(); 83 : 0 : QDomElement elemStyles = doc.createElement( QStringLiteral( "styles" ) ); 84 : 0 : for ( const QgsVectorTileBasicLabelingStyle &layerStyle : mStyles ) 85 : : { 86 : 0 : QDomElement elemStyle = doc.createElement( QStringLiteral( "style" ) ); 87 : 0 : layerStyle.writeXml( elemStyle, context ); 88 : 0 : elemStyles.appendChild( elemStyle ); 89 : 0 : } 90 : 0 : elem.appendChild( elemStyles ); 91 : 0 : } 92 : : 93 : 0 : void QgsVectorTileBasicLabeling::readXml( const QDomElement &elem, const QgsReadWriteContext &context ) 94 : : { 95 : 0 : mStyles.clear(); 96 : : 97 : 0 : QDomElement elemStyles = elem.firstChildElement( QStringLiteral( "styles" ) ); 98 : 0 : QDomElement elemStyle = elemStyles.firstChildElement( QStringLiteral( "style" ) ); 99 : 0 : while ( !elemStyle.isNull() ) 100 : : { 101 : 0 : QgsVectorTileBasicLabelingStyle layerStyle; 102 : 0 : layerStyle.readXml( elemStyle, context ); 103 : 0 : mStyles.append( layerStyle ); 104 : 0 : elemStyle = elemStyle.nextSiblingElement( QStringLiteral( "style" ) ); 105 : 0 : } 106 : 0 : } 107 : : 108 : : 109 : : // 110 : : 111 : : 112 : 0 : QgsVectorTileBasicLabelProvider::QgsVectorTileBasicLabelProvider( QgsVectorTileLayer *layer, const QList<QgsVectorTileBasicLabelingStyle> &styles ) 113 : 0 : : QgsVectorTileLabelProvider( layer ) 114 : 0 : , mStyles( styles ) 115 : 0 : { 116 : : 117 : 0 : for ( int i = 0; i < mStyles.count(); ++i ) 118 : : { 119 : 0 : const QgsVectorTileBasicLabelingStyle &style = mStyles[i]; 120 : : //QgsFields fields = QgsVectorTileUtils::makeQgisFields( mRequiredFields[style.layerName()] ); 121 : 0 : QString providerId = QString::number( i ); 122 : 0 : QgsPalLayerSettings labelSettings = style.labelSettings(); 123 : 0 : mSubProviders.append( new QgsVectorLayerLabelProvider( style.geometryType(), QgsFields(), layer->crs(), providerId, &labelSettings, layer ) ); 124 : 0 : } 125 : 0 : } 126 : : 127 : 0 : QMap<QString, QSet<QString> > QgsVectorTileBasicLabelProvider::usedAttributes( const QgsRenderContext &context, int tileZoom ) const 128 : : { 129 : 0 : QMap<QString, QSet<QString> > requiredFields; 130 : 0 : for ( const QgsVectorTileBasicLabelingStyle &layerStyle : std::as_const( mStyles ) ) 131 : : { 132 : 0 : if ( !layerStyle.isActive( tileZoom ) ) 133 : 0 : continue; 134 : : 135 : 0 : if ( !layerStyle.filterExpression().isEmpty() ) 136 : : { 137 : 0 : QgsExpression expr( layerStyle.filterExpression() ); 138 : 0 : requiredFields[layerStyle.layerName()].unite( expr.referencedColumns() ); 139 : 0 : } 140 : : 141 : 0 : requiredFields[layerStyle.layerName()].unite( layerStyle.labelSettings().referencedFields( context ) ); 142 : : } 143 : 0 : return requiredFields; 144 : 0 : } 145 : : 146 : 0 : QSet<QString> QgsVectorTileBasicLabelProvider::requiredLayers( QgsRenderContext &, int tileZoom ) const 147 : : { 148 : 0 : QSet< QString > res; 149 : 0 : for ( const QgsVectorTileBasicLabelingStyle &layerStyle : std::as_const( mStyles ) ) 150 : : { 151 : 0 : if ( layerStyle.isActive( tileZoom ) ) 152 : : { 153 : 0 : res.insert( layerStyle.layerName() ); 154 : 0 : } 155 : : } 156 : 0 : return res; 157 : 0 : } 158 : : 159 : 0 : void QgsVectorTileBasicLabelProvider::setFields( const QMap<QString, QgsFields> &perLayerFields ) 160 : : { 161 : 0 : mPerLayerFields = perLayerFields; 162 : 0 : } 163 : : 164 : 0 : QList<QgsAbstractLabelProvider *> QgsVectorTileBasicLabelProvider::subProviders() 165 : : { 166 : 0 : QList<QgsAbstractLabelProvider *> lst; 167 : 0 : for ( QgsVectorLayerLabelProvider *subprovider : std::as_const( mSubProviders ) ) 168 : : { 169 : 0 : if ( subprovider ) // sub-providers that failed to initialize are set to null 170 : 0 : lst << subprovider; 171 : : } 172 : 0 : return lst; 173 : 0 : } 174 : : 175 : 0 : bool QgsVectorTileBasicLabelProvider::prepare( QgsRenderContext &context, QSet<QString> &attributeNames ) 176 : : { 177 : 0 : for ( QgsVectorLayerLabelProvider *provider : std::as_const( mSubProviders ) ) 178 : 0 : provider->setEngine( mEngine ); 179 : : 180 : : // populate sub-providers 181 : 0 : for ( int i = 0; i < mSubProviders.count(); ++i ) 182 : : { 183 : 0 : QgsFields fields = mPerLayerFields[mStyles[i].layerName()]; 184 : : 185 : 0 : QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) ); // will be deleted by popper 186 : 0 : scope->setFields( fields ); 187 : 0 : QgsExpressionContextScopePopper popper( context.expressionContext(), scope ); 188 : : 189 : 0 : mSubProviders[i]->setFields( fields ); 190 : 0 : if ( !mSubProviders[i]->prepare( context, attributeNames ) ) 191 : : { 192 : 0 : QgsDebugMsg( QStringLiteral( "Failed to prepare labeling for style index" ) + QString::number( i ) ); 193 : 0 : mSubProviders[i] = nullptr; 194 : 0 : } 195 : 0 : } 196 : 0 : return true; 197 : 0 : } 198 : : 199 : 0 : void QgsVectorTileBasicLabelProvider::registerTileFeatures( const QgsVectorTileRendererData &tile, QgsRenderContext &context ) 200 : : { 201 : 0 : const QgsVectorTileFeatures tileData = tile.features(); 202 : 0 : int zoomLevel = tile.id().zoomLevel(); 203 : : 204 : 0 : for ( int i = 0; i < mStyles.count(); ++i ) 205 : : { 206 : 0 : const QgsVectorTileBasicLabelingStyle &layerStyle = mStyles.at( i ); 207 : 0 : if ( !layerStyle.isActive( zoomLevel ) ) 208 : 0 : continue; 209 : : 210 : 0 : QgsFields fields = mPerLayerFields[layerStyle.layerName()]; 211 : : 212 : 0 : QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) ); // will be deleted by popper 213 : 0 : scope->setFields( fields ); 214 : 0 : QgsExpressionContextScopePopper popper( context.expressionContext(), scope ); 215 : : 216 : 0 : QgsExpression filterExpression( layerStyle.filterExpression() ); 217 : 0 : filterExpression.prepare( &context.expressionContext() ); 218 : : 219 : 0 : QgsVectorLayerLabelProvider *subProvider = mSubProviders[i]; 220 : 0 : if ( !subProvider ) 221 : 0 : continue; // sub-providers that failed to initialize are set to null 222 : : 223 : 0 : if ( layerStyle.layerName().isEmpty() ) 224 : : { 225 : : // matching all layers 226 : 0 : for ( QString layerName : tileData.keys() ) 227 : : { 228 : 0 : for ( const QgsFeature &f : tileData[layerName] ) 229 : : { 230 : 0 : scope->setFeature( f ); 231 : 0 : if ( filterExpression.isValid() && !filterExpression.evaluate( &context.expressionContext() ).toBool() ) 232 : 0 : continue; 233 : : 234 : 0 : if ( QgsWkbTypes::geometryType( f.geometry().wkbType() ) == layerStyle.geometryType() ) 235 : 0 : subProvider->registerFeature( f, context ); 236 : : } 237 : 0 : } 238 : 0 : } 239 : 0 : else if ( tileData.contains( layerStyle.layerName() ) ) 240 : : { 241 : : // matching one particular layer 242 : 0 : for ( const QgsFeature &f : tileData[layerStyle.layerName()] ) 243 : : { 244 : 0 : scope->setFeature( f ); 245 : 0 : if ( filterExpression.isValid() && !filterExpression.evaluate( &context.expressionContext() ).toBool() ) 246 : 0 : continue; 247 : : 248 : 0 : if ( QgsWkbTypes::geometryType( f.geometry().wkbType() ) == layerStyle.geometryType() ) 249 : 0 : subProvider->registerFeature( f, context ); 250 : : } 251 : 0 : } 252 : 0 : } 253 : 0 : }