QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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() & Qgis::RenderContextFlag::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() & Qgis::RenderContextFlag::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() != Qgis::AngularDirection::Clockwise )
158  std::reverse( poly.begin(), poly.end() );
159  else if ( !isExteriorRing && curve.orientation() != Qgis::AngularDirection::CounterClockwise )
160  std::reverse( poly.begin(), poly.end() );
161  }
162 
163  //clip close to view extent, if needed
164  if ( clipToExtent && !( context.flags() & Qgis::RenderContextFlag::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() & Qgis::RenderContextFlag::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 ( const QgsSymbolLayer *layer : mLayers )
554  {
555  // return color of the first unlocked layer
556  if ( !layer->isLocked() )
557  {
558  const QColor layerColor = layer->color();
559  if ( layerColor.isValid() )
560  return layerColor;
561  }
562  }
563  return QColor( 0, 0, 0 );
564 }
565 
566 void QgsSymbol::drawPreviewIcon( QPainter *painter, QSize size, QgsRenderContext *customContext, bool selected, const QgsExpressionContext *expressionContext, const QgsLegendPatchShape *patchShape )
567 {
568  QgsRenderContext *context = customContext;
569  std::unique_ptr< QgsRenderContext > tempContext;
570  if ( !context )
571  {
572  tempContext.reset( new QgsRenderContext( QgsRenderContext::fromQPainter( painter ) ) );
573  context = tempContext.get();
575  }
576 
577  const bool prevForceVector = context->forceVectorOutput();
578  context->setForceVectorOutput( true );
579 
580  const double opacity = expressionContext ? dataDefinedProperties().valueAsDouble( QgsSymbol::PropertyOpacity, *expressionContext, mOpacity ) : mOpacity;
581 
582  QgsSymbolRenderContext symbolContext( *context, QgsUnitTypes::RenderUnknownUnit, opacity, false, mRenderHints, nullptr );
583  symbolContext.setSelected( selected );
584  switch ( mType )
585  {
588  break;
591  break;
594  break;
597  break;
598  }
599 
600  if ( patchShape )
601  symbolContext.setPatchShape( *patchShape );
602 
603  if ( !customContext && expressionContext )
604  {
605  context->setExpressionContext( *expressionContext );
606  }
607  else if ( !customContext )
608  {
609  // if no render context was passed, build a minimal expression context
610  QgsExpressionContext expContext;
612  context->setExpressionContext( expContext );
613  }
614 
615  for ( QgsSymbolLayer *layer : std::as_const( mLayers ) )
616  {
617  if ( !layer->enabled() || ( customContext && !customContext->isSymbolLayerEnabled( layer ) ) )
618  continue;
619 
621  {
622  // line symbol layer would normally draw just a line
623  // so we override this case to force it to draw a polygon stroke
624  QgsLineSymbolLayer *lsl = dynamic_cast<QgsLineSymbolLayer *>( layer );
625  if ( lsl )
626  {
627  // from QgsFillSymbolLayer::drawPreviewIcon() -- would be nicer to add the
628  // symbol type to QgsSymbolLayer::drawPreviewIcon so this logic could be avoided!
629 
630  // hmm... why was this using size -1 ??
631  const QSizeF targetSize = QSizeF( size.width() - 1, size.height() - 1 );
632 
633  const QList< QList< QPolygonF > > polys = patchShape ? patchShape->toQPolygonF( Qgis::SymbolType::Fill, targetSize )
635 
636  lsl->startRender( symbolContext );
637  QgsPaintEffect *effect = lsl->paintEffect();
638 
639  std::unique_ptr< QgsEffectPainter > effectPainter;
640  if ( effect && effect->enabled() )
641  effectPainter = std::make_unique< QgsEffectPainter >( symbolContext.renderContext(), effect );
642 
643  for ( const QList< QPolygonF > &poly : polys )
644  {
645  QVector< QPolygonF > rings;
646  rings.reserve( poly.size() );
647  for ( int i = 1; i < poly.size(); ++i )
648  rings << poly.at( i );
649  lsl->renderPolygonStroke( poly.value( 0 ), &rings, symbolContext );
650  }
651 
652  effectPainter.reset();
653  lsl->stopRender( symbolContext );
654  }
655  }
656  else
657  layer->drawPreviewIcon( symbolContext, size );
658  }
659 
660  context->setForceVectorOutput( prevForceVector );
661 }
662 
663 void QgsSymbol::exportImage( const QString &path, const QString &format, QSize size )
664 {
665  if ( format.compare( QLatin1String( "svg" ), Qt::CaseInsensitive ) == 0 )
666  {
667  QSvgGenerator generator;
668  generator.setFileName( path );
669  generator.setSize( size );
670  generator.setViewBox( QRect( 0, 0, size.height(), size.height() ) );
671 
672  QPainter painter( &generator );
673  drawPreviewIcon( &painter, size );
674  painter.end();
675  }
676  else
677  {
678  QImage image = asImage( size );
679  image.save( path );
680  }
681 }
682 
683 QImage QgsSymbol::asImage( QSize size, QgsRenderContext *customContext )
684 {
685  QImage image( size, QImage::Format_ARGB32_Premultiplied );
686  image.fill( 0 );
687 
688  QPainter p( &image );
689  p.setRenderHint( QPainter::Antialiasing );
690  p.setRenderHint( QPainter::SmoothPixmapTransform );
691 
692  drawPreviewIcon( &p, size, customContext );
693 
694  return image;
695 }
696 
697 
698 QImage QgsSymbol::bigSymbolPreviewImage( QgsExpressionContext *expressionContext, Qgis::SymbolPreviewFlags flags )
699 {
700  QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
701  preview.fill( 0 );
702 
703  QPainter p( &preview );
704  p.setRenderHint( QPainter::Antialiasing );
705  p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialiasing
706 
708  {
709  p.setPen( QPen( Qt::gray ) );
710  p.drawLine( 0, 50, 100, 50 );
711  p.drawLine( 50, 0, 50, 100 );
712  }
713 
718  context.setPainterFlagsUsingContext( &p );
719  if ( expressionContext )
720  context.setExpressionContext( *expressionContext );
721 
722  context.setIsGuiPreview( true );
723  startRender( context );
724 
725  if ( mType == Qgis::SymbolType::Line )
726  {
727  QPolygonF poly;
728  poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
729  static_cast<QgsLineSymbol *>( this )->renderPolyline( poly, nullptr, context );
730  }
731  else if ( mType == Qgis::SymbolType::Fill )
732  {
733  QPolygonF polygon;
734  polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
735  static_cast<QgsFillSymbol *>( this )->renderPolygon( polygon, nullptr, nullptr, context );
736  }
737  else // marker
738  {
739  static_cast<QgsMarkerSymbol *>( this )->renderPoint( QPointF( 50, 50 ), nullptr, context );
740  }
741 
742  stopRender( context );
743  return preview;
744 }
745 
746 QImage QgsSymbol::bigSymbolPreviewImage( QgsExpressionContext *expressionContext, int flags )
747 {
748  return bigSymbolPreviewImage( expressionContext, static_cast< Qgis::SymbolPreviewFlags >( flags ) );
749 }
750 
751 QString QgsSymbol::dump() const
752 {
753  QString t;
754  switch ( type() )
755  {
757  t = QStringLiteral( "MARKER" );
758  break;
760  t = QStringLiteral( "LINE" );
761  break;
763  t = QStringLiteral( "FILL" );
764  break;
765  default:
766  Q_ASSERT( false && "unknown symbol type" );
767  }
768  QString s = QStringLiteral( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerUtils::encodeColor( color() ) );
769 
770  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
771  {
772  // TODO:
773  }
774  return s;
775 }
776 
777 void QgsSymbol::toSld( QDomDocument &doc, QDomElement &element, QVariantMap props ) const
778 {
779  props[ QStringLiteral( "alpha" )] = QString::number( opacity() );
780  double scaleFactor = 1.0;
781  props[ QStringLiteral( "uom" )] = QgsSymbolLayerUtils::encodeSldUom( outputUnit(), &scaleFactor );
782  props[ QStringLiteral( "uomScale" )] = ( !qgsDoubleNear( scaleFactor, 1.0 ) ? qgsDoubleToString( scaleFactor ) : QString() );
783 
784  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
785  {
786  ( *it )->toSld( doc, element, props );
787  }
788 }
789 
791 {
792  QgsSymbolLayerList lst;
793  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
794  {
795  QgsSymbolLayer *layer = ( *it )->clone();
796  layer->setLocked( ( *it )->isLocked() );
797  layer->setRenderingPass( ( *it )->renderingPass() );
798  layer->setEnabled( ( *it )->enabled() );
799  lst.append( layer );
800  }
801  return lst;
802 }
803 
804 void QgsSymbol::renderUsingLayer( QgsSymbolLayer *layer, QgsSymbolRenderContext &context, QgsWkbTypes::GeometryType geometryType, const QPolygonF *points, const QVector<QPolygonF> *rings )
805 {
806  Q_ASSERT( layer->type() == Qgis::SymbolType::Hybrid );
807 
808  if ( layer->dataDefinedProperties().hasActiveProperties() && !layer->dataDefinedProperties().valueAsBool( QgsSymbolLayer::PropertyLayerEnabled, context.renderContext().expressionContext(), true ) )
809  return;
810 
811  QgsGeometryGeneratorSymbolLayer *generatorLayer = static_cast<QgsGeometryGeneratorSymbolLayer *>( layer );
812 
813  QgsPaintEffect *effect = generatorLayer->paintEffect();
814  if ( effect && effect->enabled() )
815  {
816  QgsEffectPainter p( context.renderContext(), effect );
817  generatorLayer->render( context, geometryType, points, rings );
818  }
819  else
820  {
821  generatorLayer->render( context, geometryType, points, rings );
822  }
823 }
824 
825 QSet<QString> QgsSymbol::usedAttributes( const QgsRenderContext &context ) const
826 {
827  // calling referencedFields() with ignoreContext=true because in our expression context
828  // we do not have valid QgsFields yet - because of that the field names from expressions
829  // wouldn't get reported
830  QSet<QString> attributes = mDataDefinedProperties.referencedFields( context.expressionContext(), true );
831  QgsSymbolLayerList::const_iterator sIt = mLayers.constBegin();
832  for ( ; sIt != mLayers.constEnd(); ++sIt )
833  {
834  if ( *sIt )
835  {
836  attributes.unite( ( *sIt )->usedAttributes( context ) );
837  }
838  }
839  return attributes;
840 }
841 
843 {
844  mDataDefinedProperties.setProperty( key, property );
845 }
846 
848 {
849  if ( mDataDefinedProperties.hasActiveProperties() )
850  return true;
851 
852  for ( QgsSymbolLayer *layer : mLayers )
853  {
854  if ( layer->hasDataDefinedProperties() )
855  return true;
856  }
857  return false;
858 }
859 
861 {
862  for ( QgsSymbolLayer *layer : mLayers )
863  {
864  if ( layer->canCauseArtifactsBetweenAdjacentTiles() )
865  return true;
866  }
867  return false;
868 }
869 
871 {
873  mLayer = layer;
875 }
876 
878 {
880  return mLayer;
882 }
883 
885 
889 class ExpressionContextScopePopper
890 {
891  public:
892 
893  ExpressionContextScopePopper() = default;
894 
895  ~ExpressionContextScopePopper()
896  {
897  if ( context )
898  context->popScope();
899  }
900 
901  QgsExpressionContext *context = nullptr;
902 };
903 
907 class GeometryRestorer
908 {
909  public:
910  GeometryRestorer( QgsRenderContext &context )
911  : mContext( context ),
912  mGeometry( context.geometry() )
913  {}
914 
915  ~GeometryRestorer()
916  {
917  mContext.setGeometry( mGeometry );
918  }
919 
920  private:
921  QgsRenderContext &mContext;
922  const QgsAbstractGeometry *mGeometry;
923 };
925 
926 void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker, Qgis::VertexMarkerType currentVertexMarkerType, double currentVertexMarkerSize )
927 {
928  if ( context.renderingStopped() )
929  return;
930 
931  const QgsGeometry geom = feature.geometry();
932  if ( geom.isNull() )
933  {
934  return;
935  }
936 
937  GeometryRestorer geomRestorer( context );
938 
939  bool usingSegmentizedGeometry = false;
940  context.setGeometry( geom.constGet() );
941 
942  if ( geom.type() != QgsWkbTypes::PointGeometry && !geom.boundingBox().isNull() )
943  {
944  try
945  {
946  const QPointF boundsOrigin = _getPoint( context, QgsPoint( geom.boundingBox().xMinimum(), geom.boundingBox().yMinimum() ) );
947  if ( std::isfinite( boundsOrigin.x() ) && std::isfinite( boundsOrigin.y() ) )
948  context.setTextureOrigin( boundsOrigin );
949  }
950  catch ( QgsCsException & )
951  {
952 
953  }
954  }
955 
956  bool clippingEnabled = clipFeaturesToExtent();
957  // do any symbol layers prevent feature clipping?
958  for ( QgsSymbolLayer *layer : std::as_const( mLayers ) )
959  {
961  {
962  clippingEnabled = false;
963  break;
964  }
965  }
966  if ( clippingEnabled && context.testFlag( Qgis::RenderContextFlag::RenderMapTile ) )
967  {
968  // If the "avoid artifacts between adjacent tiles" flag is set (RenderMapTile), then we'll force disable
969  // the geometry clipping IF (and only if) this symbol can potentially have rendering artifacts when rendered as map tiles.
970  // If the symbol won't have any artifacts anyway, then it's pointless and incredibly expensive to skip the clipping!
972  {
973  clippingEnabled = false;
974  }
975  }
976  if ( context.extent().isEmpty() )
977  clippingEnabled = false;
978 
979  mSymbolRenderContext->setGeometryPartCount( geom.constGet()->partCount() );
980  mSymbolRenderContext->setGeometryPartNum( 1 );
981 
982  const bool needsExpressionContext = hasDataDefinedProperties();
983  ExpressionContextScopePopper scopePopper;
984  if ( mSymbolRenderContext->expressionContextScope() )
985  {
986  if ( needsExpressionContext )
987  {
988  // this is somewhat nasty - by appending this scope here it's now owned
989  // by both mSymbolRenderContext AND context.expressionContext()
990  // the RAII scopePopper is required to make sure it always has ownership transferred back
991  // from context.expressionContext(), even if exceptions of other early exits occur in this
992  // function
993  context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
994  scopePopper.context = &context.expressionContext();
995 
996  QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
997  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount(), true ) );
998  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1, true ) );
999  }
1000  }
1001 
1002  // Collection of markers to paint, only used for no curve types.
1003  QPolygonF markers;
1004 
1005  QgsGeometry renderedBoundsGeom;
1006 
1007  // Step 1 - collect the set of painter coordinate geometries to render.
1008  // We do this upfront, because we only want to ever do this once, regardless how many symbol layers we need to render.
1009 
1010  struct PointInfo
1011  {
1012  QPointF renderPoint;
1013  const QgsPoint *originalGeometry = nullptr;
1014  };
1015  QVector< PointInfo > pointsToRender;
1016 
1017  struct LineInfo
1018  {
1019  QPolygonF renderLine;
1020  const QgsCurve *originalGeometry = nullptr;
1021  };
1022  QVector< LineInfo > linesToRender;
1023 
1024  struct PolygonInfo
1025  {
1026  QPolygonF renderExterior;
1027  QVector< QPolygonF > renderRings;
1028  const QgsCurvePolygon *originalGeometry = nullptr;
1029  int originalPartIndex = 0;
1030  };
1031  QVector< PolygonInfo > polygonsToRender;
1032 
1033  std::function< void ( const QgsAbstractGeometry *, int partIndex )> getPartGeometry;
1034  getPartGeometry = [&pointsToRender, &linesToRender, &polygonsToRender, &getPartGeometry, &context, &clippingEnabled, &markers, &feature, &usingSegmentizedGeometry, this]( const QgsAbstractGeometry * part, int partIndex = 0 )
1035  {
1036  Q_UNUSED( feature )
1037 
1038  if ( !part )
1039  return;
1040 
1041  // geometry preprocessing
1042  QgsGeometry temporaryGeometryContainer;
1043  const QgsAbstractGeometry *processedGeometry = nullptr;
1044 
1045  const bool isMultiPart = qgsgeometry_cast< const QgsGeometryCollection * >( part ) && qgsgeometry_cast< const QgsGeometryCollection * >( part )->numGeometries() > 1;
1046 
1047  if ( !isMultiPart )
1048  {
1049  // segmentize curved geometries
1050  const bool needsSegmentizing = QgsWkbTypes::isCurvedType( part->wkbType() ) || part->hasCurvedSegments();
1051  if ( needsSegmentizing )
1052  {
1053  std::unique_ptr< QgsAbstractGeometry > segmentizedPart( part->segmentize( context.segmentationTolerance(), context.segmentationToleranceType() ) );
1054  if ( !segmentizedPart )
1055  {
1056  return;
1057  }
1058  temporaryGeometryContainer.set( segmentizedPart.release() );
1059  processedGeometry = temporaryGeometryContainer.constGet();
1060  usingSegmentizedGeometry = true;
1061  }
1062  else
1063  {
1064  // no segmentation required
1065  processedGeometry = part;
1066  }
1067 
1068  // Simplify the geometry, if needed.
1069  if ( context.vectorSimplifyMethod().forceLocalOptimization() )
1070  {
1071  const int simplifyHints = context.vectorSimplifyMethod().simplifyHints();
1072  const QgsMapToPixelSimplifier simplifier( simplifyHints, context.vectorSimplifyMethod().tolerance(),
1074 
1075  std::unique_ptr< QgsAbstractGeometry > simplified( simplifier.simplify( processedGeometry ) );
1076  if ( simplified )
1077  {
1078  temporaryGeometryContainer.set( simplified.release() );
1079  processedGeometry = temporaryGeometryContainer.constGet();
1080  }
1081  }
1082 
1083  // clip geometry to render context clipping regions
1084  if ( !context.featureClipGeometry().isEmpty() )
1085  {
1086  // apply feature clipping from context to the rendered geometry only -- just like the render time simplification,
1087  // we should NEVER apply this to the geometry attached to the feature itself. Doing so causes issues with certain
1088  // renderer settings, e.g. if polygons are being rendered using a rule based renderer based on the feature's area,
1089  // then we need to ensure that the original feature area is used instead of the clipped area..
1090  QgsGeos geos( processedGeometry );
1091  std::unique_ptr< QgsAbstractGeometry > clippedGeom( geos.intersection( context.featureClipGeometry().constGet() ) );
1092  if ( clippedGeom )
1093  {
1094  temporaryGeometryContainer.set( clippedGeom.release() );
1095  processedGeometry = temporaryGeometryContainer.constGet();
1096  }
1097  }
1098  }
1099  else
1100  {
1101  // for multipart geometries, the processing is deferred till we're rendering the actual part...
1102  processedGeometry = part;
1103  }
1104 
1105  if ( !processedGeometry )
1106  {
1107  // shouldn't happen!
1108  QgsDebugMsg( QStringLiteral( "No processed geometry to render for part!" ) );
1109  return;
1110  }
1111 
1112  switch ( QgsWkbTypes::flatType( processedGeometry->wkbType() ) )
1113  {
1114  case QgsWkbTypes::Point:
1115  {
1117  {
1118  QgsDebugMsgLevel( QStringLiteral( "point can be drawn only with marker symbol!" ), 2 );
1119  break;
1120  }
1121 
1122  PointInfo info;
1123  info.originalGeometry = qgsgeometry_cast< const QgsPoint * >( part );
1124  info.renderPoint = _getPoint( context, *info.originalGeometry );
1125  pointsToRender << info;
1126  break;
1127  }
1128 
1130  {
1131  if ( mType != Qgis::SymbolType::Line )
1132  {
1133  QgsDebugMsgLevel( QStringLiteral( "linestring can be drawn only with line symbol!" ), 2 );
1134  break;
1135  }
1136 
1137  LineInfo info;
1138  info.originalGeometry = qgsgeometry_cast<const QgsCurve *>( part );
1139  info.renderLine = _getLineString( context, *qgsgeometry_cast<const QgsCurve *>( processedGeometry ), clippingEnabled );
1140  linesToRender << info;
1141  break;
1142  }
1143 
1144  case QgsWkbTypes::Polygon:
1145  case QgsWkbTypes::Triangle:
1146  {
1147  QPolygonF pts;
1148  if ( mType != Qgis::SymbolType::Fill )
1149  {
1150  QgsDebugMsgLevel( QStringLiteral( "polygon can be drawn only with fill symbol!" ), 2 );
1151  break;
1152  }
1153 
1154  PolygonInfo info;
1155  info.originalGeometry = qgsgeometry_cast<const QgsCurvePolygon *>( part );
1156  info.originalPartIndex = partIndex;
1157  if ( !qgsgeometry_cast<const QgsPolygon *>( processedGeometry )->exteriorRing() )
1158  {
1159  QgsDebugMsg( QStringLiteral( "cannot render polygon with no exterior ring" ) );
1160  break;
1161  }
1162 
1163  _getPolygon( info.renderExterior, info.renderRings, context, *qgsgeometry_cast<const QgsPolygon *>( processedGeometry ), clippingEnabled, mForceRHR );
1164  polygonsToRender << info;
1165  break;
1166  }
1167 
1169  {
1170  const QgsMultiPoint *mp = qgsgeometry_cast< const QgsMultiPoint * >( processedGeometry );
1171  markers.reserve( mp->numGeometries() );
1172  }
1173  FALLTHROUGH
1177  {
1178  const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( processedGeometry );
1179 
1180  const unsigned int num = geomCollection->numGeometries();
1181  for ( unsigned int i = 0; i < num; ++i )
1182  {
1183  if ( context.renderingStopped() )
1184  break;
1185 
1186  getPartGeometry( geomCollection->geometryN( i ), i );
1187  }
1188  break;
1189  }
1190 
1193  {
1194  if ( mType != Qgis::SymbolType::Fill )
1195  {
1196  QgsDebugMsgLevel( QStringLiteral( "multi-polygon can be drawn only with fill symbol!" ), 2 );
1197  break;
1198  }
1199 
1200  QPolygonF pts;
1201 
1202  const QgsGeometryCollection *geomCollection = dynamic_cast<const QgsGeometryCollection *>( processedGeometry );
1203  const unsigned int num = geomCollection->numGeometries();
1204 
1205  // Sort components by approximate area (probably a bit faster than using
1206  // area() )
1207  std::map<double, QList<unsigned int> > thisAreaToPartNum;
1208  for ( unsigned int i = 0; i < num; ++i )
1209  {
1210  const QgsRectangle r( geomCollection->geometryN( i )->boundingBox() );
1211  thisAreaToPartNum[ r.width() * r.height()] << i;
1212  }
1213 
1214  // Draw starting with larger parts down to smaller parts, so that in
1215  // case of a part being incorrectly inside another part, it is drawn
1216  // on top of it (#15419)
1217  std::map<double, QList<unsigned int> >::const_reverse_iterator iter = thisAreaToPartNum.rbegin();
1218  for ( ; iter != thisAreaToPartNum.rend(); ++iter )
1219  {
1220  const QList<unsigned int> &listPartIndex = iter->second;
1221  for ( int idx = 0; idx < listPartIndex.size(); ++idx )
1222  {
1223  const unsigned i = listPartIndex[idx];
1224  getPartGeometry( geomCollection->geometryN( i ), i );
1225  }
1226  }
1227  break;
1228  }
1229 
1230  default:
1231  QgsDebugMsg( QStringLiteral( "feature %1: unsupported wkb type %2/%3 for rendering" )
1232  .arg( feature.id() )
1233  .arg( QgsWkbTypes::displayString( part->wkbType() ) )
1234  .arg( part->wkbType(), 0, 16 ) );
1235  }
1236  };
1237 
1238  // Use the simplified type ref when rendering -- this avoids some unnecessary cloning/geometry modification
1239  // (e.g. if the original geometry is a compound curve containing only a linestring curve, we don't have
1240  // to segmentize the geometry before rendering)
1241  getPartGeometry( geom.constGet()->simplifiedTypeRef(), 0 );
1242 
1243  // step 2 - determine which layers to render
1244  std::vector< int > layers;
1245  if ( layer == -1 )
1246  {
1247  layers.reserve( mLayers.count() );
1248  for ( int i = 0; i < mLayers.count(); ++i )
1249  layers.emplace_back( i );
1250  }
1251  else
1252  {
1253  layers.emplace_back( layer );
1254  }
1255 
1256  // step 3 - render these geometries using the desired symbol layers.
1257 
1258  if ( needsExpressionContext )
1259  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_layer_count" ), mLayers.count(), true ) );
1260 
1261  for ( const int symbolLayerIndex : layers )
1262  {
1263  QgsSymbolLayer *symbolLayer = mLayers.value( symbolLayerIndex );
1264  if ( !symbolLayer || !symbolLayer->enabled() )
1265  continue;
1266 
1267  if ( needsExpressionContext )
1268  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_layer_index" ), symbolLayerIndex + 1, true ) );
1269 
1270  symbolLayer->startFeatureRender( feature, context );
1271 
1272  switch ( mType )
1273  {
1275  {
1276  int geometryPartNumber = 0;
1277  for ( const PointInfo &point : std::as_const( pointsToRender ) )
1278  {
1279  if ( context.renderingStopped() )
1280  break;
1281 
1282  mSymbolRenderContext->setGeometryPartNum( geometryPartNumber + 1 );
1283  if ( needsExpressionContext )
1284  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, geometryPartNumber + 1, true ) );
1285 
1286  static_cast<QgsMarkerSymbol *>( this )->renderPoint( point.renderPoint, &feature, context, symbolLayerIndex, selected );
1287  geometryPartNumber++;
1288  }
1289 
1290  break;
1291  }
1292 
1294  {
1295  if ( linesToRender.empty() )
1296  break;
1297 
1298  int geometryPartNumber = 0;
1299  for ( const LineInfo &line : std::as_const( linesToRender ) )
1300  {
1301  if ( context.renderingStopped() )
1302  break;
1303 
1304  mSymbolRenderContext->setGeometryPartNum( geometryPartNumber + 1 );
1305  if ( needsExpressionContext )
1306  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, geometryPartNumber + 1, true ) );
1307 
1308  context.setGeometry( line.originalGeometry );
1309  static_cast<QgsLineSymbol *>( this )->renderPolyline( line.renderLine, &feature, context, symbolLayerIndex, selected );
1310  geometryPartNumber++;
1311  }
1312  break;
1313  }
1314 
1316  {
1317  for ( const PolygonInfo &info : std::as_const( polygonsToRender ) )
1318  {
1319  if ( context.renderingStopped() )
1320  break;
1321 
1322  mSymbolRenderContext->setGeometryPartNum( info.originalPartIndex + 1 );
1323  if ( needsExpressionContext )
1324  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, info.originalPartIndex + 1, true ) );
1325 
1326  context.setGeometry( info.originalGeometry );
1327  static_cast<QgsFillSymbol *>( this )->renderPolygon( info.renderExterior, ( !info.renderRings.isEmpty() ? &info.renderRings : nullptr ), &feature, context, symbolLayerIndex, selected );
1328  }
1329 
1330  break;
1331  }
1332 
1334  break;
1335  }
1336 
1337  symbolLayer->stopFeatureRender( feature, context );
1338  }
1339 
1340  // step 4 - handle post processing steps
1341  switch ( mType )
1342  {
1344  {
1345  markers.reserve( pointsToRender.size() );
1346  for ( const PointInfo &info : std::as_const( pointsToRender ) )
1347  {
1349  {
1350  const QRectF bounds = static_cast<QgsMarkerSymbol *>( this )->bounds( info.renderPoint, context, feature );
1351  if ( context.hasRenderedFeatureHandlers() )
1352  {
1353  renderedBoundsGeom = renderedBoundsGeom.isNull() ? QgsGeometry::fromRect( bounds )
1354  : QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromRect( QgsRectangle( bounds ) ) << renderedBoundsGeom );
1355  }
1357  {
1358  //draw debugging rect
1359  context.painter()->setPen( Qt::red );
1360  context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
1361  context.painter()->drawRect( bounds );
1362  }
1363  }
1364 
1365  if ( drawVertexMarker && !usingSegmentizedGeometry )
1366  {
1367  markers.append( info.renderPoint );
1368  }
1369  }
1370  break;
1371  }
1372 
1374  {
1375  for ( const LineInfo &info : std::as_const( linesToRender ) )
1376  {
1377  if ( context.hasRenderedFeatureHandlers() && !info.renderLine.empty() )
1378  {
1379  renderedBoundsGeom = renderedBoundsGeom.isNull() ? QgsGeometry::fromQPolygonF( info.renderLine )
1380  : QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromQPolygonF( info.renderLine ) << renderedBoundsGeom );
1381  }
1382 
1383  if ( drawVertexMarker && !usingSegmentizedGeometry )
1384  {
1385  markers << info.renderLine;
1386  }
1387  }
1388  break;
1389  }
1390 
1392  {
1393  int i = 0;
1394  for ( const PolygonInfo &info : std::as_const( polygonsToRender ) )
1395  {
1396  if ( context.hasRenderedFeatureHandlers() && !info.renderExterior.empty() )
1397  {
1398  renderedBoundsGeom = renderedBoundsGeom.isNull() ? QgsGeometry::fromQPolygonF( info.renderExterior )
1399  : QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromQPolygonF( info.renderExterior ) << renderedBoundsGeom );
1400  // TODO: consider holes?
1401  }
1402 
1403  if ( drawVertexMarker && !usingSegmentizedGeometry )
1404  {
1405  markers << info.renderExterior;
1406 
1407  for ( const QPolygonF &hole : info.renderRings )
1408  {
1409  markers << hole;
1410  }
1411  }
1412  i++;
1413  }
1414  break;
1415  }
1416 
1418  break;
1419  }
1420 
1421  if ( context.hasRenderedFeatureHandlers() && !renderedBoundsGeom.isNull() )
1422  {
1424  const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
1425  for ( QgsRenderedFeatureHandlerInterface *handler : handlers )
1426  handler->handleRenderedFeature( feature, renderedBoundsGeom, featureContext );
1427  }
1428 
1429  if ( drawVertexMarker )
1430  {
1431  if ( !markers.isEmpty() && !context.renderingStopped() )
1432  {
1433  const auto constMarkers = markers;
1434  for ( QPointF marker : constMarkers )
1435  {
1436  renderVertexMarker( marker, context, currentVertexMarkerType, currentVertexMarkerSize );
1437  }
1438  }
1439  else
1440  {
1442  const QgsMapToPixel &mtp = context.mapToPixel();
1443 
1444  QgsPoint vertexPoint;
1445  QgsVertexId vertexId;
1446  double x, y, z;
1447  QPointF mapPoint;
1448  while ( geom.constGet()->nextVertex( vertexId, vertexPoint ) )
1449  {
1450  //transform
1451  x = vertexPoint.x();
1452  y = vertexPoint.y();
1453  z = 0.0;
1454  if ( ct.isValid() )
1455  {
1456  ct.transformInPlace( x, y, z );
1457  }
1458  mapPoint.setX( x );
1459  mapPoint.setY( y );
1460  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1461  renderVertexMarker( mapPoint, context, currentVertexMarkerType, currentVertexMarkerSize );
1462  }
1463  }
1464  }
1465 }
1466 
1468 {
1469  return mSymbolRenderContext.get();
1470 }
1471 
1472 void QgsSymbol::renderVertexMarker( QPointF pt, QgsRenderContext &context, Qgis::VertexMarkerType currentVertexMarkerType, double currentVertexMarkerSize )
1473 {
1474  int markerSize = context.convertToPainterUnits( currentVertexMarkerSize, QgsUnitTypes::RenderMillimeters );
1475  QgsSymbolLayerUtils::drawVertexMarker( pt.x(), pt.y(), *context.painter(), currentVertexMarkerType, markerSize );
1476 }
1477 
1478 void QgsSymbol::initPropertyDefinitions()
1479 {
1480  if ( !sPropertyDefinitions.isEmpty() )
1481  return;
1482 
1483  QString origin = QStringLiteral( "symbol" );
1484 
1485  sPropertyDefinitions = QgsPropertiesDefinition
1486  {
1487  { QgsSymbol::PropertyOpacity, QgsPropertyDefinition( "alpha", QObject::tr( "Opacity" ), QgsPropertyDefinition::Opacity, origin )},
1488  };
1489 }
1490 
1491 void QgsSymbol::startFeatureRender( const QgsFeature &feature, QgsRenderContext &context, const int layer )
1492 {
1493  if ( layer != -1 )
1494  {
1496  if ( symbolLayer && symbolLayer->enabled() )
1497  {
1498  symbolLayer->startFeatureRender( feature, context );
1499  }
1500  return;
1501  }
1502  else
1503  {
1504  const QList< QgsSymbolLayer * > layers = mLayers;
1505  for ( QgsSymbolLayer *symbolLayer : layers )
1506  {
1507  if ( !symbolLayer->enabled() )
1508  continue;
1509 
1510  symbolLayer->startFeatureRender( feature, context );
1511  }
1512  }
1513 }
1514 
1515 void QgsSymbol::stopFeatureRender( const QgsFeature &feature, QgsRenderContext &context, int layer )
1516 {
1517  if ( layer != -1 )
1518  {
1520  if ( symbolLayer && symbolLayer->enabled() )
1521  {
1522  symbolLayer->stopFeatureRender( feature, context );
1523  }
1524  return;
1525  }
1526  else
1527  {
1528  const QList< QgsSymbolLayer * > layers = mLayers;
1529  for ( QgsSymbolLayer *symbolLayer : layers )
1530  {
1531  if ( !symbolLayer->enabled() )
1532  continue;
1533 
1534  symbolLayer->stopFeatureRender( feature, context );
1535  }
1536  }
1537 }
@ CounterClockwise
Counter-clockwise direction.
@ Clockwise
Clockwise direction.
@ DisableFeatureClipping
If present, indicates that features should never be clipped to the map extent during rendering.
@ 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...
@ DrawSymbolBounds
Draw bounds of symbols (for debugging/testing)
@ RenderMapTile
Draw map such that there are no problems between adjacent tiles.
@ Antialiasing
Use antialiasing while drawing.
@ HighQualityImageTransforms
Enable high quality image transformations, which results in better appearance of scaled or rotated ra...
@ FlagIncludeCrosshairsForMarkerSymbols
Include a crosshairs reference image in the background of marker symbol previews.
VertexMarkerType
Editing vertex markers, used for showing vertices during a edit operation.
Definition: qgis.h:588
SymbolType
Symbol types.
Definition: qgis.h:183
@ 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, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const SIP_THROW(QgsCsException)
Transforms a polygon to the destination coordinate system.
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
void transformInPlace(double &x, double &y, double &z, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const SIP_THROW(QgsCsException)
Transforms an array of x, y and z double coordinates in place, from the source CRS to the destination...
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
Qgis::AngularDirection orientation() const
Returns the curve's orientation, e.g.
Definition: qgscurve.cpp:286
virtual int numPoints() const =0
Returns the number of points in the curve.
virtual QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition: qgscurve.cpp:266
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.
void render(QgsSymbolRenderContext &context, QgsWkbTypes::GeometryType geometryType=QgsWkbTypes::GeometryType::UnknownGeometry, const QPolygonF *points=nullptr, const QVector< QPolygonF > *rings=nullptr)
Will render this symbol layer using the context.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
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:127
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:128
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:80
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
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:470
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:47
@ Opacity
Opacity (0-100)
Definition: qgsproperty.h:62
A store for object properties.
Definition: qgsproperty.h:231
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 isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:469
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 setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
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 testFlag(Qgis::RenderContextFlag flag) const
Check whether a particular flag is enabled.
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.
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
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.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
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:1218
static void drawVertexMarker(double x, double y, QPainter &p, Qgis::VertexMarkerType type, int markerSize)
Draws a vertex symbol at (painter) coordinates x, y.
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)
@ 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:790
QgsSymbolRenderContext * symbolRenderContext()
Returns the symbol render context.
Definition: qgssymbol.cpp:1467
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:842
void renderUsingLayer(QgsSymbolLayer *layer, QgsSymbolRenderContext &context, QgsWkbTypes::GeometryType geometryType=QgsWkbTypes::GeometryType::UnknownGeometry, const QPolygonF *points=nullptr, const QVector< QPolygonF > *rings=nullptr)
Renders a context using a particular symbol layer without passing in a geometry.
Definition: qgssymbol.cpp:804
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:710
Q_DECL_DEPRECATED const QgsVectorLayer * mLayer
Definition: qgssymbol.h:724
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:566
void renderVertexMarker(QPointF pt, QgsRenderContext &context, Qgis::VertexMarkerType currentVertexMarkerType, double currentVertexMarkerSize)
Render editing vertex marker at specified point.
Definition: qgssymbol.cpp:1472
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:777
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:860
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:683
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:751
bool hasDataDefinedProperties() const
Returns whether the symbol utilizes any data defined properties.
Definition: qgssymbol.cpp:847
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:825
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:698
Qgis::SymbolType mType
Definition: qgssymbol.h:706
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:712
void setMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol.
Definition: qgssymbol.cpp:346
bool mForceRHR
Definition: qgssymbol.h:722
QgsSymbolLayerList mLayers
Definition: qgssymbol.h:707
Q_DECL_DEPRECATED const QgsVectorLayer * layer() const
Definition: qgssymbol.cpp:877
void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context, int layer=-1)
Called before symbol layers will be rendered for a particular feature.
Definition: qgssymbol.cpp:1491
void renderFeature(const QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false, Qgis::VertexMarkerType currentVertexMarkerType=Qgis::VertexMarkerType::SemiTransparentCircle, double currentVertexMarkerSize=0.0) SIP_THROW(QgsCsException)
Render a feature.
Definition: qgssymbol.cpp:926
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:870
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:663
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context, int layer=-1)
Called after symbol layers have been rendered for a particular feature.
Definition: qgssymbol.cpp:1515
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:911
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:732
Contains geos related utilities and functions.
Definition: qgsgeos.h:42
#define FALLTHROUGH
Definition: qgis.h:2092
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2065
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:1530
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2064
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1578
#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.
Definition: qgsvertexid.h:31