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