Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgspointdisplacementrenderer.cpp
3 : : --------------------------------
4 : : begin : January 26, 2010
5 : : copyright : (C) 2010 by Marco Hugentobler
6 : : email : marco at hugis dot net
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 "qgspointdisplacementrenderer.h"
19 : : #include "qgssymbollayerutils.h"
20 : : #include "qgsfontutils.h"
21 : : #include "qgspainteffectregistry.h"
22 : : #include "qgspainteffect.h"
23 : : #include "qgspointclusterrenderer.h"
24 : : #include "qgsstyleentityvisitor.h"
25 : : #include "qgsrenderedfeaturehandlerinterface.h"
26 : :
27 : : #include <QPainter>
28 : : #include <cmath>
29 : :
30 : 0 : QgsPointDisplacementRenderer::QgsPointDisplacementRenderer( const QString &labelAttributeName )
31 : 0 : : QgsPointDistanceRenderer( QStringLiteral( "pointDisplacement" ), labelAttributeName )
32 : 0 : , mCircleColor( QColor( 125, 125, 125 ) )
33 : 0 : {
34 : 0 : mCenterSymbol.reset( new QgsMarkerSymbol() );
35 : 0 : }
36 : :
37 : 0 : QgsPointDisplacementRenderer *QgsPointDisplacementRenderer::clone() const
38 : : {
39 : 0 : QgsPointDisplacementRenderer *r = new QgsPointDisplacementRenderer( mLabelAttributeName );
40 : 0 : if ( mRenderer )
41 : 0 : r->setEmbeddedRenderer( mRenderer->clone() );
42 : 0 : r->setCircleWidth( mCircleWidth );
43 : 0 : r->setCircleColor( mCircleColor );
44 : 0 : r->setLabelFont( mLabelFont );
45 : 0 : r->setLabelColor( mLabelColor );
46 : 0 : r->setPlacement( mPlacement );
47 : 0 : r->setCircleRadiusAddition( mCircleRadiusAddition );
48 : 0 : r->setLabelDistanceFactor( mLabelDistanceFactor );
49 : 0 : r->setMinimumLabelScale( mMinLabelScale );
50 : 0 : r->setTolerance( mTolerance );
51 : 0 : r->setToleranceUnit( mToleranceUnit );
52 : 0 : r->setToleranceMapUnitScale( mToleranceMapUnitScale );
53 : 0 : if ( mCenterSymbol )
54 : : {
55 : 0 : r->setCenterSymbol( mCenterSymbol->clone() );
56 : 0 : }
57 : 0 : copyRendererData( r );
58 : 0 : return r;
59 : 0 : }
60 : :
61 : 0 : void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderContext &context, const ClusteredGroup &group )
62 : : {
63 : :
64 : : //calculate max diagonal size from all symbols in group
65 : 0 : double diagonal = 0;
66 : 0 : QVector<double> diagonals( group.size() );
67 : : double currentDiagonal;
68 : :
69 : 0 : int groupPosition = 0;
70 : 0 : for ( const GroupedFeature &feature : group )
71 : : {
72 : 0 : if ( QgsMarkerSymbol *symbol = feature.symbol() )
73 : : {
74 : 0 : currentDiagonal = M_SQRT2 * symbol->size( context );
75 : 0 : diagonals[groupPosition] = currentDiagonal;
76 : 0 : diagonal = std::max( diagonal, currentDiagonal );
77 : :
78 : 0 : }
79 : : else
80 : : {
81 : 0 : diagonals[groupPosition] = 0.0;
82 : : }
83 : 0 : groupPosition++;
84 : : }
85 : :
86 : 0 : QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderMillimeters, 1.0, false );
87 : :
88 : 0 : QList<QPointF> symbolPositions;
89 : 0 : QList<QPointF> labelPositions;
90 : 0 : double circleRadius = -1.0;
91 : 0 : double gridRadius = -1.0;
92 : 0 : int gridSize = -1;
93 : :
94 : 0 : calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius, gridRadius, gridSize, diagonals );
95 : :
96 : : //only draw circle/grid if there's a pen present - otherwise skip drawing transparent grids
97 : 0 : if ( mCircleColor.isValid() && mCircleColor.alpha() > 0 )
98 : : {
99 : : //draw circle
100 : 0 : if ( circleRadius > 0 )
101 : 0 : drawCircle( circleRadius, symbolContext, centerPoint, group.size() );
102 : : //draw grid
103 : : else
104 : 0 : drawGrid( gridSize, symbolContext, symbolPositions, group.size() );
105 : 0 : }
106 : :
107 : 0 : if ( group.size() > 1 )
108 : : {
109 : : //draw mid point
110 : 0 : QgsFeature firstFeature = group.at( 0 ).feature;
111 : 0 : if ( mCenterSymbol )
112 : : {
113 : 0 : mCenterSymbol->renderPoint( centerPoint, &firstFeature, context, -1, false );
114 : 0 : }
115 : : else
116 : : {
117 : 0 : const double rectSize = symbolContext.renderContext().convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters );
118 : 0 : context.painter()->drawRect( QRectF( centerPoint.x() - rectSize, centerPoint.y() - rectSize, rectSize * 2, rectSize * 2 ) );
119 : : }
120 : 0 : }
121 : :
122 : : //draw symbols on the circle
123 : 0 : drawSymbols( group, context, symbolPositions );
124 : : //and also the labels
125 : 0 : if ( mLabelIndex >= 0 )
126 : : {
127 : 0 : drawLabels( centerPoint, symbolContext, labelPositions, group );
128 : 0 : }
129 : 0 : }
130 : :
131 : :
132 : 0 : void QgsPointDisplacementRenderer::startRender( QgsRenderContext &context, const QgsFields &fields )
133 : : {
134 : 0 : if ( mCenterSymbol )
135 : : {
136 : 0 : mCenterSymbol->startRender( context, fields );
137 : 0 : }
138 : :
139 : 0 : QgsPointDistanceRenderer::startRender( context, fields );
140 : 0 : }
141 : :
142 : 0 : void QgsPointDisplacementRenderer::stopRender( QgsRenderContext &context )
143 : : {
144 : 0 : QgsPointDistanceRenderer::stopRender( context );
145 : 0 : if ( mCenterSymbol )
146 : : {
147 : 0 : mCenterSymbol->stopRender( context );
148 : 0 : }
149 : 0 : }
150 : :
151 : 0 : QgsFeatureRenderer *QgsPointDisplacementRenderer::create( QDomElement &symbologyElem, const QgsReadWriteContext &context )
152 : : {
153 : 0 : QgsPointDisplacementRenderer *r = new QgsPointDisplacementRenderer();
154 : 0 : r->setLabelAttributeName( symbologyElem.attribute( QStringLiteral( "labelAttributeName" ) ) );
155 : 0 : QFont labelFont;
156 : 0 : if ( !QgsFontUtils::setFromXmlChildNode( labelFont, symbologyElem, QStringLiteral( "labelFontProperties" ) ) )
157 : : {
158 : 0 : labelFont.fromString( symbologyElem.attribute( QStringLiteral( "labelFont" ), QString() ) );
159 : 0 : }
160 : 0 : r->setLabelFont( labelFont );
161 : 0 : r->setPlacement( static_cast< Placement >( symbologyElem.attribute( QStringLiteral( "placement" ), QStringLiteral( "0" ) ).toInt() ) );
162 : 0 : r->setCircleWidth( symbologyElem.attribute( QStringLiteral( "circleWidth" ), QStringLiteral( "0.4" ) ).toDouble() );
163 : 0 : r->setCircleColor( QgsSymbolLayerUtils::decodeColor( symbologyElem.attribute( QStringLiteral( "circleColor" ), QString() ) ) );
164 : 0 : r->setLabelColor( QgsSymbolLayerUtils::decodeColor( symbologyElem.attribute( QStringLiteral( "labelColor" ), QString() ) ) );
165 : 0 : r->setCircleRadiusAddition( symbologyElem.attribute( QStringLiteral( "circleRadiusAddition" ), QStringLiteral( "0.0" ) ).toDouble() );
166 : 0 : r->setLabelDistanceFactor( symbologyElem.attribute( QStringLiteral( "labelDistanceFactor" ), QStringLiteral( "0.5" ) ).toDouble() );
167 : 0 : r->setMinimumLabelScale( symbologyElem.attribute( QStringLiteral( "maxLabelScaleDenominator" ), QStringLiteral( "-1" ) ).toDouble() );
168 : 0 : r->setTolerance( symbologyElem.attribute( QStringLiteral( "tolerance" ), QStringLiteral( "0.00001" ) ).toDouble() );
169 : 0 : r->setToleranceUnit( QgsUnitTypes::decodeRenderUnit( symbologyElem.attribute( QStringLiteral( "toleranceUnit" ), QStringLiteral( "MapUnit" ) ) ) );
170 : 0 : r->setToleranceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( symbologyElem.attribute( QStringLiteral( "toleranceUnitScale" ) ) ) );
171 : :
172 : 0 : //look for an embedded renderer <renderer-v2>
173 : 0 : QDomElement embeddedRendererElem = symbologyElem.firstChildElement( QStringLiteral( "renderer-v2" ) );
174 : 0 : if ( !embeddedRendererElem.isNull() )
175 : : {
176 : 0 : r->setEmbeddedRenderer( QgsFeatureRenderer::load( embeddedRendererElem, context ) );
177 : 0 : }
178 : :
179 : : //center symbol
180 : 0 : QDomElement centerSymbolElem = symbologyElem.firstChildElement( QStringLiteral( "symbol" ) );
181 : 0 : if ( !centerSymbolElem.isNull() )
182 : : {
183 : 0 : r->setCenterSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( centerSymbolElem, context ) );
184 : 0 : }
185 : 0 : return r;
186 : 0 : }
187 : :
188 : 0 : QgsMarkerSymbol *QgsPointDisplacementRenderer::centerSymbol()
189 : : {
190 : 0 : return mCenterSymbol.get();
191 : : }
192 : :
193 : 0 : QDomElement QgsPointDisplacementRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
194 : : {
195 : 0 : QDomElement rendererElement = doc.createElement( RENDERER_TAG_NAME );
196 : 0 : rendererElement.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
197 : 0 : rendererElement.setAttribute( QStringLiteral( "type" ), QStringLiteral( "pointDisplacement" ) );
198 : 0 : rendererElement.setAttribute( QStringLiteral( "labelAttributeName" ), mLabelAttributeName );
199 : 0 : rendererElement.appendChild( QgsFontUtils::toXmlElement( mLabelFont, doc, QStringLiteral( "labelFontProperties" ) ) );
200 : 0 : rendererElement.setAttribute( QStringLiteral( "circleWidth" ), QString::number( mCircleWidth ) );
201 : 0 : rendererElement.setAttribute( QStringLiteral( "circleColor" ), QgsSymbolLayerUtils::encodeColor( mCircleColor ) );
202 : 0 : rendererElement.setAttribute( QStringLiteral( "labelColor" ), QgsSymbolLayerUtils::encodeColor( mLabelColor ) );
203 : 0 : rendererElement.setAttribute( QStringLiteral( "circleRadiusAddition" ), QString::number( mCircleRadiusAddition ) );
204 : 0 : rendererElement.setAttribute( QStringLiteral( "labelDistanceFactor" ), QString::number( mLabelDistanceFactor ) );
205 : 0 : rendererElement.setAttribute( QStringLiteral( "placement" ), static_cast< int >( mPlacement ) );
206 : 0 : rendererElement.setAttribute( QStringLiteral( "maxLabelScaleDenominator" ), QString::number( mMinLabelScale ) );
207 : 0 : rendererElement.setAttribute( QStringLiteral( "tolerance" ), QString::number( mTolerance ) );
208 : 0 : rendererElement.setAttribute( QStringLiteral( "toleranceUnit" ), QgsUnitTypes::encodeUnit( mToleranceUnit ) );
209 : 0 : rendererElement.setAttribute( QStringLiteral( "toleranceUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mToleranceMapUnitScale ) );
210 : :
211 : 0 : if ( mRenderer )
212 : : {
213 : 0 : QDomElement embeddedRendererElem = mRenderer->save( doc, context );
214 : 0 : rendererElement.appendChild( embeddedRendererElem );
215 : 0 : }
216 : 0 : if ( mCenterSymbol )
217 : : {
218 : 0 : QDomElement centerSymbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "centerSymbol" ), mCenterSymbol.get(), doc, context );
219 : 0 : rendererElement.appendChild( centerSymbolElem );
220 : 0 : }
221 : :
222 : 0 : if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect ) )
223 : 0 : mPaintEffect->saveProperties( doc, rendererElement );
224 : :
225 : 0 : if ( !mOrderBy.isEmpty() )
226 : : {
227 : 0 : QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
228 : 0 : mOrderBy.save( orderBy );
229 : 0 : rendererElement.appendChild( orderBy );
230 : 0 : }
231 : 0 : rendererElement.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
232 : :
233 : 0 : return rendererElement;
234 : 0 : }
235 : :
236 : 0 : QSet<QString> QgsPointDisplacementRenderer::usedAttributes( const QgsRenderContext &context ) const
237 : : {
238 : 0 : QSet<QString> attr = QgsPointDistanceRenderer::usedAttributes( context );
239 : 0 : if ( mCenterSymbol )
240 : 0 : attr.unite( mCenterSymbol->usedAttributes( context ) );
241 : 0 : return attr;
242 : 0 : }
243 : :
244 : 0 : bool QgsPointDisplacementRenderer::accept( QgsStyleEntityVisitorInterface *visitor ) const
245 : : {
246 : 0 : if ( !QgsPointDistanceRenderer::accept( visitor ) )
247 : 0 : return false;
248 : :
249 : 0 : if ( mCenterSymbol )
250 : : {
251 : 0 : QgsStyleSymbolEntity entity( mCenterSymbol.get() );
252 : 0 : if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "center" ), QObject::tr( "Center Symbol" ) ) ) )
253 : 0 : return false;
254 : 0 : }
255 : :
256 : 0 : return true;
257 : 0 : }
258 : :
259 : 0 : void QgsPointDisplacementRenderer::setCenterSymbol( QgsMarkerSymbol *symbol )
260 : : {
261 : 0 : mCenterSymbol.reset( symbol );
262 : 0 : }
263 : :
264 : 0 : void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition,
265 : : double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius, double &gridRadius,
266 : : int &gridSize, QVector<double> &diagonals ) const
267 : : {
268 : 0 : symbolPositions.clear();
269 : 0 : labelShifts.clear();
270 : :
271 : 0 : if ( nPosition < 1 )
272 : : {
273 : 0 : return;
274 : : }
275 : 0 : else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position
276 : : {
277 : 0 : const double side = std::sqrt( std::pow( symbolDiagonal, 2 ) / 2.0 );
278 : 0 : symbolPositions.append( centerPoint );
279 : 0 : labelShifts.append( QPointF( side * mLabelDistanceFactor, -side * mLabelDistanceFactor ) );
280 : 0 : return;
281 : : }
282 : :
283 : 0 : double circleAdditionPainterUnits = symbolContext.renderContext().convertToPainterUnits( mCircleRadiusAddition, QgsUnitTypes::RenderMillimeters );
284 : :
285 : 0 : switch ( mPlacement )
286 : : {
287 : : case Ring:
288 : : {
289 : 0 : const double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI );
290 : 0 : const double radius = std::max( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits;
291 : :
292 : 0 : const double angleStep = 2 * M_PI / nPosition;
293 : 0 : double currentAngle = 0.0;
294 : 0 : for ( int featureIndex = 0; featureIndex < nPosition; currentAngle += angleStep, featureIndex++ )
295 : : {
296 : 0 : const double sinusCurrentAngle = std::sin( currentAngle );
297 : 0 : const double cosinusCurrentAngle = std::cos( currentAngle );
298 : 0 : const QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle );
299 : :
300 : 0 : const QPointF labelShift( ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
301 : 0 : symbolPositions.append( centerPoint + positionShift );
302 : 0 : labelShifts.append( labelShift );
303 : 0 : }
304 : 0 : circleRadius = radius;
305 : 0 : break;
306 : : }
307 : : case ConcentricRings:
308 : : {
309 : 0 : double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
310 : :
311 : 0 : int pointsRemaining = nPosition;
312 : 0 : int ringNumber = 1;
313 : 0 : double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0;
314 : 0 : int featureIndex = 0;
315 : 0 : while ( pointsRemaining > 0 )
316 : : {
317 : 0 : double radiusCurrentRing = std::max( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 );
318 : 0 : int maxPointsCurrentRing = std::max( std::floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 );
319 : 0 : int actualPointsCurrentRing = std::min( maxPointsCurrentRing, pointsRemaining );
320 : :
321 : 0 : double angleStep = 2 * M_PI / actualPointsCurrentRing;
322 : 0 : double currentAngle = 0.0;
323 : 0 : for ( int i = 0; i < actualPointsCurrentRing; ++i )
324 : : {
325 : 0 : double sinusCurrentAngle = std::sin( currentAngle );
326 : 0 : double cosinusCurrentAngle = std::cos( currentAngle );
327 : 0 : QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle );
328 : 0 : QPointF labelShift( ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
329 : 0 : symbolPositions.append( centerPoint + positionShift );
330 : 0 : labelShifts.append( labelShift );
331 : 0 : currentAngle += angleStep;
332 : 0 : featureIndex++;
333 : 0 : }
334 : :
335 : 0 : pointsRemaining -= actualPointsCurrentRing;
336 : 0 : ringNumber++;
337 : 0 : circleRadius = radiusCurrentRing;
338 : : }
339 : 0 : break;
340 : : }
341 : : case Grid:
342 : : {
343 : 0 : double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
344 : 0 : int pointsRemaining = nPosition;
345 : 0 : gridSize = std::ceil( std::sqrt( pointsRemaining ) );
346 : 0 : if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize )
347 : 0 : gridSize -= 1;
348 : 0 : double originalPointRadius = ( ( centerDiagonal / 2.0 + symbolDiagonal / 2.0 ) + symbolDiagonal ) / 2;
349 : 0 : double userPointRadius = originalPointRadius + circleAdditionPainterUnits;
350 : :
351 : 0 : int yIndex = 0;
352 : 0 : while ( pointsRemaining > 0 )
353 : : {
354 : 0 : for ( int xIndex = 0; xIndex < gridSize && pointsRemaining > 0; ++xIndex )
355 : : {
356 : 0 : QPointF positionShift( userPointRadius * xIndex, userPointRadius * yIndex );
357 : 0 : symbolPositions.append( centerPoint + positionShift );
358 : 0 : pointsRemaining--;
359 : 0 : }
360 : 0 : yIndex++;
361 : : }
362 : :
363 : 0 : centralizeGrid( symbolPositions, userPointRadius, gridSize );
364 : :
365 : : int xFactor;
366 : : int yFactor;
367 : 0 : double side = 0;
368 : 0 : for ( int symbolIndex = 0; symbolIndex < symbolPositions.size(); ++symbolIndex )
369 : : {
370 : 0 : if ( symbolPositions.at( symbolIndex ).x() < centerPoint.x() )
371 : : {
372 : 0 : xFactor = -1;
373 : 0 : }
374 : : else
375 : : {
376 : 0 : xFactor = 1;
377 : : }
378 : :
379 : 0 : if ( symbolPositions.at( symbolIndex ).y() < centerPoint.y() )
380 : : {
381 : 0 : yFactor = 1;
382 : 0 : }
383 : : else
384 : : {
385 : 0 : yFactor = -1;
386 : : }
387 : :
388 : 0 : side = std::sqrt( std::pow( diagonals.at( symbolIndex ), 2 ) / 2.0 );
389 : 0 : QPointF labelShift( ( side * mLabelDistanceFactor * xFactor ), ( -side * mLabelDistanceFactor * yFactor ) );
390 : 0 : labelShifts.append( symbolPositions.at( symbolIndex ) - centerPoint + labelShift );
391 : 0 : }
392 : :
393 : 0 : gridRadius = userPointRadius;
394 : 0 : break;
395 : : }
396 : : }
397 : 0 : }
398 : :
399 : 0 : void QgsPointDisplacementRenderer::centralizeGrid( QList<QPointF> &pointSymbolPositions, double radius, int size ) const
400 : : {
401 : 0 : double shiftAmount = -radius * ( size - 1.0 ) / 2.0;
402 : 0 : QPointF centralShift( shiftAmount, shiftAmount );
403 : 0 : for ( int i = 0; i < pointSymbolPositions.size(); ++i )
404 : : {
405 : 0 : pointSymbolPositions[i] += centralShift;
406 : 0 : }
407 : 0 : }
408 : :
409 : 0 : void QgsPointDisplacementRenderer::drawGrid( int gridSizeUnits, QgsSymbolRenderContext &context,
410 : : QList<QPointF> pointSymbolPositions, int nSymbols )
411 : : {
412 : 0 : QPainter *p = context.renderContext().painter();
413 : 0 : if ( nSymbols < 2 || !p ) //draw grid only if multiple features
414 : : {
415 : 0 : return;
416 : : }
417 : :
418 : 0 : QPen gridPen( mCircleColor );
419 : 0 : gridPen.setWidthF( context.renderContext().convertToPainterUnits( mCircleWidth, QgsUnitTypes::RenderMillimeters ) );
420 : 0 : p->setPen( gridPen );
421 : :
422 : 0 : for ( int i = 0; i < pointSymbolPositions.size(); ++i )
423 : : {
424 : 0 : if ( i + 1 < pointSymbolPositions.size() && 0 != ( i + 1 ) % gridSizeUnits )
425 : : {
426 : 0 : QLineF gridLineRow( pointSymbolPositions[i], pointSymbolPositions[i + 1] );
427 : 0 : p->drawLine( gridLineRow );
428 : 0 : }
429 : :
430 : 0 : if ( i + gridSizeUnits < pointSymbolPositions.size() )
431 : : {
432 : 0 : QLineF gridLineColumn( pointSymbolPositions[i], pointSymbolPositions[i + gridSizeUnits] );
433 : 0 : p->drawLine( gridLineColumn );
434 : 0 : }
435 : 0 : }
436 : 0 : }
437 : :
438 : 0 : void QgsPointDisplacementRenderer::drawCircle( double radiusPainterUnits, QgsSymbolRenderContext &context, QPointF centerPoint, int nSymbols )
439 : : {
440 : 0 : QPainter *p = context.renderContext().painter();
441 : 0 : if ( nSymbols < 2 || !p ) //draw circle only if multiple features
442 : : {
443 : 0 : return;
444 : : }
445 : :
446 : : //draw Circle
447 : 0 : QPen circlePen( mCircleColor );
448 : 0 : circlePen.setWidthF( context.renderContext().convertToPainterUnits( mCircleWidth, QgsUnitTypes::RenderMillimeters ) );
449 : 0 : p->setPen( circlePen );
450 : 0 : p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 );
451 : 0 : }
452 : :
453 : 0 : void QgsPointDisplacementRenderer::drawSymbols( const ClusteredGroup &group, QgsRenderContext &context, const QList<QPointF> &symbolPositions )
454 : : {
455 : 0 : QList<QPointF>::const_iterator symbolPosIt = symbolPositions.constBegin();
456 : 0 : ClusteredGroup::const_iterator groupIt = group.constBegin();
457 : 0 : for ( ; symbolPosIt != symbolPositions.constEnd() && groupIt != group.constEnd();
458 : 0 : ++symbolPosIt, ++groupIt )
459 : : {
460 : 0 : context.expressionContext().setFeature( groupIt->feature );
461 : 0 : groupIt->symbol()->startRender( context );
462 : 0 : groupIt->symbol()->renderPoint( *symbolPosIt, &( groupIt->feature ), context, -1, groupIt->isSelected );
463 : 0 : if ( context.hasRenderedFeatureHandlers() )
464 : : {
465 : 0 : const QgsGeometry bounds( QgsGeometry::fromRect( QgsRectangle( groupIt->symbol()->bounds( *symbolPosIt, context, groupIt->feature ) ) ) );
466 : 0 : const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
467 : 0 : QgsRenderedFeatureHandlerInterface::RenderedFeatureContext featureContext( context );
468 : 0 : for ( QgsRenderedFeatureHandlerInterface *handler : handlers )
469 : 0 : handler->handleRenderedFeature( groupIt->feature, bounds, featureContext );
470 : 0 : }
471 : 0 : groupIt->symbol()->stopRender( context );
472 : 0 : }
473 : 0 : }
474 : :
475 : 0 : QgsPointDisplacementRenderer *QgsPointDisplacementRenderer::convertFromRenderer( const QgsFeatureRenderer *renderer )
476 : : {
477 : 0 : if ( renderer->type() == QLatin1String( "pointDisplacement" ) )
478 : : {
479 : 0 : return dynamic_cast<QgsPointDisplacementRenderer *>( renderer->clone() );
480 : : }
481 : 0 : else if ( renderer->type() == QLatin1String( "singleSymbol" ) ||
482 : 0 : renderer->type() == QLatin1String( "categorizedSymbol" ) ||
483 : 0 : renderer->type() == QLatin1String( "graduatedSymbol" ) ||
484 : 0 : renderer->type() == QLatin1String( "RuleRenderer" ) )
485 : : {
486 : 0 : QgsPointDisplacementRenderer *pointRenderer = new QgsPointDisplacementRenderer();
487 : 0 : pointRenderer->setEmbeddedRenderer( renderer->clone() );
488 : 0 : return pointRenderer;
489 : : }
490 : 0 : else if ( renderer->type() == QLatin1String( "pointCluster" ) )
491 : : {
492 : 0 : QgsPointDisplacementRenderer *pointRenderer = new QgsPointDisplacementRenderer();
493 : 0 : const QgsPointClusterRenderer *clusterRenderer = static_cast< const QgsPointClusterRenderer * >( renderer );
494 : 0 : if ( clusterRenderer->embeddedRenderer() )
495 : 0 : pointRenderer->setEmbeddedRenderer( clusterRenderer->embeddedRenderer()->clone() );
496 : 0 : pointRenderer->setTolerance( clusterRenderer->tolerance() );
497 : 0 : pointRenderer->setToleranceUnit( clusterRenderer->toleranceUnit() );
498 : 0 : pointRenderer->setToleranceMapUnitScale( clusterRenderer->toleranceMapUnitScale() );
499 : 0 : if ( const_cast< QgsPointClusterRenderer * >( clusterRenderer )->clusterSymbol() )
500 : 0 : pointRenderer->setCenterSymbol( const_cast< QgsPointClusterRenderer * >( clusterRenderer )->clusterSymbol()->clone() );
501 : 0 : return pointRenderer;
502 : : }
503 : : else
504 : : {
505 : 0 : return nullptr;
506 : : }
507 : 0 : }
|