QGIS API Documentation  3.2.0-Bonn (bc43194)
qgssymbol.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssymbol.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgssymbol.h"
17 #include "qgssymbollayer.h"
18 
19 #include "qgslinesymbollayer.h"
20 #include "qgsmarkersymbollayer.h"
21 #include "qgsfillsymbollayer.h"
24 
25 #include "qgslogger.h"
26 #include "qgsrendercontext.h" // for bigSymbolPreview
27 
28 #include "qgsproject.h"
29 #include "qgsstyle.h"
30 #include "qgspainteffect.h"
31 #include "qgseffectstack.h"
32 
33 #include "qgsvectorlayer.h"
34 
35 #include "qgsgeometry.h"
36 #include "qgsmultipoint.h"
37 #include "qgsgeometrycollection.h"
38 #include "qgslinestring.h"
39 #include "qgspolygon.h"
40 #include "qgsclipper.h"
41 #include "qgsproperty.h"
42 #include "qgscolorschemeregistry.h"
43 
44 #include <QColor>
45 #include <QImage>
46 #include <QPainter>
47 #include <QSize>
48 #include <QSvgGenerator>
49 
50 #include <cmath>
51 #include <map>
52 #include <random>
53 
54 inline
55 QgsProperty rotateWholeSymbol( double additionalRotation, const QgsProperty &property )
56 {
57  QString exprString = property.asExpression();
58  return QgsProperty::fromExpression( QString::number( additionalRotation ) + " + (" + exprString + ')' );
59 }
60 
61 inline
62 QgsProperty scaleWholeSymbol( double scaleFactor, const QgsProperty &property )
63 {
64  QString exprString = property.asExpression();
65  return QgsProperty::fromExpression( QString::number( scaleFactor ) + "*(" + exprString + ')' );
66 }
67 
68 inline
69 QgsProperty scaleWholeSymbol( double scaleFactorX, double scaleFactorY, const QgsProperty &property )
70 {
71  QString exprString = property.asExpression();
73  ( !qgsDoubleNear( scaleFactorX, 0.0 ) ? "tostring(" + QString::number( scaleFactorX ) + "*(" + exprString + "))" : QStringLiteral( "'0'" ) ) +
74  "|| ',' || " +
75  ( !qgsDoubleNear( scaleFactorY, 0.0 ) ? "tostring(" + QString::number( scaleFactorY ) + "*(" + exprString + "))" : QStringLiteral( "'0'" ) ) );
76 }
77 
78 
80 
82  : mType( type )
83  , mLayers( layers )
84 {
85 
86  // check they're all correct symbol layers
87  for ( int i = 0; i < mLayers.count(); i++ )
88  {
89  if ( !mLayers.at( i ) )
90  {
91  mLayers.removeAt( i-- );
92  }
93  else if ( !mLayers.at( i )->isCompatibleWithSymbol( this ) )
94  {
95  delete mLayers.at( i );
96  mLayers.removeAt( i-- );
97  }
98  }
99 }
100 
101 QPolygonF QgsSymbol::_getLineString( QgsRenderContext &context, const QgsCurve &curve, bool clipToExtent )
102 {
103  const unsigned int nPoints = curve.numPoints();
104 
106  const QgsMapToPixel &mtp = context.mapToPixel();
107  QPolygonF pts;
108 
109  //apply clipping for large lines to achieve a better rendering performance
110  if ( clipToExtent && nPoints > 1 )
111  {
112  const QgsRectangle &e = context.extent();
113  const double cw = e.width() / 10;
114  const double ch = e.height() / 10;
115  const QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
116  pts = QgsClipper::clippedLine( curve, clipRect );
117  }
118  else
119  {
120  pts = curve.asQPolygonF();
121  }
122 
123  //transform the QPolygonF to screen coordinates
124  if ( ct.isValid() )
125  {
126  ct.transformPolygon( pts );
127  }
128 
129  // remove non-finite points, e.g. infinite or NaN points caused by reprojecting errors
130  pts.erase( std::remove_if( pts.begin(), pts.end(),
131  []( const QPointF point )
132  {
133  return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
134  } ), pts.end() );
135 
136  QPointF *ptr = pts.data();
137  for ( int i = 0; i < pts.size(); ++i, ++ptr )
138  {
139  mtp.transformInPlace( ptr->rx(), ptr->ry() );
140  }
141 
142  return pts;
143 }
144 
145 QPolygonF QgsSymbol::_getPolygonRing( QgsRenderContext &context, const QgsCurve &curve, bool clipToExtent )
146 {
147  const QgsCoordinateTransform ct = context.coordinateTransform();
148  const QgsMapToPixel &mtp = context.mapToPixel();
149  const QgsRectangle &e = context.extent();
150  const double cw = e.width() / 10;
151  const double ch = e.height() / 10;
152  QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
153 
154  QPolygonF poly = curve.asQPolygonF();
155 
156  if ( curve.numPoints() < 1 )
157  return QPolygonF();
158 
159  //clip close to view extent, if needed
160  const QRectF ptsRect = poly.boundingRect();
161  if ( clipToExtent && !context.extent().contains( ptsRect ) )
162  {
163  QgsClipper::trimPolygon( poly, clipRect );
164  }
165 
166  //transform the QPolygonF to screen coordinates
167  if ( ct.isValid() )
168  {
169  ct.transformPolygon( poly );
170  }
171 
172  // remove non-finite points, e.g. infinite or NaN points caused by reprojecting errors
173  poly.erase( std::remove_if( poly.begin(), poly.end(),
174  []( const QPointF point )
175  {
176  return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
177  } ), poly.end() );
178 
179  QPointF *ptr = poly.data();
180  for ( int i = 0; i < poly.size(); ++i, ++ptr )
181  {
182  mtp.transformInPlace( ptr->rx(), ptr->ry() );
183  }
184 
185  return poly;
186 }
187 
188 void QgsSymbol::_getPolygon( QPolygonF &pts, QList<QPolygonF> &holes, QgsRenderContext &context, const QgsPolygon &polygon, bool clipToExtent )
189 {
190  holes.clear();
191 
192  pts = _getPolygonRing( context, *polygon.exteriorRing(), clipToExtent );
193  for ( int idx = 0; idx < polygon.numInteriorRings(); idx++ )
194  {
195  const QPolygonF hole = _getPolygonRing( context, *( polygon.interiorRing( idx ) ), clipToExtent );
196  if ( !hole.isEmpty() ) holes.append( hole );
197  }
198 }
199 
201 {
202  // delete all symbol layers (we own them, so it's okay)
203  qDeleteAll( mLayers );
204 }
205 
207 {
208  if ( mLayers.empty() )
209  {
211  }
212 
213  QgsSymbolLayerList::const_iterator it = mLayers.constBegin();
214 
215  QgsUnitTypes::RenderUnit unit = ( *it )->outputUnit();
216 
217  for ( ; it != mLayers.constEnd(); ++it )
218  {
219  if ( ( *it )->outputUnit() != unit )
220  {
222  }
223  }
224  return unit;
225 }
226 
228 {
229  if ( mLayers.empty() )
230  {
231  return QgsMapUnitScale();
232  }
233 
234  QgsSymbolLayerList::const_iterator it = mLayers.constBegin();
235  if ( it == mLayers.constEnd() )
236  return QgsMapUnitScale();
237 
238  QgsMapUnitScale scale = ( *it )->mapUnitScale();
239  ++it;
240 
241  for ( ; it != mLayers.constEnd(); ++it )
242  {
243  if ( ( *it )->mapUnitScale() != scale )
244  {
245  return QgsMapUnitScale();
246  }
247  }
248  return scale;
249 }
250 
252 {
253  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
254  {
255  layer->setOutputUnit( u );
256  }
257 }
258 
260 {
261  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
262  {
263  layer->setMapUnitScale( scale );
264  }
265 }
266 
268 {
269  QgsSymbol *s = nullptr;
270 
271  // override global default if project has a default for this type
272  QString defaultSymbol;
273  switch ( geomType )
274  {
276  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Marker" ), QLatin1String( "" ) );
277  break;
279  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Line" ), QLatin1String( "" ) );
280  break;
282  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Fill" ), QLatin1String( "" ) );
283  break;
284  default:
285  break;
286  }
287  if ( !defaultSymbol.isEmpty() )
288  s = QgsStyle::defaultStyle()->symbol( defaultSymbol );
289 
290  // if no default found for this type, get global default (as previously)
291  if ( ! s )
292  {
293  switch ( geomType )
294  {
296  s = new QgsMarkerSymbol();
297  break;
299  s = new QgsLineSymbol();
300  break;
302  s = new QgsFillSymbol();
303  break;
304  default:
305  QgsDebugMsg( "unknown layer's geometry type" );
306  return nullptr;
307  }
308  }
309 
310  // set opacity
311  double opacity = 1.0;
312  bool ok = false;
313  // upgrade old setting
314  double alpha = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/AlphaInt" ), 255, &ok );
315  if ( ok )
316  opacity = alpha / 255.0;
317  double newOpacity = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Opacity" ), 1.0, &ok );
318  if ( ok )
319  opacity = newOpacity;
320  s->setOpacity( opacity );
321 
322  // set random color, it project prefs allow
323  if ( defaultSymbol.isEmpty() ||
324  QgsProject::instance()->readBoolEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/RandomColors" ), true ) )
325  {
326  s->setColor( QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor() );
327  }
328 
329  return s;
330 }
331 
333 {
334  return mLayers.value( layer );
335 }
336 
338 {
339  if ( index < 0 || index > mLayers.count() ) // can be added also after the last index
340  return false;
341 
342  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
343  return false;
344 
345  mLayers.insert( index, layer );
346  return true;
347 }
348 
349 
351 {
352  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
353  return false;
354 
355  mLayers.append( layer );
356  return true;
357 }
358 
359 
361 {
362  if ( index < 0 || index >= mLayers.count() )
363  return false;
364 
365  delete mLayers.at( index );
366  mLayers.removeAt( index );
367  return true;
368 }
369 
370 
372 {
373  if ( index < 0 || index >= mLayers.count() )
374  return nullptr;
375 
376  return mLayers.takeAt( index );
377 }
378 
379 
381 {
382  QgsSymbolLayer *oldLayer = mLayers.value( index );
383 
384  if ( oldLayer == layer )
385  return false;
386 
387  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
388  return false;
389 
390  delete oldLayer; // first delete the original layer
391  mLayers[index] = layer; // set new layer
392  return true;
393 }
394 
395 
396 void QgsSymbol::startRender( QgsRenderContext &context, const QgsFields &fields )
397 {
398  Q_ASSERT_X( !mStarted, "startRender", "Rendering has already been started for this symbol instance!" );
399  mStarted = true;
400 
401  mSymbolRenderContext.reset( new QgsSymbolRenderContext( context, outputUnit(), mOpacity, false, mRenderHints, nullptr, fields, mapUnitScale() ) );
402 
403  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, false, mRenderHints, nullptr, fields, mapUnitScale() );
404 
405  std::unique_ptr< QgsExpressionContextScope > scope( QgsExpressionContextUtils::updateSymbolScope( this, new QgsExpressionContextScope() ) );
406  mSymbolRenderContext->setExpressionContextScope( scope.release() );
407 
408  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
409  {
410  if ( !layer->enabled() )
411  continue;
412 
413  layer->prepareExpressions( symbolContext );
414  layer->startRender( symbolContext );
415  }
416 }
417 
419 {
420  Q_ASSERT_X( mStarted, "startRender", "startRender was not called for this symbol instance!" );
421  mStarted = false;
422 
423  Q_UNUSED( context )
424  if ( mSymbolRenderContext )
425  {
426  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
427  {
428  if ( !layer->enabled() )
429  continue;
430 
431  layer->stopRender( *mSymbolRenderContext );
432  }
433  }
434 
435  mSymbolRenderContext.reset( nullptr );
436 
437  mLayer = nullptr;
438 }
439 
440 void QgsSymbol::setColor( const QColor &color )
441 {
442  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
443  {
444  if ( !layer->isLocked() )
445  layer->setColor( color );
446  }
447 }
448 
449 QColor QgsSymbol::color() const
450 {
451  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
452  {
453  // return color of the first unlocked layer
454  if ( !( *it )->isLocked() )
455  return ( *it )->color();
456  }
457  return QColor( 0, 0, 0 );
458 }
459 
460 void QgsSymbol::drawPreviewIcon( QPainter *painter, QSize size, QgsRenderContext *customContext )
461 {
462  QgsRenderContext context = customContext ? *customContext : QgsRenderContext::fromQPainter( painter );
463  context.setForceVectorOutput( true );
464  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, false, mRenderHints, nullptr, QgsFields(), mapUnitScale() );
465 
466  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
467  {
468  if ( !layer->enabled() )
469  continue;
470 
471  if ( mType == Fill && layer->type() == Line )
472  {
473  // line symbol layer would normally draw just a line
474  // so we override this case to force it to draw a polygon stroke
475  QgsLineSymbolLayer *lsl = dynamic_cast<QgsLineSymbolLayer *>( layer );
476 
477  if ( lsl )
478  {
479  // from QgsFillSymbolLayer::drawPreviewIcon()
480  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
481  lsl->startRender( symbolContext );
482  lsl->renderPolygonStroke( poly, nullptr, symbolContext );
483  lsl->stopRender( symbolContext );
484  }
485  }
486  else
487  layer->drawPreviewIcon( symbolContext, size );
488  }
489 }
490 
491 void QgsSymbol::exportImage( const QString &path, const QString &format, QSize size )
492 {
493  if ( format.toLower() == QLatin1String( "svg" ) )
494  {
495  QSvgGenerator generator;
496  generator.setFileName( path );
497  generator.setSize( size );
498  generator.setViewBox( QRect( 0, 0, size.height(), size.height() ) );
499 
500  QPainter painter( &generator );
501  drawPreviewIcon( &painter, size );
502  painter.end();
503  }
504  else
505  {
506  QImage image = asImage( size );
507  image.save( path );
508  }
509 }
510 
511 QImage QgsSymbol::asImage( QSize size, QgsRenderContext *customContext )
512 {
513  QImage image( size, QImage::Format_ARGB32_Premultiplied );
514  image.fill( 0 );
515 
516  QPainter p( &image );
517  p.setRenderHint( QPainter::Antialiasing );
518 
519  drawPreviewIcon( &p, size, customContext );
520 
521  return image;
522 }
523 
524 
526 {
527  QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
528  preview.fill( 0 );
529 
530  QPainter p( &preview );
531  p.setRenderHint( QPainter::Antialiasing );
532  p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialising
533 
534  if ( mType == QgsSymbol::Marker )
535  {
536  p.setPen( QPen( Qt::gray ) );
537  p.drawLine( 0, 50, 100, 50 );
538  p.drawLine( 50, 0, 50, 100 );
539  }
540 
542  if ( expressionContext )
543  context.setExpressionContext( *expressionContext );
544 
545  startRender( context );
546 
547  if ( mType == QgsSymbol::Line )
548  {
549  QPolygonF poly;
550  poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
551  static_cast<QgsLineSymbol *>( this )->renderPolyline( poly, nullptr, context );
552  }
553  else if ( mType == QgsSymbol::Fill )
554  {
555  QPolygonF polygon;
556  polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
557  static_cast<QgsFillSymbol *>( this )->renderPolygon( polygon, nullptr, nullptr, context );
558  }
559  else // marker
560  {
561  static_cast<QgsMarkerSymbol *>( this )->renderPoint( QPointF( 50, 50 ), nullptr, context );
562  }
563 
564  stopRender( context );
565  return preview;
566 }
567 
568 
569 QString QgsSymbol::dump() const
570 {
571  QString t;
572  switch ( type() )
573  {
574  case QgsSymbol::Marker:
575  t = QStringLiteral( "MARKER" );
576  break;
577  case QgsSymbol::Line:
578  t = QStringLiteral( "LINE" );
579  break;
580  case QgsSymbol::Fill:
581  t = QStringLiteral( "FILL" );
582  break;
583  default:
584  Q_ASSERT( false && "unknown symbol type" );
585  }
586  QString s = QStringLiteral( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerUtils::encodeColor( color() ) );
587 
588  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
589  {
590  // TODO:
591  }
592  return s;
593 }
594 
595 void QgsSymbol::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
596 {
597  props[ QStringLiteral( "alpha" )] = QString::number( opacity() );
598  double scaleFactor = 1.0;
599  props[ QStringLiteral( "uom" )] = QgsSymbolLayerUtils::encodeSldUom( outputUnit(), &scaleFactor );
600  props[ QStringLiteral( "uomScale" )] = ( !qgsDoubleNear( scaleFactor, 1.0 ) ? qgsDoubleToString( scaleFactor ) : QLatin1String( "" ) );
601 
602  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
603  {
604  ( *it )->toSld( doc, element, props );
605  }
606 }
607 
609 {
610  QgsSymbolLayerList lst;
611  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
612  {
613  QgsSymbolLayer *layer = ( *it )->clone();
614  layer->setLocked( ( *it )->isLocked() );
615  layer->setRenderingPass( ( *it )->renderingPass() );
616  layer->setEnabled( ( *it )->enabled() );
617  lst.append( layer );
618  }
619  return lst;
620 }
621 
623 {
624  Q_ASSERT( layer->type() == Hybrid );
625 
627  return;
628 
629  QgsGeometryGeneratorSymbolLayer *generatorLayer = static_cast<QgsGeometryGeneratorSymbolLayer *>( layer );
630 
631  QgsPaintEffect *effect = generatorLayer->paintEffect();
632  if ( effect && effect->enabled() )
633  {
634  QgsEffectPainter p( context.renderContext(), effect );
635  generatorLayer->render( context );
636  }
637  else
638  {
639  generatorLayer->render( context );
640  }
641 }
642 
643 QSet<QString> QgsSymbol::usedAttributes( const QgsRenderContext &context ) const
644 {
645  QSet<QString> attributes;
646  QgsSymbolLayerList::const_iterator sIt = mLayers.constBegin();
647  for ( ; sIt != mLayers.constEnd(); ++sIt )
648  {
649  if ( *sIt )
650  {
651  attributes.unite( ( *sIt )->usedAttributes( context ) );
652  }
653  }
654  return attributes;
655 }
656 
658 {
659  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
660  {
662  return true;
663  // we treat geometry generator layers like they have data defined properties,
664  // since the WHOLE layer is based on expressions and requires the full expression
665  // context
666  if ( layer->layerType() == QLatin1String( "GeometryGenerator" ) )
667  return true;
668  }
669  return false;
670 }
671 
673 
677 class ExpressionContextScopePopper
678 {
679  public:
680 
681  ExpressionContextScopePopper() = default;
682 
683  ~ExpressionContextScopePopper()
684  {
685  if ( context )
686  context->popScope();
687  }
688 
689  QgsExpressionContext *context = nullptr;
690 };
692 
693 void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, int currentVertexMarkerSize )
694 {
695  const QgsGeometry geom = feature.geometry();
696  if ( geom.isNull() )
697  {
698  return;
699  }
700 
701  QgsGeometry segmentizedGeometry = geom;
702  bool usingSegmentizedGeometry = false;
703  context.setGeometry( geom.constGet() );
704 
705  bool tileMapRendering = context.testFlag( QgsRenderContext::RenderMapTile );
706 
707  //convert curve types to normal point/line/polygon ones
708  if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) )
709  {
711  if ( !g )
712  {
713  return;
714  }
715  segmentizedGeometry = QgsGeometry( g );
716  usingSegmentizedGeometry = true;
717  }
718 
719  mSymbolRenderContext->setGeometryPartCount( segmentizedGeometry.constGet()->partCount() );
720  mSymbolRenderContext->setGeometryPartNum( 1 );
721 
722  bool needsExpressionContext = hasDataDefinedProperties();
723  ExpressionContextScopePopper scopePopper;
724  if ( mSymbolRenderContext->expressionContextScope() )
725  {
726  if ( needsExpressionContext )
727  {
728  // this is somewhat nasty - by appending this scope here it's now owned
729  // by both mSymbolRenderContext AND context.expressionContext()
730  // the RAII scopePopper is required to make sure it always has ownership transferred back
731  // from context.expressionContext(), even if exceptions of other early exits occur in this
732  // function
733  context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
734  scopePopper.context = &context.expressionContext();
735 
736  QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
737  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount(), true ) );
738  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1, true ) );
739  }
740  }
741 
742  // Collection of markers to paint, only used for no curve types.
743  QPolygonF markers;
744 
745  // Simplify the geometry, if needed.
747  {
748  const int simplifyHints = context.vectorSimplifyMethod().simplifyHints();
749  const QgsMapToPixelSimplifier simplifier( simplifyHints, context.vectorSimplifyMethod().tolerance(),
751  segmentizedGeometry = simplifier.simplify( segmentizedGeometry );
752  }
753 
754  switch ( QgsWkbTypes::flatType( segmentizedGeometry.constGet()->wkbType() ) )
755  {
756  case QgsWkbTypes::Point:
757  {
758  if ( mType != QgsSymbol::Marker )
759  {
760  QgsDebugMsg( "point can be drawn only with marker symbol!" );
761  break;
762  }
763 
764  const QgsPoint *point = static_cast< const QgsPoint * >( segmentizedGeometry.constGet() );
765  const QPointF pt = _getPoint( context, *point );
766  static_cast<QgsMarkerSymbol *>( this )->renderPoint( pt, &feature, context, layer, selected );
767 
769  {
770  //draw debugging rect
771  context.painter()->setPen( Qt::red );
772  context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
773  context.painter()->drawRect( static_cast<QgsMarkerSymbol *>( this )->bounds( pt, context, feature ) );
774  }
775 
776  if ( drawVertexMarker && !usingSegmentizedGeometry )
777  {
778  markers << pt;
779  }
780  }
781  break;
783  {
784  if ( mType != QgsSymbol::Line )
785  {
786  QgsDebugMsg( "linestring can be drawn only with line symbol!" );
787  break;
788  }
789  const QgsCurve &curve = dynamic_cast<const QgsCurve &>( *segmentizedGeometry.constGet() );
790  const QPolygonF pts = _getLineString( context, curve, !tileMapRendering && clipFeaturesToExtent() );
791  static_cast<QgsLineSymbol *>( this )->renderPolyline( pts, &feature, context, layer, selected );
792 
793  if ( drawVertexMarker && !usingSegmentizedGeometry )
794  {
795  markers = pts;
796  }
797  }
798  break;
801  {
802  QPolygonF pts;
803  QList<QPolygonF> holes;
804  if ( mType != QgsSymbol::Fill )
805  {
806  QgsDebugMsg( "polygon can be drawn only with fill symbol!" );
807  break;
808  }
809  const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *segmentizedGeometry.constGet() );
810  if ( !polygon.exteriorRing() )
811  {
812  QgsDebugMsg( "cannot render polygon with no exterior ring" );
813  break;
814  }
815  _getPolygon( pts, holes, context, polygon, !tileMapRendering && clipFeaturesToExtent() );
816  static_cast<QgsFillSymbol *>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
817 
818  if ( drawVertexMarker && !usingSegmentizedGeometry )
819  {
820  markers = pts;
821 
822  Q_FOREACH ( const QPolygonF &hole, holes )
823  {
824  markers << hole;
825  }
826  }
827  }
828  break;
829 
831  {
832  if ( mType != QgsSymbol::Marker )
833  {
834  QgsDebugMsg( "multi-point can be drawn only with marker symbol!" );
835  break;
836  }
837 
838  const QgsMultiPoint &mp = static_cast< const QgsMultiPoint & >( *segmentizedGeometry.constGet() );
839 
840  if ( drawVertexMarker && !usingSegmentizedGeometry )
841  {
842  markers.reserve( mp.numGeometries() );
843  }
844 
845  for ( int i = 0; i < mp.numGeometries(); ++i )
846  {
847  mSymbolRenderContext->setGeometryPartNum( i + 1 );
848  if ( needsExpressionContext )
849  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
850 
851  const QgsPoint &point = static_cast< const QgsPoint & >( *mp.geometryN( i ) );
852  const QPointF pt = _getPoint( context, point );
853  static_cast<QgsMarkerSymbol *>( this )->renderPoint( pt, &feature, context, layer, selected );
854 
855  if ( drawVertexMarker && !usingSegmentizedGeometry )
856  {
857  markers.append( pt );
858  }
859  }
860  }
861  break;
862 
865  {
866  if ( mType != QgsSymbol::Line )
867  {
868  QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" );
869  break;
870  }
871 
872  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
873 
874  const unsigned int num = geomCollection.numGeometries();
875  for ( unsigned int i = 0; i < num; ++i )
876  {
877  mSymbolRenderContext->setGeometryPartNum( i + 1 );
878  if ( needsExpressionContext )
879  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
880 
881  context.setGeometry( geomCollection.geometryN( i ) );
882  const QgsCurve &curve = dynamic_cast<const QgsCurve &>( *geomCollection.geometryN( i ) );
883  const QPolygonF pts = _getLineString( context, curve, !tileMapRendering && clipFeaturesToExtent() );
884  static_cast<QgsLineSymbol *>( this )->renderPolyline( pts, &feature, context, layer, selected );
885 
886  if ( drawVertexMarker && !usingSegmentizedGeometry )
887  {
888  if ( i == 0 )
889  {
890  markers = pts;
891  }
892  else
893  {
894  markers << pts;
895  }
896  }
897  }
898  }
899  break;
900 
903  {
904  if ( mType != QgsSymbol::Fill )
905  {
906  QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" );
907  break;
908  }
909 
910  QPolygonF pts;
911  QList<QPolygonF> holes;
912 
913  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
914  const unsigned int num = geomCollection.numGeometries();
915 
916  // Sort components by approximate area (probably a bit faster than using
917  // area() )
918  std::map<double, QList<unsigned int> > mapAreaToPartNum;
919  for ( unsigned int i = 0; i < num; ++i )
920  {
921  const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *geomCollection.geometryN( i ) );
922  const QgsRectangle r( polygon.boundingBox() );
923  mapAreaToPartNum[ r.width() * r.height()] << i;
924  }
925 
926  // Draw starting with larger parts down to smaller parts, so that in
927  // case of a part being incorrectly inside another part, it is drawn
928  // on top of it (#15419)
929  std::map<double, QList<unsigned int> >::const_reverse_iterator iter = mapAreaToPartNum.rbegin();
930  for ( ; iter != mapAreaToPartNum.rend(); ++iter )
931  {
932  const QList<unsigned int> &listPartIndex = iter->second;
933  for ( int idx = 0; idx < listPartIndex.size(); ++idx )
934  {
935  const unsigned i = listPartIndex[idx];
936  mSymbolRenderContext->setGeometryPartNum( i + 1 );
937  if ( needsExpressionContext )
938  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
939 
940  context.setGeometry( geomCollection.geometryN( i ) );
941  const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *geomCollection.geometryN( i ) );
942  if ( !polygon.exteriorRing() )
943  break;
944 
945  _getPolygon( pts, holes, context, polygon, !tileMapRendering && clipFeaturesToExtent() );
946  static_cast<QgsFillSymbol *>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
947 
948  if ( drawVertexMarker && !usingSegmentizedGeometry )
949  {
950  if ( i == 0 )
951  {
952  markers = pts;
953  }
954  else
955  {
956  markers << pts;
957  }
958 
959  Q_FOREACH ( const QPolygonF &hole, holes )
960  {
961  markers << hole;
962  }
963  }
964  }
965  }
966  break;
967  }
969  {
970  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
971  if ( geomCollection.numGeometries() == 0 )
972  {
973  // skip noise from empty geometry collections from simplification
974  break;
975  }
976 
977  FALLTHROUGH;
978  }
979  default:
980  QgsDebugMsg( QString( "feature %1: unsupported wkb type %2/%3 for rendering" )
981  .arg( feature.id() )
982  .arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
983  .arg( geom.wkbType(), 0, 16 ) );
984  }
985 
986  if ( drawVertexMarker )
987  {
988  if ( !markers.isEmpty() )
989  {
990  Q_FOREACH ( QPointF marker, markers )
991  {
992  renderVertexMarker( marker, context, currentVertexMarkerType, currentVertexMarkerSize );
993  }
994  }
995  else
996  {
998  const QgsMapToPixel &mtp = context.mapToPixel();
999 
1000  QgsPoint vertexPoint;
1001  QgsVertexId vertexId;
1002  double x, y, z;
1003  QPointF mapPoint;
1004  while ( geom.constGet()->nextVertex( vertexId, vertexPoint ) )
1005  {
1006  //transform
1007  x = vertexPoint.x();
1008  y = vertexPoint.y();
1009  z = 0.0;
1010  if ( ct.isValid() )
1011  {
1012  ct.transformInPlace( x, y, z );
1013  }
1014  mapPoint.setX( x );
1015  mapPoint.setY( y );
1016  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1017  renderVertexMarker( mapPoint, context, currentVertexMarkerType, currentVertexMarkerSize );
1018  }
1019  }
1020  }
1021 }
1022 
1024 {
1025  return mSymbolRenderContext.get();
1026 }
1027 
1028 void QgsSymbol::renderVertexMarker( QPointF pt, QgsRenderContext &context, int currentVertexMarkerType, int currentVertexMarkerSize )
1029 {
1030  QgsVectorLayer::drawVertexMarker( pt.x(), pt.y(), *context.painter(), static_cast< QgsVectorLayer::VertexMarkerType >( currentVertexMarkerType ), currentVertexMarkerSize );
1031 }
1032 
1034 
1035 
1037  : mRenderContext( c )
1038  , mOutputUnit( u )
1039  , mMapUnitScale( mapUnitScale )
1040  , mOpacity( opacity )
1041  , mSelected( selected )
1042  , mRenderHints( renderHints )
1043  , mFeature( f )
1044  , mFields( fields )
1045  , mGeometryPartCount( 0 )
1046  , mGeometryPartNum( 0 )
1047 {
1048 }
1049 
1051 {
1052  mRenderContext.expressionContext().setOriginalValueVariable( value );
1053 }
1054 
1055 double QgsSymbolRenderContext::outputLineWidth( double width ) const
1056 {
1057  return mRenderContext.convertToPainterUnits( width, mOutputUnit, mMapUnitScale );
1058 }
1059 
1060 double QgsSymbolRenderContext::outputPixelSize( double size ) const
1061 {
1062  return mRenderContext.convertToPainterUnits( size, mOutputUnit, mMapUnitScale );
1063 }
1064 
1066 {
1067  // This is just a dummy implementation of assignment.
1068  // sip 4.7 generates a piece of code that needs this function to exist.
1069  // It's not generated automatically by the compiler because of
1070  // mRenderContext member which is a reference (and thus can't be changed).
1071  Q_ASSERT( false );
1072  return *this;
1073 }
1074 
1076 {
1077  return mExpressionContextScope.get();
1078 }
1079 
1081 {
1082  mExpressionContextScope.reset( contextScope );
1083 }
1084 
1086 
1088 {
1090  if ( !sl )
1091  return nullptr;
1092 
1093  QgsSymbolLayerList layers;
1094  layers.append( sl );
1095  return new QgsMarkerSymbol( layers );
1096 }
1097 
1099 {
1101  if ( !sl )
1102  return nullptr;
1103 
1104  QgsSymbolLayerList layers;
1105  layers.append( sl );
1106  return new QgsLineSymbol( layers );
1107 }
1108 
1110 {
1112  if ( !sl )
1113  return nullptr;
1114 
1115  QgsSymbolLayerList layers;
1116  layers.append( sl );
1117  return new QgsFillSymbol( layers );
1118 }
1119 
1121 
1123  : QgsSymbol( Marker, layers )
1124 {
1125  if ( mLayers.isEmpty() )
1126  mLayers.append( new QgsSimpleMarkerSymbolLayer() );
1127 }
1128 
1129 void QgsMarkerSymbol::setAngle( double symbolAngle )
1130 {
1131  double origAngle = angle();
1132  double angleDiff = symbolAngle - origAngle;
1133  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1134  {
1135  QgsMarkerSymbolLayer *markerLayer = dynamic_cast<QgsMarkerSymbolLayer *>( layer );
1136  if ( markerLayer )
1137  markerLayer->setAngle( markerLayer->angle() + angleDiff );
1138  }
1139 }
1140 
1142 {
1143  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1144  {
1145  if ( layer->type() != QgsSymbol::Marker )
1146  continue;
1147  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1148  return markerLayer->angle();
1149  }
1150  return 0;
1151 }
1152 
1153 void QgsMarkerSymbol::setLineAngle( double lineAng )
1154 {
1155  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1156  {
1157  if ( layer->type() != QgsSymbol::Marker )
1158  continue;
1159  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1160  markerLayer->setLineAngle( lineAng );
1161  }
1162 }
1163 
1165 {
1166  const double symbolRotation = angle();
1167 
1168  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1169  {
1170  if ( layer->type() != QgsSymbol::Marker )
1171  continue;
1172  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1173  if ( !property )
1174  {
1176  }
1177  else
1178  {
1179  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1180  {
1182  }
1183  else
1184  {
1185  QgsProperty rotatedDD = rotateWholeSymbol( markerLayer->angle() - symbolRotation, property );
1187  }
1188  }
1189  }
1190 }
1191 
1193 {
1194  const double symbolRotation = angle();
1195  QgsProperty symbolDD;
1196 
1197  // find the base of the "en masse" pattern
1198  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1199  {
1200  if ( layer->type() != QgsSymbol::Marker )
1201  continue;
1202  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1203  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) && markerLayer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertyAngle ) )
1204  {
1205  symbolDD = markerLayer->dataDefinedProperties().property( QgsSymbolLayer::PropertyAngle );
1206  break;
1207  }
1208  }
1209 
1210  if ( !symbolDD )
1211  return QgsProperty();
1212 
1213  // check that all layer's angle expressions match the "en masse" pattern
1214  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1215  {
1216  if ( layer->type() != QgsSymbol::Marker )
1217  continue;
1218  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1219 
1221 
1222  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1223  {
1224  if ( !layerAngleDD || layerAngleDD != symbolDD )
1225  return QgsProperty();
1226  }
1227  else
1228  {
1229  QgsProperty rotatedDD( rotateWholeSymbol( markerLayer->angle() - symbolRotation, symbolDD ) );
1230  if ( !layerAngleDD || layerAngleDD != rotatedDD )
1231  return QgsProperty();
1232  }
1233  }
1234  return symbolDD;
1235 }
1236 
1237 
1239 {
1240  double origSize = size();
1241 
1242  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1243  {
1244  if ( layer->type() != QgsSymbol::Marker )
1245  continue;
1246  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1247  if ( qgsDoubleNear( markerLayer->size(), origSize ) )
1248  markerLayer->setSize( s );
1249  else if ( !qgsDoubleNear( origSize, 0.0 ) )
1250  {
1251  // proportionally scale size
1252  markerLayer->setSize( markerLayer->size() * s / origSize );
1253  }
1254  // also scale offset to maintain relative position
1255  if ( !qgsDoubleNear( origSize, 0.0 ) && ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) ) )
1256  markerLayer->setOffset( QPointF( markerLayer->offset().x() * s / origSize,
1257  markerLayer->offset().y() * s / origSize ) );
1258  }
1259 }
1260 
1262 {
1263  // return size of the largest symbol
1264  double maxSize = 0;
1265  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1266  {
1267  if ( layer->type() != QgsSymbol::Marker )
1268  continue;
1269  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1270  double lsize = markerLayer->size();
1271  if ( lsize > maxSize )
1272  maxSize = lsize;
1273  }
1274  return maxSize;
1275 }
1276 
1278 {
1279  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1280  {
1281  if ( layer->type() != QgsSymbol::Marker )
1282  continue;
1283 
1284  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1285  markerLayer->setSizeUnit( unit );
1286  }
1287 }
1288 
1290 {
1291  bool first = true;
1293 
1294  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1295  {
1296  if ( layer->type() != QgsSymbol::Marker )
1297  continue;
1298  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1299 
1300  if ( first )
1301  unit = markerLayer->sizeUnit();
1302  else
1303  {
1304  if ( unit != markerLayer->sizeUnit() )
1306  }
1307 
1308  first = false;
1309  }
1310  return unit;
1311 }
1312 
1314 {
1315  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1316  {
1317  if ( layer->type() != QgsSymbol::Marker )
1318  continue;
1319 
1320  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1321  markerLayer->setSizeMapUnitScale( scale );
1322  }
1323 }
1324 
1326 {
1327  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1328  {
1329  if ( layer->type() != QgsSymbol::Marker )
1330  continue;
1331 
1332  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1333  return markerLayer->sizeMapUnitScale();
1334  }
1335  return QgsMapUnitScale();
1336 }
1337 
1339 {
1340  const double symbolSize = size();
1341 
1342  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1343  {
1344  if ( layer->type() != QgsSymbol::Marker )
1345  continue;
1346  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1347 
1348  if ( !property )
1349  {
1352  }
1353  else
1354  {
1355  if ( qgsDoubleNear( symbolSize, 0.0 ) || qgsDoubleNear( markerLayer->size(), symbolSize ) )
1356  {
1357  markerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, property );
1358  }
1359  else
1360  {
1361  markerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, scaleWholeSymbol( markerLayer->size() / symbolSize, property ) );
1362  }
1363 
1364  if ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) )
1365  {
1367  markerLayer->offset().x() / symbolSize,
1368  markerLayer->offset().y() / symbolSize, property ) );
1369  }
1370  }
1371  }
1372 }
1373 
1375 {
1376  const double symbolSize = size();
1377 
1378  QgsProperty symbolDD;
1379 
1380  // find the base of the "en masse" pattern
1381  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1382  {
1383  if ( layer->type() != QgsSymbol::Marker )
1384  continue;
1385  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1386  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) && markerLayer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertySize ) )
1387  {
1388  symbolDD = markerLayer->dataDefinedProperties().property( QgsSymbolLayer::PropertySize );
1389  break;
1390  }
1391  }
1392 
1393  if ( !symbolDD )
1394  return QgsProperty();
1395 
1396  // check that all layers size expressions match the "en masse" pattern
1397  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1398  {
1399  if ( layer->type() != QgsSymbol::Marker )
1400  continue;
1401  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1402 
1405 
1406  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) )
1407  {
1408  if ( !layerSizeDD || layerSizeDD != symbolDD )
1409  return QgsProperty();
1410  }
1411  else
1412  {
1413  if ( qgsDoubleNear( symbolSize, 0.0 ) )
1414  return QgsProperty();
1415 
1416  QgsProperty scaledDD( scaleWholeSymbol( markerLayer->size() / symbolSize, symbolDD ) );
1417  if ( !layerSizeDD || layerSizeDD != scaledDD )
1418  return QgsProperty();
1419  }
1420 
1421  QgsProperty scaledOffsetDD( scaleWholeSymbol( markerLayer->offset().x() / symbolSize, markerLayer->offset().y() / symbolSize, symbolDD ) );
1422  if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
1423  return QgsProperty();
1424  }
1425 
1426  return symbolDD;
1427 }
1428 
1430 {
1431  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1432  {
1433  if ( layer->type() != QgsSymbol::Marker )
1434  continue;
1435  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1436  markerLayer->setScaleMethod( scaleMethod );
1437  }
1438 }
1439 
1441 {
1442  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1443  {
1444  if ( layer->type() != QgsSymbol::Marker )
1445  continue;
1446  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1447  // return scale method of the first symbol layer
1448  return markerLayer->scaleMethod();
1449  }
1450 
1451  return DEFAULT_SCALE_METHOD;
1452 }
1453 
1454 void QgsMarkerSymbol::renderPointUsingLayer( QgsMarkerSymbolLayer *layer, QPointF point, QgsSymbolRenderContext &context )
1455 {
1456  static QPointF nullPoint( 0, 0 );
1457 
1459  return;
1460 
1461  QgsPaintEffect *effect = layer->paintEffect();
1462  if ( effect && effect->enabled() )
1463  {
1464  QgsEffectPainter p( context.renderContext() );
1465  p->translate( point );
1466  p.setEffect( effect );
1467  layer->renderPoint( nullPoint, context );
1468  }
1469  else
1470  {
1471  layer->renderPoint( point, context );
1472  }
1473 }
1474 
1475 void QgsMarkerSymbol::renderPoint( QPointF point, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1476 {
1477  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, selected, mRenderHints, f, QgsFields(), mapUnitScale() );
1478  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1479  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1480 
1481  if ( layerIdx != -1 )
1482  {
1483  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1484  if ( symbolLayer && symbolLayer->enabled() )
1485  {
1486  if ( symbolLayer->type() == QgsSymbol::Marker )
1487  {
1488  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( symbolLayer );
1489  renderPointUsingLayer( markerLayer, point, symbolContext );
1490  }
1491  else
1492  renderUsingLayer( symbolLayer, symbolContext );
1493  }
1494  return;
1495  }
1496 
1497  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1498  {
1499  if ( !symbolLayer->enabled() )
1500  continue;
1501 
1502  if ( symbolLayer->type() == QgsSymbol::Marker )
1503  {
1504  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( symbolLayer );
1505  renderPointUsingLayer( markerLayer, point, symbolContext );
1506  }
1507  else
1508  renderUsingLayer( symbolLayer, symbolContext );
1509  }
1510 }
1511 
1512 QRectF QgsMarkerSymbol::bounds( QPointF point, QgsRenderContext &context, const QgsFeature &feature ) const
1513 {
1514  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, false, mRenderHints, &feature, feature.fields(), mapUnitScale() );
1515 
1516  QRectF bound;
1517  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1518  {
1519  if ( layer->type() == QgsSymbol::Marker )
1520  {
1522  if ( bound.isNull() )
1523  bound = symbolLayer->bounds( point, symbolContext );
1524  else
1525  bound = bound.united( symbolLayer->bounds( point, symbolContext ) );
1526  }
1527  }
1528  return bound;
1529 }
1530 
1532 {
1533  QgsMarkerSymbol *cloneSymbol = new QgsMarkerSymbol( cloneLayers() );
1534  cloneSymbol->setOpacity( mOpacity );
1535  cloneSymbol->setLayer( mLayer );
1537  return cloneSymbol;
1538 }
1539 
1540 
1542 // LINE
1543 
1545  : QgsSymbol( Line, layers )
1546 {
1547  if ( mLayers.isEmpty() )
1548  mLayers.append( new QgsSimpleLineSymbolLayer() );
1549 }
1550 
1551 void QgsLineSymbol::setWidth( double w )
1552 {
1553  double origWidth = width();
1554 
1555  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1556  {
1557  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
1558 
1559  if ( lineLayer )
1560  {
1561  if ( qgsDoubleNear( lineLayer->width(), origWidth ) )
1562  {
1563  lineLayer->setWidth( w );
1564  }
1565  else if ( !qgsDoubleNear( origWidth, 0.0 ) )
1566  {
1567  // proportionally scale the width
1568  lineLayer->setWidth( lineLayer->width() * w / origWidth );
1569  }
1570  // also scale offset to maintain relative position
1571  if ( !qgsDoubleNear( origWidth, 0.0 ) && !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1572  lineLayer->setOffset( lineLayer->offset() * w / origWidth );
1573  }
1574  }
1575 }
1576 
1577 double QgsLineSymbol::width() const
1578 {
1579  double maxWidth = 0;
1580  if ( mLayers.isEmpty() )
1581  return maxWidth;
1582 
1583  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1584  {
1585  const QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( symbolLayer );
1586  if ( lineLayer )
1587  {
1588  double width = lineLayer->width();
1589  if ( width > maxWidth )
1590  maxWidth = width;
1591  }
1592  }
1593  return maxWidth;
1594 }
1595 
1597 {
1598  const double symbolWidth = width();
1599 
1600  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1601  {
1602  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
1603 
1604  if ( lineLayer )
1605  {
1606  if ( !property )
1607  {
1610  }
1611  else
1612  {
1613  if ( qgsDoubleNear( symbolWidth, 0.0 ) || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1614  {
1616  }
1617  else
1618  {
1619  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyStrokeWidth, scaleWholeSymbol( lineLayer->width() / symbolWidth, property ) );
1620  }
1621 
1622  if ( !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1623  {
1624  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyOffset, scaleWholeSymbol( lineLayer->offset() / symbolWidth, property ) );
1625  }
1626  }
1627  }
1628  }
1629 }
1630 
1632 {
1633  const double symbolWidth = width();
1634 
1635  QgsProperty symbolDD;
1636 
1637  // find the base of the "en masse" pattern
1638  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1639  {
1640  const QgsLineSymbolLayer *layer = dynamic_cast<const QgsLineSymbolLayer *>( *it );
1641  if ( layer && qgsDoubleNear( layer->width(), symbolWidth ) && layer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
1642  {
1644  break;
1645  }
1646  }
1647 
1648  if ( !symbolDD )
1649  return QgsProperty();
1650 
1651  // check that all layers width expressions match the "en masse" pattern
1652  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1653  {
1654  if ( layer->type() != QgsSymbol::Line )
1655  continue;
1656  const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
1657 
1660 
1661  if ( qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1662  {
1663  if ( !layerWidthDD || layerWidthDD != symbolDD )
1664  return QgsProperty();
1665  }
1666  else
1667  {
1668  if ( qgsDoubleNear( symbolWidth, 0.0 ) )
1669  return QgsProperty();
1670 
1671  QgsProperty scaledDD( scaleWholeSymbol( lineLayer->width() / symbolWidth, symbolDD ) );
1672  if ( !layerWidthDD || layerWidthDD != scaledDD )
1673  return QgsProperty();
1674  }
1675 
1676  QgsProperty scaledOffsetDD( scaleWholeSymbol( lineLayer->offset() / symbolWidth, symbolDD ) );
1677  if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
1678  return QgsProperty();
1679  }
1680 
1681  return symbolDD;
1682 }
1683 
1684 void QgsLineSymbol::renderPolyline( const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1685 {
1686  //save old painter
1687  QPainter *renderPainter = context.painter();
1688  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, selected, mRenderHints, f, QgsFields(), mapUnitScale() );
1690  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1691  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1692 
1693  if ( layerIdx != -1 )
1694  {
1695  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1696  if ( symbolLayer && symbolLayer->enabled() )
1697  {
1698  if ( symbolLayer->type() == QgsSymbol::Line )
1699  {
1700  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
1701  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1702  }
1703  else
1704  renderUsingLayer( symbolLayer, symbolContext );
1705  }
1706  return;
1707  }
1708 
1709  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1710  {
1711  if ( !symbolLayer->enabled() )
1712  continue;
1713 
1714  if ( symbolLayer->type() == QgsSymbol::Line )
1715  {
1716  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
1717  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1718  }
1719  else
1720  {
1721  renderUsingLayer( symbolLayer, symbolContext );
1722  }
1723  }
1724 
1725  context.setPainter( renderPainter );
1726 }
1727 
1728 void QgsLineSymbol::renderPolylineUsingLayer( QgsLineSymbolLayer *layer, const QPolygonF &points, QgsSymbolRenderContext &context )
1729 {
1731  return;
1732 
1733  QgsPaintEffect *effect = layer->paintEffect();
1734  if ( effect && effect->enabled() )
1735  {
1736  QgsEffectPainter p( context.renderContext() );
1737  p->translate( points.boundingRect().topLeft() );
1738  p.setEffect( effect );
1739  layer->renderPolyline( points.translated( -points.boundingRect().topLeft() ), context );
1740  }
1741  else
1742  {
1743  layer->renderPolyline( points, context );
1744  }
1745 }
1746 
1747 
1749 {
1750  QgsLineSymbol *cloneSymbol = new QgsLineSymbol( cloneLayers() );
1751  cloneSymbol->setOpacity( mOpacity );
1752  cloneSymbol->setLayer( mLayer );
1754  return cloneSymbol;
1755 }
1756 
1758 // FILL
1759 
1761  : QgsSymbol( Fill, layers )
1762 {
1763  if ( mLayers.isEmpty() )
1764  mLayers.append( new QgsSimpleFillSymbolLayer() );
1765 }
1766 
1767 void QgsFillSymbol::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1768 {
1769  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, selected, mRenderHints, f, QgsFields(), mapUnitScale() );
1771  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1772  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1773 
1774  if ( layerIdx != -1 )
1775  {
1776  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1777  if ( symbolLayer && symbolLayer->enabled() )
1778  {
1779  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1780  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1781  else
1782  renderUsingLayer( symbolLayer, symbolContext );
1783  }
1784  return;
1785  }
1786 
1787  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1788  {
1789  if ( !symbolLayer->enabled() )
1790  continue;
1791 
1792  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1793  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1794  else
1795  renderUsingLayer( symbolLayer, symbolContext );
1796  }
1797 }
1798 
1799 void QgsFillSymbol::renderPolygonUsingLayer( QgsSymbolLayer *layer, const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
1800 {
1802  return;
1803 
1804  QgsSymbol::SymbolType layertype = layer->type();
1805 
1806  QgsPaintEffect *effect = layer->paintEffect();
1807  if ( effect && effect->enabled() )
1808  {
1809  QRectF bounds = polygonBounds( points, rings );
1810  QList<QPolygonF> *translatedRings = translateRings( rings, -bounds.left(), -bounds.top() );
1811 
1812  QgsEffectPainter p( context.renderContext() );
1813  p->translate( bounds.topLeft() );
1814  p.setEffect( effect );
1815  if ( layertype == QgsSymbol::Fill )
1816  {
1817  ( static_cast<QgsFillSymbolLayer *>( layer ) )->renderPolygon( points.translated( -bounds.topLeft() ), translatedRings, context );
1818  }
1819  else if ( layertype == QgsSymbol::Line )
1820  {
1821  ( static_cast<QgsLineSymbolLayer *>( layer ) )->renderPolygonStroke( points.translated( -bounds.topLeft() ), translatedRings, context );
1822  }
1823  delete translatedRings;
1824  }
1825  else
1826  {
1827  if ( layertype == QgsSymbol::Fill )
1828  {
1829  ( static_cast<QgsFillSymbolLayer *>( layer ) )->renderPolygon( points, rings, context );
1830  }
1831  else if ( layertype == QgsSymbol::Line )
1832  {
1833  ( static_cast<QgsLineSymbolLayer *>( layer ) )->renderPolygonStroke( points, rings, context );
1834  }
1835  }
1836 }
1837 
1838 QRectF QgsFillSymbol::polygonBounds( const QPolygonF &points, const QList<QPolygonF> *rings ) const
1839 {
1840  QRectF bounds = points.boundingRect();
1841  if ( rings )
1842  {
1843  QList<QPolygonF>::const_iterator it = rings->constBegin();
1844  for ( ; it != rings->constEnd(); ++it )
1845  {
1846  bounds = bounds.united( ( *it ).boundingRect() );
1847  }
1848  }
1849  return bounds;
1850 }
1851 
1852 QList<QPolygonF> *QgsFillSymbol::translateRings( const QList<QPolygonF> *rings, double dx, double dy ) const
1853 {
1854  if ( !rings )
1855  return nullptr;
1856 
1857  QList<QPolygonF> *translatedRings = new QList<QPolygonF>;
1858  QList<QPolygonF>::const_iterator it = rings->constBegin();
1859  for ( ; it != rings->constEnd(); ++it )
1860  {
1861  translatedRings->append( ( *it ).translated( dx, dy ) );
1862  }
1863  return translatedRings;
1864 }
1865 
1867 {
1868  QgsFillSymbol *cloneSymbol = new QgsFillSymbol( cloneLayers() );
1869  cloneSymbol->setOpacity( mOpacity );
1870  cloneSymbol->setLayer( mLayer );
1872  return cloneSymbol;
1873 }
1874 
1876 {
1877  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1878  {
1879  if ( layer->type() != QgsSymbol::Fill )
1880  continue;
1881 
1882  QgsFillSymbolLayer *fillLayer = static_cast<QgsFillSymbolLayer *>( layer );
1883 
1884  if ( fillLayer )
1885  fillLayer->setAngle( angle );
1886  }
1887 }
1888 
1889 
void setOffset(QPointF offset)
Sets the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered marker...
bool insertSymbolLayer(int index, QgsSymbolLayer *layer)
Insert symbol layer to specified index Ownership will be transferred.
Definition: qgssymbol.cpp:337
QgsSymbolRenderContext(QgsRenderContext &c, QgsUnitTypes::RenderUnit u, qreal opacity=1.0, bool selected=false, QgsSymbol::RenderHints renderHints=nullptr, const QgsFeature *f=nullptr, const QgsFields &fields=QgsFields(), const QgsMapUnitScale &mapUnitScale=QgsMapUnitScale())
Constructor for QgsSymbolRenderContext.
Definition: qgssymbol.cpp:1036
void setForceVectorOutput(bool force)
QgsFeatureId id
Definition: qgsfeature.h:71
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbol to an expression context.
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
Definition: qgsrectangle.h:335
Single variable definition for use within a QgsExpressionContextScope.
A rectangle specified with double values.
Definition: qgsrectangle.h:40
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
double y
Definition: qgspoint.h:42
void setLineAngle(double lineAngle)
Sets the line angle modification for the symbol&#39;s angle.
void setRenderingPass(int renderingPass)
void setLocked(bool locked)
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Added in QGIS v2.4.
void setMapUnitScale(const QgsMapUnitScale &scale)
Definition: qgssymbol.cpp:259
QString readEntry(const QString &scope, const QString &key, const QString &def=QString(), bool *ok=nullptr) const
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
bool readBoolEntry(const QString &scope, const QString &key, bool def=false, bool *ok=nullptr) const
Multi point geometry collection.
Definition: qgsmultipoint.h:29
bool appendSymbolLayer(QgsSymbolLayer *layer)
Append symbol layer at the end of the list Ownership will be transferred.
Definition: qgssymbol.cpp:350
Simple marker symbol layer, consisting of a rendered shape with solid fill color and an stroke...
virtual void setWidth(double width)
SimplifyAlgorithm simplifyAlgorithm() const
Gets the local simplification algorithm of the vector layer managed.
static QgsLineSymbol * createSimple(const QgsStringMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties. ...
Definition: qgssymbol.cpp:1098
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
ScaleMethod scaleMethod()
Definition: qgssymbol.cpp:1440
const QgsMapUnitScale & sizeMapUnitScale() const
Returns the map unit scale for the symbol&#39;s size.
virtual void prepareExpressions(const QgsSymbolRenderContext &context)
Prepares all data defined property expressions for evaluation.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QgsSymbol(SymbolType type, const QgsSymbolLayerList &layers)
Definition: qgssymbol.cpp:81
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
Definition: qgssymbol.cpp:1109
QgsMapUnitScale mapUnitScale() const
Definition: qgssymbol.cpp:227
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:251
void setExpressionContextScope(QgsExpressionContextScope *contextScope)
Set an expression scope for this symbol.
Definition: qgssymbol.cpp:1080
void setAngle(double angle)
const QgsCurve * interiorRing(int i) const
VertexMarkerType
Editing vertex markers.
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Definition: qgssymbol.cpp:1684
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
Definition: qgssymbol.cpp:595
static QPointF _getPoint(QgsRenderContext &context, const QgsPoint &point)
Creates a point in screen coordinates from a QgsPoint in map coordinates.
Definition: qgssymbol.h:336
void setSize(double size)
Sets the size for the whole symbol.
Definition: qgssymbol.cpp:1238
Base class for visual effects which can be applied to QPicture drawings.
void renderVertexMarker(QPointF pt, QgsRenderContext &context, int currentVertexMarkerType, int currentVertexMarkerSize)
Render editing vertex marker at specified point.
Definition: qgssymbol.cpp:1028
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the size map unit scale for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1313
bool clipFeaturesToExtent() const
Returns whether features drawn by the symbol will be clipped to the render context&#39;s extent...
Definition: qgssymbol.h:298
double outputLineWidth(double width) const
Definition: qgssymbol.cpp:1055
bool mClipFeaturesToExtent
Definition: qgssymbol.h:400
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:104
virtual void render(QgsSymbolRenderContext &context)
Will render this symbol layer using the context.
void setGeometryPartCount(int count)
Sets the part count of current geometry.
Definition: qgssymbol.h:546
bool deleteSymbolLayer(int index)
delete symbol layer at specified index
Definition: qgssymbol.cpp:360
void setDataDefinedAngle(const QgsProperty &property)
Set data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1164
bool isLocked() const
Line symbol.
Definition: qgssymbol.h:86
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
void setAngle(double symbolAngle)
Sets the angle for the whole symbol.
Definition: qgssymbol.cpp:1129
QgsFields fields
Definition: qgsfeature.h:73
SimplifyAlgorithm
Types of simplification algorithms that can be used.
void setScaleMethod(QgsSymbol::ScaleMethod scaleMethod)
Sets the method to use for scaling the marker&#39;s size.
QgsAbstractGeometry::SegmentationToleranceType segmentationToleranceType() const
Gets segmentation tolerance type (maximum angle or maximum difference between curve and approximation...
QMap< QString, QString > QgsStringMap
Definition: qgis.h:501
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
virtual double width() const
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:396
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:46
virtual void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context)=0
void transformPolygon(QPolygonF &polygon, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transforms a polygon to the destination coordinate system.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
static QString encodeColor(const QColor &color)
QgsUnitTypes::RenderUnit outputUnit() const
Returns the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:206
virtual void setColor(const QColor &color)
The fill color.
void setOutputUnit(QgsUnitTypes::RenderUnit unit)
Sets the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:251
QgsSymbolRenderContext & operator=(const QgsSymbolRenderContext &)
Definition: qgssymbol.cpp:1065
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
void transformInPlace(double &x, double &y) const
Transform device coordinates to map coordinates.
SymbolType
Type of the symbol.
Definition: qgssymbol.h:83
void renderPoint(QPointF point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Definition: qgssymbol.cpp:1475
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
Definition: qgssymbol.cpp:1050
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
QgsProperty dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1192
SymbolType mType
Definition: qgssymbol.h:393
virtual QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition: qgscurve.cpp:191
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsSimpleMarkerSymbolLayer.
QgsSymbolLayerList mLayers
Definition: qgssymbol.h:394
int numInteriorRings() const
virtual QRectF bounds(QPointF point, QgsSymbolRenderContext &context)=0
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
QImage asImage(QSize size, QgsRenderContext *customContext=nullptr)
Generate symbol as image.
Definition: qgssymbol.cpp:511
void exportImage(const QString &path, const QString &format, QSize size)
export symbol as image format. PNG and SVG supported
Definition: qgssymbol.cpp:491
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns new default symbol for specified geometry type.
Definition: qgssymbol.cpp:267
void setOriginalGeometryType(QgsWkbTypes::GeometryType type)
Sets the geometry type for the original feature geometry being rendered.
Definition: qgssymbol.h:516
#define FALLTHROUGH
Definition: qgis.h:570
double angle() const
Returns the rotation angle for the marker, in degrees clockwise from north.
virtual void setOutputUnit(QgsUnitTypes::RenderUnit unit)
Sets the units to use for sizes and widths within the symbol layer.
QString dump() const
Definition: qgssymbol.cpp:569
Utility class for identifying a unique vertex within a geometry.
double tolerance() const
Gets the tolerance of simplification in map units. Represents the maximum distance in map units betwe...
void setGeometry(const QgsAbstractGeometry *geometry)
Sets pointer to original (unsegmentized) geometry.
const QgsVectorLayer * mLayer
Definition: qgssymbol.h:402
const QgsRectangle & extent() const
Geometry collection.
#define DEFAULT_SCALE_METHOD
QRectF bounds(QPointF point, QgsRenderContext &context, const QgsFeature &feature=QgsFeature()) const
Returns the approximate bounding box of the marker symbol, which includes the bounding box of all sym...
Definition: qgssymbol.cpp:1512
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Definition: qgssymbol.cpp:1767
double outputPixelSize(double size) const
Definition: qgssymbol.cpp:1060
void renderUsingLayer(QgsSymbolLayer *layer, QgsSymbolRenderContext &context)
Renders a context using a particular symbol layer without passing in a geometry.
Definition: qgssymbol.cpp:622
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:264
QgsFillSymbol * clone() const override
Gets a deep copy of this symbol.
Definition: qgssymbol.cpp:1866
void setGeometryPartNum(int num)
Sets the part number of current geometry.
Definition: qgssymbol.h:558
static void _getPolygon(QPolygonF &pts, QList< QPolygonF > &holes, QgsRenderContext &context, const QgsPolygon &polygon, bool clipToExtent=true)
Creates a polygon in screen coordinates from a QgsPolygonXYin map coordinates.
Definition: qgssymbol.cpp:188
void setWidth(double width)
Definition: qgssymbol.cpp:1551
double width() const
Definition: qgssymbol.cpp:1577
double size() const
Returns the symbol size.
virtual void renderPoint(QPointF point, QgsSymbolRenderContext &context)=0
Renders a marker at the specified point.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:201
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:237
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer&#39;s property collection, used for data defined overrides...
void setSize(double size)
Sets the symbol size.
QgsProperty scaleWholeSymbol(double scaleFactor, const QgsProperty &property)
Definition: qgssymbol.cpp:62
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol&#39;s size.
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
void renderFeature(const QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false, int currentVertexMarkerType=0, int currentVertexMarkerSize=0)
Render a feature.
Definition: qgssymbol.cpp:693
QgsMapUnitScale sizeMapUnitScale() const
Returns the size map unit scale for the whole symbol.
Definition: qgssymbol.cpp:1325
Draw bounds of symbols (for debugging/testing)
void drawPreviewIcon(QPainter *painter, QSize size, QgsRenderContext *customContext=nullptr)
Draw icon of the symbol that occupyies area given by size using the painter.
Definition: qgssymbol.cpp:460
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:53
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgssurface.h:45
static QString encodeSldUom(QgsUnitTypes::RenderUnit unit, double *scaleFactor)
Encodes a render unit into an SLD unit of measure string.
QColor color() const
Definition: qgssymbol.cpp:449
virtual void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size)=0
QgsSymbolRenderContext * symbolRenderContext()
Returns the symbol render context.
Definition: qgssymbol.cpp:1023
QgsSymbol::SymbolType type() const
void setScaleMethod(QgsSymbol::ScaleMethod scaleMethod)
Definition: qgssymbol.cpp:1429
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context, or an invalid transform is no coordinate tr...
bool enabled() const
Returns whether the effect is enabled.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
double offset() const
ScaleMethod
Scale method.
Definition: qgssymbol.h:94
Single scope for storing variables and functions for use within a QgsExpressionContext.
Abstract base class for all geometries.
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
void setEnabled(bool enabled)
Sets whether symbol layer is enabled and should be drawn.
void setAngle(double angle)
Definition: qgssymbol.cpp:1875
A store for object properties.
Definition: qgsproperty.h:229
QgsMarkerSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Definition: qgssymbol.cpp:1122
const QgsVectorLayer * layer() const
Definition: qgssymbol.h:315
QgsRenderContext & renderContext()
Returns a reference to the context&#39;s render context.
Definition: qgssymbol.h:453
static void drawVertexMarker(double x, double y, QPainter &p, QgsVectorLayer::VertexMarkerType type, int vertexSize)
Draws a vertex symbol at (screen) coordinates x, y. (Useful to assist vertex editing.)
Implementation of GeometrySimplifier using the "MapToPixel" algorithm.
QgsSymbolLayer * symbolLayer(int layer)
Returns a specific symbol layers contained in the symbol.
Definition: qgssymbol.cpp:332
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
void setEffect(QgsPaintEffect *effect)
Sets the effect to be painted.
static QPolygonF clippedLine(const QgsCurve &curve, const QgsRectangle &clipExtent)
Takes a linestring and clips it to clipExtent.
Definition: qgsclipper.cpp:41
void setDataDefinedWidth(const QgsProperty &property)
Set data defined width for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1596
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the size units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1277
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
int numGeometries() const
Returns the number of geometries within the collection.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
QgsSymbol::ScaleMethod scaleMethod() const
Returns the method to use for scaling the marker&#39;s size.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the size units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1289
QgsExpressionContext & expressionContext()
Gets the expression context.
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transforms an array of x, y and z double coordinates in place, from the source CRS to the destination...
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1374
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
virtual bool isCompatibleWithSymbol(QgsSymbol *symbol) const
Returns if the layer can be used below the specified symbol.
bool valueAsBool(int key, const QgsExpressionContext &context, bool defaultValue=false, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an boolean...
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:137
bool changeSymbolLayer(int index, QgsSymbolLayer *layer)
delete layer at specified index and set a new one
Definition: qgssymbol.cpp:380
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol&#39;s size.
Marker symbol.
Definition: qgssymbol.h:85
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application&#39;s color scheme registry, used for managing color schemes. ...
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
Definition: qgssymbol.cpp:643
Fill symbol.
Definition: qgssymbol.h:87
Contains information about the context of a rendering operation.
Abstract base class for marker symbol layers.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
double segmentationTolerance() const
Gets the segmentation tolerance applied when rendering curved geometries.
virtual void setMapUnitScale(const QgsMapUnitScale &scale)
QPainter * painter()
Returns the destination QPainter for the render operation.
const QgsMapToPixel & mapToPixel() const
virtual ~QgsSymbol()
Definition: qgssymbol.cpp:200
QgsSymbolLayerList cloneLayers() const
Retrieve a cloned list of all layers that make up this symbol.
Definition: qgssymbol.cpp:608
QgsGeometry simplify(const QgsGeometry &geometry) const override
Returns a simplified version the specified geometry.
bool hasDataDefinedProperties() const
Returns whether the symbol utilizes any data defined properties.
Definition: qgssymbol.cpp:657
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
bool enabled() const
Returns true if symbol layer is enabled and will be drawn.
SymbolType type() const
Definition: qgssymbol.h:113
virtual void stopRender(QgsSymbolRenderContext &context)=0
Struct for storing maximum and minimum scales for measurements in map units.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the symbol&#39;s size.
RenderHints mRenderHints
Definition: qgssymbol.h:399
QgsProperty rotateWholeSymbol(double additionalRotation, const QgsProperty &property)
Definition: qgssymbol.cpp:55
static bool isCurvedType(Type type)
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:606
void setLayer(const QgsVectorLayer *layer)
Definition: qgssymbol.h:314
double size() const
Returns the size for the whole symbol, which is the maximum size of all marker symbol layers in the s...
Definition: qgssymbol.cpp:1261
bool forceLocalOptimization() const
Gets where the simplification executes, after fetch the geometries from provider, or when supported...
RenderHints renderHints() const
Returns the rendering hint flags for the symbol.
Definition: qgssymbol.h:276
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:391
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
Class for doing transforms between two map coordinate systems.
static QString displayString(Type type)
Returns a display string type for a WKB type, e.g., the geometry name used in WKT geometry representa...
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
virtual void renderPolygonStroke(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolRenderContext &context)
void setAngle(double angle)
Sets the rotation angle for the marker.
void setLineAngle(double lineAngle)
Sets the line angle modification for the symbol&#39;s angle.
Definition: qgssymbol.cpp:1153
QgsLineSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Definition: qgssymbol.cpp:1544
double readDoubleEntry(const QString &scope, const QString &key, double def=0, bool *ok=nullptr) const
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
QgsSymbolLayer * takeSymbolLayer(int index)
Remove symbol layer from the list and return pointer to it.
Definition: qgssymbol.cpp:371
static QPolygonF _getPolygonRing(QgsRenderContext &context, const QgsCurve &curve, bool clipToExtent)
Creates a polygon ring in screen coordinates from a QgsCurve in map coordinates.
Definition: qgssymbol.cpp:145
QgsSymbol * symbol(const QString &name)
Returns a NEW copy of symbol.
Definition: qgsstyle.cpp:169
static QgsMarkerSymbol * createSimple(const QgsStringMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
Definition: qgssymbol.cpp:1087
static QPolygonF _getLineString(QgsRenderContext &context, const QgsCurve &curve, bool clipToExtent=true)
Creates a line string in screen coordinates from a QgsCurve in map coordinates.
Definition: qgssymbol.cpp:101
void setDataDefinedSize(const QgsProperty &property)
Set data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1338
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
void setClipFeaturesToExtent(bool clipFeaturesToExtent)
Sets whether features drawn by the symbol should be clipped to the render context&#39;s extent...
Definition: qgssymbol.h:287
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:257
Polygon geometry type.
Definition: qgspolygon.h:31
Draw map such that there are no problems between adjacent tiles.
const QgsCurve * exteriorRing() const
static void trimPolygon(QPolygonF &pts, const QgsRectangle &clipRect)
Definition: qgsclipper.h:202
static const QString EXPR_GEOMETRY_PART_NUM
Inbuilt variable name for geometry part number variable.
QImage bigSymbolPreviewImage(QgsExpressionContext *expressionContext=nullptr)
Returns a large (roughly 100x100 pixel) preview image for the symbol.
Definition: qgssymbol.cpp:525
QPointF offset() const
Returns the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered mar...
static const QString EXPR_GEOMETRY_PART_COUNT
Inbuilt variable name for geometry part count variable.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:427
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
Whether symbol layer is enabled.
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:418
virtual int numPoints() const =0
Returns the number of points in the curve.
qreal mOpacity
Symbol opacity (in the range 0 - 1)
Definition: qgssymbol.h:397
Hybrid symbol.
Definition: qgssymbol.h:88
QgsProperty dataDefinedWidth() const
Returns data defined width for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1631
A class to manager painter saving and restoring required for effect drawing.
double angle() const
Returns the marker angle for the whole symbol.
Definition: qgssymbol.cpp:1141
QgsFillSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Definition: qgssymbol.cpp:1760
QgsMarkerSymbol * clone() const override
Gets a deep copy of this symbol.
Definition: qgssymbol.cpp:1531
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:100
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
virtual int partCount() const =0
Returns count of parts contained in the geometry.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:208
void setOffset(double offset)
virtual void startRender(QgsSymbolRenderContext &context)=0
QgsLineSymbol * clone() const override
Gets a deep copy of this symbol.
Definition: qgssymbol.cpp:1748
virtual QString layerType() const =0
Returns a string that represents this layer type.
void setColor(const QColor &color)
Definition: qgssymbol.cpp:440
double x
Definition: qgspoint.h:41
QgsExpressionContextScope * expressionContextScope()
This scope is always available when a symbol of this type is being rendered.
Definition: qgssymbol.cpp:1075