QGIS API Documentation  2.17.0-Master (0497e4a)
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  {
338  return false;
339  }
340  return mRenderer->willRenderFeature( feat, context );
341 }
342 
343 
345 {
346  mRenderer->startRender( context, fields );
347 
348  mDisplacementGroups.clear();
349  mGroupIndex.clear();
350  mSpatialIndex = new QgsSpatialIndex;
351  mSelectedFeatures.clear();
352 
353  if ( mLabelAttributeName.isEmpty() )
354  {
355  mLabelIndex = -1;
356  }
357  else
358  {
359  mLabelIndex = fields.fieldNameIndex( mLabelAttributeName );
360  }
361 
362  if ( mMaxLabelScaleDenominator > 0 && context.rendererScale() > mMaxLabelScaleDenominator )
363  {
364  mDrawLabels = false;
365  }
366  else
367  {
368  mDrawLabels = true;
369  }
370 
371  if ( mCenterSymbol )
372  {
373  mCenterSymbol->startRender( context, &fields );
374  }
375  return;
376 }
377 
379 {
380  QgsDebugMsg( "QgsPointDisplacementRenderer::stopRender" );
381 
382  //printInfoDisplacementGroups(); //just for debugging
383 
384  Q_FOREACH ( const DisplacementGroup& group, mDisplacementGroups )
385  {
386  drawGroup( group, context );
387  }
388 
389  mDisplacementGroups.clear();
390  mGroupIndex.clear();
391  delete mSpatialIndex;
392  mSpatialIndex = nullptr;
393  mSelectedFeatures.clear();
394 
395  mRenderer->stopRender( context );
396  if ( mCenterSymbol )
397  {
398  mCenterSymbol->stopRender( context );
399  }
400 }
401 
403 {
405  r->setLabelAttributeName( symbologyElem.attribute( "labelAttributeName" ) );
407  if ( !QgsFontUtils::setFromXmlChildNode( labelFont, symbologyElem, "labelFontProperties" ) )
408  {
409  labelFont.fromString( symbologyElem.attribute( "labelFont", "" ) );
410  }
411  r->setLabelFont( labelFont );
412  r->setPlacement( static_cast< Placement >( symbologyElem.attribute( "placement", "0" ).toInt() ) );
413  r->setCircleWidth( symbologyElem.attribute( "circleWidth", "0.4" ).toDouble() );
414  r->setCircleColor( QgsSymbolLayerV2Utils::decodeColor( symbologyElem.attribute( "circleColor", "" ) ) );
415  r->setLabelColor( QgsSymbolLayerV2Utils::decodeColor( symbologyElem.attribute( "labelColor", "" ) ) );
416  r->setCircleRadiusAddition( symbologyElem.attribute( "circleRadiusAddition", "0.0" ).toDouble() );
417  r->setMaxLabelScaleDenominator( symbologyElem.attribute( "maxLabelScaleDenominator", "-1" ).toDouble() );
418  r->setTolerance( symbologyElem.attribute( "tolerance", "0.00001" ).toDouble() );
419  r->setToleranceUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( symbologyElem.attribute( "toleranceUnit", "MapUnit" ) ) );
420  r->setToleranceMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( symbologyElem.attribute( "toleranceUnitScale" ) ) );
421 
422  //look for an embedded renderer <renderer-v2>
423  QDomElement embeddedRendererElem = symbologyElem.firstChildElement( "renderer-v2" );
424  if ( !embeddedRendererElem.isNull() )
425  {
426  r->setEmbeddedRenderer( QgsFeatureRendererV2::load( embeddedRendererElem ) );
427  }
428 
429  //center symbol
430  QDomElement centerSymbolElem = symbologyElem.firstChildElement( "symbol" );
431  if ( !centerSymbolElem.isNull() )
432  {
433  r->setCenterSymbol( QgsSymbolLayerV2Utils::loadSymbol<QgsMarkerSymbolV2>( centerSymbolElem ) );
434  }
435  return r;
436 }
437 
439 {
440  QDomElement rendererElement = doc.createElement( RENDERER_TAG_NAME );
441  rendererElement.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );
442  rendererElement.setAttribute( "type", "pointDisplacement" );
443  rendererElement.setAttribute( "labelAttributeName", mLabelAttributeName );
444  rendererElement.appendChild( QgsFontUtils::toXmlElement( mLabelFont, doc, "labelFontProperties" ) );
445  rendererElement.setAttribute( "circleWidth", QString::number( mCircleWidth ) );
446  rendererElement.setAttribute( "circleColor", QgsSymbolLayerV2Utils::encodeColor( mCircleColor ) );
447  rendererElement.setAttribute( "labelColor", QgsSymbolLayerV2Utils::encodeColor( mLabelColor ) );
448  rendererElement.setAttribute( "circleRadiusAddition", QString::number( mCircleRadiusAddition ) );
449  rendererElement.setAttribute( "placement", static_cast< int >( mPlacement ) );
450  rendererElement.setAttribute( "maxLabelScaleDenominator", QString::number( mMaxLabelScaleDenominator ) );
451  rendererElement.setAttribute( "tolerance", QString::number( mTolerance ) );
452  rendererElement.setAttribute( "toleranceUnit", QgsSymbolLayerV2Utils::encodeOutputUnit( mToleranceUnit ) );
453  rendererElement.setAttribute( "toleranceUnitScale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mToleranceMapUnitScale ) );
454 
455  if ( mRenderer )
456  {
457  QDomElement embeddedRendererElem = mRenderer->save( doc );
458  rendererElement.appendChild( embeddedRendererElem );
459  }
460  if ( mCenterSymbol )
461  {
462  QDomElement centerSymbolElem = QgsSymbolLayerV2Utils::saveSymbol( "centerSymbol", mCenterSymbol, doc );
463  rendererElement.appendChild( centerSymbolElem );
464  }
465 
467  mPaintEffect->saveProperties( doc, rendererElement );
468 
469  if ( !mOrderBy.isEmpty() )
470  {
471  QDomElement orderBy = doc.createElement( "orderby" );
472  mOrderBy.save( orderBy );
473  rendererElement.appendChild( orderBy );
474  }
475  rendererElement.setAttribute( "enableorderby", ( mOrderByEnabled ? "1" : "0" ) );
476 
477  return rendererElement;
478 }
479 
481 {
482  if ( mRenderer )
483  {
484  return mRenderer->legendSymbologyItems( iconSize );
485  }
486  return QgsLegendSymbologyList();
487 }
488 
490 {
491  if ( mRenderer )
492  {
493  return mRenderer->legendSymbolItems( scaleDenominator, rule );
494  }
495  return QgsLegendSymbolList();
496 }
497 
498 
499 QgsRectangle QgsPointDisplacementRenderer::searchRect( const QgsPoint& p, double distance ) const
500 {
501  return QgsRectangle( p.x() - distance, p.y() - distance, p.x() + distance, p.y() + distance );
502 }
503 
504 void QgsPointDisplacementRenderer::printInfoDisplacementGroups()
505 {
506  int nGroups = mDisplacementGroups.size();
507  QgsDebugMsg( "number of displacement groups:" + QString::number( nGroups ) );
508  for ( int i = 0; i < nGroups; ++i )
509  {
510  QgsDebugMsg( "***************displacement group " + QString::number( i ) );
511  DisplacementGroup::const_iterator it = mDisplacementGroups.at( i ).constBegin();
512  for ( ; it != mDisplacementGroups.at( i ).constEnd(); ++it )
513  {
514  QgsDebugMsg( FID_TO_STRING( it.key() ) );
515  }
516  }
517 }
518 
519 QString QgsPointDisplacementRenderer::getLabel( const QgsFeature& f )
520 {
521  QString attribute;
522  QgsAttributes attrs = f.attributes();
523  if ( mLabelIndex >= 0 && mLabelIndex < attrs.count() )
524  {
525  attribute = attrs.at( mLabelIndex ).toString();
526  }
527  return attribute;
528 }
529 
531 {
532  delete mCenterSymbol;
533  mCenterSymbol = symbol;
534 }
535 
536 
537 
538 void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolV2RenderContext& symbolContext, QPointF centerPoint, int nPosition,
539  double symbolDiagonal, QList<QPointF>& symbolPositions, QList<QPointF>& labelShifts, double& circleRadius ) const
540 {
541  symbolPositions.clear();
542  labelShifts.clear();
543 
544  if ( nPosition < 1 )
545  {
546  return;
547  }
548  else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position
549  {
550  symbolPositions.append( centerPoint );
551  labelShifts.append( QPointF( symbolDiagonal / 2.0, -symbolDiagonal / 2.0 ) );
552  return;
553  }
554 
555  double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition );
556 
557  switch ( mPlacement )
558  {
559  case Ring:
560  {
561  double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI );
562  double radius = qMax( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits;
563 
564  double fullPerimeter = 2 * M_PI;
565  double angleStep = fullPerimeter / nPosition;
566  for ( double currentAngle = 0.0; currentAngle < fullPerimeter; currentAngle += angleStep )
567  {
568  double sinusCurrentAngle = sin( currentAngle );
569  double cosinusCurrentAngle = cos( currentAngle );
570  QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle );
571  QPointF labelShift(( radius + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radius + symbolDiagonal / 2 ) * cosinusCurrentAngle );
572  symbolPositions.append( centerPoint + positionShift );
573  labelShifts.append( labelShift );
574  }
575 
576  circleRadius = radius;
577  break;
578  }
579  case ConcentricRings:
580  {
581  double centerDiagonal = QgsSymbolLayerV2Utils::convertToPainterUnits( symbolContext.renderContext(),
582  M_SQRT2 * mCenterSymbol->size(),
583  mCenterSymbol->sizeUnit(), mCenterSymbol->sizeMapUnitScale() );
584 
585  int pointsRemaining = nPosition;
586  int ringNumber = 1;
587  double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0;
588  while ( pointsRemaining > 0 )
589  {
590  double radiusCurrentRing = qMax( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 );
591  int maxPointsCurrentRing = qMax( floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 );
592  int actualPointsCurrentRing = qMin( maxPointsCurrentRing, pointsRemaining );
593 
594  double angleStep = 2 * M_PI / actualPointsCurrentRing;
595  double currentAngle = 0.0;
596  for ( int i = 0; i < actualPointsCurrentRing; ++i )
597  {
598  double sinusCurrentAngle = sin( currentAngle );
599  double cosinusCurrentAngle = cos( currentAngle );
600  QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle );
601  QPointF labelShift(( radiusCurrentRing + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radiusCurrentRing + symbolDiagonal / 2 ) * cosinusCurrentAngle );
602  symbolPositions.append( centerPoint + positionShift );
603  labelShifts.append( labelShift );
604  currentAngle += angleStep;
605  }
606 
607  pointsRemaining -= actualPointsCurrentRing;
608  ringNumber++;
609  circleRadius = radiusCurrentRing;
610  }
611  break;
612  }
613  }
614 }
615 
616 void QgsPointDisplacementRenderer::drawCircle( double radiusPainterUnits, QgsSymbolV2RenderContext& context, QPointF centerPoint, int nSymbols )
617 {
618  QPainter* p = context.renderContext().painter();
619  if ( nSymbols < 2 || !p ) //draw circle only if multiple features
620  {
621  return;
622  }
623 
624  //draw Circle
625  QPen circlePen( mCircleColor );
626  circlePen.setWidthF( context.outputLineWidth( mCircleWidth ) );
627  p->setPen( circlePen );
628  p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 );
629 }
630 
631 void QgsPointDisplacementRenderer::drawSymbols( const QgsFeatureList& features, QgsRenderContext& context,
632  const QList< QgsMarkerSymbolV2* >& symbolList, const QList<QPointF>& symbolPositions, bool selected )
633 {
634  QList<QPointF>::const_iterator symbolPosIt = symbolPositions.constBegin();
636  QgsFeatureList::const_iterator featIt = features.constBegin();
637  for ( ; symbolPosIt != symbolPositions.constEnd() && symbolIt != symbolList.constEnd() && featIt != features.constEnd();
638  ++symbolPosIt, ++symbolIt, ++featIt )
639  {
640  if ( *symbolIt )
641  {
642  context.expressionContext().setFeature( *featIt );
643  ( *symbolIt )->startRender( context );
644  ( *symbolIt )->renderPoint( *symbolPosIt, &( *featIt ), context, -1, selected );
645  ( *symbolIt )->stopRender( context );
646  }
647  }
648 }
649 
650 void QgsPointDisplacementRenderer::drawLabels( QPointF centerPoint, QgsSymbolV2RenderContext& context, const QList<QPointF>& labelShifts, const QStringList& labelList )
651 {
652  QPainter* p = context.renderContext().painter();
653  if ( !p )
654  {
655  return;
656  }
657 
658  QPen labelPen( mLabelColor );
659  p->setPen( labelPen );
660 
661  //scale font (for printing)
662  QFont pixelSizeFont = mLabelFont;
663  pixelSizeFont.setPixelSize( context.outputLineWidth( mLabelFont.pointSizeF() * 0.3527 ) );
664  QFont scaledFont = pixelSizeFont;
665  scaledFont.setPixelSize( pixelSizeFont.pixelSize() * context.renderContext().rasterScaleFactor() );
666  p->setFont( scaledFont );
667 
668  QFontMetricsF fontMetrics( pixelSizeFont );
669  QPointF currentLabelShift; //considers the signs to determine the label position
670 
671  QList<QPointF>::const_iterator labelPosIt = labelShifts.constBegin();
672  QStringList::const_iterator text_it = labelList.constBegin();
673 
674  for ( ; labelPosIt != labelShifts.constEnd() && text_it != labelList.constEnd(); ++labelPosIt, ++text_it )
675  {
676  currentLabelShift = *labelPosIt;
677  if ( currentLabelShift.x() < 0 )
678  {
679  currentLabelShift.setX( currentLabelShift.x() - fontMetrics.width( *text_it ) );
680  }
681  if ( currentLabelShift.y() > 0 )
682  {
683  currentLabelShift.setY( currentLabelShift.y() + fontMetrics.ascent() );
684  }
685 
686  QPointF drawingPoint( centerPoint + currentLabelShift );
687  p->save();
688  p->translate( drawingPoint.x(), drawingPoint.y() );
689  p->scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
690  p->drawText( QPointF( 0, 0 ), *text_it );
691  p->restore();
692  }
693 }
694 
695 QgsSymbolV2* QgsPointDisplacementRenderer::firstSymbolForFeature( QgsFeatureRendererV2* r, QgsFeature& f, QgsRenderContext &context )
696 {
697  if ( !r )
698  {
699  return nullptr;
700  }
701 
702  QgsSymbolV2List symbolList = r->symbolsForFeature( f, context );
703  if ( symbolList.size() < 1 )
704  {
705  return nullptr;
706  }
707 
708  return symbolList.at( 0 );
709 }
710 
712 {
713  if ( renderer->type() == "pointDisplacement" )
714  {
715  return dynamic_cast<QgsPointDisplacementRenderer*>( renderer->clone() );
716  }
717 
718  if ( renderer->type() == "singleSymbol" ||
719  renderer->type() == "categorizedSymbol" ||
720  renderer->type() == "graduatedSymbol" ||
721  renderer->type() == "RuleRenderer" )
722  {
724  pointRenderer->setEmbeddedRenderer( renderer->clone() );
725  return pointRenderer;
726  }
727  return nullptr;
728 }
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
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:356
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.