Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgspointclusterrenderer.cpp 3 : : --------------------------- 4 : : begin : February 2016 5 : : copyright : (C) 2016 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : ***************************************************************************/ 8 : : 9 : : /*************************************************************************** 10 : : * * 11 : : * This program is free software; you can redistribute it and/or modify * 12 : : * it under the terms of the GNU General Public License as published by * 13 : : * the Free Software Foundation; either version 2 of the License, or * 14 : : * (at your option) any later version. * 15 : : * * 16 : : ***************************************************************************/ 17 : : 18 : : #include "qgspointclusterrenderer.h" 19 : : #include "qgspointdisplacementrenderer.h" 20 : : #include "qgssymbollayerutils.h" 21 : : #include "qgspainteffectregistry.h" 22 : : #include "qgspainteffect.h" 23 : : #include "qgsmarkersymbollayer.h" 24 : : #include "qgsproperty.h" 25 : : #include "qgsstyleentityvisitor.h" 26 : : #include <cmath> 27 : : 28 : 0 : QgsPointClusterRenderer::QgsPointClusterRenderer() 29 : 0 : : QgsPointDistanceRenderer( QStringLiteral( "pointCluster" ) ) 30 : 0 : { 31 : 0 : mClusterSymbol.reset( new QgsMarkerSymbol() ); 32 : 0 : mClusterSymbol->setSize( 4 ); 33 : 0 : mClusterSymbol->setColor( QColor( 245, 75, 80 ) ); 34 : : 35 : 0 : QgsFontMarkerSymbolLayer *fm = new QgsFontMarkerSymbolLayer(); 36 : 0 : fm->setFontFamily( QFont().defaultFamily() ); 37 : 0 : fm->setColor( QColor( 255, 255, 255 ) ); 38 : 0 : fm->setSize( 3.2 ); 39 : 0 : fm->setOffset( QPointF( 0, -0.4 ) ); 40 : 0 : fm->setDataDefinedProperty( QgsSymbolLayer::PropertyCharacter, QgsProperty::fromExpression( QStringLiteral( "@cluster_size" ) ) ); 41 : 0 : mClusterSymbol->insertSymbolLayer( 1, fm ); 42 : 0 : } 43 : : 44 : 0 : QgsPointClusterRenderer *QgsPointClusterRenderer::clone() const 45 : : { 46 : 0 : QgsPointClusterRenderer *r = new QgsPointClusterRenderer(); 47 : 0 : if ( mRenderer ) 48 : 0 : r->setEmbeddedRenderer( mRenderer->clone() ); 49 : 0 : r->setLabelFont( mLabelFont ); 50 : 0 : r->setLabelColor( mLabelColor ); 51 : 0 : r->setMinimumLabelScale( mMinLabelScale ); 52 : 0 : r->setTolerance( mTolerance ); 53 : 0 : r->setToleranceUnit( mToleranceUnit ); 54 : 0 : r->setToleranceMapUnitScale( mToleranceMapUnitScale ); 55 : 0 : if ( mClusterSymbol ) 56 : : { 57 : 0 : r->setClusterSymbol( mClusterSymbol->clone() ); 58 : 0 : } 59 : 0 : copyRendererData( r ); 60 : 0 : return r; 61 : 0 : } 62 : : 63 : 0 : void QgsPointClusterRenderer::drawGroup( QPointF centerPoint, QgsRenderContext &context, const ClusteredGroup &group ) 64 : : { 65 : 0 : if ( group.size() > 1 ) 66 : : { 67 : 0 : mClusterSymbol->renderPoint( centerPoint, &( group.at( 0 ).feature ), context, -1, false ); 68 : 0 : } 69 : : else 70 : : { 71 : : //single isolated symbol, draw it untouched 72 : 0 : QgsMarkerSymbol *symbol = group.at( 0 ).symbol(); 73 : 0 : symbol->startRender( context ); 74 : 0 : symbol->renderPoint( centerPoint, &( group.at( 0 ).feature ), context, -1, group.at( 0 ).isSelected ); 75 : 0 : symbol->stopRender( context ); 76 : : } 77 : 0 : } 78 : : 79 : 0 : void QgsPointClusterRenderer::startRender( QgsRenderContext &context, const QgsFields &fields ) 80 : : { 81 : 0 : if ( mClusterSymbol ) 82 : : { 83 : 0 : mClusterSymbol->startRender( context, fields ); 84 : 0 : } 85 : 0 : QgsPointDistanceRenderer::startRender( context, fields ); 86 : 0 : } 87 : : 88 : 0 : void QgsPointClusterRenderer::stopRender( QgsRenderContext &context ) 89 : : { 90 : 0 : QgsPointDistanceRenderer::stopRender( context ); 91 : 0 : if ( mClusterSymbol ) 92 : : { 93 : 0 : mClusterSymbol->stopRender( context ); 94 : 0 : } 95 : 0 : } 96 : : 97 : 0 : QgsFeatureRenderer *QgsPointClusterRenderer::create( QDomElement &symbologyElem, const QgsReadWriteContext &context ) 98 : : { 99 : 0 : QgsPointClusterRenderer *r = new QgsPointClusterRenderer(); 100 : 0 : r->setTolerance( symbologyElem.attribute( QStringLiteral( "tolerance" ), QStringLiteral( "0.00001" ) ).toDouble() ); 101 : 0 : r->setToleranceUnit( QgsUnitTypes::decodeRenderUnit( symbologyElem.attribute( QStringLiteral( "toleranceUnit" ), QStringLiteral( "MapUnit" ) ) ) ); 102 : 0 : r->setToleranceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( symbologyElem.attribute( QStringLiteral( "toleranceUnitScale" ) ) ) ); 103 : : 104 : : //look for an embedded renderer <renderer-v2> 105 : 0 : QDomElement embeddedRendererElem = symbologyElem.firstChildElement( QStringLiteral( "renderer-v2" ) ); 106 : 0 : if ( !embeddedRendererElem.isNull() ) 107 : : { 108 : 0 : r->setEmbeddedRenderer( QgsFeatureRenderer::load( embeddedRendererElem, context ) ); 109 : 0 : } 110 : : 111 : : //center symbol 112 : 0 : QDomElement centerSymbolElem = symbologyElem.firstChildElement( QStringLiteral( "symbol" ) ); 113 : 0 : if ( !centerSymbolElem.isNull() ) 114 : : { 115 : 0 : r->setClusterSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( centerSymbolElem, context ) ); 116 : 0 : } 117 : 0 : return r; 118 : 0 : } 119 : : 120 : 0 : QgsMarkerSymbol *QgsPointClusterRenderer::clusterSymbol() 121 : : { 122 : 0 : return mClusterSymbol.get(); 123 : : } 124 : : 125 : 0 : QDomElement QgsPointClusterRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context ) 126 : : { 127 : 0 : QDomElement rendererElement = doc.createElement( RENDERER_TAG_NAME ); 128 : 0 : rendererElement.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) ); 129 : 0 : rendererElement.setAttribute( QStringLiteral( "type" ), QStringLiteral( "pointCluster" ) ); 130 : 0 : rendererElement.setAttribute( QStringLiteral( "tolerance" ), QString::number( mTolerance ) ); 131 : 0 : rendererElement.setAttribute( QStringLiteral( "toleranceUnit" ), QgsUnitTypes::encodeUnit( mToleranceUnit ) ); 132 : 0 : rendererElement.setAttribute( QStringLiteral( "toleranceUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mToleranceMapUnitScale ) ); 133 : : 134 : 0 : if ( mRenderer ) 135 : : { 136 : 0 : QDomElement embeddedRendererElem = mRenderer->save( doc, context ); 137 : 0 : rendererElement.appendChild( embeddedRendererElem ); 138 : 0 : } 139 : 0 : if ( mClusterSymbol ) 140 : : { 141 : 0 : QDomElement centerSymbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "centerSymbol" ), mClusterSymbol.get(), doc, context ); 142 : 0 : rendererElement.appendChild( centerSymbolElem ); 143 : 0 : } 144 : : 145 : 0 : if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect ) ) 146 : 0 : mPaintEffect->saveProperties( doc, rendererElement ); 147 : : 148 : 0 : if ( !mOrderBy.isEmpty() ) 149 : : { 150 : 0 : QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) ); 151 : 0 : mOrderBy.save( orderBy ); 152 : 0 : rendererElement.appendChild( orderBy ); 153 : 0 : } 154 : 0 : rendererElement.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) ); 155 : : 156 : 0 : return rendererElement; 157 : 0 : } 158 : : 159 : 0 : QSet<QString> QgsPointClusterRenderer::usedAttributes( const QgsRenderContext &context ) const 160 : : { 161 : 0 : QSet<QString> attr = QgsPointDistanceRenderer::usedAttributes( context ); 162 : 0 : if ( mClusterSymbol ) 163 : 0 : attr.unite( mClusterSymbol->usedAttributes( context ) ); 164 : 0 : return attr; 165 : 0 : } 166 : : 167 : 0 : bool QgsPointClusterRenderer::accept( QgsStyleEntityVisitorInterface *visitor ) const 168 : : { 169 : 0 : if ( !QgsPointDistanceRenderer::accept( visitor ) ) 170 : 0 : return false; 171 : : 172 : 0 : if ( mClusterSymbol ) 173 : : { 174 : 0 : QgsStyleSymbolEntity entity( mClusterSymbol.get() ); 175 : 0 : if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "cluster" ), QObject::tr( "Cluster Symbol" ) ) ) ) 176 : 0 : return false; 177 : 0 : } 178 : : 179 : 0 : return true; 180 : 0 : } 181 : : 182 : 0 : void QgsPointClusterRenderer::setClusterSymbol( QgsMarkerSymbol *symbol ) 183 : : { 184 : 0 : mClusterSymbol.reset( symbol ); 185 : 0 : } 186 : : 187 : 0 : QgsPointClusterRenderer *QgsPointClusterRenderer::convertFromRenderer( const QgsFeatureRenderer *renderer ) 188 : : { 189 : 0 : if ( renderer->type() == QLatin1String( "pointCluster" ) ) 190 : : { 191 : 0 : return dynamic_cast<QgsPointClusterRenderer *>( renderer->clone() ); 192 : : } 193 : 0 : else if ( renderer->type() == QLatin1String( "singleSymbol" ) || 194 : 0 : renderer->type() == QLatin1String( "categorizedSymbol" ) || 195 : 0 : renderer->type() == QLatin1String( "graduatedSymbol" ) || 196 : 0 : renderer->type() == QLatin1String( "RuleRenderer" ) ) 197 : : { 198 : 0 : QgsPointClusterRenderer *pointRenderer = new QgsPointClusterRenderer(); 199 : 0 : pointRenderer->setEmbeddedRenderer( renderer->clone() ); 200 : 0 : return pointRenderer; 201 : : } 202 : 0 : else if ( renderer->type() == QLatin1String( "pointDisplacement" ) ) 203 : : { 204 : 0 : QgsPointClusterRenderer *pointRenderer = new QgsPointClusterRenderer(); 205 : 0 : const QgsPointDisplacementRenderer *displacementRenderer = static_cast< const QgsPointDisplacementRenderer * >( renderer ); 206 : 0 : if ( displacementRenderer->embeddedRenderer() ) 207 : 0 : pointRenderer->setEmbeddedRenderer( displacementRenderer->embeddedRenderer()->clone() ); 208 : 0 : pointRenderer->setTolerance( displacementRenderer->tolerance() ); 209 : 0 : pointRenderer->setToleranceUnit( displacementRenderer->toleranceUnit() ); 210 : 0 : pointRenderer->setToleranceMapUnitScale( displacementRenderer->toleranceMapUnitScale() ); 211 : 0 : if ( const_cast< QgsPointDisplacementRenderer * >( displacementRenderer )->centerSymbol() ) 212 : 0 : pointRenderer->setClusterSymbol( const_cast< QgsPointDisplacementRenderer * >( displacementRenderer )->centerSymbol()->clone() ); 213 : 0 : return pointRenderer; 214 : : } 215 : : else 216 : : { 217 : 0 : return nullptr; 218 : : } 219 : 0 : }