QGIS API Documentation  3.9.0-Master (224899f119)
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  return poly;
211 }
212 
213 void QgsSymbol::_getPolygon( QPolygonF &pts, QList<QPolygonF> &holes, QgsRenderContext &context, const QgsPolygon &polygon, const bool clipToExtent, const bool correctRingOrientation )
214 {
215  holes.clear();
216 
217  pts = _getPolygonRing( context, *polygon.exteriorRing(), clipToExtent, true, correctRingOrientation );
218  for ( int idx = 0; idx < polygon.numInteriorRings(); idx++ )
219  {
220  const QPolygonF hole = _getPolygonRing( context, *( polygon.interiorRing( idx ) ), clipToExtent, false, correctRingOrientation );
221  if ( !hole.isEmpty() ) holes.append( hole );
222  }
223 }
224 
226 {
227  // delete all symbol layers (we own them, so it's okay)
228  qDeleteAll( mLayers );
229 }
230 
232 {
233  if ( mLayers.empty() )
234  {
236  }
237 
238  QgsSymbolLayerList::const_iterator it = mLayers.constBegin();
239 
240  QgsUnitTypes::RenderUnit unit = ( *it )->outputUnit();
241 
242  for ( ; it != mLayers.constEnd(); ++it )
243  {
244  if ( ( *it )->outputUnit() != unit )
245  {
247  }
248  }
249  return unit;
250 }
251 
253 {
254  if ( mLayers.empty() )
255  {
256  return QgsMapUnitScale();
257  }
258 
259  QgsSymbolLayerList::const_iterator it = mLayers.constBegin();
260  if ( it == mLayers.constEnd() )
261  return QgsMapUnitScale();
262 
263  QgsMapUnitScale scale = ( *it )->mapUnitScale();
264  ++it;
265 
266  for ( ; it != mLayers.constEnd(); ++it )
267  {
268  if ( ( *it )->mapUnitScale() != scale )
269  {
270  return QgsMapUnitScale();
271  }
272  }
273  return scale;
274 }
275 
277 {
278  const auto constMLayers = mLayers;
279  for ( QgsSymbolLayer *layer : constMLayers )
280  {
281  layer->setOutputUnit( u );
282  }
283 }
284 
286 {
287  const auto constMLayers = mLayers;
288  for ( QgsSymbolLayer *layer : constMLayers )
289  {
290  layer->setMapUnitScale( scale );
291  }
292 }
293 
295 {
296  std::unique_ptr< QgsSymbol > s;
297 
298  // override global default if project has a default for this type
299  QString defaultSymbol;
300  switch ( geomType )
301  {
303  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Marker" ) );
304  break;
306  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Line" ) );
307  break;
309  defaultSymbol = QgsProject::instance()->readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Fill" ) );
310  break;
311  default:
312  break;
313  }
314  if ( !defaultSymbol.isEmpty() )
315  s.reset( QgsStyle::defaultStyle()->symbol( defaultSymbol ) );
316 
317  // if no default found for this type, get global default (as previously)
318  if ( !s )
319  {
320  switch ( geomType )
321  {
323  s = qgis::make_unique< QgsMarkerSymbol >();
324  break;
326  s = qgis::make_unique< QgsLineSymbol >();
327  break;
329  s = qgis::make_unique< QgsFillSymbol >();
330  break;
331  default:
332  QgsDebugMsg( QStringLiteral( "unknown layer's geometry type" ) );
333  return nullptr;
334  }
335  }
336 
337  // set opacity
338  double opacity = 1.0;
339  bool ok = false;
340  // upgrade old setting
341  double alpha = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/AlphaInt" ), 255, &ok );
342  if ( ok )
343  opacity = alpha / 255.0;
344  double newOpacity = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Opacity" ), 1.0, &ok );
345  if ( ok )
346  opacity = newOpacity;
347  s->setOpacity( opacity );
348 
349  // set random color, it project prefs allow
350  if ( defaultSymbol.isEmpty() ||
351  QgsProject::instance()->readBoolEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/RandomColors" ), true ) )
352  {
353  s->setColor( QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor() );
354  }
355 
356  return s.release();
357 }
358 
360 {
361  return mLayers.value( layer );
362 }
363 
365 {
366  if ( index < 0 || index > mLayers.count() ) // can be added also after the last index
367  return false;
368 
369  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
370  return false;
371 
372  mLayers.insert( index, layer );
373  return true;
374 }
375 
376 
378 {
379  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
380  return false;
381 
382  mLayers.append( layer );
383  return true;
384 }
385 
386 
388 {
389  if ( index < 0 || index >= mLayers.count() )
390  return false;
391 
392  delete mLayers.at( index );
393  mLayers.removeAt( index );
394  return true;
395 }
396 
397 
399 {
400  if ( index < 0 || index >= mLayers.count() )
401  return nullptr;
402 
403  return mLayers.takeAt( index );
404 }
405 
406 
408 {
409  QgsSymbolLayer *oldLayer = mLayers.value( index );
410 
411  if ( oldLayer == layer )
412  return false;
413 
414  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
415  return false;
416 
417  delete oldLayer; // first delete the original layer
418  mLayers[index] = layer; // set new layer
419  return true;
420 }
421 
422 
423 void QgsSymbol::startRender( QgsRenderContext &context, const QgsFields &fields )
424 {
425  Q_ASSERT_X( !mStarted, "startRender", "Rendering has already been started for this symbol instance!" );
426  mStarted = true;
427 
428  mSymbolRenderContext.reset( new QgsSymbolRenderContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, false, mRenderHints, nullptr, fields ) );
429 
430  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, false, mRenderHints, nullptr, fields );
431 
432  std::unique_ptr< QgsExpressionContextScope > scope( QgsExpressionContextUtils::updateSymbolScope( this, new QgsExpressionContextScope() ) );
433  mSymbolRenderContext->setExpressionContextScope( scope.release() );
434 
435  const auto constMLayers = mLayers;
436  for ( QgsSymbolLayer *layer : constMLayers )
437  {
438  if ( !layer->enabled() )
439  continue;
440 
441  layer->prepareExpressions( symbolContext );
442  layer->startRender( symbolContext );
443  }
444 }
445 
447 {
448  Q_ASSERT_X( mStarted, "startRender", "startRender was not called for this symbol instance!" );
449  mStarted = false;
450 
451  Q_UNUSED( context )
452  if ( mSymbolRenderContext )
453  {
454  const auto constMLayers = mLayers;
455  for ( QgsSymbolLayer *layer : constMLayers )
456  {
457  if ( !layer->enabled() )
458  continue;
459 
460  layer->stopRender( *mSymbolRenderContext );
461  }
462  }
463 
464  mSymbolRenderContext.reset( nullptr );
465 
467  mLayer = nullptr;
469 }
470 
471 void QgsSymbol::setColor( const QColor &color )
472 {
473  const auto constMLayers = mLayers;
474  for ( QgsSymbolLayer *layer : constMLayers )
475  {
476  if ( !layer->isLocked() )
477  layer->setColor( color );
478  }
479 }
480 
481 QColor QgsSymbol::color() const
482 {
483  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
484  {
485  // return color of the first unlocked layer
486  if ( !( *it )->isLocked() )
487  return ( *it )->color();
488  }
489  return QColor( 0, 0, 0 );
490 }
491 
492 void QgsSymbol::drawPreviewIcon( QPainter *painter, QSize size, QgsRenderContext *customContext, bool selected )
493 {
494  QgsRenderContext context = customContext ? *customContext : QgsRenderContext::fromQPainter( painter );
495  context.setForceVectorOutput( true );
496  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, false, mRenderHints, nullptr );
497  symbolContext.setSelected( selected );
499 
500  if ( !customContext )
501  {
502  // if no render context was passed, build a minimal expression context
503  QgsExpressionContext expContext;
505  context.setExpressionContext( expContext );
506  }
507 
508  const auto constMLayers = mLayers;
509  for ( QgsSymbolLayer *layer : constMLayers )
510  {
511  if ( !layer->enabled() )
512  continue;
513 
514  if ( mType == Fill && layer->type() == Line )
515  {
516  // line symbol layer would normally draw just a line
517  // so we override this case to force it to draw a polygon stroke
518  QgsLineSymbolLayer *lsl = dynamic_cast<QgsLineSymbolLayer *>( layer );
519 
520  if ( lsl )
521  {
522  // from QgsFillSymbolLayer::drawPreviewIcon()
523  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
524  lsl->startRender( symbolContext );
525  lsl->renderPolygonStroke( poly, nullptr, symbolContext );
526  lsl->stopRender( symbolContext );
527  }
528  }
529  else
530  layer->drawPreviewIcon( symbolContext, size );
531  }
532 }
533 
534 void QgsSymbol::exportImage( const QString &path, const QString &format, QSize size )
535 {
536  if ( format.compare( QLatin1String( "svg" ), Qt::CaseInsensitive ) == 0 )
537  {
538  QSvgGenerator generator;
539  generator.setFileName( path );
540  generator.setSize( size );
541  generator.setViewBox( QRect( 0, 0, size.height(), size.height() ) );
542 
543  QPainter painter( &generator );
544  drawPreviewIcon( &painter, size );
545  painter.end();
546  }
547  else
548  {
549  QImage image = asImage( size );
550  image.save( path );
551  }
552 }
553 
554 QImage QgsSymbol::asImage( QSize size, QgsRenderContext *customContext )
555 {
556  QImage image( size, QImage::Format_ARGB32_Premultiplied );
557  image.fill( 0 );
558 
559  QPainter p( &image );
560  p.setRenderHint( QPainter::Antialiasing );
561 
562  drawPreviewIcon( &p, size, customContext );
563 
564  return image;
565 }
566 
567 
569 {
570  QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
571  preview.fill( 0 );
572 
573  QPainter p( &preview );
574  p.setRenderHint( QPainter::Antialiasing );
575  p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialising
576 
577  if ( mType == QgsSymbol::Marker )
578  {
579  p.setPen( QPen( Qt::gray ) );
580  p.drawLine( 0, 50, 100, 50 );
581  p.drawLine( 50, 0, 50, 100 );
582  }
583 
585  if ( expressionContext )
586  context.setExpressionContext( *expressionContext );
587 
588  startRender( context );
589 
590  if ( mType == QgsSymbol::Line )
591  {
592  QPolygonF poly;
593  poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
594  static_cast<QgsLineSymbol *>( this )->renderPolyline( poly, nullptr, context );
595  }
596  else if ( mType == QgsSymbol::Fill )
597  {
598  QPolygonF polygon;
599  polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
600  static_cast<QgsFillSymbol *>( this )->renderPolygon( polygon, nullptr, nullptr, context );
601  }
602  else // marker
603  {
604  static_cast<QgsMarkerSymbol *>( this )->renderPoint( QPointF( 50, 50 ), nullptr, context );
605  }
606 
607  stopRender( context );
608  return preview;
609 }
610 
611 
612 QString QgsSymbol::dump() const
613 {
614  QString t;
615  switch ( type() )
616  {
617  case QgsSymbol::Marker:
618  t = QStringLiteral( "MARKER" );
619  break;
620  case QgsSymbol::Line:
621  t = QStringLiteral( "LINE" );
622  break;
623  case QgsSymbol::Fill:
624  t = QStringLiteral( "FILL" );
625  break;
626  default:
627  Q_ASSERT( false && "unknown symbol type" );
628  }
629  QString s = QStringLiteral( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerUtils::encodeColor( color() ) );
630 
631  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
632  {
633  // TODO:
634  }
635  return s;
636 }
637 
638 void QgsSymbol::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
639 {
640  props[ QStringLiteral( "alpha" )] = QString::number( opacity() );
641  double scaleFactor = 1.0;
642  props[ QStringLiteral( "uom" )] = QgsSymbolLayerUtils::encodeSldUom( outputUnit(), &scaleFactor );
643  props[ QStringLiteral( "uomScale" )] = ( !qgsDoubleNear( scaleFactor, 1.0 ) ? qgsDoubleToString( scaleFactor ) : QString() );
644 
645  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
646  {
647  ( *it )->toSld( doc, element, props );
648  }
649 }
650 
652 {
653  QgsSymbolLayerList lst;
654  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
655  {
656  QgsSymbolLayer *layer = ( *it )->clone();
657  layer->setLocked( ( *it )->isLocked() );
658  layer->setRenderingPass( ( *it )->renderingPass() );
659  layer->setEnabled( ( *it )->enabled() );
660  lst.append( layer );
661  }
662  return lst;
663 }
664 
666 {
667  Q_ASSERT( layer->type() == Hybrid );
668 
670  return;
671 
672  QgsGeometryGeneratorSymbolLayer *generatorLayer = static_cast<QgsGeometryGeneratorSymbolLayer *>( layer );
673 
674  QgsPaintEffect *effect = generatorLayer->paintEffect();
675  if ( effect && effect->enabled() )
676  {
677  QgsEffectPainter p( context.renderContext(), effect );
678  generatorLayer->render( context );
679  }
680  else
681  {
682  generatorLayer->render( context );
683  }
684 }
685 
686 QSet<QString> QgsSymbol::usedAttributes( const QgsRenderContext &context ) const
687 {
688  QSet<QString> attributes;
689  QgsSymbolLayerList::const_iterator sIt = mLayers.constBegin();
690  for ( ; sIt != mLayers.constEnd(); ++sIt )
691  {
692  if ( *sIt )
693  {
694  attributes.unite( ( *sIt )->usedAttributes( context ) );
695  }
696  }
697  return attributes;
698 }
699 
701 {
702  const auto constMLayers = mLayers;
703  for ( QgsSymbolLayer *layer : constMLayers )
704  {
705  if ( layer->hasDataDefinedProperties() )
706  return true;
707  }
708  return false;
709 }
710 
712 {
714  mLayer = layer;
716 }
717 
719 {
721  return mLayer;
723 }
724 
726 
730 class ExpressionContextScopePopper
731 {
732  public:
733 
734  ExpressionContextScopePopper() = default;
735 
736  ~ExpressionContextScopePopper()
737  {
738  if ( context )
739  context->popScope();
740  }
741 
742  QgsExpressionContext *context = nullptr;
743 };
744 
748 class GeometryRestorer
749 {
750  public:
751  GeometryRestorer( QgsRenderContext &context )
752  : mContext( context ),
753  mGeometry( context.geometry() )
754  {}
755 
756  ~GeometryRestorer()
757  {
758  mContext.setGeometry( mGeometry );
759  }
760 
761  private:
762  QgsRenderContext &mContext;
763  const QgsAbstractGeometry *mGeometry;
764 };
766 
767 void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, double currentVertexMarkerSize )
768 {
769  if ( context.renderingStopped() )
770  return;
771 
772  const QgsGeometry geom = feature.geometry();
773  if ( geom.isNull() )
774  {
775  return;
776  }
777 
778  GeometryRestorer geomRestorer( context );
779  QgsGeometry segmentizedGeometry = geom;
780  bool usingSegmentizedGeometry = false;
781  context.setGeometry( geom.constGet() );
782 
783  bool tileMapRendering = context.testFlag( QgsRenderContext::RenderMapTile );
784 
785  //convert curve types to normal point/line/polygon ones
786  if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) )
787  {
789  if ( !g )
790  {
791  return;
792  }
793  segmentizedGeometry = QgsGeometry( g );
794  usingSegmentizedGeometry = true;
795  }
796 
797  mSymbolRenderContext->setGeometryPartCount( segmentizedGeometry.constGet()->partCount() );
798  mSymbolRenderContext->setGeometryPartNum( 1 );
799 
800  bool needsExpressionContext = hasDataDefinedProperties();
801  ExpressionContextScopePopper scopePopper;
802  if ( mSymbolRenderContext->expressionContextScope() )
803  {
804  if ( needsExpressionContext )
805  {
806  // this is somewhat nasty - by appending this scope here it's now owned
807  // by both mSymbolRenderContext AND context.expressionContext()
808  // the RAII scopePopper is required to make sure it always has ownership transferred back
809  // from context.expressionContext(), even if exceptions of other early exits occur in this
810  // function
811  context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
812  scopePopper.context = &context.expressionContext();
813 
814  QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
815  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount(), true ) );
816  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1, true ) );
817  }
818  }
819 
820  // Collection of markers to paint, only used for no curve types.
821  QPolygonF markers;
822 
823  // Simplify the geometry, if needed.
825  {
826  const int simplifyHints = context.vectorSimplifyMethod().simplifyHints();
827  const QgsMapToPixelSimplifier simplifier( simplifyHints, context.vectorSimplifyMethod().tolerance(),
829  segmentizedGeometry = simplifier.simplify( segmentizedGeometry );
830  }
831 
832  QgsGeometry renderedBoundsGeom;
833 
834  switch ( QgsWkbTypes::flatType( segmentizedGeometry.constGet()->wkbType() ) )
835  {
836  case QgsWkbTypes::Point:
837  {
838  if ( mType != QgsSymbol::Marker )
839  {
840  QgsDebugMsg( QStringLiteral( "point can be drawn only with marker symbol!" ) );
841  break;
842  }
843 
844  const QgsPoint *point = static_cast< const QgsPoint * >( segmentizedGeometry.constGet() );
845  const QPointF pt = _getPoint( context, *point );
846  static_cast<QgsMarkerSymbol *>( this )->renderPoint( pt, &feature, context, layer, selected );
847 
849  {
850  const QRectF bounds = static_cast<QgsMarkerSymbol *>( this )->bounds( pt, context, feature );
851  if ( context.hasRenderedFeatureHandlers() )
852  {
853  renderedBoundsGeom = QgsGeometry::fromRect( QgsRectangle( bounds ) );
854  }
856  {
857  //draw debugging rect
858  context.painter()->setPen( Qt::red );
859  context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
860  context.painter()->drawRect( bounds );
861  }
862  }
863 
864  if ( drawVertexMarker && !usingSegmentizedGeometry )
865  {
866  markers << pt;
867  }
868  }
869  break;
871  {
872  if ( mType != QgsSymbol::Line )
873  {
874  QgsDebugMsg( QStringLiteral( "linestring can be drawn only with line symbol!" ) );
875  break;
876  }
877  const QgsCurve &curve = dynamic_cast<const QgsCurve &>( *segmentizedGeometry.constGet() );
878  const QPolygonF pts = _getLineString( context, curve, !tileMapRendering && clipFeaturesToExtent() );
879  static_cast<QgsLineSymbol *>( this )->renderPolyline( pts, &feature, context, layer, selected );
880 
881  if ( context.hasRenderedFeatureHandlers() )
882  renderedBoundsGeom = QgsGeometry::fromQPolygonF( pts );
883 
884  if ( drawVertexMarker && !usingSegmentizedGeometry )
885  {
886  markers = pts;
887  }
888  }
889  break;
892  {
893  QPolygonF pts;
894  QList<QPolygonF> holes;
895  if ( mType != QgsSymbol::Fill )
896  {
897  QgsDebugMsg( QStringLiteral( "polygon can be drawn only with fill symbol!" ) );
898  break;
899  }
900  const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *segmentizedGeometry.constGet() );
901  if ( !polygon.exteriorRing() )
902  {
903  QgsDebugMsg( QStringLiteral( "cannot render polygon with no exterior ring" ) );
904  break;
905  }
906  _getPolygon( pts, holes, context, polygon, !tileMapRendering && clipFeaturesToExtent(), mForceRHR );
907  static_cast<QgsFillSymbol *>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
908 
909  if ( context.hasRenderedFeatureHandlers() )
910  renderedBoundsGeom = QgsGeometry::fromQPolygonF( pts ); // TODO - consider holes?
911 
912  if ( drawVertexMarker && !usingSegmentizedGeometry )
913  {
914  markers = pts;
915 
916  const auto constHoles = holes;
917  for ( const QPolygonF &hole : constHoles )
918  {
919  markers << hole;
920  }
921  }
922  }
923  break;
924 
926  {
927  if ( mType != QgsSymbol::Marker )
928  {
929  QgsDebugMsg( QStringLiteral( "multi-point can be drawn only with marker symbol!" ) );
930  break;
931  }
932 
933  const QgsMultiPoint &mp = static_cast< const QgsMultiPoint & >( *segmentizedGeometry.constGet() );
934 
935  if ( drawVertexMarker && !usingSegmentizedGeometry )
936  {
937  markers.reserve( mp.numGeometries() );
938  }
939 
940  for ( int i = 0; i < mp.numGeometries(); ++i )
941  {
942  if ( context.renderingStopped() )
943  break;
944 
945  mSymbolRenderContext->setGeometryPartNum( i + 1 );
946  if ( needsExpressionContext )
947  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
948 
949  const QgsPoint &point = static_cast< const QgsPoint & >( *mp.geometryN( i ) );
950  const QPointF pt = _getPoint( context, point );
951  static_cast<QgsMarkerSymbol *>( this )->renderPoint( pt, &feature, context, layer, selected );
952 
953  if ( context.hasRenderedFeatureHandlers() )
954  {
955  const QRectF bounds = static_cast<QgsMarkerSymbol *>( this )->bounds( pt, context, feature );
956  renderedBoundsGeom = QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromRect( QgsRectangle( bounds ) ) << renderedBoundsGeom );
957  }
958 
959  if ( drawVertexMarker && !usingSegmentizedGeometry )
960  {
961  markers.append( pt );
962  }
963  }
964  }
965  break;
966 
969  {
970  if ( mType != QgsSymbol::Line )
971  {
972  QgsDebugMsg( QStringLiteral( "multi-linestring can be drawn only with line symbol!" ) );
973  break;
974  }
975 
976  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
977 
978  const unsigned int num = geomCollection.numGeometries();
979  for ( unsigned int i = 0; i < num; ++i )
980  {
981  if ( context.renderingStopped() )
982  break;
983 
984  mSymbolRenderContext->setGeometryPartNum( i + 1 );
985  if ( needsExpressionContext )
986  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
987 
988  context.setGeometry( geomCollection.geometryN( i ) );
989  const QgsCurve &curve = dynamic_cast<const QgsCurve &>( *geomCollection.geometryN( i ) );
990  const QPolygonF pts = _getLineString( context, curve, !tileMapRendering && clipFeaturesToExtent() );
991  static_cast<QgsLineSymbol *>( this )->renderPolyline( pts, &feature, context, layer, selected );
992 
993  if ( context.hasRenderedFeatureHandlers() )
994  {
995  renderedBoundsGeom = QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromQPolygonF( pts ) << renderedBoundsGeom );
996  }
997 
998  if ( drawVertexMarker && !usingSegmentizedGeometry )
999  {
1000  markers << pts;
1001  }
1002  }
1003  }
1004  break;
1005 
1008  {
1009  if ( mType != QgsSymbol::Fill )
1010  {
1011  QgsDebugMsg( QStringLiteral( "multi-polygon can be drawn only with fill symbol!" ) );
1012  break;
1013  }
1014 
1015  QPolygonF pts;
1016  QList<QPolygonF> holes;
1017 
1018  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
1019  const unsigned int num = geomCollection.numGeometries();
1020 
1021  // Sort components by approximate area (probably a bit faster than using
1022  // area() )
1023  std::map<double, QList<unsigned int> > mapAreaToPartNum;
1024  for ( unsigned int i = 0; i < num; ++i )
1025  {
1026  const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *geomCollection.geometryN( i ) );
1027  const QgsRectangle r( polygon.boundingBox() );
1028  mapAreaToPartNum[ r.width() * r.height()] << i;
1029  }
1030 
1031  // Draw starting with larger parts down to smaller parts, so that in
1032  // case of a part being incorrectly inside another part, it is drawn
1033  // on top of it (#15419)
1034  std::map<double, QList<unsigned int> >::const_reverse_iterator iter = mapAreaToPartNum.rbegin();
1035  for ( ; iter != mapAreaToPartNum.rend(); ++iter )
1036  {
1037  const QList<unsigned int> &listPartIndex = iter->second;
1038  for ( int idx = 0; idx < listPartIndex.size(); ++idx )
1039  {
1040  if ( context.renderingStopped() )
1041  break;
1042 
1043  const unsigned i = listPartIndex[idx];
1044  mSymbolRenderContext->setGeometryPartNum( i + 1 );
1045  if ( needsExpressionContext )
1046  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
1047 
1048  context.setGeometry( geomCollection.geometryN( i ) );
1049  const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *geomCollection.geometryN( i ) );
1050  if ( !polygon.exteriorRing() )
1051  break;
1052 
1053  _getPolygon( pts, holes, context, polygon, !tileMapRendering && clipFeaturesToExtent(), mForceRHR );
1054  static_cast<QgsFillSymbol *>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
1055 
1056  if ( context.hasRenderedFeatureHandlers() )
1057  {
1058  renderedBoundsGeom = QgsGeometry::collectGeometry( QVector< QgsGeometry>() << QgsGeometry::fromQPolygonF( pts ) << renderedBoundsGeom ); // TODO: consider holes?
1059  }
1060 
1061  if ( drawVertexMarker && !usingSegmentizedGeometry )
1062  {
1063  markers << pts;
1064 
1065  const auto constHoles = holes;
1066  for ( const QPolygonF &hole : constHoles )
1067  {
1068  markers << hole;
1069  }
1070  }
1071  }
1072  }
1073  break;
1074  }
1076  {
1077  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
1078  if ( geomCollection.numGeometries() == 0 )
1079  {
1080  // skip noise from empty geometry collections from simplification
1081  break;
1082  }
1083 
1084  FALLTHROUGH
1085  }
1086  default:
1087  QgsDebugMsg( QStringLiteral( "feature %1: unsupported wkb type %2/%3 for rendering" )
1088  .arg( feature.id() )
1089  .arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
1090  .arg( geom.wkbType(), 0, 16 ) );
1091  }
1092 
1093  if ( context.hasRenderedFeatureHandlers() )
1094  {
1096  const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
1097  for ( QgsRenderedFeatureHandlerInterface *handler : handlers )
1098  handler->handleRenderedFeature( feature, renderedBoundsGeom, featureContext );
1099  }
1100 
1101  if ( drawVertexMarker )
1102  {
1103  if ( !markers.isEmpty() && !context.renderingStopped() )
1104  {
1105  const auto constMarkers = markers;
1106  for ( QPointF marker : constMarkers )
1107  {
1108  renderVertexMarker( marker, context, currentVertexMarkerType, currentVertexMarkerSize );
1109  }
1110  }
1111  else
1112  {
1114  const QgsMapToPixel &mtp = context.mapToPixel();
1115 
1116  QgsPoint vertexPoint;
1117  QgsVertexId vertexId;
1118  double x, y, z;
1119  QPointF mapPoint;
1120  while ( geom.constGet()->nextVertex( vertexId, vertexPoint ) )
1121  {
1122  //transform
1123  x = vertexPoint.x();
1124  y = vertexPoint.y();
1125  z = 0.0;
1126  if ( ct.isValid() )
1127  {
1128  ct.transformInPlace( x, y, z );
1129  }
1130  mapPoint.setX( x );
1131  mapPoint.setY( y );
1132  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1133  renderVertexMarker( mapPoint, context, currentVertexMarkerType, currentVertexMarkerSize );
1134  }
1135  }
1136  }
1137 }
1138 
1140 {
1141  return mSymbolRenderContext.get();
1142 }
1143 
1144 void QgsSymbol::renderVertexMarker( QPointF pt, QgsRenderContext &context, int currentVertexMarkerType, double currentVertexMarkerSize )
1145 {
1146  int markerSize = context.convertToPainterUnits( currentVertexMarkerSize, QgsUnitTypes::RenderMillimeters );
1147  QgsSymbolLayerUtils::drawVertexMarker( pt.x(), pt.y(), *context.painter(), static_cast< QgsSymbolLayerUtils::VertexMarkerType >( currentVertexMarkerType ), markerSize );
1148 }
1149 
1151 
1152 
1154  : mRenderContext( c )
1155  , mOutputUnit( u )
1156  , mMapUnitScale( mapUnitScale )
1157  , mOpacity( opacity )
1158  , mSelected( selected )
1159  , mRenderHints( renderHints )
1160  , mFeature( f )
1161  , mFields( fields )
1162  , mGeometryPartCount( 0 )
1163  , mGeometryPartNum( 0 )
1164 {
1165 }
1166 
1168 {
1169  mRenderContext.expressionContext().setOriginalValueVariable( value );
1170 }
1171 
1172 double QgsSymbolRenderContext::outputLineWidth( double width ) const
1173 {
1174  return mRenderContext.convertToPainterUnits( width, mOutputUnit, mMapUnitScale );
1175 }
1176 
1177 double QgsSymbolRenderContext::outputPixelSize( double size ) const
1178 {
1179  return mRenderContext.convertToPainterUnits( size, mOutputUnit, mMapUnitScale );
1180 }
1181 
1183 {
1184  // This is just a dummy implementation of assignment.
1185  // sip 4.7 generates a piece of code that needs this function to exist.
1186  // It's not generated automatically by the compiler because of
1187  // mRenderContext member which is a reference (and thus can't be changed).
1188  Q_ASSERT( false );
1189  return *this;
1190 }
1191 
1193 {
1194  return mExpressionContextScope.get();
1195 }
1196 
1198 {
1199  mExpressionContextScope.reset( contextScope );
1200 }
1201 
1203 
1205 {
1207  if ( !sl )
1208  return nullptr;
1209 
1210  QgsSymbolLayerList layers;
1211  layers.append( sl );
1212  return new QgsMarkerSymbol( layers );
1213 }
1214 
1216 {
1218  if ( !sl )
1219  return nullptr;
1220 
1221  QgsSymbolLayerList layers;
1222  layers.append( sl );
1223  return new QgsLineSymbol( layers );
1224 }
1225 
1227 {
1229  if ( !sl )
1230  return nullptr;
1231 
1232  QgsSymbolLayerList layers;
1233  layers.append( sl );
1234  return new QgsFillSymbol( layers );
1235 }
1236 
1238 
1240  : QgsSymbol( Marker, layers )
1241 {
1242  if ( mLayers.isEmpty() )
1243  mLayers.append( new QgsSimpleMarkerSymbolLayer() );
1244 }
1245 
1246 void QgsMarkerSymbol::setAngle( double symbolAngle )
1247 {
1248  double origAngle = angle();
1249  double angleDiff = symbolAngle - origAngle;
1250  const auto constMLayers = mLayers;
1251  for ( QgsSymbolLayer *layer : constMLayers )
1252  {
1253  QgsMarkerSymbolLayer *markerLayer = dynamic_cast<QgsMarkerSymbolLayer *>( layer );
1254  if ( markerLayer )
1255  markerLayer->setAngle( markerLayer->angle() + angleDiff );
1256  }
1257 }
1258 
1260 {
1261  const auto constMLayers = mLayers;
1262  for ( QgsSymbolLayer *layer : constMLayers )
1263  {
1264  if ( layer->type() != QgsSymbol::Marker )
1265  continue;
1266  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1267  return markerLayer->angle();
1268  }
1269  return 0;
1270 }
1271 
1272 void QgsMarkerSymbol::setLineAngle( double lineAng )
1273 {
1274  const auto constMLayers = mLayers;
1275  for ( QgsSymbolLayer *layer : constMLayers )
1276  {
1277  if ( layer->type() != QgsSymbol::Marker )
1278  continue;
1279  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1280  markerLayer->setLineAngle( lineAng );
1281  }
1282 }
1283 
1285 {
1286  const double symbolRotation = angle();
1287 
1288  const auto constMLayers = mLayers;
1289  for ( QgsSymbolLayer *layer : constMLayers )
1290  {
1291  if ( layer->type() != QgsSymbol::Marker )
1292  continue;
1293  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1294  if ( !property )
1295  {
1296  layer->setDataDefinedProperty( QgsSymbolLayer::PropertyAngle, QgsProperty() );
1297  }
1298  else
1299  {
1300  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1301  {
1302  layer->setDataDefinedProperty( QgsSymbolLayer::PropertyAngle, property );
1303  }
1304  else
1305  {
1306  QgsProperty rotatedDD = rotateWholeSymbol( markerLayer->angle() - symbolRotation, property );
1307  layer->setDataDefinedProperty( QgsSymbolLayer::PropertyAngle, rotatedDD );
1308  }
1309  }
1310  }
1311 }
1312 
1314 {
1315  const double symbolRotation = angle();
1316  QgsProperty symbolDD;
1317 
1318  // find the base of the "en masse" pattern
1319  const auto layers = mLayers;
1320  for ( QgsSymbolLayer *layer : layers )
1321  {
1322  if ( layer->type() != QgsSymbol::Marker )
1323  continue;
1324  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1325  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) && markerLayer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertyAngle ) )
1326  {
1327  symbolDD = markerLayer->dataDefinedProperties().property( QgsSymbolLayer::PropertyAngle );
1328  break;
1329  }
1330  }
1331 
1332  if ( !symbolDD )
1333  return QgsProperty();
1334 
1335  // check that all layer's angle expressions match the "en masse" pattern
1336  for ( QgsSymbolLayer *layer : layers )
1337  {
1338  if ( layer->type() != QgsSymbol::Marker )
1339  continue;
1340  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1341 
1343 
1344  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1345  {
1346  if ( !layerAngleDD || layerAngleDD != symbolDD )
1347  return QgsProperty();
1348  }
1349  else
1350  {
1351  QgsProperty rotatedDD( rotateWholeSymbol( markerLayer->angle() - symbolRotation, symbolDD ) );
1352  if ( !layerAngleDD || layerAngleDD != rotatedDD )
1353  return QgsProperty();
1354  }
1355  }
1356  return symbolDD;
1357 }
1358 
1359 
1361 {
1362  double origSize = size();
1363 
1364  const auto constMLayers = mLayers;
1365  for ( QgsSymbolLayer *layer : constMLayers )
1366  {
1367  if ( layer->type() != QgsSymbol::Marker )
1368  continue;
1369  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1370  if ( qgsDoubleNear( markerLayer->size(), origSize ) )
1371  markerLayer->setSize( s );
1372  else if ( !qgsDoubleNear( origSize, 0.0 ) )
1373  {
1374  // proportionally scale size
1375  markerLayer->setSize( markerLayer->size() * s / origSize );
1376  }
1377  // also scale offset to maintain relative position
1378  if ( !qgsDoubleNear( origSize, 0.0 ) && ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) ) )
1379  markerLayer->setOffset( QPointF( markerLayer->offset().x() * s / origSize,
1380  markerLayer->offset().y() * s / origSize ) );
1381  }
1382 }
1383 
1385 {
1386  // return size of the largest symbol
1387  double maxSize = 0;
1388  const auto constMLayers = mLayers;
1389  for ( QgsSymbolLayer *layer : constMLayers )
1390  {
1391  if ( layer->type() != QgsSymbol::Marker )
1392  continue;
1393  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1394  double lsize = markerLayer->size();
1395  if ( lsize > maxSize )
1396  maxSize = lsize;
1397  }
1398  return maxSize;
1399 }
1400 
1401 double QgsMarkerSymbol::size( const QgsRenderContext &context ) const
1402 {
1403  // return size of the largest symbol
1404  double maxSize = 0;
1405  for ( QgsSymbolLayer *layer : mLayers )
1406  {
1407  if ( layer->type() != QgsSymbol::Marker )
1408  continue;
1409  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1410  const double layerSize = context.convertToPainterUnits( markerLayer->size(), markerLayer->sizeUnit(), markerLayer->sizeMapUnitScale() );
1411  maxSize = std::max( maxSize, layerSize );
1412  }
1413  return maxSize;
1414 }
1415 
1417 {
1418  const auto constMLayers = mLayers;
1419  for ( QgsSymbolLayer *layer : constMLayers )
1420  {
1421  if ( layer->type() != QgsSymbol::Marker )
1422  continue;
1423 
1424  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1425  markerLayer->setSizeUnit( unit );
1426  }
1427 }
1428 
1430 {
1431  bool first = true;
1433 
1434  const auto constMLayers = mLayers;
1435  for ( QgsSymbolLayer *layer : constMLayers )
1436  {
1437  if ( layer->type() != QgsSymbol::Marker )
1438  continue;
1439  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1440 
1441  if ( first )
1442  unit = markerLayer->sizeUnit();
1443  else
1444  {
1445  if ( unit != markerLayer->sizeUnit() )
1447  }
1448 
1449  first = false;
1450  }
1451  return unit;
1452 }
1453 
1455 {
1456  const auto constMLayers = mLayers;
1457  for ( QgsSymbolLayer *layer : constMLayers )
1458  {
1459  if ( layer->type() != QgsSymbol::Marker )
1460  continue;
1461 
1462  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1463  markerLayer->setSizeMapUnitScale( scale );
1464  }
1465 }
1466 
1468 {
1469  const auto constMLayers = mLayers;
1470  for ( QgsSymbolLayer *layer : constMLayers )
1471  {
1472  if ( layer->type() != QgsSymbol::Marker )
1473  continue;
1474 
1475  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1476  return markerLayer->sizeMapUnitScale();
1477  }
1478  return QgsMapUnitScale();
1479 }
1480 
1482 {
1483  const double symbolSize = size();
1484 
1485  const auto constMLayers = mLayers;
1486  for ( QgsSymbolLayer *layer : constMLayers )
1487  {
1488  if ( layer->type() != QgsSymbol::Marker )
1489  continue;
1490  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1491 
1492  if ( !property )
1493  {
1496  }
1497  else
1498  {
1499  if ( qgsDoubleNear( symbolSize, 0.0 ) || qgsDoubleNear( markerLayer->size(), symbolSize ) )
1500  {
1501  markerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, property );
1502  }
1503  else
1504  {
1505  markerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, scaleWholeSymbol( markerLayer->size() / symbolSize, property ) );
1506  }
1507 
1508  if ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) )
1509  {
1511  markerLayer->offset().x() / symbolSize,
1512  markerLayer->offset().y() / symbolSize, property ) );
1513  }
1514  }
1515  }
1516 }
1517 
1519 {
1520  const double symbolSize = size();
1521 
1522  QgsProperty symbolDD;
1523 
1524  // find the base of the "en masse" pattern
1525  const auto layers = mLayers;
1526  for ( QgsSymbolLayer *layer : layers )
1527  {
1528  if ( layer->type() != QgsSymbol::Marker )
1529  continue;
1530  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1531  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) && markerLayer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertySize ) )
1532  {
1533  symbolDD = markerLayer->dataDefinedProperties().property( QgsSymbolLayer::PropertySize );
1534  break;
1535  }
1536  }
1537 
1538  if ( !symbolDD )
1539  return QgsProperty();
1540 
1541  // check that all layers size expressions match the "en masse" pattern
1542  for ( QgsSymbolLayer *layer : layers )
1543  {
1544  if ( layer->type() != QgsSymbol::Marker )
1545  continue;
1546  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1547 
1550 
1551  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) )
1552  {
1553  if ( !layerSizeDD || layerSizeDD != symbolDD )
1554  return QgsProperty();
1555  }
1556  else
1557  {
1558  if ( qgsDoubleNear( symbolSize, 0.0 ) )
1559  return QgsProperty();
1560 
1561  QgsProperty scaledDD( scaleWholeSymbol( markerLayer->size() / symbolSize, symbolDD ) );
1562  if ( !layerSizeDD || layerSizeDD != scaledDD )
1563  return QgsProperty();
1564  }
1565 
1566  QgsProperty scaledOffsetDD( scaleWholeSymbol( markerLayer->offset().x() / symbolSize, markerLayer->offset().y() / symbolSize, symbolDD ) );
1567  if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
1568  return QgsProperty();
1569  }
1570 
1571  return symbolDD;
1572 }
1573 
1575 {
1576  const auto constMLayers = mLayers;
1577  for ( QgsSymbolLayer *layer : constMLayers )
1578  {
1579  if ( layer->type() != QgsSymbol::Marker )
1580  continue;
1581  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1582  markerLayer->setScaleMethod( scaleMethod );
1583  }
1584 }
1585 
1587 {
1588  const auto constMLayers = mLayers;
1589  for ( QgsSymbolLayer *layer : constMLayers )
1590  {
1591  if ( layer->type() != QgsSymbol::Marker )
1592  continue;
1593  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1594  // return scale method of the first symbol layer
1595  return markerLayer->scaleMethod();
1596  }
1597 
1598  return DEFAULT_SCALE_METHOD;
1599 }
1600 
1601 void QgsMarkerSymbol::renderPointUsingLayer( QgsMarkerSymbolLayer *layer, QPointF point, QgsSymbolRenderContext &context )
1602 {
1603  static QPointF nullPoint( 0, 0 );
1604 
1606  return;
1607 
1608  QgsPaintEffect *effect = layer->paintEffect();
1609  if ( effect && effect->enabled() )
1610  {
1611  QgsEffectPainter p( context.renderContext() );
1612  p->translate( point );
1613  p.setEffect( effect );
1614  layer->renderPoint( nullPoint, context );
1615  }
1616  else
1617  {
1618  layer->renderPoint( point, context );
1619  }
1620 }
1621 
1622 void QgsMarkerSymbol::renderPoint( QPointF point, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1623 {
1624  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, selected, mRenderHints, f );
1625  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1626  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1627 
1628  if ( layerIdx != -1 )
1629  {
1630  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1631  if ( symbolLayer && symbolLayer->enabled() )
1632  {
1633  if ( symbolLayer->type() == QgsSymbol::Marker )
1634  {
1635  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( symbolLayer );
1636  renderPointUsingLayer( markerLayer, point, symbolContext );
1637  }
1638  else
1639  renderUsingLayer( symbolLayer, symbolContext );
1640  }
1641  return;
1642  }
1643 
1644  const auto constMLayers = mLayers;
1645  for ( QgsSymbolLayer *symbolLayer : constMLayers )
1646  {
1647  if ( context.renderingStopped() )
1648  break;
1649 
1650  if ( !symbolLayer->enabled() )
1651  continue;
1652 
1653  if ( symbolLayer->type() == QgsSymbol::Marker )
1654  {
1655  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( symbolLayer );
1656  renderPointUsingLayer( markerLayer, point, symbolContext );
1657  }
1658  else
1659  renderUsingLayer( symbolLayer, symbolContext );
1660  }
1661 }
1662 
1663 QRectF QgsMarkerSymbol::bounds( QPointF point, QgsRenderContext &context, const QgsFeature &feature ) const
1664 {
1665  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, false, mRenderHints, &feature, feature.fields() );
1666 
1667  QRectF bound;
1668  const auto constMLayers = mLayers;
1669  for ( QgsSymbolLayer *layer : constMLayers )
1670  {
1671  if ( layer->type() == QgsSymbol::Marker )
1672  {
1674  if ( bound.isNull() )
1675  bound = symbolLayer->bounds( point, symbolContext );
1676  else
1677  bound = bound.united( symbolLayer->bounds( point, symbolContext ) );
1678  }
1679  }
1680  return bound;
1681 }
1682 
1684 {
1685  QgsMarkerSymbol *cloneSymbol = new QgsMarkerSymbol( cloneLayers() );
1686  cloneSymbol->setOpacity( mOpacity );
1688  cloneSymbol->setLayer( mLayer );
1691  cloneSymbol->setForceRHR( mForceRHR );
1692  return cloneSymbol;
1693 }
1694 
1695 
1697 // LINE
1698 
1700  : QgsSymbol( Line, layers )
1701 {
1702  if ( mLayers.isEmpty() )
1703  mLayers.append( new QgsSimpleLineSymbolLayer() );
1704 }
1705 
1706 void QgsLineSymbol::setWidth( double w )
1707 {
1708  double origWidth = width();
1709 
1710  const auto constMLayers = mLayers;
1711  for ( QgsSymbolLayer *layer : constMLayers )
1712  {
1713  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
1714 
1715  if ( lineLayer )
1716  {
1717  if ( qgsDoubleNear( lineLayer->width(), origWidth ) )
1718  {
1719  lineLayer->setWidth( w );
1720  }
1721  else if ( !qgsDoubleNear( origWidth, 0.0 ) )
1722  {
1723  // proportionally scale the width
1724  lineLayer->setWidth( lineLayer->width() * w / origWidth );
1725  }
1726  // also scale offset to maintain relative position
1727  if ( !qgsDoubleNear( origWidth, 0.0 ) && !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1728  lineLayer->setOffset( lineLayer->offset() * w / origWidth );
1729  }
1730  }
1731 }
1732 
1733 double QgsLineSymbol::width() const
1734 {
1735  double maxWidth = 0;
1736  if ( mLayers.isEmpty() )
1737  return maxWidth;
1738 
1739  const auto constMLayers = mLayers;
1740  for ( QgsSymbolLayer *symbolLayer : constMLayers )
1741  {
1742  const QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( symbolLayer );
1743  if ( lineLayer )
1744  {
1745  double width = lineLayer->width();
1746  if ( width > maxWidth )
1747  maxWidth = width;
1748  }
1749  }
1750  return maxWidth;
1751 }
1752 
1753 double QgsLineSymbol::width( const QgsRenderContext &context ) const
1754 {
1755  // return width of the largest symbol
1756  double maxWidth = 0;
1757  for ( QgsSymbolLayer *layer : mLayers )
1758  {
1759  if ( layer->type() != QgsSymbol::Line )
1760  continue;
1761  const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
1762  const double layerWidth = lineLayer->width( context );
1763  maxWidth = std::max( maxWidth, layerWidth );
1764  }
1765  return maxWidth;
1766 }
1767 
1769 {
1770  const double symbolWidth = width();
1771 
1772  const auto constMLayers = mLayers;
1773  for ( QgsSymbolLayer *layer : constMLayers )
1774  {
1775  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
1776 
1777  if ( lineLayer )
1778  {
1779  if ( !property )
1780  {
1783  }
1784  else
1785  {
1786  if ( qgsDoubleNear( symbolWidth, 0.0 ) || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1787  {
1789  }
1790  else
1791  {
1792  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyStrokeWidth, scaleWholeSymbol( lineLayer->width() / symbolWidth, property ) );
1793  }
1794 
1795  if ( !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1796  {
1797  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyOffset, scaleWholeSymbol( lineLayer->offset() / symbolWidth, property ) );
1798  }
1799  }
1800  }
1801  }
1802 }
1803 
1805 {
1806  const double symbolWidth = width();
1807 
1808  QgsProperty symbolDD;
1809 
1810  // find the base of the "en masse" pattern
1811  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1812  {
1813  const QgsLineSymbolLayer *layer = dynamic_cast<const QgsLineSymbolLayer *>( *it );
1814  if ( layer && qgsDoubleNear( layer->width(), symbolWidth ) && layer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
1815  {
1817  break;
1818  }
1819  }
1820 
1821  if ( !symbolDD )
1822  return QgsProperty();
1823 
1824  // check that all layers width expressions match the "en masse" pattern
1825  const auto constMLayers = mLayers;
1826  for ( QgsSymbolLayer *layer : constMLayers )
1827  {
1828  if ( layer->type() != QgsSymbol::Line )
1829  continue;
1830  const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
1831 
1834 
1835  if ( qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1836  {
1837  if ( !layerWidthDD || layerWidthDD != symbolDD )
1838  return QgsProperty();
1839  }
1840  else
1841  {
1842  if ( qgsDoubleNear( symbolWidth, 0.0 ) )
1843  return QgsProperty();
1844 
1845  QgsProperty scaledDD( scaleWholeSymbol( lineLayer->width() / symbolWidth, symbolDD ) );
1846  if ( !layerWidthDD || layerWidthDD != scaledDD )
1847  return QgsProperty();
1848  }
1849 
1850  QgsProperty scaledOffsetDD( scaleWholeSymbol( lineLayer->offset() / symbolWidth, symbolDD ) );
1851  if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
1852  return QgsProperty();
1853  }
1854 
1855  return symbolDD;
1856 }
1857 
1858 void QgsLineSymbol::renderPolyline( const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1859 {
1860  //save old painter
1861  QPainter *renderPainter = context.painter();
1862  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, selected, mRenderHints, f );
1864  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1865  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1866 
1867  if ( layerIdx != -1 )
1868  {
1869  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1870  if ( symbolLayer && symbolLayer->enabled() )
1871  {
1872  if ( symbolLayer->type() == QgsSymbol::Line )
1873  {
1874  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
1875  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1876  }
1877  else
1878  renderUsingLayer( symbolLayer, symbolContext );
1879  }
1880  return;
1881  }
1882 
1883  const auto constMLayers = mLayers;
1884  for ( QgsSymbolLayer *symbolLayer : constMLayers )
1885  {
1886  if ( context.renderingStopped() )
1887  break;;
1888 
1889  if ( !symbolLayer->enabled() )
1890  continue;
1891 
1892  if ( symbolLayer->type() == QgsSymbol::Line )
1893  {
1894  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
1895  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1896  }
1897  else
1898  {
1899  renderUsingLayer( symbolLayer, symbolContext );
1900  }
1901  }
1902 
1903  context.setPainter( renderPainter );
1904 }
1905 
1906 void QgsLineSymbol::renderPolylineUsingLayer( QgsLineSymbolLayer *layer, const QPolygonF &points, QgsSymbolRenderContext &context )
1907 {
1909  return;
1910 
1911  QgsPaintEffect *effect = layer->paintEffect();
1912  if ( effect && effect->enabled() )
1913  {
1914  QgsEffectPainter p( context.renderContext() );
1915  p->translate( points.boundingRect().topLeft() );
1916  p.setEffect( effect );
1917  layer->renderPolyline( points.translated( -points.boundingRect().topLeft() ), context );
1918  }
1919  else
1920  {
1921  layer->renderPolyline( points, context );
1922  }
1923 }
1924 
1925 
1927 {
1928  QgsLineSymbol *cloneSymbol = new QgsLineSymbol( cloneLayers() );
1929  cloneSymbol->setOpacity( mOpacity );
1931  cloneSymbol->setLayer( mLayer );
1934  cloneSymbol->setForceRHR( mForceRHR );
1935  return cloneSymbol;
1936 }
1937 
1939 // FILL
1940 
1942  : QgsSymbol( Fill, layers )
1943 {
1944  if ( mLayers.isEmpty() )
1945  mLayers.append( new QgsSimpleFillSymbolLayer() );
1946 }
1947 
1948 void QgsFillSymbol::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1949 {
1950  QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, selected, mRenderHints, f );
1952  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1953  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1954 
1955  if ( layerIdx != -1 )
1956  {
1957  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1958  if ( symbolLayer && symbolLayer->enabled() )
1959  {
1960  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1961  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1962  else
1963  renderUsingLayer( symbolLayer, symbolContext );
1964  }
1965  return;
1966  }
1967 
1968  const auto constMLayers = mLayers;
1969  for ( QgsSymbolLayer *symbolLayer : constMLayers )
1970  {
1971  if ( context.renderingStopped() )
1972  break;
1973 
1974  if ( !symbolLayer->enabled() )
1975  continue;
1976 
1977  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1978  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1979  else
1980  renderUsingLayer( symbolLayer, symbolContext );
1981  }
1982 }
1983 
1984 void QgsFillSymbol::renderPolygonUsingLayer( QgsSymbolLayer *layer, const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
1985 {
1987  return;
1988 
1989  QgsSymbol::SymbolType layertype = layer->type();
1990 
1991  QgsPaintEffect *effect = layer->paintEffect();
1992  if ( effect && effect->enabled() )
1993  {
1994  QRectF bounds = polygonBounds( points, rings );
1995  QList<QPolygonF> *translatedRings = translateRings( rings, -bounds.left(), -bounds.top() );
1996 
1997  QgsEffectPainter p( context.renderContext() );
1998  p->translate( bounds.topLeft() );
1999  p.setEffect( effect );
2000  if ( layertype == QgsSymbol::Fill )
2001  {
2002  ( static_cast<QgsFillSymbolLayer *>( layer ) )->renderPolygon( points.translated( -bounds.topLeft() ), translatedRings, context );
2003  }
2004  else if ( layertype == QgsSymbol::Line )
2005  {
2006  ( static_cast<QgsLineSymbolLayer *>( layer ) )->renderPolygonStroke( points.translated( -bounds.topLeft() ), translatedRings, context );
2007  }
2008  delete translatedRings;
2009  }
2010  else
2011  {
2012  if ( layertype == QgsSymbol::Fill )
2013  {
2014  ( static_cast<QgsFillSymbolLayer *>( layer ) )->renderPolygon( points, rings, context );
2015  }
2016  else if ( layertype == QgsSymbol::Line )
2017  {
2018  ( static_cast<QgsLineSymbolLayer *>( layer ) )->renderPolygonStroke( points, rings, context );
2019  }
2020  }
2021 }
2022 
2023 QRectF QgsFillSymbol::polygonBounds( const QPolygonF &points, const QList<QPolygonF> *rings ) const
2024 {
2025  QRectF bounds = points.boundingRect();
2026  if ( rings )
2027  {
2028  QList<QPolygonF>::const_iterator it = rings->constBegin();
2029  for ( ; it != rings->constEnd(); ++it )
2030  {
2031  bounds = bounds.united( ( *it ).boundingRect() );
2032  }
2033  }
2034  return bounds;
2035 }
2036 
2037 QList<QPolygonF> *QgsFillSymbol::translateRings( const QList<QPolygonF> *rings, double dx, double dy ) const
2038 {
2039  if ( !rings )
2040  return nullptr;
2041 
2042  QList<QPolygonF> *translatedRings = new QList<QPolygonF>;
2043  QList<QPolygonF>::const_iterator it = rings->constBegin();
2044  for ( ; it != rings->constEnd(); ++it )
2045  {
2046  translatedRings->append( ( *it ).translated( dx, dy ) );
2047  }
2048  return translatedRings;
2049 }
2050 
2052 {
2053  QgsFillSymbol *cloneSymbol = new QgsFillSymbol( cloneLayers() );
2054  cloneSymbol->setOpacity( mOpacity );
2056  cloneSymbol->setLayer( mLayer );
2059  cloneSymbol->setForceRHR( mForceRHR );
2060  return cloneSymbol;
2061 }
2062 
2064 {
2065  const auto constMLayers = mLayers;
2066  for ( QgsSymbolLayer *layer : constMLayers )
2067  {
2068  if ( layer->type() != QgsSymbol::Fill )
2069  continue;
2070 
2071  QgsFillSymbolLayer *fillLayer = static_cast<QgsFillSymbolLayer *>( layer );
2072 
2073  if ( fillLayer )
2074  fillLayer->setAngle( angle );
2075  }
2076 }
2077 
2078 
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:364
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:1153
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...
void drawPreviewIcon(QPainter *painter, QSize size, QgsRenderContext *customContext=nullptr, bool selected=false)
Draws an icon of the symbol that occupies an area given by size using the specified painter...
Definition: qgssymbol.cpp:492
double y
Definition: qgspoint.h:42
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:285
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:1144
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:377
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:1215
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
ScaleMethod scaleMethod()
Definition: qgssymbol.cpp:1586
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:1226
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:252
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:265
void setExpressionContextScope(QgsExpressionContextScope *contextScope)
Set an expression scope for this symbol.
Definition: qgssymbol.cpp:1197
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:1858
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
Converts the symbol to a SLD representation.
Definition: qgssymbol.cpp:638
static QPointF _getPoint(QgsRenderContext &context, const QgsPoint &point)
Creates a point in screen coordinates from a QgsPoint in map coordinates.
Definition: qgssymbol.h:540
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:634
void setSize(double size)
Sets the size for the whole symbol.
Definition: qgssymbol.cpp:1360
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:1454
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:473
Q_DECL_DEPRECATED double outputLineWidth(double width) const
Definition: qgssymbol.cpp:1172
bool mClipFeaturesToExtent
Definition: qgssymbol.h:611
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:121
Mixed or unknown units.
Definition: qgsunittypes.h:121
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:785
bool deleteSymbolLayer(int index)
Removes and deletes the symbol layer at the specified index.
Definition: qgssymbol.cpp:387
void setDataDefinedAngle(const QgsProperty &property)
Set data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1284
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:1246
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:597
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:859
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:1059
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:423
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:614
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:231
void setOutputUnit(QgsUnitTypes::RenderUnit unit)
Sets the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:276
QgsSymbolRenderContext & operator=(const QgsSymbolRenderContext &)
Definition: qgssymbol.cpp:1182
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:1622
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
Definition: qgssymbol.cpp:1167
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:1313
SymbolType mType
Definition: qgssymbol.h:604
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:605
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
bool mForceRHR
Definition: qgssymbol.h:612
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:554
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:534
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:294
void setOriginalGeometryType(QgsWkbTypes::GeometryType type)
Sets the geometry type for the original feature geometry being rendered.
Definition: qgssymbol.h:755
#define FALLTHROUGH
Definition: qgis.h:666
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:612
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:1663
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:1948
Q_DECL_DEPRECATED double outputPixelSize(double size) const
Definition: qgssymbol.cpp:1177
void renderUsingLayer(QgsSymbolLayer *layer, QgsSymbolRenderContext &context)
Renders a context using a particular symbol layer without passing in a geometry.
Definition: qgssymbol.cpp:665
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:439
QgsFillSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:2051
void setGeometryPartNum(int num)
Sets the part number of current geometry.
Definition: qgssymbol.h:797
void setWidth(double width)
Sets the width for the whole line symbol.
Definition: qgssymbol.cpp:1706
double width() const
Returns the estimated width for the whole symbol, which is the maximum width of all marker symbol lay...
Definition: qgssymbol.cpp:1733
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:225
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:1467
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:481
QgsSymbolRenderContext * symbolRenderContext()
Returns the symbol render context.
Definition: qgssymbol.cpp:1139
QgsSymbol::SymbolType type() const
void setScaleMethod(QgsSymbol::ScaleMethod scaleMethod)
Definition: qgssymbol.cpp:1574
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:729
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:2063
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:1239
QgsRenderContext & renderContext()
Returns a reference to the context&#39;s render context.
Definition: qgssymbol.h:667
Implementation of GeometrySimplifier using the "MapToPixel" algorithm.
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
Definition: qgssymbol.cpp:359
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:1768
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the size units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1416
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:1429
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:1518
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
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:635
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:407
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:686
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:225
QgsSymbolLayerList cloneLayers() const
Retrieve a cloned list of all layers that make up this symbol.
Definition: qgssymbol.cpp:651
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:700
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:767
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the symbol&#39;s size.
RenderHints mRenderHints
Definition: qgssymbol.h:610
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:711
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
Definition: qgssymbol.cpp:1384
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:213
RenderHints renderHints() const
Returns the rendering hint flags for the symbol.
Definition: qgssymbol.h:451
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:441
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:1272
QgsLineSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Constructor for QgsLineSymbol, with the specified list of initial symbol layers.
Definition: qgssymbol.cpp:1699
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:398
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgssymbol.h:1154
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:1204
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:1481
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:462
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:432
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:484
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:568
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:718
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:446
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:608
Hybrid symbol.
Definition: qgssymbol.h:88
QgsProperty dataDefinedWidth() const
Returns data defined width for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1804
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:1259
QgsFillSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Constructor for QgsFillSymbol, with the specified list of initial symbol layers.
Definition: qgssymbol.cpp:1941
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:1683
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:113
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:1926
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:471
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:1192