QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 #include "qgsgeos.h"
55 #include "qgsmarkersymbol.h"
56 #include "qgslinesymbol.h"
57 #include "qgsfillsymbol.h"
58 
59 QgsPropertiesDefinition QgsSymbol::sPropertyDefinitions;
60 
61 Q_NOWARN_DEPRECATED_PUSH // because of deprecated mLayer
63  : mType( type )
64  , mLayers( layers )
65 {
66 
67  // check they're all correct symbol layers
68  for ( int i = 0; i < mLayers.count(); i++ )
69  {
70  if ( !mLayers.at( i ) )
71  {
72  mLayers.removeAt( i-- );
73  }
74  else if ( !mLayers.at( i )->isCompatibleWithSymbol( this ) )
75  {
76  delete mLayers.at( i );
77  mLayers.removeAt( i-- );
78  }
79  }
80 }
82 
83 QPolygonF QgsSymbol::_getLineString( QgsRenderContext &context, const QgsCurve &curve, bool clipToExtent )
84 {
85  const unsigned int nPoints = curve.numPoints();
86 
88  const QgsMapToPixel &mtp = context.mapToPixel();
89  QPolygonF pts;
90 
91  //apply clipping for large lines to achieve a better rendering performance
92  if ( clipToExtent && nPoints > 1 && !( context.flags() & QgsRenderContext::ApplyClipAfterReprojection ) )
93  {
94  const QgsRectangle e = context.extent();
95  const double cw = e.width() / 10;
96  const double ch = e.height() / 10;
97  const QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
98  pts = QgsClipper::clippedLine( curve, clipRect );
99  }
100  else
101  {
102  pts = curve.asQPolygonF();
103  }
104 
105  //transform the QPolygonF to screen coordinates
106  if ( ct.isValid() )
107  {
108  try
109  {
110  ct.transformPolygon( pts );
111  }
112  catch ( QgsCsException & )
113  {
114  // we don't abort the rendering here, instead we remove any invalid points and just plot those which ARE valid
115  }
116  }
117 
118  // remove non-finite points, e.g. infinite or NaN points caused by reprojecting errors
119  pts.erase( std::remove_if( pts.begin(), pts.end(),
120  []( const QPointF point )
121  {
122  return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
123  } ), pts.end() );
124 
125  if ( clipToExtent && nPoints > 1 && context.flags() & QgsRenderContext::ApplyClipAfterReprojection )
126  {
127  // early clipping was not possible, so we have to apply it here after transformation
128  const QgsRectangle e = context.mapExtent();
129  const double cw = e.width() / 10;
130  const double ch = e.height() / 10;
131  const QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
132  pts = QgsClipper::clippedLine( pts, clipRect );
133  }
134 
135  QPointF *ptr = pts.data();
136  for ( int i = 0; i < pts.size(); ++i, ++ptr )
137  {
138  mtp.transformInPlace( ptr->rx(), ptr->ry() );
139  }
140 
141  return pts;
142 }
143 
144 QPolygonF QgsSymbol::_getPolygonRing( QgsRenderContext &context, const QgsCurve &curve, const bool clipToExtent, const bool isExteriorRing, const bool correctRingOrientation )
145 {
146  const QgsCoordinateTransform ct = context.coordinateTransform();
147  const QgsMapToPixel &mtp = context.mapToPixel();
148 
149  QPolygonF poly = curve.asQPolygonF();
150 
151  if ( curve.numPoints() < 1 )
152  return QPolygonF();
153 
154  if ( correctRingOrientation )
155  {
156  // ensure consistent polygon ring orientation
157  if ( isExteriorRing && curve.orientation() != QgsCurve::Clockwise )
158  std::reverse( poly.begin(), poly.end() );
159  else if ( !isExteriorRing && curve.orientation() != QgsCurve::CounterClockwise )
160  std::reverse( poly.begin(), poly.end() );
161  }
162 
163  //clip close to view extent, if needed
164  if ( clipToExtent && !( context.flags() & QgsRenderContext::ApplyClipAfterReprojection ) && !context.extent().contains( poly.boundingRect() ) )
165  {
166  const QgsRectangle e = context.extent();
167  const double cw = e.width() / 10;
168  const double ch = e.height() / 10;
169  const QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
170  QgsClipper::trimPolygon( poly, clipRect );
171  }
172 
173  //transform the QPolygonF to screen coordinates
174  if ( ct.isValid() )
175  {
176  try
177  {
178  ct.transformPolygon( poly );
179  }
180  catch ( QgsCsException & )
181  {
182  // we don't abort the rendering here, instead we remove any invalid points and just plot those which ARE valid
183  }
184  }
185 
186  // remove non-finite points, e.g. infinite or NaN points caused by reprojecting errors
187  poly.erase( std::remove_if( poly.begin(), poly.end(),
188  []( const QPointF point )
189  {
190  return !std::isfinite( point.x() ) || !std::isfinite( point.y() );
191  } ), poly.end() );
192 
193  if ( clipToExtent && context.flags() & QgsRenderContext::ApplyClipAfterReprojection && !context.mapExtent().contains( poly.boundingRect() ) )
194  {
195  // early clipping was not possible, so we have to apply it here after transformation
196  const QgsRectangle e = context.mapExtent();
197  const double cw = e.width() / 10;
198  const double ch = e.height() / 10;
199  const QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
200  QgsClipper::trimPolygon( poly, clipRect );
201  }
202 
203  QPointF *ptr = poly.data();
204  for ( int i = 0; i < poly.size(); ++i, ++ptr )
205  {
206  mtp.transformInPlace( ptr->rx(), ptr->ry() );
207  }
208 
209  if ( !poly.empty() && !poly.isClosed() )
210  poly << poly.at( 0 );
211 
212  return poly;
213 }
214 
215 void QgsSymbol::_getPolygon( QPolygonF &pts, QVector<QPolygonF> &holes, QgsRenderContext &context, const QgsPolygon &polygon, const bool clipToExtent, const bool correctRingOrientation )
216 {
217  holes.clear();
218 
219  pts = _getPolygonRing( context, *polygon.exteriorRing(), clipToExtent, true, correctRingOrientation );
220  const int ringCount = polygon.numInteriorRings();
221  holes.reserve( ringCount );
222  for ( int idx = 0; idx < ringCount; idx++ )
223  {
224  const QPolygonF hole = _getPolygonRing( context, *( polygon.interiorRing( idx ) ), clipToExtent, false, correctRingOrientation );
225  if ( !hole.isEmpty() )
226  holes.append( hole );
227  }
228 }
229 
231 {
232  switch ( type )
233  {
235  return QObject::tr( "Marker" );
237  return QObject::tr( "Line" );
239  return QObject::tr( "Fill" );
241  return QObject::tr( "Hybrid" );
242  }
243  return QString();
244 }
245 
247 {
248  switch ( type )
249  {
253  return Qgis::SymbolType::Line;
255  return Qgis::SymbolType::Fill;
259  }
261 }
262 
264 {
265  QgsSymbol::initPropertyDefinitions();
266  return sPropertyDefinitions;
267 }
268 
270 {
271  // delete all symbol layers (we own them, so it's okay)
272  qDeleteAll( mLayers );
273 }
274 
276 {
277  if ( mLayers.empty() )
278  {
280  }
281 
282  QgsSymbolLayerList::const_iterator it = mLayers.constBegin();
283 
284  QgsUnitTypes::RenderUnit unit = ( *it )->outputUnit();
285 
286  for ( ; it != mLayers.constEnd(); ++it )
287  {
288  if ( ( *it )->outputUnit() != unit )
289  {
291  }
292  }
293  return unit;
294 }
295 
297 {
298  if ( mLayers.empty() )
299  {
300  return false;
301  }
302 
303  for ( const QgsSymbolLayer *layer : mLayers )
304  {
305  if ( layer->usesMapUnits() )
306  {
307  return true;
308  }
309  }
310  return false;
311 }
312 
314 {
315  if ( mLayers.empty() )
316  {
317  return QgsMapUnitScale();
318  }
319 
320  QgsSymbolLayerList::const_iterator it = mLayers.constBegin();
321  if ( it == mLayers.constEnd() )
322  return QgsMapUnitScale();
323 
324  QgsMapUnitScale scale = ( *it )->mapUnitScale();
325  ++it;
326 
327  for ( ; it != mLayers.constEnd(); ++it )
328  {
329  if ( ( *it )->mapUnitScale() != scale )
330  {
331  return QgsMapUnitScale();
332  }
333  }
334  return scale;
335 }
336 
338 {
339  const auto constMLayers = mLayers;
340  for ( QgsSymbolLayer *layer : constMLayers )
341  {
342  layer->setOutputUnit( u );
343  }
344 }
345 
347 {
348  const auto constMLayers = mLayers;
349  for ( QgsSymbolLayer *layer : constMLayers )
350  {
351  layer->setMapUnitScale( scale );
352  }
353 }
354 
356 {
357  std::unique_ptr< QgsSymbol > s;
358 
359  // override global default if project has a default for this type
360  QString defaultSymbol;
361  switch ( geomType )
362  {
364  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Marker" ) );
365  break;
367  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Line" ) );
368  break;
370  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Fill" ) );
371  break;
372  default:
373  break;
374  }
375  if ( !defaultSymbol.isEmpty() )
376  s.reset( QgsStyle::defaultStyle()->symbol( defaultSymbol ) );
377 
378  // if no default found for this type, get global default (as previously)
379  if ( !s )
380  {
381  switch ( geomType )
382  {
384  s = std::make_unique< QgsMarkerSymbol >();
385  break;
387  s = std::make_unique< QgsLineSymbol >();
388  break;
390  s = std::make_unique< QgsFillSymbol >();
391  break;
392  default:
393  QgsDebugMsg( QStringLiteral( "unknown layer's geometry type" ) );
394  return nullptr;
395  }
396  }
397 
398  // set opacity
399  double opacity = 1.0;
400  bool ok = false;
401  // upgrade old setting
402  double alpha = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/AlphaInt" ), 255, &ok );
403  if ( ok )
404  opacity = alpha / 255.0;
405  double newOpacity = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Opacity" ), 1.0, &ok );
406  if ( ok )
407  opacity = newOpacity;
408  s->setOpacity( opacity );
409 
410  // set random color, it project prefs allow
411  if ( defaultSymbol.isEmpty() ||
412  QgsProject::instance()->readBoolEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/RandomColors" ), true ) )
413  {
414  s->setColor( QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor() );
415  }
416 
417  return s.release();
418 }
419 
421 {
422  return mLayers.value( layer );
423 }
424 
425 const QgsSymbolLayer *QgsSymbol::symbolLayer( int layer ) const
426 {
427  return mLayers.value( layer );
428 }
429 
431 {
432  if ( index < 0 || index > mLayers.count() ) // can be added also after the last index
433  return false;
434 
435  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
436  return false;
437 
438  mLayers.insert( index, layer );
439  return true;
440 }
441 
442 
444 {
445  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
446  return false;
447 
448  mLayers.append( layer );
449  return true;
450 }
451 
452 
454 {
455  if ( index < 0 || index >= mLayers.count() )
456  return false;
457 
458  delete mLayers.at( index );
459  mLayers.removeAt( index );
460  return true;
461 }
462 
463 
465 {
466  if ( index < 0 || index >= mLayers.count() )
467  return nullptr;
468 
469  return mLayers.takeAt( index );
470 }
471 
472 
474 {
475  QgsSymbolLayer *oldLayer = mLayers.value( index );
476 
477  if ( oldLayer == layer )
478  return false;
479 
480  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
481  return false;
482 
483  delete oldLayer; // first delete the original layer
484  mLayers[index] = layer; // set new layer
485  return true;
486 }
487 
488 
489 void QgsSymbol::startRender( QgsRenderContext &context, const QgsFields &fields )
490 {
491  Q_ASSERT_X( !mStarted, "startRender", "Rendering has already been started for this symbol instance!" );
492  mStarted = true;
493 
494  mSymbolRenderContext.reset( new QgsSymbolRenderContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, false, mRenderHints, nullptr, fields ) );
495 
496  // Why do we need a copy here ? Is it to make sure the symbol layer rendering does not mess with the symbol render context ?
497  // Or is there another profound reason ?
498  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, false, mRenderHints, nullptr, fields );
499 
500  std::unique_ptr< QgsExpressionContextScope > scope( QgsExpressionContextUtils::updateSymbolScope( this, new QgsExpressionContextScope() ) );
501  mSymbolRenderContext->setExpressionContextScope( scope.release() );
502 
503  mDataDefinedProperties.prepare( context.expressionContext() );
504 
505  const auto constMLayers = mLayers;
506  for ( QgsSymbolLayer *layer : constMLayers )
507  {
508  if ( !layer->enabled() || !context.isSymbolLayerEnabled( layer ) )
509  continue;
510 
511  layer->prepareExpressions( symbolContext );
512  layer->startRender( symbolContext );
513  }
514 }
515 
517 {
518  Q_ASSERT_X( mStarted, "startRender", "startRender was not called for this symbol instance!" );
519  mStarted = false;
520 
521  Q_UNUSED( context )
522  if ( mSymbolRenderContext )
523  {
524  const auto constMLayers = mLayers;
525  for ( QgsSymbolLayer *layer : constMLayers )
526  {
527  if ( !layer->enabled() || !context.isSymbolLayerEnabled( layer ) )
528  continue;
529 
530  layer->stopRender( *mSymbolRenderContext );
531  }
532  }
533 
534  mSymbolRenderContext.reset( nullptr );
535 
537  mLayer = nullptr;
539 }
540 
541 void QgsSymbol::setColor( const QColor &color )
542 {
543  const auto constMLayers = mLayers;
544  for ( QgsSymbolLayer *layer : constMLayers )
545  {
546  if ( !layer->isLocked() )
547  layer->setColor( color );
548  }
549 }
550 
551 QColor QgsSymbol::color() const
552 {
553  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
554  {
555  // return color of the first unlocked layer
556  if ( !( *it )->isLocked() )
557  return ( *it )->color();
558  }
559  return QColor( 0, 0, 0 );
560 }
561 
562 void QgsSymbol::drawPreviewIcon( QPainter *painter, QSize size, QgsRenderContext *customContext, bool selected, const QgsExpressionContext *expressionContext, const QgsLegendPatchShape *patchShape )
563 {
564  QgsRenderContext *context = customContext;
565  std::unique_ptr< QgsRenderContext > tempContext;
566  if ( !context )
567  {
568  tempContext.reset( new QgsRenderContext( QgsRenderContext::fromQPainter( painter ) ) );
569  context = tempContext.get();
571  }
572 
573  const bool prevForceVector = context->forceVectorOutput();
574  context->setForceVectorOutput( true );
575 
576  const double opacity = expressionContext ? dataDefinedProperties().valueAsDouble( QgsSymbol::PropertyOpacity, *expressionContext, mOpacity ) : mOpacity;
577 
578  QgsSymbolRenderContext symbolContext( *context, QgsUnitTypes::RenderUnknownUnit, opacity, false, mRenderHints, nullptr );
579  symbolContext.setSelected( selected );
581  if ( patchShape )
582  symbolContext.setPatchShape( *patchShape );
583 
584  if ( !customContext && expressionContext )
585  {
586  context->setExpressionContext( *expressionContext );
587  }
588  else if ( !customContext )
589  {
590  // if no render context was passed, build a minimal expression context
591  QgsExpressionContext expContext;
593  context->setExpressionContext( expContext );
594  }
595 
596  for ( QgsSymbolLayer *layer : std::as_const( mLayers ) )
597  {
598  if ( !layer->enabled() || ( customContext && !customContext->isSymbolLayerEnabled( layer ) ) )
599  continue;
600 
602  {
603  // line symbol layer would normally draw just a line
604  // so we override this case to force it to draw a polygon stroke
605  QgsLineSymbolLayer *lsl = dynamic_cast<QgsLineSymbolLayer *>( layer );
606  if ( lsl )
607  {
608  // from QgsFillSymbolLayer::drawPreviewIcon() -- would be nicer to add the
609  // symbol type to QgsSymbolLayer::drawPreviewIcon so this logic could be avoided!
610 
611  // hmm... why was this using size -1 ??
612  const QSizeF targetSize = QSizeF( size.width() - 1, size.height() - 1 );
613 
614  const QList< QList< QPolygonF > > polys = patchShape ? patchShape->toQPolygonF( Qgis::SymbolType::Fill, targetSize )
616 
617  lsl->startRender( symbolContext );
618  QgsPaintEffect *effect = lsl->paintEffect();
619 
620  std::unique_ptr< QgsEffectPainter > effectPainter;
621  if ( effect && effect->enabled() )
622  effectPainter = std::make_unique< QgsEffectPainter >( symbolContext.renderContext(), effect );
623 
624  for ( const QList< QPolygonF > &poly : polys )
625  {
626  QVector< QPolygonF > rings;
627  rings.reserve( poly.size() );
628  for ( int i = 1; i < poly.size(); ++i )
629  rings << poly.at( i );
630  lsl->renderPolygonStroke( poly.value( 0 ), &rings, symbolContext );
631  }
632 
633  effectPainter.reset();
634  lsl->stopRender( symbolContext );
635  }
636  }
637  else
638  layer->drawPreviewIcon( symbolContext, size );
639  }
640 
641  context->setForceVectorOutput( prevForceVector );
642 }
643 
644 void QgsSymbol::exportImage( const QString &path, const QString &format, QSize size )
645 {
646  if ( format.compare( QLatin1String( "svg" ), Qt::CaseInsensitive ) == 0 )
647  {
648  QSvgGenerator generator;
649  generator.setFileName( path );
650  generator.setSize( size );
651  generator.setViewBox( QRect( 0, 0, size.height(), size.height() ) );
652 
653  QPainter painter( &generator );
654  drawPreviewIcon( &painter, size );
655  painter.end();
656  }
657  else
658  {
659  QImage image = asImage( size );
660  image.save( path );
661  }
662 }
663 
664 QImage QgsSymbol::asImage( QSize size, QgsRenderContext *customContext )
665 {
666  QImage image( size, QImage::Format_ARGB32_Premultiplied );
667  image.fill( 0 );
668 
669  QPainter p( &image );
670  p.setRenderHint( QPainter::Antialiasing );
671 
672  drawPreviewIcon( &p, size, customContext );
673 
674  return image;
675 }
676 
677 
678 QImage QgsSymbol::bigSymbolPreviewImage( QgsExpressionContext *expressionContext, Qgis::SymbolPreviewFlags flags )
679 {
680  QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
681  preview.fill( 0 );
682 
683  QPainter p( &preview );
684  p.setRenderHint( QPainter::Antialiasing );
685  p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialiasing
686 
688  {
689  p.setPen( QPen( Qt::gray ) );
690  p.drawLine( 0, 50, 100, 50 );
691  p.drawLine( 50, 0, 50, 100 );
692  }
693 
696  if ( expressionContext )
697  context.setExpressionContext( *expressionContext );
698 
699  context.setIsGuiPreview( true );
700  startRender( context );
701 
702  if ( mType == Qgis::SymbolType::Line )
703  {
704  QPolygonF poly;
705  poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
706  static_cast<QgsLineSymbol *>( this )->renderPolyline( poly, nullptr, context );
707  }
708  else if ( mType == Qgis::SymbolType::Fill )
709  {
710  QPolygonF polygon;
711  polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
712  static_cast<QgsFillSymbol *>( this )->renderPolygon( polygon, nullptr, nullptr, context );
713  }
714  else // marker
715  {
716  static_cast<QgsMarkerSymbol *>( this )->renderPoint( QPointF( 50, 50 ), nullptr, context );
717  }
718 
719  stopRender( context );
720  return preview;
721 }
722 
723 QImage QgsSymbol::bigSymbolPreviewImage( QgsExpressionContext *expressionContext, int flags )
724 {
725  return bigSymbolPreviewImage( expressionContext, static_cast< Qgis::SymbolPreviewFlags >( flags ) );
726 }
727 
728 QString QgsSymbol::dump() const
729 {
730  QString t;
731  switch ( type() )
732  {
734  t = QStringLiteral( "MARKER" );
735  break;
737  t = QStringLiteral( "LINE" );
738  break;
740  t = QStringLiteral( "FILL" );
741  break;
742  default:
743  Q_ASSERT( false && "unknown symbol type" );
744  }
745  QString s = QStringLiteral( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerUtils::encodeColor( color() ) );
746 
747  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
748  {
749  // TODO:
750  }
751  return s;
752 }
753 
754 void QgsSymbol::toSld( QDomDocument &doc, QDomElement &element, QVariantMap props ) const
755 {
756  props[ QStringLiteral( "alpha" )] = QString::number( opacity() );
757  double scaleFactor = 1.0;
758  props[ QStringLiteral( "uom" )] = QgsSymbolLayerUtils::encodeSldUom( outputUnit(), &scaleFactor );
759  props[ QStringLiteral( "uomScale" )] = ( !qgsDoubleNear( scaleFactor, 1.0 ) ? qgsDoubleToString( scaleFactor ) : QString() );
760 
761  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
762  {
763  ( *it )->toSld( doc, element, props );
764  }
765 }
766 
768 {
769  QgsSymbolLayerList lst;
770  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
771  {
772  QgsSymbolLayer *layer = ( *it )->clone();
773  layer->setLocked( ( *it )->isLocked() );
774  layer->setRenderingPass( ( *it )->renderingPass() );
775  layer->setEnabled( ( *it )->enabled() );
776  lst.append( layer );
777  }
778  return lst;
779 }
780 
782 {
783  Q_ASSERT( layer->type() == Qgis::SymbolType::Hybrid );
784 
785  if ( layer->dataDefinedProperties().hasActiveProperties() && !layer->dataDefinedProperties().valueAsBool( QgsSymbolLayer::PropertyLayerEnabled, context.renderContext().expressionContext(), true ) )
786  return;
787 
788  QgsGeometryGeneratorSymbolLayer *generatorLayer = static_cast<QgsGeometryGeneratorSymbolLayer *>( layer );
789 
790  QgsPaintEffect *effect = generatorLayer->paintEffect();
791  if ( effect && effect->enabled() )
792  {
793  QgsEffectPainter p( context.renderContext(), effect );
794  generatorLayer->render( context );
795  }
796  else
797  {
798  generatorLayer->render( context );
799  }
800 }
801 
802 QSet<QString> QgsSymbol::usedAttributes( const QgsRenderContext &context ) const
803 {
804  // calling referencedFields() with ignoreContext=true because in our expression context
805  // we do not have valid QgsFields yet - because of that the field names from expressions
806  // wouldn't get reported
807  QSet<QString> attributes = mDataDefinedProperties.referencedFields( context.expressionContext(), true );
808  QgsSymbolLayerList::const_iterator sIt = mLayers.constBegin();
809  for ( ; sIt != mLayers.constEnd(); ++sIt )
810  {
811  if ( *sIt )
812  {
813  attributes.unite( ( *sIt )->usedAttributes( context ) );
814  }
815  }
816  return attributes;
817 }
818 
820 {
821  mDataDefinedProperties.setProperty( key, property );
822 }
823 
825 {
826  if ( mDataDefinedProperties.hasActiveProperties() )
827  return true;
828 
829  for ( QgsSymbolLayer *layer : mLayers )
830  {
831  if ( layer->hasDataDefinedProperties() )
832  return true;
833  }
834  return false;
835 }
836 
838 {
839  for ( QgsSymbolLayer *layer : mLayers )
840  {
841  if ( layer->canCauseArtifactsBetweenAdjacentTiles() )
842  return true;
843  }
844  return false;
845 }
846 
848 {
850  mLayer = layer;
852 }
853 
855 {
857  return mLayer;
859 }
860 
862 
866 class ExpressionContextScopePopper
867 {
868  public:
869 
870  ExpressionContextScopePopper() = default;
871 
872  ~ExpressionContextScopePopper()
873  {
874  if ( context )
875  context->popScope();
876  }
877 
878  QgsExpressionContext *context = nullptr;
879 };
880 
884 class GeometryRestorer
885 {
886  public:
887  GeometryRestorer( QgsRenderContext &context )
888  : mContext( context ),
889  mGeometry( context.geometry() )
890  {}
891 
892  ~GeometryRestorer()
893  {
894  mContext.setGeometry( mGeometry );
895  }
896 
897  private:
898  QgsRenderContext &mContext;
899  const QgsAbstractGeometry *mGeometry;
900 };
902 
903 void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, double currentVertexMarkerSize )
904 {
905  if ( context.renderingStopped() )
906  return;
907 
908  const QgsGeometry geom = feature.geometry();
909  if ( geom.isNull() )
910  {
911  return;
912  }
913 
914  GeometryRestorer geomRestorer( context );
915 
916  bool usingSegmentizedGeometry = false;
917  context.setGeometry( geom.constGet() );
918 
919  if ( geom.type() != QgsWkbTypes::PointGeometry && !geom.boundingBox().isNull() )
920  {
921  try
922  {
923  const QPointF boundsOrigin = _getPoint( context, QgsPoint( geom.boundingBox().xMinimum(), geom.boundingBox().yMinimum() ) );
924  if ( std::isfinite( boundsOrigin.x() ) && std::isfinite( boundsOrigin.y() ) )
925  context.setTextureOrigin( boundsOrigin );
926  }
927  catch ( QgsCsException & )
928  {
929 
930  }
931  }
932 
933  bool clippingEnabled = clipFeaturesToExtent();
934  if ( clippingEnabled && context.testFlag( QgsRenderContext::RenderMapTile ) )
935  {
936  // If the "avoid artifacts between adjacent tiles" flag is set (RenderMapTile), then we'll force disable
937  // the geometry clipping IF (and only if) this symbol can potentially have rendering artifacts when rendered as map tiles.
938  // If the symbol won't have any artifacts anyway, then it's pointless and incredibly expensive to skip the clipping!
940  {
941  clippingEnabled = false;
942  }
943  }
944 
945  mSymbolRenderContext->setGeometryPartCount( geom.constGet()->partCount() );
946  mSymbolRenderContext->setGeometryPartNum( 1 );
947 
948  const bool needsExpressionContext = hasDataDefinedProperties();
949  ExpressionContextScopePopper scopePopper;
950  if ( mSymbolRenderContext->expressionContextScope() )
951  {
952  if ( needsExpressionContext )
953  {
954  // this is somewhat nasty - by appending this scope here it's now owned
955  // by both mSymbolRenderContext AND context.expressionContext()
956  // the RAII scopePopper is required to make sure it always has ownership transferred back
957  // from context.expressionContext(), even if exceptions of other early exits occur in this
958  // function
959  context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
960  scopePopper.context = &context.expressionContext();
961 
962  QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
963  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount(), true ) );
964  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1, true ) );
965  }
966  }
967 
968  // Collection of markers to paint, only used for no curve types.
969  QPolygonF markers;
970 
971  QgsGeometry renderedBoundsGeom;
972 
973  // Step 1 - collect the set of painter coordinate geometries to render.
974  // We do this upfront, because we only want to ever do this once, regardless how many symbol layers we need to render.
975 
976  struct PointInfo
977  {
978  QPointF renderPoint;
979  const QgsPoint *originalGeometry = nullptr;
980  };
981  QVector< PointInfo > pointsToRender;
982 
983  struct LineInfo
984  {
985  QPolygonF renderLine;
986  const QgsCurve *originalGeometry = nullptr;
987  };
988  QVector< LineInfo > linesToRender;
989 
990  struct PolygonInfo
991  {
992  QPolygonF renderExterior;
993  QVector< QPolygonF > renderRings;
994  const QgsCurvePolygon *originalGeometry = nullptr;
995  int originalPartIndex = 0;
996  };
997  QVector< PolygonInfo > polygonsToRender;
998 
999  std::function< void ( const QgsAbstractGeometry *, int partIndex )> getPartGeometry;
1000  getPartGeometry = [&pointsToRender, &linesToRender, &polygonsToRender, &getPartGeometry, &context, &clippingEnabled, &markers, &feature, &usingSegmentizedGeometry, this]( const QgsAbstractGeometry * part, int partIndex = 0 )
1001  {
1002  Q_UNUSED( feature )
1003 
1004  if ( !part )
1005  return;
1006 
1007  // geometry preprocessing
1008  QgsGeometry temporaryGeometryContainer;
1009  const QgsAbstractGeometry *processedGeometry = nullptr;
1010 
1011  const bool isMultiPart = qgsgeometry_cast< const QgsGeometryCollection * >( part ) && qgsgeometry_cast< const QgsGeometryCollection * >( part )->numGeometries() > 1;
1012 
1013  if ( !isMultiPart )
1014  {
1015  // segmentize curved geometries
1016  const bool needsSegmentizing = QgsWkbTypes::isCurvedType( part->wkbType() ) || part->hasCurvedSegments();
1017  if ( needsSegmentizing )
1018  {
1019  std::unique_ptr< QgsAbstractGeometry > segmentizedPart( part->segmentize( context.segmentationTolerance(), context.segmentationToleranceType() ) );
1020  if ( !segmentizedPart )
1021  {
1022  return;
1023  }
1024  temporaryGeometryContainer.set( segmentizedPart.release() );
1025  processedGeometry = temporaryGeometryContainer.constGet();
1026  usingSegmentizedGeometry = true;
1027  }
1028  else
1029  {
1030  // no segmentation required
1031  processedGeometry = part;
1032  }
1033 
1034  // Simplify the geometry, if needed.
1035  if ( context.vectorSimplifyMethod().forceLocalOptimization() )
1036  {
1037  const int simplifyHints = context.vectorSimplifyMethod().simplifyHints();
1038  const QgsMapToPixelSimplifier simplifier( simplifyHints, context.vectorSimplifyMethod().tolerance(),
1040 
1041  std::unique_ptr< QgsAbstractGeometry > simplified( simplifier.simplify( processedGeometry ) );
1042  if ( simplified )
1043  {
1044  temporaryGeometryContainer.set( simplified.release() );
1045  processedGeometry = temporaryGeometryContainer.constGet();
1046  }
1047  }
1048 
1049  // clip geometry to render context clipping regions
1050  if ( !context.featureClipGeometry().isEmpty() )
1051  {
1052  // apply feature clipping from context to the rendered geometry only -- just like the render time simplification,
1053  // we should NEVER apply this to the geometry attached to the feature itself. Doing so causes issues with certain
1054  // renderer settings, e.g. if polygons are being rendered using a rule based renderer based on the feature's area,
1055  // then we need to ensure that the original feature area is used instead of the clipped area..
1056  QgsGeos geos( processedGeometry );
1057  std::unique_ptr< QgsAbstractGeometry > clippedGeom( geos.intersection( context.featureClipGeometry().constGet() ) );
1058  if ( clippedGeom )
1059  {
1060  temporaryGeometryContainer.set( clippedGeom.release() );
1061  processedGeometry = temporaryGeometryContainer.constGet();
1062  }
1063  }
1064  }
1065  else
1066  {
1067  // for multipart geometries, the processing is deferred till we're rendering the actual part...
1068  processedGeometry = part;
1069  }
1070 
1071  if ( !processedGeometry )
1072  {
1073  // shouldn't happen!
1074  QgsDebugMsg( QStringLiteral( "No processed geometry to render for part!" ) );
1075  return;
1076  }
1077 
1078  switch ( QgsWkbTypes::flatType( processedGeometry->wkbType() ) )
1079  {
1080  case QgsWkbTypes::Point:
1081  {
1083  {
1084  QgsDebugMsgLevel( QStringLiteral( "point can be drawn only with marker symbol!" ), 2 );
1085  break;
1086  }
1087 
1088  PointInfo info;
1089  info.originalGeometry = qgsgeometry_cast< const QgsPoint * >( part );
1090  info.renderPoint = _getPoint( context, *info.originalGeometry );
1091  pointsToRender << info;
1092  break;
1093  }
1094 
1096  {
1097  if ( mType != Qgis::SymbolType::Line )
1098  {
1099  QgsDebugMsgLevel( QStringLiteral( "linestring can be drawn only with line symbol!" ), 2 );
1100  break;
1101  }
1102 
1103  LineInfo info;
1104  info.originalGeometry = qgsgeometry_cast<const QgsCurve *>( part );
1105  info.renderLine = _getLineString( context, *qgsgeometry_cast<const QgsCurve *>( processedGeometry ), clippingEnabled );
1106  linesToRender << info;
1107  break;
1108  }
1109 
1110  case QgsWkbTypes::Polygon:
1111  case QgsWkbTypes::Triangle:
1112  {
1113  QPolygonF pts;
1114  if ( mType != Qgis::SymbolType::Fill )
1115  {
1116  QgsDebugMsgLevel( QStringLiteral( "polygon can be drawn only with fill symbol!" ), 2 );
1117  break;
1118  }
1119 
1120  PolygonInfo info;
1121  info.originalGeometry = qgsgeometry_cast<const QgsCurvePolygon *>( part );
1122  info.originalPartIndex = partIndex;
1123  if ( !qgsgeometry_cast<const QgsPolygon *>( processedGeometry )->exteriorRing() )
1124  {
1125  QgsDebugMsg( QStringLiteral( "cannot render polygon with no exterior ring" ) );
1126  break;
1127  }
1128 
1129  _getPolygon( info.renderExterior, info.renderRings, context, *qgsgeometry_cast<const QgsPolygon *>( processedGeometry ), clippingEnabled, mForceRHR );
1130  polygonsToRender << info;
1131  break;
1132  }
1133 
1135  {
1136  const QgsMultiPoint *mp = qgsgeometry_cast< const QgsMultiPoint * >( part );
1137  markers.reserve( mp->numGeometries() );
1138  }
1139  FALLTHROUGH
1143  {
1144  const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( part );
1145 
1146  const unsigned int num = geomCollection->numGeometries();
1147  for ( unsigned int i = 0; i < num; ++i )
1148  {
1149  if ( context.renderingStopped() )
1150  break;
1151 
1152  getPartGeometry( geomCollection->geometryN( i ), i );
1153  }
1154  break;
1155  }
1156 
1159  {
1160  if ( mType != Qgis::SymbolType::Fill )
1161  {
1162  QgsDebugMsgLevel( QStringLiteral( "multi-polygon can be drawn only with fill symbol!" ), 2 );
1163  break;
1164  }
1165 
1166  QPolygonF pts;
1167 
1168  const QgsGeometryCollection *geomCollection = dynamic_cast<const QgsGeometryCollection *>( part );
1169  const unsigned int num = geomCollection->numGeometries();
1170 
1171  // Sort components by approximate area (probably a bit faster than using
1172  // area() )
1173  std::map<double, QList<unsigned int> > thisAreaToPartNum;
1174  for ( unsigned int i = 0; i < num; ++i )
1175  {
1176  const QgsRectangle r( geomCollection->geometryN( i )->boundingBox() );
1177  thisAreaToPartNum[ r.width() * r.height()] << i;
1178  }
1179 
1180  // Draw starting with larger parts down to smaller parts, so that in
1181  // case of a part being incorrectly inside another part, it is drawn
1182  // on top of it (#15419)
1183  std::map<double, QList<unsigned int> >::const_reverse_iterator iter = thisAreaToPartNum.rbegin();
1184  for ( ; iter != thisAreaToPartNum.rend(); ++iter )
1185  {
1186  const QList<unsigned int> &listPartIndex = iter->second;
1187  for ( int idx = 0; idx < listPartIndex.size(); ++idx )
1188  {
1189  const unsigned i = listPartIndex[idx];
1190  getPartGeometry( geomCollection->geometryN( i ), i );
1191  }
1192  }
1193  break;
1194  }
1195 
1196  default:
1197  QgsDebugMsg( QStringLiteral( "feature %1: unsupported wkb type %2/%3 for rendering" )
1198  .arg( feature.id() )
1199  .arg( QgsWkbTypes::displayString( part->wkbType() ) )
1200  .arg( part->wkbType(), 0, 16 ) );
1201  }
1202  };
1203 
1204  // Use the simplified type ref when rendering -- this avoids some unnecessary cloning/geometry modification
1205  // (e.g. if the original geometry is a compound curve containing only a linestring curve, we don't have
1206  // to segmentize the geometry before rendering)
1207  getPartGeometry( geom.constGet()->simplifiedTypeRef(), 0 );
1208 
1209  // step 2 - determine which layers to render
1210  std::vector< int > layers;
1211  if ( layer == -1 )
1212  {
1213  layers.reserve( mLayers.count() );
1214  for ( int i = 0; i < mLayers.count(); ++i )
1215  layers.emplace_back( i );
1216  }
1217  else
1218  {
1219  layers.emplace_back( layer );
1220  }
1221 
1222  // step 3 - render these geometries using the desired symbol layers.
1223 
1224  if ( needsExpressionContext )
1225  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_layer_count" ), mLayers.count(), true ) );
1226 
1227  for ( const int symbolLayerIndex : layers )
1228  {
1229  QgsSymbolLayer *symbolLayer = mLayers.value( symbolLayerIndex );
1230  if ( !symbolLayer || !symbolLayer->enabled() )
1231  continue;
1232 
1233  if ( needsExpressionContext )
1234  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_layer_index" ), symbolLayerIndex + 1, true ) );
1235 
1236  symbolLayer->startFeatureRender( feature, context );
1237 
1238  switch ( mType )
1239  {
1241  {
1242  int geometryPartNumber = 0;
1243  for ( const PointInfo &point : std::as_const( pointsToRender ) )
1244  {
1245  if ( context.renderingStopped() )
1246  break;
1247 
1248  mSymbolRenderContext->setGeometryPartNum( geometryPartNumber + 1 );
1249  if ( needsExpressionContext )
1250  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, geometryPartNumber + 1, true ) );
1251 
1252  static_cast<QgsMarkerSymbol *>( this )->renderPoint( point.renderPoint, &feature, context, symbolLayerIndex, selected );
1253  geometryPartNumber++;
1254  }
1255 
1256  break;
1257  }
1258 
1260  {
1261  if ( linesToRender.empty() )
1262  break;
1263 
1264  int geometryPartNumber = 0;
1265  for ( const LineInfo &line : std::as_const( linesToRender ) )
1266  {
1267  if ( context.renderingStopped() )
1268  break;
1269 
1270  mSymbolRenderContext->setGeometryPartNum( geometryPartNumber + 1 );
1271  if ( needsExpressionContext )
1272  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, geometryPartNumber + 1, true ) );
1273 
1274  context.setGeometry( line.originalGeometry );
1275  static_cast<QgsLineSymbol *>( this )->renderPolyline( line.renderLine, &feature, context, symbolLayerIndex, selected );
1276  geometryPartNumber++;
1277  }
1278  break;
1279  }
1280 
1282  {
1283  for ( const PolygonInfo &info : std::as_const( polygonsToRender ) )
1284  {
1285  if ( context.renderingStopped() )
1286  break;
1287 
1288  mSymbolRenderContext->setGeometryPartNum( info.originalPartIndex + 1 );
1289  if ( needsExpressionContext )
1290  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, info.originalPartIndex + 1, true ) );
1291 
1292  context.setGeometry( info.originalGeometry );
1293  static_cast<QgsFillSymbol *>( this )->renderPolygon( info.renderExterior, ( !info.renderRings.isEmpty() ? &info.renderRings : nullptr ), &feature, context, symbolLayerIndex, selected );
1294  }
1295 
1296  break;
1297  }
1298 
1300  break;
1301  }
1302 
1303  symbolLayer->stopFeatureRender( feature, context );
1304  }
1305 
1306  // step 4 - handle post processing steps
1307  switch ( mType )
1308  {
1310  {
1311  markers.reserve( pointsToRender.size() );
1312  for ( const PointInfo &info : std::as_const( pointsToRender ) )
1313  {
1315  {
1316  const QRectF bounds = static_cast<QgsMarkerSymbol *>( this )->bounds( info.renderPoint, context, feature );
1317  if ( context.hasRenderedFeatureHandlers() )
1318  {
1319  renderedBoundsGeom = renderedBoundsGeom.isNull() ? QgsGeometry::fromRect( bounds )
1320  : QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromRect( QgsRectangle( bounds ) ) << renderedBoundsGeom );
1321  }
1323  {
1324  //draw debugging rect
1325  context.painter()->setPen( Qt::red );
1326  context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
1327  context.painter()->drawRect( bounds );
1328  }
1329  }
1330 
1331  if ( drawVertexMarker && !usingSegmentizedGeometry )
1332  {
1333  markers.append( info.renderPoint );
1334  }
1335  }
1336  break;
1337  }
1338 
1340  {
1341  for ( const LineInfo &info : std::as_const( linesToRender ) )
1342  {
1343  if ( context.hasRenderedFeatureHandlers() && !info.renderLine.empty() )
1344  {
1345  renderedBoundsGeom = renderedBoundsGeom.isNull() ? QgsGeometry::fromQPolygonF( info.renderLine )
1346  : QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromQPolygonF( info.renderLine ) << renderedBoundsGeom );
1347  }
1348 
1349  if ( drawVertexMarker && !usingSegmentizedGeometry )
1350  {
1351  markers << info.renderLine;
1352  }
1353  }
1354  break;
1355  }
1356 
1358  {
1359  int i = 0;
1360  for ( const PolygonInfo &info : std::as_const( polygonsToRender ) )
1361  {
1362  if ( context.hasRenderedFeatureHandlers() && !info.renderExterior.empty() )
1363  {
1364  renderedBoundsGeom = renderedBoundsGeom.isNull() ? QgsGeometry::fromQPolygonF( info.renderExterior )
1365  : QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromQPolygonF( info.renderExterior ) << renderedBoundsGeom );
1366  // TODO: consider holes?
1367  }
1368 
1369  if ( drawVertexMarker && !usingSegmentizedGeometry )
1370  {
1371  markers << info.renderExterior;
1372 
1373  for ( const QPolygonF &hole : info.renderRings )
1374  {
1375  markers << hole;
1376  }
1377  }
1378  i++;
1379  }
1380  break;
1381  }
1382 
1384  break;
1385  }
1386 
1387  if ( context.hasRenderedFeatureHandlers() && !renderedBoundsGeom.isNull() )
1388  {
1390  const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
1391  for ( QgsRenderedFeatureHandlerInterface *handler : handlers )
1392  handler->handleRenderedFeature( feature, renderedBoundsGeom, featureContext );
1393  }
1394 
1395  if ( drawVertexMarker )
1396  {
1397  if ( !markers.isEmpty() && !context.renderingStopped() )
1398  {
1399  const auto constMarkers = markers;
1400  for ( QPointF marker : constMarkers )
1401  {
1402  renderVertexMarker( marker, context, currentVertexMarkerType, currentVertexMarkerSize );
1403  }
1404  }
1405  else
1406  {
1408  const QgsMapToPixel &mtp = context.mapToPixel();
1409 
1410  QgsPoint vertexPoint;
1411  QgsVertexId vertexId;
1412  double x, y, z;
1413  QPointF mapPoint;
1414  while ( geom.constGet()->nextVertex( vertexId, vertexPoint ) )
1415  {
1416  //transform
1417  x = vertexPoint.x();
1418  y = vertexPoint.y();
1419  z = 0.0;
1420  if ( ct.isValid() )
1421  {
1422  ct.transformInPlace( x, y, z );
1423  }
1424  mapPoint.setX( x );
1425  mapPoint.setY( y );
1426  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1427  renderVertexMarker( mapPoint, context, currentVertexMarkerType, currentVertexMarkerSize );
1428  }
1429  }
1430  }
1431 }
1432 
1434 {
1435  return mSymbolRenderContext.get();
1436 }
1437 
1438 void QgsSymbol::renderVertexMarker( QPointF pt, QgsRenderContext &context, int currentVertexMarkerType, double currentVertexMarkerSize )
1439 {
1440  int markerSize = context.convertToPainterUnits( currentVertexMarkerSize, QgsUnitTypes::RenderMillimeters );
1441  QgsSymbolLayerUtils::drawVertexMarker( pt.x(), pt.y(), *context.painter(), static_cast< QgsSymbolLayerUtils::VertexMarkerType >( currentVertexMarkerType ), markerSize );
1442 }
1443 
1444 void QgsSymbol::initPropertyDefinitions()
1445 {
1446  if ( !sPropertyDefinitions.isEmpty() )
1447  return;
1448 
1449  QString origin = QStringLiteral( "symbol" );
1450 
1451  sPropertyDefinitions = QgsPropertiesDefinition
1452  {
1453  { QgsSymbol::PropertyOpacity, QgsPropertyDefinition( "alpha", QObject::tr( "Opacity" ), QgsPropertyDefinition::Opacity, origin )},
1454  };
1455 }
1456 
1457 void QgsSymbol::startFeatureRender( const QgsFeature &feature, QgsRenderContext &context, const int layer )
1458 {
1459  if ( layer != -1 )
1460  {
1462  if ( symbolLayer && symbolLayer->enabled() )
1463  {
1464  symbolLayer->startFeatureRender( feature, context );
1465  }
1466  return;
1467  }
1468  else
1469  {
1470  const QList< QgsSymbolLayer * > layers = mLayers;
1471  for ( QgsSymbolLayer *symbolLayer : layers )
1472  {
1473  if ( !symbolLayer->enabled() )
1474  continue;
1475 
1476  symbolLayer->startFeatureRender( feature, context );
1477  }
1478  }
1479 }
1480 
1481 void QgsSymbol::stopFeatureRender( const QgsFeature &feature, QgsRenderContext &context, int layer )
1482 {
1483  if ( layer != -1 )
1484  {
1486  if ( symbolLayer && symbolLayer->enabled() )
1487  {
1488  symbolLayer->stopFeatureRender( feature, context );
1489  }
1490  return;
1491  }
1492  else
1493  {
1494  const QList< QgsSymbolLayer * > layers = mLayers;
1495  for ( QgsSymbolLayer *symbolLayer : layers )
1496  {
1497  if ( !symbolLayer->enabled() )
1498  continue;
1499 
1500  symbolLayer->stopFeatureRender( feature, context );
1501  }
1502  }
1503 }
@ FlagIncludeCrosshairsForMarkerSymbols
Include a crosshairs reference image in the background of marker symbol previews.
SymbolType
Symbol types.
Definition: qgis.h:168
@ Marker
Marker symbol.
@ Line
Line symbol.
@ Fill
Fill symbol.
@ Hybrid
Hybrid symbol.
Abstract base class for all geometries.
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
virtual const QgsAbstractGeometry * simplifiedTypeRef() const SIP_HOLDGIL
Returns a reference to the simplest lossless representation of this geometry, e.g.
virtual int partCount() const =0
Returns count of parts contained in the geometry.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application's color scheme registry, used for managing color schemes.
static void trimPolygon(QPolygonF &pts, const QgsRectangle &clipRect)
Definition: qgsclipper.h:210
static QPolygonF clippedLine(const QgsCurve &curve, const QgsRectangle &clipExtent)
Takes a linestring and clips it to clipExtent.
Definition: qgsclipper.cpp:41
Class for doing transforms between two map coordinate systems.
void transformPolygon(QPolygonF &polygon, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transforms a polygon to the destination coordinate system.
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...
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
Curve polygon geometry type.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
virtual int numPoints() const =0
Returns the number of points in the curve.
Orientation orientation() const
Returns the curve's orientation, e.g.
Definition: qgscurve.cpp:285
virtual QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition: qgscurve.cpp:265
@ Clockwise
Clockwise orientation.
Definition: qgscurve.h:266
@ CounterClockwise
Counter-clockwise orientation.
Definition: qgscurve.h:267
A class to manager painter saving and restoring required for effect drawing.
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbol to an expression context.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static const QString EXPR_GEOMETRY_PART_COUNT
Inbuilt variable name for geometry part count variable.
static const QString EXPR_GEOMETRY_PART_NUM
Inbuilt variable name for geometry part number variable.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsGeometry geometry
Definition: qgsfeature.h:67
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Container of fields for a vector layer.
Definition: qgsfields.h:45
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgsfillsymbol.h:30
Geometry collection.
int numGeometries() const SIP_HOLDGIL
Returns the number of geometries within the collection.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
virtual void render(QgsSymbolRenderContext &context)
Will render this symbol layer using the context.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
Q_GADGET bool isNull
Definition: qgsgeometry.h:126
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:127
void set(QgsAbstractGeometry *geometry)
Sets the underlying geometry store.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Does vector analysis using the geos library and handles import, export, exception handling*.
Definition: qgsgeos.h:104
Represents a patch shape for use in map legends.
QList< QList< QPolygonF > > toQPolygonF(Qgis::SymbolType type, QSizeF size) const
Converts the patch shape to a set of QPolygonF objects representing how the patch should be drawn for...
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.
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:30
QgsMapLayerType type
Definition: qgsmaplayer.h:77
Implementation of GeometrySimplifier using the "MapToPixel" algorithm.
SimplifyAlgorithm
Types of simplification algorithms that can be used.
QgsGeometry simplify(const QgsGeometry &geometry) const override
Returns a simplified version the specified geometry.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
void transformInPlace(double &x, double &y) const
Transforms device coordinates to map coordinates.
Struct for storing maximum and minimum scales for measurements in map units.
A marker symbol type, for rendering Point and MultiPoint geometries.
Multi point geometry collection.
Definition: qgsmultipoint.h:30
Base class for visual effects which can be applied to QPicture drawings.
bool enabled() const
Returns whether the effect is enabled.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
Q_GADGET double x
Definition: qgspoint.h:52
double y
Definition: qgspoint.h:53
Polygon geometry type.
Definition: qgspolygon.h:34
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
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.
bool readBoolEntry(const QString &scope, const QString &key, bool def=false, bool *ok=nullptr) const
Reads a boolean from the specified scope and key.
double readDoubleEntry(const QString &scope, const QString &key, double def=0, bool *ok=nullptr) const
Reads a double from the specified scope and key.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), bool ignoreContext=false) const override
Returns the set of any fields referenced by the active properties from the collection.
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
Definition for a property.
Definition: qgsproperty.h:48
@ Opacity
Opacity (0-100)
Definition: qgsproperty.h:63
A store for object properties.
Definition: qgsproperty.h:232
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
bool contains(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle contains other rectangle.
Definition: qgsrectangle.h:363
Contains information about the context of a rendering operation.
void setForceVectorOutput(bool force)
Sets whether rendering operations should use vector operations instead of any faster raster shortcuts...
void setTextureOrigin(const QPointF &origin)
Sets the texture origin, which should be used as a brush transform when rendering using QBrush object...
bool hasRenderedFeatureHandlers() const
Returns true if the context has any rendered feature handlers.
double segmentationTolerance() const
Gets the segmentation tolerance applied when rendering curved geometries.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
void setGeometry(const QgsAbstractGeometry *geometry)
Sets pointer to original (unsegmentized) geometry.
QgsGeometry featureClipGeometry() const
Returns the geometry to use to clip features at render time.
bool forceVectorOutput() const
Returns true if rendering operations should use vector operations instead of any faster raster shortc...
void setIsGuiPreview(bool preview)
Sets GUI preview mode.
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
QList< QgsRenderedFeatureHandlerInterface * > renderedFeatureHandlers() const
Returns the list of rendered feature handlers to use while rendering map layers.
@ DrawSymbolBounds
Draw bounds of symbols (for debugging/testing)
@ RenderMapTile
Draw map such that there are no problems between adjacent tiles.
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
@ ApplyClipAfterReprojection
Feature geometry clipping to mapExtent() must be performed after the geometries are transformed using...
Flags flags() const
Returns combination of flags used for rendering.
bool isSymbolLayerEnabled(const QgsSymbolLayer *layer) const
When rendering a map layer in a second pass (for selective masking), some symbol layers may be disabl...
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
QgsAbstractGeometry::SegmentationToleranceType segmentationToleranceType() const
Gets segmentation tolerance type (maximum angle or maximum difference between curve and approximation...
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Returns the simplification settings to use when rendering vector layers.
An interface for classes which provider custom handlers for features rendered as part of a map render...
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:131
QList< QList< QPolygonF > > defaultPatchAsQPolygonF(Qgis::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:1215
static QString encodeSldUom(QgsUnitTypes::RenderUnit unit, double *scaleFactor)
Encodes a render unit into an SLD unit of measure string.
static QString encodeColor(const QColor &color)
VertexMarkerType
Editing vertex markers.
static void drawVertexMarker(double x, double y, QPainter &p, QgsSymbolLayerUtils::VertexMarkerType type, int markerSize)
Draws a vertex symbol at (painter) coordinates x, y.
@ PropertyLayerEnabled
Whether symbol layer is enabled.
virtual void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context)
Called before the layer will be rendered for a particular feature.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
virtual void startRender(QgsSymbolRenderContext &context)=0
Called before a set of rendering operations commences on the supplied render context.
bool enabled() const
Returns true if symbol layer is enabled and will be drawn.
virtual void stopRender(QgsSymbolRenderContext &context)=0
Called after a set of rendering operations has finished on the supplied render context.
virtual void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context)
Called after the layer has been rendered for a particular feature.
void setSelected(bool selected)
Sets whether symbols should be rendered using the selected symbol coloring and style.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
void setPatchShape(const QgsLegendPatchShape &shape)
Sets the symbol patch shape, to use if rendering symbol preview icons.
void setOriginalGeometryType(QgsWkbTypes::GeometryType type)
Sets the geometry type for the original feature geometry being rendered.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:38
QgsSymbolLayerList cloneLayers() const
Retrieve a cloned list of all layers that make up this symbol.
Definition: qgssymbol.cpp:767
QgsSymbolRenderContext * symbolRenderContext()
Returns the symbol render context.
Definition: qgssymbol.cpp:1433
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
Definition: qgssymbol.cpp:420
Property
Data definable properties.
Definition: qgssymbol.h:75
@ PropertyOpacity
Opacity.
Definition: qgssymbol.h:76
void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the symbol.
Definition: qgssymbol.cpp:819
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:83
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:516
qreal mOpacity
Symbol opacity (in the range 0 - 1)
Definition: qgssymbol.h:707
Q_DECL_DEPRECATED const QgsVectorLayer * mLayer
Definition: qgssymbol.h:721
void setOutputUnit(QgsUnitTypes::RenderUnit unit)
Sets the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:337
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:144
static Qgis::SymbolType symbolTypeForGeometryType(QgsWkbTypes::GeometryType type)
Returns the default symbol type required for the specified geometry type.
Definition: qgssymbol.cpp:246
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:562
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:903
static QPointF _getPoint(QgsRenderContext &context, const QgsPoint &point)
Creates a point in screen coordinates from a QgsPoint in map coordinates.
Definition: qgssymbol.h:639
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the symbol property definitions.
Definition: qgssymbol.cpp:263
bool appendSymbolLayer(QgsSymbolLayer *layer)
Appends a symbol layer at the end of the current symbol layer list.
Definition: qgssymbol.cpp:443
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:355
bool usesMapUnits() const
Returns true if the symbol has any components which use map unit based sizes.
Definition: qgssymbol.cpp:296
QgsUnitTypes::RenderUnit outputUnit() const
Returns the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:275
Qgis::SymbolFlags flags() const
Returns flags for the symbol.
Definition: qgssymbol.h:475
void toSld(QDomDocument &doc, QDomElement &element, QVariantMap props) const
Converts the symbol to a SLD representation.
Definition: qgssymbol.cpp:754
bool insertSymbolLayer(int index, QgsSymbolLayer *layer)
Inserts a symbol layer to specified index.
Definition: qgssymbol.cpp:430
QgsMapUnitScale mapUnitScale() const
Returns the map unit scale for the symbol.
Definition: qgssymbol.cpp:313
static QString symbolTypeToString(Qgis::SymbolType type)
Returns a translated string version of the specified symbol type.
Definition: qgssymbol.cpp:230
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:440
bool canCauseArtifactsBetweenAdjacentTiles() const
Returns true if the symbol rendering can cause visible artifacts across a single feature when the fea...
Definition: qgssymbol.cpp:837
bool clipFeaturesToExtent() const
Returns whether features drawn by the symbol will be clipped to the render context's extent.
Definition: qgssymbol.h:497
QImage asImage(QSize size, QgsRenderContext *customContext=nullptr)
Returns an image of the symbol at the specified size.
Definition: qgssymbol.cpp:664
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:215
QString dump() const
Returns a string dump of the symbol's properties.
Definition: qgssymbol.cpp:728
bool hasDataDefinedProperties() const
Returns whether the symbol utilizes any data defined properties.
Definition: qgssymbol.cpp:824
bool deleteSymbolLayer(int index)
Removes and deletes the symbol layer at the specified index.
Definition: qgssymbol.cpp:453
virtual ~QgsSymbol()
Definition: qgssymbol.cpp:269
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
Definition: qgssymbol.cpp:802
QImage bigSymbolPreviewImage(QgsExpressionContext *expressionContext=nullptr, Qgis::SymbolPreviewFlags flags=Qgis::SymbolPreviewFlag::FlagIncludeCrosshairsForMarkerSymbols)
Returns a large (roughly 100x100 pixel) preview image for the symbol.
Definition: qgssymbol.cpp:678
Qgis::SymbolType mType
Definition: qgssymbol.h:703
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:541
bool changeSymbolLayer(int index, QgsSymbolLayer *layer)
Deletes the current layer at the specified index and replaces it with layer.
Definition: qgssymbol.cpp:473
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol's property collection, used for data defined overrides.
Definition: qgssymbol.h:543
QgsSymbolLayer * takeSymbolLayer(int index)
Removes a symbol layer from the list and returns a pointer to it.
Definition: qgssymbol.cpp:464
Qgis::SymbolRenderHints mRenderHints
Definition: qgssymbol.h:709
void setMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol.
Definition: qgssymbol.cpp:346
bool mForceRHR
Definition: qgssymbol.h:719
QgsSymbolLayerList mLayers
Definition: qgssymbol.h:704
Q_DECL_DEPRECATED const QgsVectorLayer * layer() const
Definition: qgssymbol.cpp:854
void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context, int layer=-1)
Called before symbol layers will be rendered for a particular feature.
Definition: qgssymbol.cpp:1457
void renderUsingLayer(QgsSymbolLayer *layer, QgsSymbolRenderContext &context)
Renders a context using a particular symbol layer without passing in a geometry.
Definition: qgssymbol.cpp:781
QColor color() const
Returns the symbol's color.
Definition: qgssymbol.cpp:551
Qgis::SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:97
QgsSymbol(Qgis::SymbolType type, const QgsSymbolLayerList &layers)
Constructor for a QgsSymbol of the specified type.
Definition: qgssymbol.cpp:62
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:489
Q_DECL_DEPRECATED void setLayer(const QgsVectorLayer *layer)
Definition: qgssymbol.cpp:847
void renderVertexMarker(QPointF pt, QgsRenderContext &context, int currentVertexMarkerType, double currentVertexMarkerSize)
Render editing vertex marker at specified point.
Definition: qgssymbol.cpp:1438
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:644
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context, int layer=-1)
Called after symbol layers have been rendered for a particular feature.
Definition: qgssymbol.cpp:1481
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:168
@ RenderUnknownUnit
Mixed or unknown units.
Definition: qgsunittypes.h:175
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
Represents a vector layer which manages a vector based data sets.
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
double tolerance() const
Gets the tolerance of simplification in map units. Represents the maximum distance in map units betwe...
bool forceLocalOptimization() const
Gets where the simplification executes, after fetch the geometries from provider, or when supported,...
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
SimplifyAlgorithm simplifyAlgorithm() const
Gets the local simplification algorithm of the vector layer managed.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
@ GeometryCollection
Definition: qgswkbtypes.h:79
static QString displayString(Type type) SIP_HOLDGIL
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
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
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:702
Contains geos related utilities and functions.
Definition: qgsgeos.h:42
#define FALLTHROUGH
Definition: qgis.h:1111
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:1080
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:550
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:1079
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:598
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:27
Single variable definition for use within a QgsExpressionContextScope.
Utility class for identifying a unique vertex within a geometry.