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