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