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