QGIS API Documentation  2.14.11-Essen
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 }
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: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.
WkbType
Used for symbology operations.
Definition: qgis.h:57
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:392
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:136
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: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)
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:83
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:65
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:503
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:346
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.
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
static QgsConstWkbPtr _getPoint(QPointF &pt, QgsRenderContext &context, QgsConstWkbPtr wkb)
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:128
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.