QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
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 <QColor>
17 #include <QImage>
18 #include <QPainter>
19 #include <QSize>
20 #include <QSvgGenerator>
21 
22 #include <cmath>
23 #include <map>
24 #include <random>
25 
26 #include "qgssymbol.h"
27 #include "qgssymbollayer.h"
28 
29 #include "qgslinesymbollayer.h"
30 #include "qgsmarkersymbollayer.h"
31 #include "qgsfillsymbollayer.h"
34 #include "qgslogger.h"
35 #include "qgsrendercontext.h" // for bigSymbolPreview
36 #include "qgsproject.h"
37 #include "qgsstyle.h"
38 #include "qgspainteffect.h"
39 #include "qgseffectstack.h"
40 #include "qgsvectorlayer.h"
41 #include "qgsfeature.h"
42 #include "qgsgeometry.h"
43 #include "qgsmultipoint.h"
44 #include "qgsgeometrycollection.h"
45 #include "qgslinestring.h"
46 #include "qgspolygon.h"
47 #include "qgsclipper.h"
48 #include "qgsproperty.h"
49 #include "qgscolorschemeregistry.h"
50 #include "qgsapplication.h"
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 
81 Q_NOWARN_DEPRECATED_PUSH // because of deprecated mLayer
83  : mType( type )
84  , mLayers( layers )
85 {
86 
87  // check they're all correct symbol layers
88  for ( int i = 0; i < mLayers.count(); i++ )
89  {
90  if ( !mLayers.at( i ) )
91  {
92  mLayers.removeAt( i-- );
93  }
94  else if ( !mLayers.at( i )->isCompatibleWithSymbol( this ) )
95  {
96  delete mLayers.at( i );
97  mLayers.removeAt( i-- );
98  }
99  }
100 }
102 
103 QPolygonF QgsSymbol::_getLineString( QgsRenderContext &context, const QgsCurve &curve, bool clipToExtent )
104 {
105  const unsigned int nPoints = curve.numPoints();
106 
108  const QgsMapToPixel &mtp = context.mapToPixel();
109  QPolygonF pts;
110 
111  //apply clipping for large lines to achieve a better rendering performance
112  if ( clipToExtent && nPoints > 1 )
113  {
114  const QgsRectangle &e = context.extent();
115  const double cw = e.width() / 10;
116  const double ch = e.height() / 10;
117  const QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
118  pts = QgsClipper::clippedLine( curve, clipRect );
119  }
120  else
121  {
122  pts = curve.asQPolygonF();
123  }
124 
125  //transform the QPolygonF to screen coordinates
126  if ( ct.isValid() )
127  {
128  try
129  {
130  ct.transformPolygon( pts );
131  }
132  catch ( QgsCsException & )
133  {
134  // we don't abort the rendering here, instead we remove any invalid points and just plot those which ARE valid
135  }
136  }
137 
138  // remove non-finite points, e.g. infinite or NaN points caused by reprojecting errors
139  pts.erase( std::remove_if( pts.begin(), pts.end(),
140  []( const QPointF point )
141  {
142  return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
143  } ), pts.end() );
144 
145  QPointF *ptr = pts.data();
146  for ( int i = 0; i < pts.size(); ++i, ++ptr )
147  {
148  mtp.transformInPlace( ptr->rx(), ptr->ry() );
149  }
150 
151  return pts;
152 }
153 
154 QPolygonF QgsSymbol::_getPolygonRing( QgsRenderContext &context, const QgsCurve &curve, const bool clipToExtent, const bool isExteriorRing, const bool correctRingOrientation )
155 {
156  const QgsCoordinateTransform ct = context.coordinateTransform();
157  const QgsMapToPixel &mtp = context.mapToPixel();
158  const QgsRectangle &e = context.extent();
159  const double cw = e.width() / 10;
160  const double ch = e.height() / 10;
161  QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
162 
163  QPolygonF poly = curve.asQPolygonF();
164 
165  if ( curve.numPoints() < 1 )
166  return QPolygonF();
167 
168  if ( correctRingOrientation )
169  {
170  // ensure consistent polygon ring orientation
171  if ( isExteriorRing && curve.orientation() != QgsCurve::Clockwise )
172  std::reverse( poly.begin(), poly.end() );
173  else if ( !isExteriorRing && curve.orientation() != QgsCurve::CounterClockwise )
174  std::reverse( poly.begin(), poly.end() );
175  }
176 
177  //clip close to view extent, if needed
178  const QRectF ptsRect = poly.boundingRect();
179  if ( clipToExtent && !context.extent().contains( ptsRect ) )
180  {
181  QgsClipper::trimPolygon( poly, clipRect );
182  }
183 
184  //transform the QPolygonF to screen coordinates
185  if ( ct.isValid() )
186  {
187  try
188  {
189  ct.transformPolygon( poly );
190  }
191  catch ( QgsCsException & )
192  {
193  // we don't abort the rendering here, instead we remove any invalid points and just plot those which ARE valid
194  }
195  }
196 
197  // remove non-finite points, e.g. infinite or NaN points caused by reprojecting errors
198  poly.erase( std::remove_if( poly.begin(), poly.end(),
199  []( const QPointF point )
200  {
201  return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
202  } ), poly.end() );
203 
204  QPointF *ptr = poly.data();
205  for ( int i = 0; i < poly.size(); ++i, ++ptr )
206  {
207  mtp.transformInPlace( ptr->rx(), ptr->ry() );
208  }
209 
210  if ( !poly.empty() && !poly.isClosed() )
211  poly << poly.at( 0 );
212 
213  return poly;
214 }
215 
216 void QgsSymbol::_getPolygon( QPolygonF &pts, QList<QPolygonF> &holes, QgsRenderContext &context, const QgsPolygon &polygon, const bool clipToExtent, const bool correctRingOrientation )
217 {
218  holes.clear();
219 
220  pts = _getPolygonRing( context, *polygon.exteriorRing(), clipToExtent, true, correctRingOrientation );
221  for ( int idx = 0; idx < polygon.numInteriorRings(); idx++ )
222  {
223  const QPolygonF hole = _getPolygonRing( context, *( polygon.interiorRing( idx ) ), clipToExtent, false, correctRingOrientation );
224  if ( !hole.isEmpty() ) holes.append( hole );
225  }
226 }
227 
229 {
230  // delete all symbol layers (we own them, so it's okay)
231  qDeleteAll( mLayers );
232 }
233 
235 {
236  if ( mLayers.empty() )
237  {
239  }
240 
241  QgsSymbolLayerList::const_iterator it = mLayers.constBegin();
242 
243  QgsUnitTypes::RenderUnit unit = ( *it )->outputUnit();
244 
245  for ( ; it != mLayers.constEnd(); ++it )
246  {
247  if ( ( *it )->outputUnit() != unit )
248  {
250  }
251  }
252  return unit;
253 }
254 
256 {
257  if ( mLayers.empty() )
258  {
259  return QgsMapUnitScale();
260  }
261 
262  QgsSymbolLayerList::const_iterator it = mLayers.constBegin();
263  if ( it == mLayers.constEnd() )
264  return QgsMapUnitScale();
265 
266  QgsMapUnitScale scale = ( *it )->mapUnitScale();
267  ++it;
268 
269  for ( ; it != mLayers.constEnd(); ++it )
270  {
271  if ( ( *it )->mapUnitScale() != scale )
272  {
273  return QgsMapUnitScale();
274  }
275  }
276  return scale;
277 }
278 
280 {
281  const auto constMLayers = mLayers;
282  for ( QgsSymbolLayer *layer : constMLayers )
283  {
284  layer->setOutputUnit( u );
285  }
286 }
287 
289 {
290  const auto constMLayers = mLayers;
291  for ( QgsSymbolLayer *layer : constMLayers )
292  {
293  layer->setMapUnitScale( scale );
294  }
295 }
296 
298 {
299  std::unique_ptr< QgsSymbol > s;
300 
301  // override global default if project has a default for this type
302  QString defaultSymbol;
303  switch ( geomType )
304  {
306  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Marker" ) );
307  break;
309  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Line" ) );
310  break;
312  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Fill" ) );
313  break;
314  default:
315  break;
316  }
317  if ( !defaultSymbol.isEmpty() )
318  s.reset( QgsStyle::defaultStyle()->symbol( defaultSymbol ) );
319 
320  // if no default found for this type, get global default (as previously)
321  if ( !s )
322  {
323  switch ( geomType )
324  {
326  s = qgis::make_unique< QgsMarkerSymbol >();
327  break;
329  s = qgis::make_unique< QgsLineSymbol >();
330  break;
332  s = qgis::make_unique< QgsFillSymbol >();
333  break;
334  default:
335  QgsDebugMsg( QStringLiteral( "unknown layer's geometry type" ) );
336  return nullptr;
337  }
338  }
339 
340  // set opacity
341  double opacity = 1.0;
342  bool ok = false;
343  // upgrade old setting
344  double alpha = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/AlphaInt" ), 255, &ok );
345  if ( ok )
346  opacity = alpha / 255.0;
347  double newOpacity = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Opacity" ), 1.0, &ok );
348  if ( ok )
349  opacity = newOpacity;
350  s->setOpacity( opacity );
351 
352  // set random color, it project prefs allow
353  if ( defaultSymbol.isEmpty() ||
354  QgsProject::instance()->readBoolEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/RandomColors" ), true ) )
355  {
356  s->setColor( QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor() );
357  }
358 
359  return s.release();
360 }
361 
363 {
364  return mLayers.value( layer );
365 }
366 
368 {
369  return mLayers.value( layer );
370 }
371 
373 {
374  if ( index < 0 || index > mLayers.count() ) // can be added also after the last index
375  return false;
376 
377  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
378  return false;
379 
380  mLayers.insert( index, layer );
381  return true;
382 }
383 
384 
386 {
387  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
388  return false;
389 
390  mLayers.append( layer );
391  return true;
392 }
393 
394 
396 {
397  if ( index < 0 || index >= mLayers.count() )
398  return false;
399 
400  delete mLayers.at( index );
401  mLayers.removeAt( index );
402  return true;
403 }
404 
405 
407 {
408  if ( index < 0 || index >= mLayers.count() )
409  return nullptr;
410 
411  return mLayers.takeAt( index );
412 }
413 
414 
416 {
417  QgsSymbolLayer *oldLayer = mLayers.value( index );
418 
419  if ( oldLayer == layer )
420  return false;
421 
422  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
423  return false;
424 
425  delete oldLayer; // first delete the original layer
426  mLayers[index] = layer; // set new layer
427  return true;
428 }
429 
430 
431 void QgsSymbol::startRender( QgsRenderContext &context, const QgsFields &fields )
432 {
433  Q_ASSERT_X( !mStarted, "startRender", "Rendering has already been started for this symbol instance!" );
434  mStarted = true;
435 
436  mSymbolRenderContext.reset( new QgsSymbolRenderContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, false, mRenderHints, nullptr, fields ) );
437 
438  // Why do we need a copy here ? Is it to make sure the symbol layer rendering does not mess with the symbol render context ?
439  // Or is there another profound reason ?
440  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, false, mRenderHints, nullptr, fields );
441 
442  std::unique_ptr< QgsExpressionContextScope > scope( QgsExpressionContextUtils::updateSymbolScope( this, new QgsExpressionContextScope() ) );
443  mSymbolRenderContext->setExpressionContextScope( scope.release() );
444 
445  const auto constMLayers = mLayers;
446  for ( QgsSymbolLayer *layer : constMLayers )
447  {
448  if ( !layer->enabled() || !context.isSymbolLayerEnabled( layer ) )
449  continue;
450 
451  layer->prepareExpressions( symbolContext );
452  layer->startRender( symbolContext );
453  }
454 }
455 
457 {
458  Q_ASSERT_X( mStarted, "startRender", "startRender was not called for this symbol instance!" );
459  mStarted = false;
460 
461  Q_UNUSED( context )
462  if ( mSymbolRenderContext )
463  {
464  const auto constMLayers = mLayers;
465  for ( QgsSymbolLayer *layer : constMLayers )
466  {
467  if ( !layer->enabled() || !context.isSymbolLayerEnabled( layer ) )
468  continue;
469 
470  layer->stopRender( *mSymbolRenderContext );
471  }
472  }
473 
474  mSymbolRenderContext.reset( nullptr );
475 
477  mLayer = nullptr;
479 }
480 
481 void QgsSymbol::setColor( const QColor &color )
482 {
483  const auto constMLayers = mLayers;
484  for ( QgsSymbolLayer *layer : constMLayers )
485  {
486  if ( !layer->isLocked() )
487  layer->setColor( color );
488  }
489 }
490 
491 QColor QgsSymbol::color() const
492 {
493  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
494  {
495  // return color of the first unlocked layer
496  if ( !( *it )->isLocked() )
497  return ( *it )->color();
498  }
499  return QColor( 0, 0, 0 );
500 }
501 
502 void QgsSymbol::drawPreviewIcon( QPainter *painter, QSize size, QgsRenderContext *customContext, bool selected, const QgsExpressionContext *expressionContext )
503 {
504  QgsRenderContext *context = customContext;
505  std::unique_ptr< QgsRenderContext > tempContext;
506  if ( !context )
507  {
508  tempContext.reset( new QgsRenderContext( QgsRenderContext::fromQPainter( painter ) ) );
509  context = tempContext.get();
510  }
511 
512  const bool prevForceVector = context->forceVectorOutput();
513  context->setForceVectorOutput( true );
514  QgsSymbolRenderContext symbolContext( *context, QgsUnitTypes::RenderUnknownUnit, mOpacity, false, mRenderHints, nullptr );
515  symbolContext.setSelected( selected );
517 
518  if ( !customContext && expressionContext )
519  {
520  context->setExpressionContext( *expressionContext );
521  }
522  else if ( !customContext )
523  {
524  // if no render context was passed, build a minimal expression context
525  QgsExpressionContext expContext;
527  context->setExpressionContext( expContext );
528  }
529 
530  for ( QgsSymbolLayer *layer : qgis::as_const( mLayers ) )
531  {
532  if ( !layer->enabled() || ( customContext && !customContext->isSymbolLayerEnabled( layer ) ) )
533  continue;
534 
535  if ( mType == Fill && layer->type() == Line )
536  {
537  // line symbol layer would normally draw just a line
538  // so we override this case to force it to draw a polygon stroke
539  QgsLineSymbolLayer *lsl = dynamic_cast<QgsLineSymbolLayer *>( layer );
540  if ( lsl )
541  {
542  // from QgsFillSymbolLayer::drawPreviewIcon()
543  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
544  lsl->startRender( symbolContext );
545  QgsPaintEffect *effect = lsl->paintEffect();
546  if ( effect && effect->enabled() )
547  {
548  QgsEffectPainter p( symbolContext.renderContext(), effect );
549  lsl->renderPolygonStroke( poly, nullptr, symbolContext );
550  }
551  else
552  {
553  lsl->renderPolygonStroke( poly, nullptr, symbolContext );
554  }
555  lsl->stopRender( symbolContext );
556  }
557  }
558  else
559  layer->drawPreviewIcon( symbolContext, size );
560  }
561 
562  context->setForceVectorOutput( prevForceVector );
563 }
564 
565 void QgsSymbol::exportImage( const QString &path, const QString &format, QSize size )
566 {
567  if ( format.compare( QLatin1String( "svg" ), Qt::CaseInsensitive ) == 0 )
568  {
569  QSvgGenerator generator;
570  generator.setFileName( path );
571  generator.setSize( size );
572  generator.setViewBox( QRect( 0, 0, size.height(), size.height() ) );
573 
574  QPainter painter( &generator );
575  drawPreviewIcon( &painter, size );
576  painter.end();
577  }
578  else
579  {
580  QImage image = asImage( size );
581  image.save( path );
582  }
583 }
584 
585 QImage QgsSymbol::asImage( QSize size, QgsRenderContext *customContext )
586 {
587  QImage image( size, QImage::Format_ARGB32_Premultiplied );
588  image.fill( 0 );
589 
590  QPainter p( &image );
591  p.setRenderHint( QPainter::Antialiasing );
592 
593  drawPreviewIcon( &p, size, customContext );
594 
595  return image;
596 }
597 
598 
600 {
601  QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
602  preview.fill( 0 );
603 
604  QPainter p( &preview );
605  p.setRenderHint( QPainter::Antialiasing );
606  p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialiasing
607 
608  if ( mType == QgsSymbol::Marker )
609  {
610  p.setPen( QPen( Qt::gray ) );
611  p.drawLine( 0, 50, 100, 50 );
612  p.drawLine( 50, 0, 50, 100 );
613  }
614 
616  if ( expressionContext )
617  context.setExpressionContext( *expressionContext );
618 
619  context.setIsGuiPreview( true );
620  startRender( context );
621 
622  if ( mType == QgsSymbol::Line )
623  {
624  QPolygonF poly;
625  poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
626  static_cast<QgsLineSymbol *>( this )->renderPolyline( poly, nullptr, context );
627  }
628  else if ( mType == QgsSymbol::Fill )
629  {
630  QPolygonF polygon;
631  polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
632  static_cast<QgsFillSymbol *>( this )->renderPolygon( polygon, nullptr, nullptr, context );
633  }
634  else // marker
635  {
636  static_cast<QgsMarkerSymbol *>( this )->renderPoint( QPointF( 50, 50 ), nullptr, context );
637  }
638 
639  stopRender( context );
640  return preview;
641 }
642 
643 
644 QString QgsSymbol::dump() const
645 {
646  QString t;
647  switch ( type() )
648  {
649  case QgsSymbol::Marker:
650  t = QStringLiteral( "MARKER" );
651  break;
652  case QgsSymbol::Line:
653  t = QStringLiteral( "LINE" );
654  break;
655  case QgsSymbol::Fill:
656  t = QStringLiteral( "FILL" );
657  break;
658  default:
659  Q_ASSERT( false && "unknown symbol type" );
660  }
661  QString s = QStringLiteral( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerUtils::encodeColor( color() ) );
662 
663  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
664  {
665  // TODO:
666  }
667  return s;
668 }
669 
670 void QgsSymbol::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
671 {
672  props[ QStringLiteral( "alpha" )] = QString::number( opacity() );
673  double scaleFactor = 1.0;
674  props[ QStringLiteral( "uom" )] = QgsSymbolLayerUtils::encodeSldUom( outputUnit(), &scaleFactor );
675  props[ QStringLiteral( "uomScale" )] = ( !qgsDoubleNear( scaleFactor, 1.0 ) ? qgsDoubleToString( scaleFactor ) : QString() );
676 
677  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
678  {
679  ( *it )->toSld( doc, element, props );
680  }
681 }
682 
684 {
685  QgsSymbolLayerList lst;
686  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
687  {
688  QgsSymbolLayer *layer = ( *it )->clone();
689  layer->setLocked( ( *it )->isLocked() );
690  layer->setRenderingPass( ( *it )->renderingPass() );
691  layer->setEnabled( ( *it )->enabled() );
692  lst.append( layer );
693  }
694  return lst;
695 }
696 
698 {
699  Q_ASSERT( layer->type() == Hybrid );
700 
702  return;
703 
704  QgsGeometryGeneratorSymbolLayer *generatorLayer = static_cast<QgsGeometryGeneratorSymbolLayer *>( layer );
705 
706  QgsPaintEffect *effect = generatorLayer->paintEffect();
707  if ( effect && effect->enabled() )
708  {
709  QgsEffectPainter p( context.renderContext(), effect );
710  generatorLayer->render( context );
711  }
712  else
713  {
714  generatorLayer->render( context );
715  }
716 }
717 
718 QSet<QString> QgsSymbol::usedAttributes( const QgsRenderContext &context ) const
719 {
720  QSet<QString> attributes;
721  QgsSymbolLayerList::const_iterator sIt = mLayers.constBegin();
722  for ( ; sIt != mLayers.constEnd(); ++sIt )
723  {
724  if ( *sIt )
725  {
726  attributes.unite( ( *sIt )->usedAttributes( context ) );
727  }
728  }
729  return attributes;
730 }
731 
733 {
734  const auto constMLayers = mLayers;
735  for ( QgsSymbolLayer *layer : constMLayers )
736  {
737  if ( layer->hasDataDefinedProperties() )
738  return true;
739  }
740  return false;
741 }
742 
744 {
746  mLayer = layer;
748 }
749 
751 {
753  return mLayer;
755 }
756 
758 
762 class ExpressionContextScopePopper
763 {
764  public:
765 
766  ExpressionContextScopePopper() = default;
767 
768  ~ExpressionContextScopePopper()
769  {
770  if ( context )
771  context->popScope();
772  }
773 
774  QgsExpressionContext *context = nullptr;
775 };
776 
780 class GeometryRestorer
781 {
782  public:
783  GeometryRestorer( QgsRenderContext &context )
784  : mContext( context ),
785  mGeometry( context.geometry() )
786  {}
787 
788  ~GeometryRestorer()
789  {
790  mContext.setGeometry( mGeometry );
791  }
792 
793  private:
794  QgsRenderContext &mContext;
795  const QgsAbstractGeometry *mGeometry;
796 };
798 
799 void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, double currentVertexMarkerSize )
800 {
801  if ( context.renderingStopped() )
802  return;
803 
804  const QgsGeometry geom = feature.geometry();
805  if ( geom.isNull() )
806  {
807  return;
808  }
809 
810  GeometryRestorer geomRestorer( context );
811  QgsGeometry segmentizedGeometry = geom;
812  bool usingSegmentizedGeometry = false;
813  context.setGeometry( geom.constGet() );
814 
815  bool tileMapRendering = context.testFlag( QgsRenderContext::RenderMapTile );
816 
817  //convert curve types to normal point/line/polygon ones
818  if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) )
819  {
821  if ( !g )
822  {
823  return;
824  }
825  segmentizedGeometry = QgsGeometry( g );
826  usingSegmentizedGeometry = true;
827  }
828 
829  mSymbolRenderContext->setGeometryPartCount( segmentizedGeometry.constGet()->partCount() );
830  mSymbolRenderContext->setGeometryPartNum( 1 );
831 
832  bool needsExpressionContext = hasDataDefinedProperties();
833  ExpressionContextScopePopper scopePopper;
834  if ( mSymbolRenderContext->expressionContextScope() )
835  {
836  if ( needsExpressionContext )
837  {
838  // this is somewhat nasty - by appending this scope here it's now owned
839  // by both mSymbolRenderContext AND context.expressionContext()
840  // the RAII scopePopper is required to make sure it always has ownership transferred back
841  // from context.expressionContext(), even if exceptions of other early exits occur in this
842  // function
843  context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
844  scopePopper.context = &context.expressionContext();
845 
846  QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
847  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount(), true ) );
848  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1, true ) );
849  }
850  }
851 
852  // Collection of markers to paint, only used for no curve types.
853  QPolygonF markers;
854 
855  // Simplify the geometry, if needed.
857  {
858  const int simplifyHints = context.vectorSimplifyMethod().simplifyHints();
859  const QgsMapToPixelSimplifier simplifier( simplifyHints, context.vectorSimplifyMethod().tolerance(),
861  segmentizedGeometry = simplifier.simplify( segmentizedGeometry );
862  }
863 
864  QgsGeometry renderedBoundsGeom;
865 
866  startFeatureRender( feature, context, layer );
867 
868  switch ( QgsWkbTypes::flatType( segmentizedGeometry.constGet()->wkbType() ) )
869  {
870  case QgsWkbTypes::Point:
871  {
872  if ( mType != QgsSymbol::Marker )
873  {
874  QgsDebugMsg( QStringLiteral( "point can be drawn only with marker symbol!" ) );
875  break;
876  }
877 
878  const QgsPoint *point = static_cast< const QgsPoint * >( segmentizedGeometry.constGet() );
879  const QPointF pt = _getPoint( context, *point );
880  static_cast<QgsMarkerSymbol *>( this )->renderPoint( pt, &feature, context, layer, selected );
881 
883  {
884  const QRectF bounds = static_cast<QgsMarkerSymbol *>( this )->bounds( pt, context, feature );
885  if ( context.hasRenderedFeatureHandlers() )
886  {
887  renderedBoundsGeom = QgsGeometry::fromRect( QgsRectangle( bounds ) );
888  }
890  {
891  //draw debugging rect
892  context.painter()->setPen( Qt::red );
893  context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
894  context.painter()->drawRect( bounds );
895  }
896  }
897 
898  if ( drawVertexMarker && !usingSegmentizedGeometry )
899  {
900  markers << pt;
901  }
902  }
903  break;
905  {
906  if ( mType != QgsSymbol::Line )
907  {
908  QgsDebugMsg( QStringLiteral( "linestring can be drawn only with line symbol!" ) );
909  break;
910  }
911  const QgsCurve &curve = dynamic_cast<const QgsCurve &>( *segmentizedGeometry.constGet() );
912  const QPolygonF pts = _getLineString( context, curve, !tileMapRendering && clipFeaturesToExtent() );
913  static_cast<QgsLineSymbol *>( this )->renderPolyline( pts, &feature, context, layer, selected );
914 
915  if ( context.hasRenderedFeatureHandlers() )
916  renderedBoundsGeom = QgsGeometry::fromQPolygonF( pts );
917 
918  if ( drawVertexMarker && !usingSegmentizedGeometry )
919  {
920  markers = pts;
921  }
922  }
923  break;
926  {
927  QPolygonF pts;
928  QList<QPolygonF> holes;
929  if ( mType != QgsSymbol::Fill )
930  {
931  QgsDebugMsg( QStringLiteral( "polygon can be drawn only with fill symbol!" ) );
932  break;
933  }
934  const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *segmentizedGeometry.constGet() );
935  if ( !polygon.exteriorRing() )
936  {
937  QgsDebugMsg( QStringLiteral( "cannot render polygon with no exterior ring" ) );
938  break;
939  }
940  _getPolygon( pts, holes, context, polygon, !tileMapRendering && clipFeaturesToExtent(), mForceRHR );
941  static_cast<QgsFillSymbol *>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
942 
943  if ( context.hasRenderedFeatureHandlers() )
944  renderedBoundsGeom = QgsGeometry::fromQPolygonF( pts ); // TODO - consider holes?
945 
946  if ( drawVertexMarker && !usingSegmentizedGeometry )
947  {
948  markers = pts;
949 
950  const auto constHoles = holes;
951  for ( const QPolygonF &hole : constHoles )
952  {
953  markers << hole;
954  }
955  }
956  }
957  break;
958 
960  {
961  if ( mType != QgsSymbol::Marker )
962  {
963  QgsDebugMsg( QStringLiteral( "multi-point can be drawn only with marker symbol!" ) );
964  break;
965  }
966 
967  const QgsMultiPoint &mp = static_cast< const QgsMultiPoint & >( *segmentizedGeometry.constGet() );
968 
969  if ( drawVertexMarker && !usingSegmentizedGeometry )
970  {
971  markers.reserve( mp.numGeometries() );
972  }
973 
974  for ( int i = 0; i < mp.numGeometries(); ++i )
975  {
976  if ( context.renderingStopped() )
977  break;
978 
979  mSymbolRenderContext->setGeometryPartNum( i + 1 );
980  if ( needsExpressionContext )
981  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
982 
983  const QgsPoint &point = static_cast< const QgsPoint & >( *mp.geometryN( i ) );
984  const QPointF pt = _getPoint( context, point );
985  static_cast<QgsMarkerSymbol *>( this )->renderPoint( pt, &feature, context, layer, selected );
986 
987  if ( context.hasRenderedFeatureHandlers() )
988  {
989  const QRectF bounds = static_cast<QgsMarkerSymbol *>( this )->bounds( pt, context, feature );
990  renderedBoundsGeom = QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromRect( QgsRectangle( bounds ) ) << renderedBoundsGeom );
991  }
992 
993  if ( drawVertexMarker && !usingSegmentizedGeometry )
994  {
995  markers.append( pt );
996  }
997  }
998  }
999  break;
1000 
1003  {
1004  if ( mType != QgsSymbol::Line )
1005  {
1006  QgsDebugMsg( QStringLiteral( "multi-linestring can be drawn only with line symbol!" ) );
1007  break;
1008  }
1009 
1010  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
1011 
1012  const unsigned int num = geomCollection.numGeometries();
1013  for ( unsigned int i = 0; i < num; ++i )
1014  {
1015  if ( context.renderingStopped() )
1016  break;
1017 
1018  mSymbolRenderContext->setGeometryPartNum( i + 1 );
1019  if ( needsExpressionContext )
1020  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
1021 
1022  context.setGeometry( geomCollection.geometryN( i ) );
1023  const QgsCurve &curve = dynamic_cast<const QgsCurve &>( *geomCollection.geometryN( i ) );
1024  const QPolygonF pts = _getLineString( context, curve, !tileMapRendering && clipFeaturesToExtent() );
1025  static_cast<QgsLineSymbol *>( this )->renderPolyline( pts, &feature, context, layer, selected );
1026 
1027  if ( context.hasRenderedFeatureHandlers() )
1028  {
1029  renderedBoundsGeom = QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromQPolygonF( pts ) << renderedBoundsGeom );
1030  }
1031 
1032  if ( drawVertexMarker && !usingSegmentizedGeometry )
1033  {
1034  markers << pts;
1035  }
1036  }
1037  }
1038  break;
1039 
1042  {
1043  if ( mType != QgsSymbol::Fill )
1044  {
1045  QgsDebugMsg( QStringLiteral( "multi-polygon can be drawn only with fill symbol!" ) );
1046  break;
1047  }
1048 
1049  QPolygonF pts;
1050  QList<QPolygonF> holes;
1051 
1052  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
1053  const unsigned int num = geomCollection.numGeometries();
1054 
1055  // Sort components by approximate area (probably a bit faster than using
1056  // area() )
1057  std::map<double, QList<unsigned int> > mapAreaToPartNum;
1058  for ( unsigned int i = 0; i < num; ++i )
1059  {
1060  const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *geomCollection.geometryN( i ) );
1061  const QgsRectangle r( polygon.boundingBox() );
1062  mapAreaToPartNum[ r.width() * r.height()] << i;
1063  }
1064 
1065  // Draw starting with larger parts down to smaller parts, so that in
1066  // case of a part being incorrectly inside another part, it is drawn
1067  // on top of it (#15419)
1068  std::map<double, QList<unsigned int> >::const_reverse_iterator iter = mapAreaToPartNum.rbegin();
1069  for ( ; iter != mapAreaToPartNum.rend(); ++iter )
1070  {
1071  const QList<unsigned int> &listPartIndex = iter->second;
1072  for ( int idx = 0; idx < listPartIndex.size(); ++idx )
1073  {
1074  if ( context.renderingStopped() )
1075  break;
1076 
1077  const unsigned i = listPartIndex[idx];
1078  mSymbolRenderContext->setGeometryPartNum( i + 1 );
1079  if ( needsExpressionContext )
1080  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
1081 
1082  context.setGeometry( geomCollection.geometryN( i ) );
1083  const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *geomCollection.geometryN( i ) );
1084  if ( !polygon.exteriorRing() )
1085  break;
1086 
1087  _getPolygon( pts, holes, context, polygon, !tileMapRendering && clipFeaturesToExtent(), mForceRHR );
1088  static_cast<QgsFillSymbol *>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
1089 
1090  if ( context.hasRenderedFeatureHandlers() )
1091  {
1092  renderedBoundsGeom = QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromQPolygonF( pts ) << renderedBoundsGeom ); // TODO: consider holes?
1093  }
1094 
1095  if ( drawVertexMarker && !usingSegmentizedGeometry )
1096  {
1097  markers << pts;
1098 
1099  const auto constHoles = holes;
1100  for ( const QPolygonF &hole : constHoles )
1101  {
1102  markers << hole;
1103  }
1104  }
1105  }
1106  }
1107  break;
1108  }
1110  {
1111  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
1112  if ( geomCollection.numGeometries() == 0 )
1113  {
1114  // skip noise from empty geometry collections from simplification
1115  break;
1116  }
1117 
1118  FALLTHROUGH
1119  }
1120  default:
1121  QgsDebugMsg( QStringLiteral( "feature %1: unsupported wkb type %2/%3 for rendering" )
1122  .arg( feature.id() )
1123  .arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
1124  .arg( geom.wkbType(), 0, 16 ) );
1125  }
1126 
1127  stopFeatureRender( feature, context, layer );
1128 
1129  if ( context.hasRenderedFeatureHandlers() )
1130  {
1132  const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
1133  for ( QgsRenderedFeatureHandlerInterface *handler : handlers )
1134  handler->handleRenderedFeature( feature, renderedBoundsGeom, featureContext );
1135  }
1136 
1137  if ( drawVertexMarker )
1138  {
1139  if ( !markers.isEmpty() && !context.renderingStopped() )
1140  {
1141  const auto constMarkers = markers;
1142  for ( QPointF marker : constMarkers )
1143  {
1144  renderVertexMarker( marker, context, currentVertexMarkerType, currentVertexMarkerSize );
1145  }
1146  }
1147  else
1148  {
1150  const QgsMapToPixel &mtp = context.mapToPixel();
1151 
1152  QgsPoint vertexPoint;
1153  QgsVertexId vertexId;
1154  double x, y, z;
1155  QPointF mapPoint;
1156  while ( geom.constGet()->nextVertex( vertexId, vertexPoint ) )
1157  {
1158  //transform
1159  x = vertexPoint.x();
1160  y = vertexPoint.y();
1161  z = 0.0;
1162  if ( ct.isValid() )
1163  {
1164  ct.transformInPlace( x, y, z );
1165  }
1166  mapPoint.setX( x );
1167  mapPoint.setY( y );
1168  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1169  renderVertexMarker( mapPoint, context, currentVertexMarkerType, currentVertexMarkerSize );
1170  }
1171  }
1172  }
1173 }
1174 
1176 {
1177  return mSymbolRenderContext.get();
1178 }
1179 
1180 void QgsSymbol::renderVertexMarker( QPointF pt, QgsRenderContext &context, int currentVertexMarkerType, double currentVertexMarkerSize )
1181 {
1182  int markerSize = context.convertToPainterUnits( currentVertexMarkerSize, QgsUnitTypes::RenderMillimeters );
1183  QgsSymbolLayerUtils::drawVertexMarker( pt.x(), pt.y(), *context.painter(), static_cast< QgsSymbolLayerUtils::VertexMarkerType >( currentVertexMarkerType ), markerSize );
1184 }
1185 
1186 void QgsSymbol::startFeatureRender( const QgsFeature &feature, QgsRenderContext &context, const int layer )
1187 {
1188  if ( layer != -1 )
1189  {
1190  QgsSymbolLayer *symbolLayer = mLayers.value( layer );
1191  if ( symbolLayer && symbolLayer->enabled() )
1192  {
1193  symbolLayer->startFeatureRender( feature, context );
1194  }
1195  return;
1196  }
1197  else
1198  {
1199  const QList< QgsSymbolLayer * > layers = mLayers;
1200  for ( QgsSymbolLayer *symbolLayer : layers )
1201  {
1202  if ( !symbolLayer->enabled() )
1203  continue;
1204 
1205  symbolLayer->startFeatureRender( feature, context );
1206  }
1207  }
1208 }
1209 
1210 void QgsSymbol::stopFeatureRender( const QgsFeature &feature, QgsRenderContext &context, int layer )
1211 {
1212  if ( layer != -1 )
1213  {
1214  QgsSymbolLayer *symbolLayer = mLayers.value( layer );
1215  if ( symbolLayer && symbolLayer->enabled() )
1216  {
1217  symbolLayer->stopFeatureRender( feature, context );
1218  }
1219  return;
1220  }
1221  else
1222  {
1223  const QList< QgsSymbolLayer * > layers = mLayers;
1224  for ( QgsSymbolLayer *symbolLayer : layers )
1225  {
1226  if ( !symbolLayer->enabled() )
1227  continue;
1228 
1229  symbolLayer->stopFeatureRender( feature, context );
1230  }
1231  }
1232 }
1233 
1235 
1236 
1238  : mRenderContext( c )
1239  , mOutputUnit( u )
1240  , mMapUnitScale( mapUnitScale )
1241  , mOpacity( opacity )
1242  , mSelected( selected )
1243  , mRenderHints( renderHints )
1244  , mFeature( f )
1245  , mFields( fields )
1246  , mGeometryPartCount( 0 )
1247  , mGeometryPartNum( 0 )
1248 {
1249 }
1250 
1252 {
1253  mRenderContext.expressionContext().setOriginalValueVariable( value );
1254 }
1255 
1256 double QgsSymbolRenderContext::outputLineWidth( double width ) const
1257 {
1258  return mRenderContext.convertToPainterUnits( width, mOutputUnit, mMapUnitScale );
1259 }
1260 
1261 double QgsSymbolRenderContext::outputPixelSize( double size ) const
1262 {
1263  return mRenderContext.convertToPainterUnits( size, mOutputUnit, mMapUnitScale );
1264 }
1265 
1267 {
1268  // This is just a dummy implementation of assignment.
1269  // sip 4.7 generates a piece of code that needs this function to exist.
1270  // It's not generated automatically by the compiler because of
1271  // mRenderContext member which is a reference (and thus can't be changed).
1272  Q_ASSERT( false );
1273  return *this;
1274 }
1275 
1277 {
1278  return mExpressionContextScope.get();
1279 }
1280 
1282 {
1283  mExpressionContextScope.reset( contextScope );
1284 }
1285 
1287 
1289 {
1291  if ( !sl )
1292  return nullptr;
1293 
1294  QgsSymbolLayerList layers;
1295  layers.append( sl );
1296  return new QgsMarkerSymbol( layers );
1297 }
1298 
1300 {
1302  if ( !sl )
1303  return nullptr;
1304 
1305  QgsSymbolLayerList layers;
1306  layers.append( sl );
1307  return new QgsLineSymbol( layers );
1308 }
1309 
1311 {
1313  if ( !sl )
1314  return nullptr;
1315 
1316  QgsSymbolLayerList layers;
1317  layers.append( sl );
1318  return new QgsFillSymbol( layers );
1319 }
1320 
1322 
1324  : QgsSymbol( Marker, layers )
1325 {
1326  if ( mLayers.isEmpty() )
1327  mLayers.append( new QgsSimpleMarkerSymbolLayer() );
1328 }
1329 
1330 void QgsMarkerSymbol::setAngle( double symbolAngle )
1331 {
1332  double origAngle = angle();
1333  double angleDiff = symbolAngle - origAngle;
1334  const auto constMLayers = mLayers;
1335  for ( QgsSymbolLayer *layer : constMLayers )
1336  {
1337  QgsMarkerSymbolLayer *markerLayer = dynamic_cast<QgsMarkerSymbolLayer *>( layer );
1338  if ( markerLayer )
1339  markerLayer->setAngle( markerLayer->angle() + angleDiff );
1340  }
1341 }
1342 
1344 {
1345  for ( QgsSymbolLayer *layer : qgis::as_const( mLayers ) )
1346  {
1347  if ( layer->type() != QgsSymbol::Marker )
1348  continue;
1349  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1350  return markerLayer->angle();
1351  }
1352  return 0;
1353 }
1354 
1355 void QgsMarkerSymbol::setLineAngle( double lineAng )
1356 {
1357  const auto constMLayers = mLayers;
1358  for ( QgsSymbolLayer *layer : constMLayers )
1359  {
1360  if ( layer->type() != QgsSymbol::Marker )
1361  continue;
1362  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1363  markerLayer->setLineAngle( lineAng );
1364  }
1365 }
1366 
1368 {
1369  const double symbolRotation = angle();
1370 
1371 
1372  for ( QgsSymbolLayer *layer : qgis::as_const( mLayers ) )
1373  {
1374  if ( layer->type() != QgsSymbol::Marker )
1375  continue;
1376  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1377  if ( !property )
1378  {
1379  layer->setDataDefinedProperty( QgsSymbolLayer::PropertyAngle, QgsProperty() );
1380  }
1381  else
1382  {
1383  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1384  {
1385  layer->setDataDefinedProperty( QgsSymbolLayer::PropertyAngle, property );
1386  }
1387  else
1388  {
1389  QgsProperty rotatedDD = rotateWholeSymbol( markerLayer->angle() - symbolRotation, property );
1390  layer->setDataDefinedProperty( QgsSymbolLayer::PropertyAngle, rotatedDD );
1391  }
1392  }
1393  }
1394 }
1395 
1397 {
1398  const double symbolRotation = angle();
1399  QgsProperty symbolDD;
1400 
1401  // find the base of the "en masse" pattern
1402  const auto layers = mLayers;
1403  for ( QgsSymbolLayer *layer : layers )
1404  {
1405  if ( layer->type() != QgsSymbol::Marker )
1406  continue;
1407  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1408  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) && markerLayer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertyAngle ) )
1409  {
1410  symbolDD = markerLayer->dataDefinedProperties().property( QgsSymbolLayer::PropertyAngle );
1411  break;
1412  }
1413  }
1414 
1415  if ( !symbolDD )
1416  return QgsProperty();
1417 
1418  // check that all layer's angle expressions match the "en masse" pattern
1419  for ( QgsSymbolLayer *layer : layers )
1420  {
1421  if ( layer->type() != QgsSymbol::Marker )
1422  continue;
1423  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1424 
1426 
1427  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1428  {
1429  if ( !layerAngleDD || layerAngleDD != symbolDD )
1430  return QgsProperty();
1431  }
1432  else
1433  {
1434  QgsProperty rotatedDD( rotateWholeSymbol( markerLayer->angle() - symbolRotation, symbolDD ) );
1435  if ( !layerAngleDD || layerAngleDD != rotatedDD )
1436  return QgsProperty();
1437  }
1438  }
1439  return symbolDD;
1440 }
1441 
1442 
1444 {
1445  double origSize = size();
1446 
1447  const auto constMLayers = mLayers;
1448  for ( QgsSymbolLayer *layer : constMLayers )
1449  {
1450  if ( layer->type() != QgsSymbol::Marker )
1451  continue;
1452  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1453  if ( qgsDoubleNear( markerLayer->size(), origSize ) )
1454  markerLayer->setSize( s );
1455  else if ( !qgsDoubleNear( origSize, 0.0 ) )
1456  {
1457  // proportionally scale size
1458  markerLayer->setSize( markerLayer->size() * s / origSize );
1459  }
1460  // also scale offset to maintain relative position
1461  if ( !qgsDoubleNear( origSize, 0.0 ) && ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) ) )
1462  markerLayer->setOffset( QPointF( markerLayer->offset().x() * s / origSize,
1463  markerLayer->offset().y() * s / origSize ) );
1464  }
1465 }
1466 
1468 {
1469  // return size of the largest symbol
1470  double maxSize = 0;
1471  const auto constMLayers = mLayers;
1472  for ( QgsSymbolLayer *layer : constMLayers )
1473  {
1474  if ( layer->type() != QgsSymbol::Marker )
1475  continue;
1476  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1477  double lsize = markerLayer->size();
1478  if ( lsize > maxSize )
1479  maxSize = lsize;
1480  }
1481  return maxSize;
1482 }
1483 
1484 double QgsMarkerSymbol::size( const QgsRenderContext &context ) const
1485 {
1486  // return size of the largest symbol
1487  double maxSize = 0;
1488  for ( QgsSymbolLayer *layer : mLayers )
1489  {
1490  if ( layer->type() != QgsSymbol::Marker )
1491  continue;
1492  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1493  const double layerSize = context.convertToPainterUnits( markerLayer->size(), markerLayer->sizeUnit(), markerLayer->sizeMapUnitScale() );
1494  maxSize = std::max( maxSize, layerSize );
1495  }
1496  return maxSize;
1497 }
1498 
1500 {
1501  const auto constMLayers = mLayers;
1502  for ( QgsSymbolLayer *layer : constMLayers )
1503  {
1504  if ( layer->type() != QgsSymbol::Marker )
1505  continue;
1506 
1507  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1508  markerLayer->setSizeUnit( unit );
1509  }
1510 }
1511 
1513 {
1514  bool first = true;
1516 
1517  const auto constMLayers = mLayers;
1518  for ( QgsSymbolLayer *layer : constMLayers )
1519  {
1520  if ( layer->type() != QgsSymbol::Marker )
1521  continue;
1522  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1523 
1524  if ( first )
1525  unit = markerLayer->sizeUnit();
1526  else
1527  {
1528  if ( unit != markerLayer->sizeUnit() )
1530  }
1531 
1532  first = false;
1533  }
1534  return unit;
1535 }
1536 
1538 {
1539  const auto constMLayers = mLayers;
1540  for ( QgsSymbolLayer *layer : constMLayers )
1541  {
1542  if ( layer->type() != QgsSymbol::Marker )
1543  continue;
1544 
1545  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1546  markerLayer->setSizeMapUnitScale( scale );
1547  }
1548 }
1549 
1551 {
1552  const auto constMLayers = mLayers;
1553  for ( QgsSymbolLayer *layer : constMLayers )
1554  {
1555  if ( layer->type() != QgsSymbol::Marker )
1556  continue;
1557 
1558  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1559  return markerLayer->sizeMapUnitScale();
1560  }
1561  return QgsMapUnitScale();
1562 }
1563 
1565 {
1566  const double symbolSize = size();
1567 
1568  const auto constMLayers = mLayers;
1569  for ( QgsSymbolLayer *layer : constMLayers )
1570  {
1571  if ( layer->type() != QgsSymbol::Marker )
1572  continue;
1573  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1574 
1575  if ( !property )
1576  {
1579  }
1580  else
1581  {
1582  if ( qgsDoubleNear( symbolSize, 0.0 ) || qgsDoubleNear( markerLayer->size(), symbolSize ) )
1583  {
1584  markerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, property );
1585  }
1586  else
1587  {
1588  markerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, scaleWholeSymbol( markerLayer->size() / symbolSize, property ) );
1589  }
1590 
1591  if ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) )
1592  {
1594  markerLayer->offset().x() / symbolSize,
1595  markerLayer->offset().y() / symbolSize, property ) );
1596  }
1597  }
1598  }
1599 }
1600 
1602 {
1603  const double symbolSize = size();
1604 
1605  QgsProperty symbolDD;
1606 
1607  // find the base of the "en masse" pattern
1608  const auto layers = mLayers;
1609  for ( QgsSymbolLayer *layer : layers )
1610  {
1611  if ( layer->type() != QgsSymbol::Marker )
1612  continue;
1613  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1614  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) && markerLayer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertySize ) )
1615  {
1616  symbolDD = markerLayer->dataDefinedProperties().property( QgsSymbolLayer::PropertySize );
1617  break;
1618  }
1619  }
1620 
1621  if ( !symbolDD )
1622  return QgsProperty();
1623 
1624  // check that all layers size expressions match the "en masse" pattern
1625  for ( QgsSymbolLayer *layer : layers )
1626  {
1627  if ( layer->type() != QgsSymbol::Marker )
1628  continue;
1629  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1630 
1633 
1634  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) )
1635  {
1636  if ( !layerSizeDD || layerSizeDD != symbolDD )
1637  return QgsProperty();
1638  }
1639  else
1640  {
1641  if ( qgsDoubleNear( symbolSize, 0.0 ) )
1642  return QgsProperty();
1643 
1644  QgsProperty scaledDD( scaleWholeSymbol( markerLayer->size() / symbolSize, symbolDD ) );
1645  if ( !layerSizeDD || layerSizeDD != scaledDD )
1646  return QgsProperty();
1647  }
1648 
1649  QgsProperty scaledOffsetDD( scaleWholeSymbol( markerLayer->offset().x() / symbolSize, markerLayer->offset().y() / symbolSize, symbolDD ) );
1650  if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
1651  return QgsProperty();
1652  }
1653 
1654  return symbolDD;
1655 }
1656 
1658 {
1659  const auto constMLayers = mLayers;
1660  for ( QgsSymbolLayer *layer : constMLayers )
1661  {
1662  if ( layer->type() != QgsSymbol::Marker )
1663  continue;
1664  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1665  markerLayer->setScaleMethod( scaleMethod );
1666  }
1667 }
1668 
1670 {
1671  const auto constMLayers = mLayers;
1672  for ( QgsSymbolLayer *layer : constMLayers )
1673  {
1674  if ( layer->type() != QgsSymbol::Marker )
1675  continue;
1676  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1677  // return scale method of the first symbol layer
1678  return markerLayer->scaleMethod();
1679  }
1680 
1681  return DEFAULT_SCALE_METHOD;
1682 }
1683 
1684 void QgsMarkerSymbol::renderPointUsingLayer( QgsMarkerSymbolLayer *layer, QPointF point, QgsSymbolRenderContext &context )
1685 {
1686  static QPointF nullPoint( 0, 0 );
1687 
1689  return;
1690 
1691  QgsPaintEffect *effect = layer->paintEffect();
1692  if ( effect && effect->enabled() )
1693  {
1694  QgsEffectPainter p( context.renderContext() );
1695  p->translate( point );
1696  p.setEffect( effect );
1697  layer->renderPoint( nullPoint, context );
1698  }
1699  else
1700  {
1701  layer->renderPoint( point, context );
1702  }
1703 }
1704 
1705 void QgsMarkerSymbol::renderPoint( QPointF point, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1706 {
1707  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, selected, mRenderHints, f );
1708  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1709  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1710 
1711  if ( layerIdx != -1 )
1712  {
1713  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1714  if ( symbolLayer && symbolLayer->enabled() && context.isSymbolLayerEnabled( symbolLayer ) )
1715  {
1716  if ( symbolLayer->type() == QgsSymbol::Marker )
1717  {
1718  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( symbolLayer );
1719  renderPointUsingLayer( markerLayer, point, symbolContext );
1720  }
1721  else
1722  renderUsingLayer( symbolLayer, symbolContext );
1723  }
1724  return;
1725  }
1726 
1727 
1728  for ( QgsSymbolLayer *symbolLayer : qgis::as_const( mLayers ) )
1729  {
1730  if ( context.renderingStopped() )
1731  break;
1732 
1733  if ( !symbolLayer->enabled() || !context.isSymbolLayerEnabled( symbolLayer ) )
1734  continue;
1735 
1736  if ( symbolLayer->type() == QgsSymbol::Marker )
1737  {
1738  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( symbolLayer );
1739  renderPointUsingLayer( markerLayer, point, symbolContext );
1740  }
1741  else
1742  renderUsingLayer( symbolLayer, symbolContext );
1743  }
1744 }
1745 
1746 QRectF QgsMarkerSymbol::bounds( QPointF point, QgsRenderContext &context, const QgsFeature &feature ) const
1747 {
1748  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, false, mRenderHints, &feature, feature.fields() );
1749 
1750  QRectF bound;
1751  const auto constMLayers = mLayers;
1752  for ( QgsSymbolLayer *layer : constMLayers )
1753  {
1754  if ( layer->type() == QgsSymbol::Marker )
1755  {
1757  if ( bound.isNull() )
1758  bound = symbolLayer->bounds( point, symbolContext );
1759  else
1760  bound = bound.united( symbolLayer->bounds( point, symbolContext ) );
1761  }
1762  }
1763  return bound;
1764 }
1765 
1767 {
1768  QgsMarkerSymbol *cloneSymbol = new QgsMarkerSymbol( cloneLayers() );
1769  cloneSymbol->setOpacity( mOpacity );
1771  cloneSymbol->setLayer( mLayer );
1774  cloneSymbol->setForceRHR( mForceRHR );
1775  return cloneSymbol;
1776 }
1777 
1778 
1780 // LINE
1781 
1783  : QgsSymbol( Line, layers )
1784 {
1785  if ( mLayers.isEmpty() )
1786  mLayers.append( new QgsSimpleLineSymbolLayer() );
1787 }
1788 
1789 void QgsLineSymbol::setWidth( double w )
1790 {
1791  double origWidth = width();
1792 
1793  const auto constMLayers = mLayers;
1794  for ( QgsSymbolLayer *layer : constMLayers )
1795  {
1796  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
1797 
1798  if ( lineLayer )
1799  {
1800  if ( qgsDoubleNear( lineLayer->width(), origWidth ) )
1801  {
1802  lineLayer->setWidth( w );
1803  }
1804  else if ( !qgsDoubleNear( origWidth, 0.0 ) )
1805  {
1806  // proportionally scale the width
1807  lineLayer->setWidth( lineLayer->width() * w / origWidth );
1808  }
1809  // also scale offset to maintain relative position
1810  if ( !qgsDoubleNear( origWidth, 0.0 ) && !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1811  lineLayer->setOffset( lineLayer->offset() * w / origWidth );
1812  }
1813  }
1814 }
1815 
1816 double QgsLineSymbol::width() const
1817 {
1818  double maxWidth = 0;
1819  if ( mLayers.isEmpty() )
1820  return maxWidth;
1821 
1822  const auto constMLayers = mLayers;
1823  for ( QgsSymbolLayer *symbolLayer : constMLayers )
1824  {
1825  const QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( symbolLayer );
1826  if ( lineLayer )
1827  {
1828  double width = lineLayer->width();
1829  if ( width > maxWidth )
1830  maxWidth = width;
1831  }
1832  }
1833  return maxWidth;
1834 }
1835 
1836 double QgsLineSymbol::width( const QgsRenderContext &context ) const
1837 {
1838  // return width of the largest symbol
1839  double maxWidth = 0;
1840  for ( QgsSymbolLayer *layer : mLayers )
1841  {
1842  if ( layer->type() != QgsSymbol::Line )
1843  continue;
1844  const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
1845  const double layerWidth = lineLayer->width( context );
1846  maxWidth = std::max( maxWidth, layerWidth );
1847  }
1848  return maxWidth;
1849 }
1850 
1852 {
1853  const double symbolWidth = width();
1854 
1855  const auto constMLayers = mLayers;
1856  for ( QgsSymbolLayer *layer : constMLayers )
1857  {
1858  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
1859 
1860  if ( lineLayer )
1861  {
1862  if ( !property )
1863  {
1866  }
1867  else
1868  {
1869  if ( qgsDoubleNear( symbolWidth, 0.0 ) || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1870  {
1872  }
1873  else
1874  {
1875  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyStrokeWidth, scaleWholeSymbol( lineLayer->width() / symbolWidth, property ) );
1876  }
1877 
1878  if ( !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1879  {
1880  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyOffset, scaleWholeSymbol( lineLayer->offset() / symbolWidth, property ) );
1881  }
1882  }
1883  }
1884  }
1885 }
1886 
1888 {
1889  const double symbolWidth = width();
1890 
1891  QgsProperty symbolDD;
1892 
1893  // find the base of the "en masse" pattern
1894  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1895  {
1896  const QgsLineSymbolLayer *layer = dynamic_cast<const QgsLineSymbolLayer *>( *it );
1897  if ( layer && qgsDoubleNear( layer->width(), symbolWidth ) && layer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
1898  {
1900  break;
1901  }
1902  }
1903 
1904  if ( !symbolDD )
1905  return QgsProperty();
1906 
1907  // check that all layers width expressions match the "en masse" pattern
1908  const auto constMLayers = mLayers;
1909  for ( QgsSymbolLayer *layer : constMLayers )
1910  {
1911  if ( layer->type() != QgsSymbol::Line )
1912  continue;
1913  const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
1914 
1917 
1918  if ( qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1919  {
1920  if ( !layerWidthDD || layerWidthDD != symbolDD )
1921  return QgsProperty();
1922  }
1923  else
1924  {
1925  if ( qgsDoubleNear( symbolWidth, 0.0 ) )
1926  return QgsProperty();
1927 
1928  QgsProperty scaledDD( scaleWholeSymbol( lineLayer->width() / symbolWidth, symbolDD ) );
1929  if ( !layerWidthDD || layerWidthDD != scaledDD )
1930  return QgsProperty();
1931  }
1932 
1933  QgsProperty scaledOffsetDD( scaleWholeSymbol( lineLayer->offset() / symbolWidth, symbolDD ) );
1934  if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
1935  return QgsProperty();
1936  }
1937 
1938  return symbolDD;
1939 }
1940 
1941 void QgsLineSymbol::renderPolyline( const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1942 {
1943  //save old painter
1944  QPainter *renderPainter = context.painter();
1945  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, selected, mRenderHints, f );
1947  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1948  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1949 
1950  if ( layerIdx != -1 )
1951  {
1952  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1953  if ( symbolLayer && symbolLayer->enabled() && context.isSymbolLayerEnabled( symbolLayer ) )
1954  {
1955  if ( symbolLayer->type() == QgsSymbol::Line )
1956  {
1957  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
1958  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1959  }
1960  else
1961  renderUsingLayer( symbolLayer, symbolContext );
1962  }
1963  return;
1964  }
1965 
1966  const auto constMLayers = mLayers;
1967  for ( QgsSymbolLayer *symbolLayer : constMLayers )
1968  {
1969  if ( context.renderingStopped() )
1970  break;
1971 
1972  if ( !symbolLayer->enabled() || !context.isSymbolLayerEnabled( symbolLayer ) )
1973  continue;
1974 
1975  if ( symbolLayer->type() == QgsSymbol::Line )
1976  {
1977  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
1978  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1979  }
1980  else
1981  {
1982  renderUsingLayer( symbolLayer, symbolContext );
1983  }
1984  }
1985 
1986  context.setPainter( renderPainter );
1987 }
1988 
1989 void QgsLineSymbol::renderPolylineUsingLayer( QgsLineSymbolLayer *layer, const QPolygonF &points, QgsSymbolRenderContext &context )
1990 {
1992  return;
1993 
1994  QgsPaintEffect *effect = layer->paintEffect();
1995  if ( effect && effect->enabled() )
1996  {
1997  QgsEffectPainter p( context.renderContext() );
1998  p->translate( points.boundingRect().topLeft() );
1999  p.setEffect( effect );
2000  layer->renderPolyline( points.translated( -points.boundingRect().topLeft() ), context );
2001  }
2002  else
2003  {
2004  layer->renderPolyline( points, context );
2005  }
2006 }
2007 
2008 
2010 {
2011  QgsLineSymbol *cloneSymbol = new QgsLineSymbol( cloneLayers() );
2012  cloneSymbol->setOpacity( mOpacity );
2014  cloneSymbol->setLayer( mLayer );
2017  cloneSymbol->setForceRHR( mForceRHR );
2018  return cloneSymbol;
2019 }
2020 
2022 // FILL
2023 
2025  : QgsSymbol( Fill, layers )
2026 {
2027  if ( mLayers.isEmpty() )
2028  mLayers.append( new QgsSimpleFillSymbolLayer() );
2029 }
2030 
2031 void QgsFillSymbol::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
2032 {
2033  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, selected, mRenderHints, f );
2035  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
2036  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
2037 
2038  if ( layerIdx != -1 )
2039  {
2040  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
2041  if ( symbolLayer && symbolLayer->enabled() && context.isSymbolLayerEnabled( symbolLayer ) )
2042  {
2043  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
2044  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
2045  else
2046  renderUsingLayer( symbolLayer, symbolContext );
2047  }
2048  return;
2049  }
2050 
2051  const auto constMLayers = mLayers;
2052  for ( QgsSymbolLayer *symbolLayer : constMLayers )
2053  {
2054  if ( context.renderingStopped() )
2055  break;
2056 
2057  if ( !symbolLayer->enabled() || !context.isSymbolLayerEnabled( symbolLayer ) )
2058  continue;
2059 
2060  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
2061  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
2062  else
2063  renderUsingLayer( symbolLayer, symbolContext );
2064  }
2065 }
2066 
2067 void QgsFillSymbol::renderPolygonUsingLayer( QgsSymbolLayer *layer, const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
2068 {
2070  return;
2071 
2072  QgsSymbol::SymbolType layertype = layer->type();
2073 
2074  QgsPaintEffect *effect = layer->paintEffect();
2075  if ( effect && effect->enabled() )
2076  {
2077  QRectF bounds = polygonBounds( points, rings );
2078  QList<QPolygonF> *translatedRings = translateRings( rings, -bounds.left(), -bounds.top() );
2079 
2080  QgsEffectPainter p( context.renderContext() );
2081  p->translate( bounds.topLeft() );
2082  p.setEffect( effect );
2083  if ( layertype == QgsSymbol::Fill )
2084  {
2085  ( static_cast<QgsFillSymbolLayer *>( layer ) )->renderPolygon( points.translated( -bounds.topLeft() ), translatedRings, context );
2086  }
2087  else if ( layertype == QgsSymbol::Line )
2088  {
2089  ( static_cast<QgsLineSymbolLayer *>( layer ) )->renderPolygonStroke( points.translated( -bounds.topLeft() ), translatedRings, context );
2090  }
2091  delete translatedRings;
2092  }
2093  else
2094  {
2095  if ( layertype == QgsSymbol::Fill )
2096  {
2097  ( static_cast<QgsFillSymbolLayer *>( layer ) )->renderPolygon( points, rings, context );
2098  }
2099  else if ( layertype == QgsSymbol::Line )
2100  {
2101  ( static_cast<QgsLineSymbolLayer *>( layer ) )->renderPolygonStroke( points, rings, context );
2102  }
2103  }
2104 }
2105 
2106 QRectF QgsFillSymbol::polygonBounds( const QPolygonF &points, const QList<QPolygonF> *rings ) const
2107 {
2108  QRectF bounds = points.boundingRect();
2109  if ( rings )
2110  {
2111  QList<QPolygonF>::const_iterator it = rings->constBegin();
2112  for ( ; it != rings->constEnd(); ++it )
2113  {
2114  bounds = bounds.united( ( *it ).boundingRect() );
2115  }
2116  }
2117  return bounds;
2118 }
2119 
2120 QList<QPolygonF> *QgsFillSymbol::translateRings( const QList<QPolygonF> *rings, double dx, double dy ) const
2121 {
2122  if ( !rings )
2123  return nullptr;
2124 
2125  QList<QPolygonF> *translatedRings = new QList<QPolygonF>;
2126  QList<QPolygonF>::const_iterator it = rings->constBegin();
2127  for ( ; it != rings->constEnd(); ++it )
2128  {
2129  translatedRings->append( ( *it ).translated( dx, dy ) );
2130  }
2131  return translatedRings;
2132 }
2133 
2135 {
2136  QgsFillSymbol *cloneSymbol = new QgsFillSymbol( cloneLayers() );
2137  cloneSymbol->setOpacity( mOpacity );
2139  cloneSymbol->setLayer( mLayer );
2142  cloneSymbol->setForceRHR( mForceRHR );
2143  return cloneSymbol;
2144 }
2145 
2147 {
2148  const auto constMLayers = mLayers;
2149  for ( QgsSymbolLayer *layer : constMLayers )
2150  {
2151  if ( layer->type() != QgsSymbol::Fill )
2152  continue;
2153 
2154  QgsFillSymbolLayer *fillLayer = static_cast<QgsFillSymbolLayer *>( layer );
2155 
2156  if ( fillLayer )
2157  fillLayer->setAngle( angle );
2158  }
2159 }
2160 
2161 
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)
Inserts a symbol layer to specified index.
Definition: qgssymbol.cpp:372
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:1237
void setForceVectorOutput(bool force)
Sets whether rendering operations should use vector operations instead of any faster raster shortcuts...
QgsFeatureId id
Definition: qgsfeature.h:64
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:342
Single variable definition for use within a QgsExpressionContextScope.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
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 drawPreviewIcon(QPainter *painter, QSize size, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr)
Draws an icon of the symbol that occupies an area given by size using the specified painter...
Definition: qgssymbol.cpp:502
void setLineAngle(double lineAngle)
Sets the line angle modification for the symbol&#39;s angle.
void setRenderingPass(int renderingPass)
Specifies the rendering pass in which this symbol layer should be rendered.
void setLocked(bool locked)
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Returns the simplification settings to use when rendering vector layers.
QgsMapLayerType type() const
Returns the type of the layer.
static QPolygonF _getPolygonRing(QgsRenderContext &context, const QgsCurve &curve, bool clipToExtent, bool isExteriorRing=false, bool correctRingOrientation=false)
Creates a polygon ring in screen coordinates from a QgsCurve in map coordinates.
Definition: qgssymbol.cpp:154
void setMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol.
Definition: qgssymbol.cpp:288
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.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:62
void renderVertexMarker(QPointF pt, QgsRenderContext &context, int currentVertexMarkerType, double currentVertexMarkerSize)
Render editing vertex marker at specified point.
Definition: qgssymbol.cpp:1180
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)
Appends a symbol layer at the end of the current symbol layer list.
Definition: qgssymbol.cpp:385
Simple marker symbol layer, consisting of a rendered shape with solid fill color and an stroke...
virtual void setWidth(double width)
Sets the width of the line symbol layer.
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:1299
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
ScaleMethod scaleMethod()
Definition: qgssymbol.cpp:1669
const QgsMapUnitScale & sizeMapUnitScale() const
Returns the map unit scale for the symbol&#39;s size.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
Definition: qgssymbol.cpp:1310
QList< QgsRenderedFeatureHandlerInterface * > renderedFeatureHandlers() const
Returns the list of rendered feature handlers to use while rendering map layers.
QgsMapUnitScale mapUnitScale() const
Returns the map unit scale for the symbol.
Definition: qgssymbol.cpp:255
A simple line symbol layer, which renders lines using a line in a variety of styles (e...
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
void setExpressionContextScope(QgsExpressionContextScope *contextScope)
Set an expression scope for this symbol.
Definition: qgssymbol.cpp:1281
void setAngle(double angle)
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Renders the symbol along the line joining points, using the given render context. ...
Definition: qgssymbol.cpp:1941
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
Converts the symbol to a SLD representation.
Definition: qgssymbol.cpp:670
static QPointF _getPoint(QgsRenderContext &context, const QgsPoint &point)
Creates a point in screen coordinates from a QgsPoint in map coordinates.
Definition: qgssymbol.h:550
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:731
void setSize(double size)
Sets the size for the whole symbol.
Definition: qgssymbol.cpp:1443
Base class for visual effects which can be applied to QPicture drawings.
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:1537
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
bool clipFeaturesToExtent() const
Returns whether features drawn by the symbol will be clipped to the render context&#39;s extent...
Definition: qgssymbol.h:483
void setIsGuiPreview(bool preview)
Sets GUI preview mode.
Q_DECL_DEPRECATED double outputLineWidth(double width) const
Definition: qgssymbol.cpp:1256
bool mClipFeaturesToExtent
Definition: qgssymbol.h:621
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
Mixed or unknown units.
Definition: qgsunittypes.h:153
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:821
bool deleteSymbolLayer(int index)
Removes and deletes the symbol layer at the specified index.
Definition: qgssymbol.cpp:395
void setDataDefinedAngle(const QgsProperty &property)
Set data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1367
Line symbol.
Definition: qgssymbol.h:87
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
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:1330
QgsFields fields
Definition: qgsfeature.h:66
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:694
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
Returns the estimated width for the line symbol layer.
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:895
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1095
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:431
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:74
virtual void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context)=0
Renders the line symbol layer along the line joining points, using the given render context...
void transformPolygon(QPolygonF &polygon, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transforms a polygon to the destination coordinate system.
Q_DECL_DEPRECATED const QgsVectorLayer * mLayer
Definition: qgssymbol.h:624
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
bool hasRenderedFeatureHandlers() const
Returns true if the context has any rendered feature handlers.
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:234
void setOutputUnit(QgsUnitTypes::RenderUnit unit)
Sets the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:279
QgsSymbolRenderContext & operator=(const QgsSymbolRenderContext &)
Definition: qgssymbol.cpp:1266
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:84
void renderPoint(QPointF point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Renders the symbol at the specified point, using the given render context.
Definition: qgssymbol.cpp:1705
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
Definition: qgssymbol.cpp:1251
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:37
QgsProperty dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1396
SymbolType mType
Definition: qgssymbol.h:614
virtual QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition: qgscurve.cpp:223
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsSimpleMarkerSymbolLayer.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QgsSymbolLayerList mLayers
Definition: qgssymbol.h:615
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
bool mForceRHR
Definition: qgssymbol.h:622
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)
Returns an image of the symbol at the specified size.
Definition: qgssymbol.cpp:585
void exportImage(const QString &path, const QString &format, QSize size)
Export the symbol as an image format, to the specified path and with the given size.
Definition: qgssymbol.cpp:565
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:297
void setOriginalGeometryType(QgsWkbTypes::GeometryType type)
Sets the geometry type for the original feature geometry being rendered.
Definition: qgssymbol.h:791
#define FALLTHROUGH
Definition: qgis.h:763
double angle() const
Returns the rotation angle for the marker, in degrees clockwise from north.
QString dump() const
Returns a string dump of the symbol&#39;s properties.
Definition: qgssymbol.cpp:644
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 QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
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:1746
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Renders the symbol using the given render context.
Definition: qgssymbol.cpp:2031
Q_DECL_DEPRECATED double outputPixelSize(double size) const
Definition: qgssymbol.cpp:1261
void renderUsingLayer(QgsSymbolLayer *layer, QgsSymbolRenderContext &context)
Renders a context using a particular symbol layer without passing in a geometry.
Definition: qgssymbol.cpp:697
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:449
QgsFillSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:2134
void setGeometryPartNum(int num)
Sets the part number of current geometry.
Definition: qgssymbol.h:833
void setWidth(double width)
Sets the width for the whole line symbol.
Definition: qgssymbol.cpp:1789
double width() const
Returns the estimated width for the whole symbol, which is the maximum width of all marker symbol lay...
Definition: qgssymbol.cpp:1816
const QgsAbstractGeometry * geometry() const
Returns pointer to the unsegmentized geometry.
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:202
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:275
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
virtual void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context)
Called before the layer will be rendered for a particular feature.
An interface for classes which provider custom handlers for features rendered as part of a map render...
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer&#39;s property collection, used for data defined overrides...
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.
QgsMapUnitScale sizeMapUnitScale() const
Returns the size map unit scale for the whole symbol.
Definition: qgssymbol.cpp:1550
Draw bounds of symbols (for debugging/testing)
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:52
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:42
static QString encodeSldUom(QgsUnitTypes::RenderUnit unit, double *scaleFactor)
Encodes a render unit into an SLD unit of measure string.
QColor color() const
Returns the symbol&#39;s color.
Definition: qgssymbol.cpp:491
QgsSymbolRenderContext * symbolRenderContext()
Returns the symbol render context.
Definition: qgssymbol.cpp:1175
QgsSymbol::SymbolType type() const
void setScaleMethod(QgsSymbol::ScaleMethod scaleMethod)
Definition: qgssymbol.cpp:1657
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
void setSelected(bool selected)
Sets whether symbols should be rendered using the selected symbol coloring and style.
Definition: qgssymbol.h:765
bool enabled() const
Returns whether the effect is enabled.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
double offset() const
Returns the line&#39;s offset.
ScaleMethod
Scale method.
Definition: qgssymbol.h:95
Single scope for storing variables and functions for use within a QgsExpressionContext.
Abstract base class for all geometries.
void setEnabled(bool enabled)
Sets whether symbol layer is enabled and should be drawn.
void setAngle(double angle)
Definition: qgssymbol.cpp:2146
A store for object properties.
Definition: qgsproperty.h:229
QgsMarkerSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Constructor for QgsMarkerSymbol, with the specified list of initial symbol layers.
Definition: qgssymbol.cpp:1323
QgsRenderContext & renderContext()
Returns a reference to the context&#39;s render context.
Definition: qgssymbol.h:703
Implementation of GeometrySimplifier using the "MapToPixel" algorithm.
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
Definition: qgssymbol.cpp:362
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Counter-clockwise orientation.
Definition: qgscurve.h:239
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:1851
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the size units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1499
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsSimpleLineSymbolLayer, using the settings serialized in the properties map (correspo...
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:177
QgsSymbol::ScaleMethod scaleMethod() const
Returns the method to use for scaling the marker&#39;s size.
Clockwise orientation.
Definition: qgscurve.h:238
Orientation orientation() const
Returns the curve&#39;s orientation, e.g.
Definition: qgscurve.cpp:249
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the size units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1512
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...
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:103
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1601
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
bool forceVectorOutput() const
Returns true if rendering operations should use vector operations instead of any faster raster shortc...
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:139
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:732
VertexMarkerType
Editing vertex markers.
static void drawVertexMarker(double x, double y, QPainter &p, QgsSymbolLayerUtils::VertexMarkerType type, int markerSize)
Draws a vertex symbol at (painter) coordinates x, y.
bool changeSymbolLayer(int index, QgsSymbolLayer *layer)
Deletes the current layer at the specified index and replaces it with layer.
Definition: qgssymbol.cpp:415
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol&#39;s size.
Marker symbol.
Definition: qgssymbol.h:86
void reserve(int size)
Attempts to allocate memory for at least size geometries.
bool isSymbolLayerEnabled(const QgsSymbolLayer *layer) const
When rendering a map layer in a second pass (for selective masking), some symbol layers may be disabl...
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:718
Fill symbol.
Definition: qgssymbol.h:88
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.
QPainter * painter()
Returns the destination QPainter for the render operation.
const QgsMapToPixel & mapToPixel() const
Returns the context&#39;s map to pixel transform, which transforms between map coordinates and device coo...
virtual ~QgsSymbol()
Definition: qgssymbol.cpp:228
QgsSymbolLayerList cloneLayers() const
Retrieve a cloned list of all layers that make up this symbol.
Definition: qgssymbol.cpp:683
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:732
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsSimpleFillSymbolLayer using the specified properties map containing symbol propertie...
bool enabled() const
Returns true if symbol layer is enabled and will be drawn.
SymbolType type() const
Returns the symbol&#39;s type.
Definition: qgssymbol.h:121
virtual void stopRender(QgsSymbolRenderContext &context)=0
Called after a set of rendering operations has finished on the supplied render context.
Struct for storing maximum and minimum scales for measurements in map units.
void renderFeature(const QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false, int currentVertexMarkerType=0, double currentVertexMarkerSize=0.0) SIP_THROW(QgsCsException)
Render a feature.
Definition: qgssymbol.cpp:799
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the symbol&#39;s size.
RenderHints mRenderHints
Definition: qgssymbol.h:620
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:755
Q_DECL_DEPRECATED void setLayer(const QgsVectorLayer *layer)
Definition: qgssymbol.cpp:743
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
Definition: qgssymbol.cpp:1467
bool forceLocalOptimization() const
Gets where the simplification executes, after fetch the geometries from provider, or when supported...
static void _getPolygon(QPolygonF &pts, QList< QPolygonF > &holes, QgsRenderContext &context, const QgsPolygon &polygon, bool clipToExtent=true, bool correctRingOrientation=false)
Creates a polygon in screen coordinates from a QgsPolygonXYin map coordinates.
Definition: qgssymbol.cpp:216
RenderHints renderHints() const
Returns the rendering hint flags for the symbol.
Definition: qgssymbol.h:461
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:450
QgsSymbol(SymbolType type, const QgsSymbolLayerList &layers)
Definition: qgssymbol.cpp:82
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
virtual void setSize(double size)
Sets the symbol size.
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
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:167
virtual void renderPolygonStroke(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolRenderContext &context)
Renders the line symbol layer along the outline of polygon, using the given render 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:1355
QgsLineSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Constructor for QgsLineSymbol, with the specified list of initial symbol layers.
Definition: qgssymbol.cpp:1782
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:172
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)
Removes a symbol layer from the list and returns a pointer to it.
Definition: qgssymbol.cpp:406
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgssymbol.h:1190
void appendScopes(const QList< QgsExpressionContextScope *> &scopes)
Appends a list of scopes to the end of the context.
QgsSymbol * symbol(const QString &name)
Returns a NEW copy of symbol.
Definition: qgsstyle.cpp:214
QgsGeometry geometry
Definition: qgsfeature.h:67
static QgsMarkerSymbol * createSimple(const QgsStringMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
Definition: qgssymbol.cpp:1288
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
void setDataDefinedSize(const QgsProperty &property)
Set data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1564
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:472
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:442
Polygon geometry type.
Definition: qgspolygon.h:31
void setForceRHR(bool force)
Sets whether polygon features drawn by the symbol should be reoriented to follow the standard right-h...
Definition: qgssymbol.h:494
Draw map such that there are no problems between adjacent tiles.
const QgsCurve * exteriorRing() const
Returns the curve polygon&#39;s exterior ring.
virtual void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context)
Called after the layer has been rendered for a particular feature.
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:599
QPointF offset() const
Returns the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered mar...
Q_DECL_DEPRECATED const QgsVectorLayer * layer() const
Definition: qgssymbol.cpp:750
Represents a vector layer which manages a vector based data sets.
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:576
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:456
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
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:618
Hybrid symbol.
Definition: qgssymbol.h:89
QgsProperty dataDefinedWidth() const
Returns data defined width for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1887
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:1343
QgsFillSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Constructor for QgsFillSymbol, with the specified list of initial symbol layers.
Definition: qgssymbol.cpp:2024
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:1766
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:145
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:209
void setOffset(double offset)
Sets the line&#39;s offset.
virtual void startRender(QgsSymbolRenderContext &context)=0
Called before a set of rendering operations commences on the supplied render context.
QgsLineSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:2009
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:481
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:1276