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