Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsvectortilebasicrenderer.cpp 3 : : -------------------------------------- 4 : : Date : March 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 "qgsvectortilebasicrenderer.h" 17 : : 18 : : #include "qgsapplication.h" 19 : : #include "qgscolorschemeregistry.h" 20 : : #include "qgsexpressioncontextutils.h" 21 : : #include "qgsfillsymbollayer.h" 22 : : #include "qgslinesymbollayer.h" 23 : : #include "qgsmarkersymbollayer.h" 24 : : #include "qgssymbollayerutils.h" 25 : : #include "qgsvectortileutils.h" 26 : : 27 : 0 : QgsVectorTileBasicRendererStyle::QgsVectorTileBasicRendererStyle( const QString &stName, const QString &laName, QgsWkbTypes::GeometryType geomType ) 28 : 0 : : mStyleName( stName ) 29 : 0 : , mLayerName( laName ) 30 : 0 : , mGeometryType( geomType ) 31 : : { 32 : 0 : } 33 : : 34 : 0 : QgsVectorTileBasicRendererStyle::QgsVectorTileBasicRendererStyle( const QgsVectorTileBasicRendererStyle &other ) 35 : : { 36 : 0 : operator=( other ); 37 : 0 : } 38 : : 39 : 0 : QgsVectorTileBasicRendererStyle &QgsVectorTileBasicRendererStyle::operator=( const QgsVectorTileBasicRendererStyle &other ) 40 : : { 41 : 0 : mStyleName = other.mStyleName; 42 : 0 : mLayerName = other.mLayerName; 43 : 0 : mGeometryType = other.mGeometryType; 44 : 0 : mSymbol.reset( other.mSymbol ? other.mSymbol->clone() : nullptr ); 45 : 0 : mEnabled = other.mEnabled; 46 : 0 : mExpression = other.mExpression; 47 : 0 : mMinZoomLevel = other.mMinZoomLevel; 48 : 0 : mMaxZoomLevel = other.mMaxZoomLevel; 49 : 0 : return *this; 50 : : } 51 : : 52 : 0 : QgsVectorTileBasicRendererStyle::~QgsVectorTileBasicRendererStyle() = default; 53 : : 54 : 0 : void QgsVectorTileBasicRendererStyle::setSymbol( QgsSymbol *sym ) 55 : : { 56 : 0 : mSymbol.reset( sym ); 57 : 0 : } 58 : : 59 : 0 : void QgsVectorTileBasicRendererStyle::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const 60 : : { 61 : 0 : elem.setAttribute( QStringLiteral( "name" ), mStyleName ); 62 : 0 : elem.setAttribute( QStringLiteral( "layer" ), mLayerName ); 63 : 0 : elem.setAttribute( QStringLiteral( "geometry" ), mGeometryType ); 64 : 0 : elem.setAttribute( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ); 65 : 0 : elem.setAttribute( QStringLiteral( "expression" ), mExpression ); 66 : 0 : elem.setAttribute( QStringLiteral( "min-zoom" ), mMinZoomLevel ); 67 : 0 : elem.setAttribute( QStringLiteral( "max-zoom" ), mMaxZoomLevel ); 68 : : 69 : 0 : QDomDocument doc = elem.ownerDocument(); 70 : 0 : QgsSymbolMap symbols; 71 : 0 : symbols[QStringLiteral( "0" )] = mSymbol.get(); 72 : 0 : QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context ); 73 : 0 : elem.appendChild( symbolsElem ); 74 : 0 : } 75 : : 76 : 0 : void QgsVectorTileBasicRendererStyle::readXml( const QDomElement &elem, const QgsReadWriteContext &context ) 77 : : { 78 : 0 : mStyleName = elem.attribute( QStringLiteral( "name" ) ); 79 : 0 : mLayerName = elem.attribute( QStringLiteral( "layer" ) ); 80 : 0 : mGeometryType = static_cast<QgsWkbTypes::GeometryType>( elem.attribute( QStringLiteral( "geometry" ) ).toInt() ); 81 : 0 : mEnabled = elem.attribute( QStringLiteral( "enabled" ) ).toInt(); 82 : 0 : mExpression = elem.attribute( QStringLiteral( "expression" ) ); 83 : 0 : mMinZoomLevel = elem.attribute( QStringLiteral( "min-zoom" ) ).toInt(); 84 : 0 : mMaxZoomLevel = elem.attribute( QStringLiteral( "max-zoom" ) ).toInt(); 85 : : 86 : 0 : mSymbol.reset(); 87 : 0 : QDomElement symbolsElem = elem.firstChildElement( QStringLiteral( "symbols" ) ); 88 : 0 : if ( !symbolsElem.isNull() ) 89 : : { 90 : 0 : QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context ); 91 : 0 : if ( symbolMap.contains( QStringLiteral( "0" ) ) ) 92 : : { 93 : 0 : mSymbol.reset( symbolMap.take( QStringLiteral( "0" ) ) ); 94 : 0 : } 95 : 0 : } 96 : 0 : } 97 : : 98 : : //////// 99 : : 100 : : 101 : 0 : QgsVectorTileBasicRenderer::QgsVectorTileBasicRenderer() 102 : 0 : { 103 : 0 : } 104 : : 105 : 0 : QString QgsVectorTileBasicRenderer::type() const 106 : : { 107 : 0 : return QStringLiteral( "basic" ); 108 : : } 109 : : 110 : 0 : QgsVectorTileBasicRenderer *QgsVectorTileBasicRenderer::clone() const 111 : : { 112 : 0 : QgsVectorTileBasicRenderer *r = new QgsVectorTileBasicRenderer; 113 : 0 : r->mStyles = mStyles; 114 : 0 : r->mStyles.detach(); // make a deep copy to make sure symbols get cloned 115 : 0 : return r; 116 : 0 : } 117 : : 118 : 0 : void QgsVectorTileBasicRenderer::startRender( QgsRenderContext &context, int tileZoom, const QgsTileRange &tileRange ) 119 : : { 120 : 0 : Q_UNUSED( context ) 121 : 0 : Q_UNUSED( tileRange ) 122 : : // figure out required fields for different layers 123 : 0 : for ( const QgsVectorTileBasicRendererStyle &layerStyle : std::as_const( mStyles ) ) 124 : : { 125 : 0 : if ( layerStyle.isActive( tileZoom ) ) 126 : : { 127 : 0 : if ( !layerStyle.filterExpression().isEmpty() ) 128 : : { 129 : 0 : QgsExpression expr( layerStyle.filterExpression() ); 130 : 0 : mRequiredFields[layerStyle.layerName()].unite( expr.referencedColumns() ); 131 : 0 : } 132 : 0 : if ( auto *lSymbol = layerStyle.symbol() ) 133 : : { 134 : 0 : mRequiredFields[layerStyle.layerName()].unite( lSymbol->usedAttributes( context ) ); 135 : 0 : } 136 : 0 : } 137 : : } 138 : 0 : } 139 : : 140 : 0 : QMap<QString, QSet<QString> > QgsVectorTileBasicRenderer::usedAttributes( const QgsRenderContext & ) 141 : : { 142 : 0 : return mRequiredFields; 143 : : } 144 : : 145 : 0 : QSet<QString> QgsVectorTileBasicRenderer::requiredLayers( QgsRenderContext &, int tileZoom ) const 146 : : { 147 : 0 : QSet< QString > res; 148 : 0 : for ( const QgsVectorTileBasicRendererStyle &layerStyle : std::as_const( mStyles ) ) 149 : : { 150 : 0 : if ( layerStyle.isActive( tileZoom ) ) 151 : : { 152 : 0 : res.insert( layerStyle.layerName() ); 153 : 0 : } 154 : : } 155 : 0 : return res; 156 : 0 : } 157 : : 158 : 0 : void QgsVectorTileBasicRenderer::stopRender( QgsRenderContext &context ) 159 : : { 160 : 0 : Q_UNUSED( context ) 161 : 0 : } 162 : : 163 : 0 : void QgsVectorTileBasicRenderer::renderTile( const QgsVectorTileRendererData &tile, QgsRenderContext &context ) 164 : : { 165 : 0 : const QgsVectorTileFeatures tileData = tile.features(); 166 : 0 : int zoomLevel = tile.id().zoomLevel(); 167 : : 168 : 0 : for ( const QgsVectorTileBasicRendererStyle &layerStyle : std::as_const( mStyles ) ) 169 : : { 170 : 0 : if ( !layerStyle.isActive( zoomLevel ) ) 171 : 0 : continue; 172 : : 173 : 0 : QgsExpressionContextScope *scope = new QgsExpressionContextScope( QObject::tr( "Layer" ) ); // will be deleted by popper 174 : 0 : scope->setFields( tile.fields()[layerStyle.layerName()] ); 175 : 0 : QgsExpressionContextScopePopper popper( context.expressionContext(), scope ); 176 : : 177 : 0 : QgsExpression filterExpression( layerStyle.filterExpression() ); 178 : 0 : filterExpression.prepare( &context.expressionContext() ); 179 : : 180 : 0 : QgsSymbol *sym = layerStyle.symbol(); 181 : 0 : sym->startRender( context, QgsFields() ); 182 : 0 : if ( layerStyle.layerName().isEmpty() ) 183 : : { 184 : : // matching all layers 185 : 0 : for ( QString layerName : tileData.keys() ) 186 : : { 187 : 0 : for ( const QgsFeature &f : tileData[layerName] ) 188 : : { 189 : 0 : scope->setFeature( f ); 190 : 0 : if ( filterExpression.isValid() && !filterExpression.evaluate( &context.expressionContext() ).toBool() ) 191 : 0 : continue; 192 : : 193 : 0 : const QgsWkbTypes::GeometryType featureType = QgsWkbTypes::geometryType( f.geometry().wkbType() ); 194 : 0 : if ( featureType == layerStyle.geometryType() ) 195 : : { 196 : 0 : sym->renderFeature( f, context ); 197 : 0 : } 198 : 0 : else if ( featureType == QgsWkbTypes::PolygonGeometry && layerStyle.geometryType() == QgsWkbTypes::LineGeometry ) 199 : : { 200 : : // be tolerant and permit rendering polygons with a line layer style, as some style definitions use this approach 201 : : // to render the polygon borders only 202 : 0 : QgsFeature exterior = f; 203 : 0 : exterior.setGeometry( QgsGeometry( f.geometry().constGet()->boundary() ) ); 204 : 0 : sym->renderFeature( exterior, context ); 205 : 0 : } 206 : : } 207 : 0 : } 208 : 0 : } 209 : 0 : else if ( tileData.contains( layerStyle.layerName() ) ) 210 : : { 211 : : // matching one particular layer 212 : 0 : for ( const QgsFeature &f : tileData[layerStyle.layerName()] ) 213 : : { 214 : 0 : scope->setFeature( f ); 215 : 0 : if ( filterExpression.isValid() && !filterExpression.evaluate( &context.expressionContext() ).toBool() ) 216 : 0 : continue; 217 : : 218 : 0 : const QgsWkbTypes::GeometryType featureType = QgsWkbTypes::geometryType( f.geometry().wkbType() ); 219 : 0 : if ( featureType == layerStyle.geometryType() ) 220 : : { 221 : 0 : sym->renderFeature( f, context ); 222 : 0 : } 223 : 0 : else if ( featureType == QgsWkbTypes::PolygonGeometry && layerStyle.geometryType() == QgsWkbTypes::LineGeometry ) 224 : : { 225 : : // be tolerant and permit rendering polygons with a line layer style, as some style definitions use this approach 226 : : // to render the polygon borders only 227 : 0 : QgsFeature exterior = f; 228 : 0 : exterior.setGeometry( QgsGeometry( f.geometry().constGet()->boundary() ) ); 229 : 0 : sym->renderFeature( exterior, context ); 230 : 0 : } 231 : : } 232 : 0 : } 233 : 0 : sym->stopRender( context ); 234 : 0 : } 235 : 0 : } 236 : : 237 : 0 : void QgsVectorTileBasicRenderer::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const 238 : : { 239 : 0 : QDomDocument doc = elem.ownerDocument(); 240 : 0 : QDomElement elemStyles = doc.createElement( QStringLiteral( "styles" ) ); 241 : 0 : for ( const QgsVectorTileBasicRendererStyle &layerStyle : mStyles ) 242 : : { 243 : 0 : QDomElement elemStyle = doc.createElement( QStringLiteral( "style" ) ); 244 : 0 : layerStyle.writeXml( elemStyle, context ); 245 : 0 : elemStyles.appendChild( elemStyle ); 246 : 0 : } 247 : 0 : elem.appendChild( elemStyles ); 248 : 0 : } 249 : : 250 : 0 : void QgsVectorTileBasicRenderer::readXml( const QDomElement &elem, const QgsReadWriteContext &context ) 251 : : { 252 : 0 : mStyles.clear(); 253 : : 254 : 0 : QDomElement elemStyles = elem.firstChildElement( QStringLiteral( "styles" ) ); 255 : 0 : QDomElement elemStyle = elemStyles.firstChildElement( QStringLiteral( "style" ) ); 256 : 0 : while ( !elemStyle.isNull() ) 257 : : { 258 : 0 : QgsVectorTileBasicRendererStyle layerStyle; 259 : 0 : layerStyle.readXml( elemStyle, context ); 260 : 0 : mStyles.append( layerStyle ); 261 : 0 : elemStyle = elemStyle.nextSiblingElement( QStringLiteral( "style" ) ); 262 : 0 : } 263 : 0 : } 264 : : 265 : 0 : void QgsVectorTileBasicRenderer::setStyles( const QList<QgsVectorTileBasicRendererStyle> &styles ) 266 : : { 267 : 0 : mStyles = styles; 268 : 0 : } 269 : : 270 : 0 : QList<QgsVectorTileBasicRendererStyle> QgsVectorTileBasicRenderer::styles() const 271 : : { 272 : 0 : return mStyles; 273 : : } 274 : : 275 : 0 : QList<QgsVectorTileBasicRendererStyle> QgsVectorTileBasicRenderer::simpleStyleWithRandomColors() 276 : : { 277 : 0 : QColor polygonFillColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor(); 278 : 0 : QColor polygonStrokeColor = polygonFillColor; 279 : 0 : polygonFillColor.setAlpha( 100 ); 280 : 0 : double polygonStrokeWidth = DEFAULT_LINE_WIDTH; 281 : : 282 : 0 : QColor lineStrokeColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor(); 283 : 0 : double lineStrokeWidth = DEFAULT_LINE_WIDTH; 284 : : 285 : 0 : QColor pointFillColor = QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor(); 286 : 0 : QColor pointStrokeColor = pointFillColor; 287 : 0 : pointFillColor.setAlpha( 100 ); 288 : 0 : double pointSize = DEFAULT_POINT_SIZE; 289 : : 290 : 0 : return simpleStyle( polygonFillColor, polygonStrokeColor, polygonStrokeWidth, 291 : 0 : lineStrokeColor, lineStrokeWidth, 292 : 0 : pointFillColor, pointStrokeColor, pointSize ); 293 : : } 294 : : 295 : 0 : QList<QgsVectorTileBasicRendererStyle> QgsVectorTileBasicRenderer::simpleStyle( 296 : : const QColor &polygonFillColor, const QColor &polygonStrokeColor, double polygonStrokeWidth, 297 : : const QColor &lineStrokeColor, double lineStrokeWidth, 298 : : const QColor &pointFillColor, const QColor &pointStrokeColor, double pointSize ) 299 : : { 300 : 0 : QgsSimpleFillSymbolLayer *fillSymbolLayer = new QgsSimpleFillSymbolLayer(); 301 : 0 : fillSymbolLayer->setFillColor( polygonFillColor ); 302 : 0 : fillSymbolLayer->setStrokeColor( polygonStrokeColor ); 303 : 0 : fillSymbolLayer->setStrokeWidth( polygonStrokeWidth ); 304 : 0 : QgsFillSymbol *fillSymbol = new QgsFillSymbol( QgsSymbolLayerList() << fillSymbolLayer ); 305 : : 306 : 0 : QgsSimpleLineSymbolLayer *lineSymbolLayer = new QgsSimpleLineSymbolLayer; 307 : 0 : lineSymbolLayer->setColor( lineStrokeColor ); 308 : 0 : lineSymbolLayer->setWidth( lineStrokeWidth ); 309 : 0 : QgsLineSymbol *lineSymbol = new QgsLineSymbol( QgsSymbolLayerList() << lineSymbolLayer ); 310 : : 311 : 0 : QgsSimpleMarkerSymbolLayer *markerSymbolLayer = new QgsSimpleMarkerSymbolLayer; 312 : 0 : markerSymbolLayer->setFillColor( pointFillColor ); 313 : 0 : markerSymbolLayer->setStrokeColor( pointStrokeColor ); 314 : 0 : markerSymbolLayer->setSize( pointSize ); 315 : 0 : QgsMarkerSymbol *markerSymbol = new QgsMarkerSymbol( QgsSymbolLayerList() << markerSymbolLayer ); 316 : : 317 : 0 : QgsVectorTileBasicRendererStyle st1( QStringLiteral( "Polygons" ), QString(), QgsWkbTypes::PolygonGeometry ); 318 : 0 : st1.setSymbol( fillSymbol ); 319 : : 320 : 0 : QgsVectorTileBasicRendererStyle st2( QStringLiteral( "Lines" ), QString(), QgsWkbTypes::LineGeometry ); 321 : 0 : st2.setSymbol( lineSymbol ); 322 : : 323 : 0 : QgsVectorTileBasicRendererStyle st3( QStringLiteral( "Points" ), QString(), QgsWkbTypes::PointGeometry ); 324 : 0 : st3.setSymbol( markerSymbol ); 325 : : 326 : 0 : QList<QgsVectorTileBasicRendererStyle> lst; 327 : 0 : lst << st1 << st2 << st3; 328 : 0 : return lst; 329 : 0 : }