QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgspointdisplacementrenderer.cpp
Go to the documentation of this file.
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 
19 #include "qgsgeometry.h"
20 #include "qgslogger.h"
21 #include "qgsspatialindex.h"
22 #include "qgssymbolv2.h"
23 #include "qgssymbollayerv2utils.h"
24 #include "qgsvectorlayer.h"
26 #include "qgspainteffect.h"
27 #include "qgspainteffectregistry.h"
28 #include "qgsfontutils.h"
29 #include "qgsmultipointv2.h"
30 #include "qgspointv2.h"
31 #include "qgsunittypes.h"
32 #include "qgswkbptr.h"
33 
34 #include <QDomElement>
35 #include <QPainter>
36 
37 #include <cmath>
38 
39 #ifndef M_SQRT2
40 #define M_SQRT2 1.41421356237309504880
41 #endif
42 
44  : QgsFeatureRendererV2( "pointDisplacement" )
45  , mLabelAttributeName( labelAttributeName )
46  , mLabelIndex( -1 )
47  , mTolerance( 3 )
48  , mToleranceUnit( QgsSymbolV2::MM )
49  , mPlacement( Ring )
50  , mCircleWidth( 0.4 )
51  , mCircleColor( QColor( 125, 125, 125 ) )
52  , mCircleRadiusAddition( 0 )
53  , mMaxLabelScaleDenominator( -1 )
54  , mSpatialIndex( nullptr )
55 {
57  mCenterSymbol = new QgsMarkerSymbolV2(); //the symbol for the center of a displacement group
58  mDrawLabels = true;
59 }
60 
62 {
63  delete mCenterSymbol;
64  delete mRenderer;
65 }
66 
68 {
69  QgsPointDisplacementRenderer* r = new QgsPointDisplacementRenderer( mLabelAttributeName );
70  if ( mRenderer )
71  r->setEmbeddedRenderer( mRenderer->clone() );
72  r->setCircleWidth( mCircleWidth );
73  r->setCircleColor( mCircleColor );
74  r->setLabelFont( mLabelFont );
75  r->setLabelColor( mLabelColor );
76  r->setPlacement( mPlacement );
77  r->setCircleRadiusAddition( mCircleRadiusAddition );
78  r->setMaxLabelScaleDenominator( mMaxLabelScaleDenominator );
79  r->setTolerance( mTolerance );
80  r->setToleranceUnit( mToleranceUnit );
81  r->setToleranceMapUnitScale( mToleranceMapUnitScale );
82  if ( mCenterSymbol )
83  {
84  r->setCenterSymbol( mCenterSymbol->clone() );
85  }
86  copyRendererData( r );
87  return r;
88 }
89 
91 {
92  toSld( doc, element, QgsStringMap() );
93 }
94 
96 {
97  mRenderer->toSld( doc, element, props );
98 }
99 
100 
101 bool QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
102 {
103  Q_UNUSED( drawVertexMarker );
104  Q_UNUSED( context );
105  Q_UNUSED( layer );
106 
107  //check, if there is already a point at that position
108  if ( !feature.constGeometry() )
109  return false;
110 
111  QgsSymbolV2* symbol = firstSymbolForFeature( mRenderer, feature, context );
112 
113  //if the feature has no symbol (eg, no matching rule in a rule-based renderer), skip it
114  if ( !symbol )
115  return false;
116 
117  //point position in screen coords
118  const QgsGeometry* geom = feature.constGeometry();
119  QGis::WkbType geomType = geom->wkbType();
120  if ( geomType != QGis::WKBPoint && geomType != QGis::WKBPoint25D )
121  {
122  //can only render point type
123  return false;
124  }
125 
126  if ( selected )
127  mSelectedFeatures.insert( feature.id() );
128 
129  double searchDistance = mTolerance * QgsSymbolLayerV2Utils::mapUnitScaleFactor( context, mToleranceUnit, mToleranceMapUnitScale );
130  QList<QgsFeatureId> intersectList = mSpatialIndex->intersects( searchRect( feature.constGeometry()->asPoint(), searchDistance ) );
131  if ( intersectList.empty() )
132  {
133  mSpatialIndex->insertFeature( feature );
134  // create new group
135  DisplacementGroup newGroup;
136  newGroup.insert( feature.id(), qMakePair( feature, symbol ) );
137  mDisplacementGroups.push_back( newGroup );
138  // add to group index
139  mGroupIndex.insert( feature.id(), mDisplacementGroups.count() - 1 );
140  return true;
141  }
142 
143  //go through all the displacement group maps and search an entry where the id equals the result of the spatial search
144  QgsFeatureId existingEntry = intersectList.at( 0 );
145 
146  int groupIdx = mGroupIndex[ existingEntry ];
147  DisplacementGroup& group = mDisplacementGroups[groupIdx];
148 
149  // add to a group
150  group.insert( feature.id(), qMakePair( feature, symbol ) );
151  // add to group index
152  mGroupIndex.insert( feature.id(), groupIdx );
153  return true;
154 }
155 
156 void QgsPointDisplacementRenderer::drawGroup( const DisplacementGroup& group, QgsRenderContext& context )
157 {
158  const QgsFeature& feature = group.begin().value().first;
159  bool selected = mSelectedFeatures.contains( feature.id() ); // maybe we should highlight individual features instead of the whole group?
160 
161 
162 
163  //get list of labels and symbols
164  QStringList labelAttributeList;
165  QList< QgsMarkerSymbolV2* > symbolList;
166  QgsFeatureList featureList;
167 
168  QgsMultiPointV2* groupMultiPoint = new QgsMultiPointV2();
169  for ( DisplacementGroup::const_iterator attIt = group.constBegin(); attIt != group.constEnd(); ++attIt )
170  {
171  labelAttributeList << ( mDrawLabels ? getLabel( attIt.value().first ) : QString() );
172  symbolList << dynamic_cast<QgsMarkerSymbolV2*>( attIt.value().second );
173  featureList << attIt.value().first;
174  groupMultiPoint->addGeometry( attIt.value().first.constGeometry()->geometry()->clone() );
175  }
176 
177  //calculate centroid of all points, this will be center of group
178  QgsGeometry groupGeom( groupMultiPoint );
179  QgsGeometry* centroid = groupGeom.centroid();
180  QPointF pt;
181  QgsConstWkbPtr wkbPtr( centroid->asWkb(), centroid->wkbSize() );
182  _getPoint( pt, context, wkbPtr );
183  delete centroid;
184 
185  //calculate max diagonal size from all symbols in group
186  double diagonal = 0;
187  Q_FOREACH ( QgsMarkerSymbolV2* symbol, symbolList )
188  {
189  if ( symbol )
190  {
191  diagonal = qMax( diagonal, QgsSymbolLayerV2Utils::convertToPainterUnits( context,
192  M_SQRT2 * symbol->size(),
193  symbol->sizeUnit(), symbol->sizeMapUnitScale() ) );
194  }
195  }
196 
197  QgsSymbolV2RenderContext symbolContext( context, QgsSymbolV2::MM, 1.0, selected );
198 
199  QList<QPointF> symbolPositions;
200  QList<QPointF> labelPositions;
201  double circleRadius = -1.0;
202  calculateSymbolAndLabelPositions( symbolContext, pt, symbolList.size(), diagonal, symbolPositions, labelPositions, circleRadius );
203 
204  //draw Circle
205  if ( circleRadius > 0 )
206  drawCircle( circleRadius, symbolContext, pt, symbolList.size() );
207 
208  //draw mid point
209  if ( labelAttributeList.size() > 1 )
210  {
211  if ( mCenterSymbol )
212  {
213  mCenterSymbol->renderPoint( pt, &feature, context, -1, selected );
214  }
215  else
216  {
217  context.painter()->drawRect( QRectF( pt.x() - symbolContext.outputLineWidth( 1 ), pt.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) );
218  }
219  }
220 
221  //draw symbols on the circle
222  drawSymbols( featureList, context, symbolList, symbolPositions, selected );
223  //and also the labels
224  drawLabels( pt, symbolContext, labelPositions, labelAttributeList );
225 }
226 
228 {
229  delete mRenderer;
230  mRenderer = r;
231 }
232 
234 {
235  return mRenderer;
236 }
237 
239 {
240  if ( !mRenderer )
241  return;
242 
243  mRenderer->setLegendSymbolItem( key, symbol );
244 }
245 
247 {
248  if ( !mRenderer )
249  return false;
250 
251  return mRenderer->legendSymbolItemsCheckable();
252 }
253 
255 {
256  if ( !mRenderer )
257  return false;
258 
259  return mRenderer->legendSymbolItemChecked( key );
260 }
261 
263 {
264  if ( !mRenderer )
265  return;
266 
267  return mRenderer->checkLegendSymbolItem( key, state );
268 }
269 
271 {
272  QList<QString> attributeList;
273  if ( !mLabelAttributeName.isEmpty() )
274  {
275  attributeList.push_back( mLabelAttributeName );
276  }
277  if ( mRenderer )
278  {
279  attributeList += mRenderer->usedAttributes();
280  }
281  return attributeList;
282 }
283 
285 {
286  if ( !mRenderer )
287  {
288  return 0;
289  }
290  return mRenderer->capabilities();
291 }
292 
294 {
295  if ( !mRenderer )
296  {
297  return QgsSymbolV2List();
298  }
299  return mRenderer->symbols( context );
300 }
301 
303 {
304  if ( !mRenderer )
305  {
306  return nullptr;
307  }
308  return mRenderer->symbolForFeature( feature, context );
309 }
310 
312 {
313  if ( !mRenderer )
314  return nullptr;
315  return mRenderer->originalSymbolForFeature( feat, context );
316 }
317 
319 {
320  if ( !mRenderer )
321  {
322  return QgsSymbolV2List();
323  }
324  return mRenderer->symbolsForFeature( feature, context );
325 }
326 
328 {
329  if ( !mRenderer )
330  return QgsSymbolV2List();
331  return mRenderer->originalSymbolsForFeature( feat, context );
332 }
333 
335 {
336  if ( !mRenderer )
337  return QSet< QString >() << QString();
338  return mRenderer->legendKeysForFeature( feat, context );
339 }
340 
342 {
343  if ( !mRenderer )
344  {
345  return false;
346  }
347  return mRenderer->willRenderFeature( feat, context );
348 }
349 
350 
352 {
353  mRenderer->startRender( context, fields );
354 
355  mDisplacementGroups.clear();
356  mGroupIndex.clear();
357  mSpatialIndex = new QgsSpatialIndex;
358  mSelectedFeatures.clear();
359 
360  if ( mLabelAttributeName.isEmpty() )
361  {
362  mLabelIndex = -1;
363  }
364  else
365  {
366  mLabelIndex = fields.fieldNameIndex( mLabelAttributeName );
367  }
368 
369  if ( mMaxLabelScaleDenominator > 0 && context.rendererScale() > mMaxLabelScaleDenominator )
370  {
371  mDrawLabels = false;
372  }
373  else
374  {
375  mDrawLabels = true;
376  }
377 
378  if ( mCenterSymbol )
379  {
380  mCenterSymbol->startRender( context, &fields );
381  }
382  return;
383 }
384 
386 {
387  QgsDebugMsg( "QgsPointDisplacementRenderer::stopRender" );
388 
389  //printInfoDisplacementGroups(); //just for debugging
390 
391  Q_FOREACH ( const DisplacementGroup& group, mDisplacementGroups )
392  {
393  drawGroup( group, context );
394  }
395 
396  mDisplacementGroups.clear();
397  mGroupIndex.clear();
398  delete mSpatialIndex;
399  mSpatialIndex = nullptr;
400  mSelectedFeatures.clear();
401 
402  mRenderer->stopRender( context );
403  if ( mCenterSymbol )
404  {
405  mCenterSymbol->stopRender( context );
406  }
407 }
408 
410 {
412  r->setLabelAttributeName( symbologyElem.attribute( "labelAttributeName" ) );
414  if ( !QgsFontUtils::setFromXmlChildNode( labelFont, symbologyElem, "labelFontProperties" ) )
415  {
416  labelFont.fromString( symbologyElem.attribute( "labelFont", "" ) );
417  }
418  r->setLabelFont( labelFont );
419  r->setPlacement( static_cast< Placement >( symbologyElem.attribute( "placement", "0" ).toInt() ) );
420  r->setCircleWidth( symbologyElem.attribute( "circleWidth", "0.4" ).toDouble() );
421  r->setCircleColor( QgsSymbolLayerV2Utils::decodeColor( symbologyElem.attribute( "circleColor", "" ) ) );
422  r->setLabelColor( QgsSymbolLayerV2Utils::decodeColor( symbologyElem.attribute( "labelColor", "" ) ) );
423  r->setCircleRadiusAddition( symbologyElem.attribute( "circleRadiusAddition", "0.0" ).toDouble() );
424  r->setMaxLabelScaleDenominator( symbologyElem.attribute( "maxLabelScaleDenominator", "-1" ).toDouble() );
425  r->setTolerance( symbologyElem.attribute( "tolerance", "0.00001" ).toDouble() );
426  r->setToleranceUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( symbologyElem.attribute( "toleranceUnit", "MapUnit" ) ) );
427  r->setToleranceMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( symbologyElem.attribute( "toleranceUnitScale" ) ) );
428 
429  //look for an embedded renderer <renderer-v2>
430  QDomElement embeddedRendererElem = symbologyElem.firstChildElement( "renderer-v2" );
431  if ( !embeddedRendererElem.isNull() )
432  {
433  r->setEmbeddedRenderer( QgsFeatureRendererV2::load( embeddedRendererElem ) );
434  }
435 
436  //center symbol
437  QDomElement centerSymbolElem = symbologyElem.firstChildElement( "symbol" );
438  if ( !centerSymbolElem.isNull() )
439  {
440  r->setCenterSymbol( QgsSymbolLayerV2Utils::loadSymbol<QgsMarkerSymbolV2>( centerSymbolElem ) );
441  }
442  return r;
443 }
444 
446 {
447  QDomElement rendererElement = doc.createElement( RENDERER_TAG_NAME );
448  rendererElement.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );
449  rendererElement.setAttribute( "type", "pointDisplacement" );
450  rendererElement.setAttribute( "labelAttributeName", mLabelAttributeName );
451  rendererElement.appendChild( QgsFontUtils::toXmlElement( mLabelFont, doc, "labelFontProperties" ) );
452  rendererElement.setAttribute( "circleWidth", QString::number( mCircleWidth ) );
453  rendererElement.setAttribute( "circleColor", QgsSymbolLayerV2Utils::encodeColor( mCircleColor ) );
454  rendererElement.setAttribute( "labelColor", QgsSymbolLayerV2Utils::encodeColor( mLabelColor ) );
455  rendererElement.setAttribute( "circleRadiusAddition", QString::number( mCircleRadiusAddition ) );
456  rendererElement.setAttribute( "placement", static_cast< int >( mPlacement ) );
457  rendererElement.setAttribute( "maxLabelScaleDenominator", QString::number( mMaxLabelScaleDenominator ) );
458  rendererElement.setAttribute( "tolerance", QString::number( mTolerance ) );
459  rendererElement.setAttribute( "toleranceUnit", QgsSymbolLayerV2Utils::encodeOutputUnit( mToleranceUnit ) );
460  rendererElement.setAttribute( "toleranceUnitScale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mToleranceMapUnitScale ) );
461 
462  if ( mRenderer )
463  {
464  QDomElement embeddedRendererElem = mRenderer->save( doc );
465  rendererElement.appendChild( embeddedRendererElem );
466  }
467  if ( mCenterSymbol )
468  {
469  QDomElement centerSymbolElem = QgsSymbolLayerV2Utils::saveSymbol( "centerSymbol", mCenterSymbol, doc );
470  rendererElement.appendChild( centerSymbolElem );
471  }
472 
474  mPaintEffect->saveProperties( doc, rendererElement );
475 
476  if ( !mOrderBy.isEmpty() )
477  {
478  QDomElement orderBy = doc.createElement( "orderby" );
479  mOrderBy.save( orderBy );
480  rendererElement.appendChild( orderBy );
481  }
482  rendererElement.setAttribute( "enableorderby", ( mOrderByEnabled ? "1" : "0" ) );
483 
484  return rendererElement;
485 }
486 
488 {
489  if ( mRenderer )
490  {
491  return mRenderer->legendSymbologyItems( iconSize );
492  }
493  return QgsLegendSymbologyList();
494 }
495 
497 {
498  if ( mRenderer )
499  {
500  return mRenderer->legendSymbolItems( scaleDenominator, rule );
501  }
502  return QgsLegendSymbolList();
503 }
504 
505 
506 QgsRectangle QgsPointDisplacementRenderer::searchRect( const QgsPoint& p, double distance ) const
507 {
508  return QgsRectangle( p.x() - distance, p.y() - distance, p.x() + distance, p.y() + distance );
509 }
510 
511 void QgsPointDisplacementRenderer::printInfoDisplacementGroups()
512 {
513  int nGroups = mDisplacementGroups.size();
514  QgsDebugMsg( "number of displacement groups:" + QString::number( nGroups ) );
515  for ( int i = 0; i < nGroups; ++i )
516  {
517  QgsDebugMsg( "***************displacement group " + QString::number( i ) );
518  DisplacementGroup::const_iterator it = mDisplacementGroups.at( i ).constBegin();
519  for ( ; it != mDisplacementGroups.at( i ).constEnd(); ++it )
520  {
521  QgsDebugMsg( FID_TO_STRING( it.key() ) );
522  }
523  }
524 }
525 
526 QString QgsPointDisplacementRenderer::getLabel( const QgsFeature& f )
527 {
528  QString attribute;
529  QgsAttributes attrs = f.attributes();
530  if ( mLabelIndex >= 0 && mLabelIndex < attrs.count() )
531  {
532  attribute = attrs.at( mLabelIndex ).toString();
533  }
534  return attribute;
535 }
536 
538 {
539  delete mCenterSymbol;
540  mCenterSymbol = symbol;
541 }
542 
543 
544 
545 void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolV2RenderContext& symbolContext, QPointF centerPoint, int nPosition,
546  double symbolDiagonal, QList<QPointF>& symbolPositions, QList<QPointF>& labelShifts, double& circleRadius ) const
547 {
548  symbolPositions.clear();
549  labelShifts.clear();
550 
551  if ( nPosition < 1 )
552  {
553  return;
554  }
555  else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position
556  {
557  symbolPositions.append( centerPoint );
558  labelShifts.append( QPointF( symbolDiagonal / 2.0, -symbolDiagonal / 2.0 ) );
559  return;
560  }
561 
562  double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition );
563 
564  switch ( mPlacement )
565  {
566  case Ring:
567  {
568  double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI );
569  double radius = qMax( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits;
570 
571  double fullPerimeter = 2 * M_PI;
572  double angleStep = fullPerimeter / nPosition;
573  for ( double currentAngle = 0.0; currentAngle < fullPerimeter; currentAngle += angleStep )
574  {
575  double sinusCurrentAngle = sin( currentAngle );
576  double cosinusCurrentAngle = cos( currentAngle );
577  QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle );
578  QPointF labelShift(( radius + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radius + symbolDiagonal / 2 ) * cosinusCurrentAngle );
579  symbolPositions.append( centerPoint + positionShift );
580  labelShifts.append( labelShift );
581  }
582 
583  circleRadius = radius;
584  break;
585  }
586  case ConcentricRings:
587  {
588  double centerDiagonal = QgsSymbolLayerV2Utils::convertToPainterUnits( symbolContext.renderContext(),
589  M_SQRT2 * mCenterSymbol->size(),
590  mCenterSymbol->sizeUnit(), mCenterSymbol->sizeMapUnitScale() );
591 
592  int pointsRemaining = nPosition;
593  int ringNumber = 1;
594  double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0;
595  while ( pointsRemaining > 0 )
596  {
597  double radiusCurrentRing = qMax( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 );
598  int maxPointsCurrentRing = qMax( floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 );
599  int actualPointsCurrentRing = qMin( maxPointsCurrentRing, pointsRemaining );
600 
601  double angleStep = 2 * M_PI / actualPointsCurrentRing;
602  double currentAngle = 0.0;
603  for ( int i = 0; i < actualPointsCurrentRing; ++i )
604  {
605  double sinusCurrentAngle = sin( currentAngle );
606  double cosinusCurrentAngle = cos( currentAngle );
607  QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle );
608  QPointF labelShift(( radiusCurrentRing + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radiusCurrentRing + symbolDiagonal / 2 ) * cosinusCurrentAngle );
609  symbolPositions.append( centerPoint + positionShift );
610  labelShifts.append( labelShift );
611  currentAngle += angleStep;
612  }
613 
614  pointsRemaining -= actualPointsCurrentRing;
615  ringNumber++;
616  circleRadius = radiusCurrentRing;
617  }
618  break;
619  }
620  }
621 }
622 
623 void QgsPointDisplacementRenderer::drawCircle( double radiusPainterUnits, QgsSymbolV2RenderContext& context, QPointF centerPoint, int nSymbols )
624 {
625  QPainter* p = context.renderContext().painter();
626  if ( nSymbols < 2 || !p ) //draw circle only if multiple features
627  {
628  return;
629  }
630 
631  //draw Circle
632  QPen circlePen( mCircleColor );
633  circlePen.setWidthF( context.outputLineWidth( mCircleWidth ) );
634  p->setPen( circlePen );
635  p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 );
636 }
637 
638 void QgsPointDisplacementRenderer::drawSymbols( const QgsFeatureList& features, QgsRenderContext& context,
639  const QList< QgsMarkerSymbolV2* >& symbolList, const QList<QPointF>& symbolPositions, bool selected )
640 {
641  QList<QPointF>::const_iterator symbolPosIt = symbolPositions.constBegin();
643  QgsFeatureList::const_iterator featIt = features.constBegin();
644  for ( ; symbolPosIt != symbolPositions.constEnd() && symbolIt != symbolList.constEnd() && featIt != features.constEnd();
645  ++symbolPosIt, ++symbolIt, ++featIt )
646  {
647  if ( *symbolIt )
648  {
649  context.expressionContext().setFeature( *featIt );
650  ( *symbolIt )->startRender( context );
651  ( *symbolIt )->renderPoint( *symbolPosIt, &( *featIt ), context, -1, selected );
652  ( *symbolIt )->stopRender( context );
653  }
654  }
655 }
656 
657 void QgsPointDisplacementRenderer::drawLabels( QPointF centerPoint, QgsSymbolV2RenderContext& context, const QList<QPointF>& labelShifts, const QStringList& labelList )
658 {
659  QPainter* p = context.renderContext().painter();
660  if ( !p )
661  {
662  return;
663  }
664 
665  QPen labelPen( mLabelColor );
666  p->setPen( labelPen );
667 
668  //scale font (for printing)
669  QFont pixelSizeFont = mLabelFont;
670  pixelSizeFont.setPixelSize( context.outputLineWidth( mLabelFont.pointSizeF() * 0.3527 ) );
671  QFont scaledFont = pixelSizeFont;
672  scaledFont.setPixelSize( pixelSizeFont.pixelSize() * context.renderContext().rasterScaleFactor() );
673  p->setFont( scaledFont );
674 
675  QFontMetricsF fontMetrics( pixelSizeFont );
676  QPointF currentLabelShift; //considers the signs to determine the label position
677 
678  QList<QPointF>::const_iterator labelPosIt = labelShifts.constBegin();
679  QStringList::const_iterator text_it = labelList.constBegin();
680 
681  for ( ; labelPosIt != labelShifts.constEnd() && text_it != labelList.constEnd(); ++labelPosIt, ++text_it )
682  {
683  currentLabelShift = *labelPosIt;
684  if ( currentLabelShift.x() < 0 )
685  {
686  currentLabelShift.setX( currentLabelShift.x() - fontMetrics.width( *text_it ) );
687  }
688  if ( currentLabelShift.y() > 0 )
689  {
690  currentLabelShift.setY( currentLabelShift.y() + fontMetrics.ascent() );
691  }
692 
693  QPointF drawingPoint( centerPoint + currentLabelShift );
694  p->save();
695  p->translate( drawingPoint.x(), drawingPoint.y() );
696  p->scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
697  p->drawText( QPointF( 0, 0 ), *text_it );
698  p->restore();
699  }
700 }
701 
702 QgsSymbolV2* QgsPointDisplacementRenderer::firstSymbolForFeature( QgsFeatureRendererV2* r, QgsFeature& f, QgsRenderContext &context )
703 {
704  if ( !r )
705  {
706  return nullptr;
707  }
708 
709  QgsSymbolV2List symbolList = r->symbolsForFeature( f, context );
710  if ( symbolList.size() < 1 )
711  {
712  return nullptr;
713  }
714 
715  return symbolList.at( 0 );
716 }
717 
719 {
720  if ( renderer->type() == "pointDisplacement" )
721  {
722  return dynamic_cast<QgsPointDisplacementRenderer*>( renderer->clone() );
723  }
724 
725  if ( renderer->type() == "singleSymbol" ||
726  renderer->type() == "categorizedSymbol" ||
727  renderer->type() == "graduatedSymbol" ||
728  renderer->type() == "RuleRenderer" )
729  {
731  pointRenderer->setEmbeddedRenderer( renderer->clone() );
732  return pointRenderer;
733  }
734  return nullptr;
735 }
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
virtual bool addGeometry(QgsAbstractGeometryV2 *g) override
Adds a geometry and takes ownership.
void clear()
#define RENDERER_TAG_NAME
Definition: qgsrendererv2.h:49
A rectangle specified with double values.
Definition: qgsrectangle.h:35
double rendererScale() const
virtual QSet< QString > legendKeysForFeature(QgsFeature &feature, QgsRenderContext &context)
Return legend keys matching a specified feature.
virtual QSet< QString > legendKeysForFeature(QgsFeature &feature, QgsRenderContext &context) override
Returns which legend keys match the feature.
QgsAttributes attributes() const
Returns the feature&#39;s attributes.
Definition: qgsfeature.cpp:110
QGis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QgsPointDisplacementRenderer * clone() const override
QgsPoint asPoint() const
Return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
int pixelSize() const
QList< QgsSymbolV2 * > QgsSymbolV2List
Definition: qgsrendererv2.h:40
virtual void checkLegendSymbolItem(const QString &key, bool state=true) override
item in symbology was checked
QDomNode appendChild(const QDomNode &newChild)
virtual void setLegendSymbolItem(const QString &key, QgsSymbolV2 *symbol) override
Sets the symbol to be used for a legend symbol item.
void push_back(const T &value)
QString attribute(const QString &name, const QString &defValue) const
static QgsFeatureRendererV2 * create(QDomElement &symbologyElem)
create a renderer from XML element
static double mapUnitScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns scale factor painter units -> map units.
qreal pointSizeF() const
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
virtual Q_DECL_DEPRECATED QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature)
Return symbol for feature.
void setLabelAttributeName(const QString &name)
static QString encodeColor(const QColor &color)
virtual QDomElement save(QDomDocument &doc)
store renderer info to XML element
void setCenterSymbol(QgsMarkerSymbolV2 *symbol)
Sets the center symbol (takes ownership)
void scale(qreal sx, qreal sy)
QList< QgsFeatureId > intersects(const QgsRectangle &rect) const
Returns features that intersect the specified rectangle.
const_iterator constBegin() const
const T & at(int i) const
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
QgsLegendSymbologyList legendSymbologyItems(QSize iconSize) override
return a list of symbology items for the legend
#define FID_TO_STRING(fid)
Definition: qgsfeature.h:89
static QDomElement saveSymbol(const QString &symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
void save()
Container of fields for a vector layer.
Definition: qgsfield.h:252
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
static QgsPointDisplacementRenderer * convertFromRenderer(const QgsFeatureRendererV2 *renderer)
creates a QgsPointDisplacementRenderer from an existing renderer.
WkbType
Used for symbology operations.
Definition: qgis.h:61
QDomElement save(QDomDocument &doc) override
store renderer info to XML element
virtual QgsSymbolV2List symbolsForFeature(QgsFeature &feat, QgsRenderContext &context) override
Proxy that will call this method on the embedded renderer.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
double size() const
Returns the size for the whole symbol, which is the maximum size of all marker symbol layers in the s...
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
virtual QList< QString > usedAttributes()=0
Returns a set of attributes required for this renderer.
Multi point geometry collection.
QgsPointDisplacementRenderer(const QString &labelAttributeName="")
const_iterator insert(const T &value)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
void clear()
double toDouble(bool *ok) const
virtual void toSld(QDomDocument &doc, QDomElement &element) const
used from subclasses to create SLD Rule elements following SLD v1.1 specs
virtual void startRender(QgsRenderContext &context, const QgsFields &fields) override
Needs to be called when a new render cycle is started.
int wkbSize() const
Returns the size of the WKB in asWkb().
virtual Q_DECL_DEPRECATED bool willRenderFeature(QgsFeature &feat)
Returns whether the renderer will render a feature or not.
virtual bool legendSymbolItemChecked(const QString &key)
items of symbology items in legend is checked
QMap< QString, QString > QgsStringMap
Definition: qgis.h:492
qreal width(const QString &text) const
QgsPaintEffect * mPaintEffect
virtual void checkLegendSymbolItem(const QString &key, bool state=true)
item in symbology was checked
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize)
return a list of symbology items for the legend
int size() const
double y() const
Get the y value of the point.
Definition: qgspoint.h:193
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)=0
Needs to be called when a new render cycle is started.
QgsGeometry * centroid() const
Returns the center of mass of a geometry.
void setToleranceUnit(QgsSymbolV2::OutputUnit unit)
Sets the units for the tolerance distance.
T value(int i) const
virtual void stopRender(QgsRenderContext &context)=0
Needs to be called when a render cycle has finished to clean up.
static QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
virtual Q_DECL_DEPRECATED QgsSymbolV2List originalSymbolsForFeature(QgsFeature &feat)
Equivalent of originalSymbolsForFeature() call extended to support renderers that may use more symbol...
void drawRect(const QRectF &rectangle)
void setPixelSize(int pixelSize)
virtual QgsFeatureRendererV2 * clone() const =0
void setFont(const QFont &font)
The output shall be in millimeters.
Definition: qgssymbolv2.h:67
QString number(int n, int base)
virtual Q_DECL_DEPRECATED QgsSymbolV2 * symbolForFeature(QgsFeature &feature)
To be overridden.
qreal x() const
qreal y() const
void append(const T &value)
virtual QgsSymbolV2List originalSymbolsForFeature(QgsFeature &feat, QgsRenderContext &context) override
Proxy that will call this method on the embedded renderer.
bool empty() const
void startRender(QgsRenderContext &context, const QgsFields *fields=nullptr)
bool fromString(const QString &descrip)
const Key & key() const
double outputLineWidth(double width) const
void drawArc(const QRectF &rectangle, int startAngle, int spanAngle)
static double convertToPainterUnits(const QgsRenderContext &c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale())
Converts a size from the specied units to painter units.
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, const QString &rule="")
return a list of item text / symbol
void setPen(const QColor &color)
void setAttribute(const QString &name, const QString &value)
int toInt(bool *ok, int base) const
bool isEmpty() const
QString type() const
Definition: qgsrendererv2.h:92
bool isEmpty() const
const_iterator constEnd() const
#define M_PI
virtual void toSld(QDomDocument &doc, QDomElement &element) const override
Writes the SLD element following the SLD v1.1 specs.
void setWidthF(qreal width)
OutputUnit sizeUnit() const
Returns the size units for the whole symbol (including all symbol layers).
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feat, QgsRenderContext &context) override
Proxy that will call this method on the embedded renderer.
void drawText(const QPointF &position, const QString &text)
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
void setPlacement(Placement placement)
Sets the placement method used for dispersing the points.
static QgsFeatureRendererV2 * defaultRenderer(QGis::GeometryType geomType)
return a new renderer - used by default in vector layers
virtual Q_DECL_DEPRECATED QgsSymbolV2List symbols()
For symbol levels.
T & value() const
A class to represent a point.
Definition: qgspoint.h:117
iterator begin()
bool renderFeature(QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false) override
Reimplemented from QgsFeatureRendererV2.
virtual bool willRenderFeature(QgsFeature &feat, QgsRenderContext &context) override
Proxy that will call this method on the embedded renderer.
QList< QPair< QString, QPixmap > > QgsLegendSymbologyList
virtual bool legendSymbolItemChecked(const QString &key) override
items of symbology items in legend is checked
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
void stopRender(QgsRenderContext &context) override
Needs to be called when a render cycle has finished to clean up.
int fieldNameIndex(const QString &fieldName) const
Look up field&#39;s index from name also looks up case-insensitive if there is no match otherwise...
Definition: qgsfield.cpp:571
QgsExpressionContext & expressionContext()
Gets the expression context.
A renderer that automatically displaces points with the same position.
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature, QgsRenderContext &context) override
Proxy that will call this method on the embedded renderer.
bool contains(const T &value) const
bool isNull() const
void restore()
void setEmbeddedRenderer(QgsFeatureRendererV2 *r) override
Sets an embedded renderer (subrenderer) for this feature renderer.
const T & at(int i) const
QgsFeatureRequest::OrderBy orderBy() const
Get the order in which features shall be processed by this renderer.
void copyRendererData(QgsFeatureRendererV2 *destRenderer) const
Clones generic renderer data to another renderer.
Contains information about the context of a rendering operation.
QgsMapUnitScale sizeMapUnitScale() const
Returns the size map unit scale for the whole symbol.
bool insertFeature(const QgsFeature &f)
Add feature to index.
QPainter * painter()
void stopRender(QgsRenderContext &context)
QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, const QString &rule="") override
qreal ascent() const
virtual Q_DECL_DEPRECATED QgsSymbolV2List symbolsForFeature(QgsFeature &feat)
Returns list of symbols used for rendering the feature.
static QgsFeatureRendererV2 * load(QDomElement &symbologyElem)
create a renderer from XML element
QgsFeatureRequest::OrderBy mOrderBy
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:359
void setX(qreal x)
void setY(qreal y)
QDomElement firstChildElement(const QString &tagName) const
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
int count(const T &value) const
void renderPoint(QPointF point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
void translate(const QPointF &offset)
qint64 QgsFeatureId
Definition: qgsfeature.h:31
virtual int capabilities() override
Proxy that will call this method on the embedded renderer.
static QColor decodeColor(const QString &str)
iterator insert(const Key &key, const T &value)
void setToleranceMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the distance tolerance.
static QgsConstWkbPtr _getPoint(QPointF &pt, QgsRenderContext &context, QgsConstWkbPtr &wkb)
Creates a point in screen coordinates from a wkb string in map coordinates.
virtual bool legendSymbolItemsCheckable() const override
items of symbology items in legend should be checkable
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
virtual bool legendSymbolItemsCheckable() const
items of symbology items in legend should be checkable
double rasterScaleFactor() const
const_iterator constEnd() const
virtual int capabilities()
returns bitwise OR-ed capabilities of the renderer
QDomElement createElement(const QString &tagName)
void clear()
const_iterator constBegin() const
A vector of attributes.
Definition: qgsfeature.h:115
virtual QList< QString > usedAttributes() override
Partial proxy that will call this method on the embedded renderer.
QList< QPair< QString, QgsSymbolV2 * > > QgsLegendSymbolList
Definition: qgsrendererv2.h:44
virtual void setLegendSymbolItem(const QString &key, QgsSymbolV2 *symbol)
Sets the symbol to be used for a legend symbol item.
const QgsFeatureRendererV2 * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
double x() const
Get the x value of the point.
Definition: qgspoint.h:185
virtual QgsMarkerSymbolV2 * clone() const override
void setTolerance(double t)
Sets the tolerance distance for grouping points.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.