QGIS API Documentation  3.4.3-Madeira (2f64a3c)
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  {
673  return true;
674  // we treat geometry generator layers like they have data defined properties,
675  // since the WHOLE layer is based on expressions and requires the full expression
676  // context
677  if ( layer->layerType() == QLatin1String( "GeometryGenerator" ) )
678  return true;
679  }
680  return false;
681 }
682 
684 {
686  mLayer = layer;
688 }
689 
691 {
693  return mLayer;
695 }
696 
698 
702 class ExpressionContextScopePopper
703 {
704  public:
705 
706  ExpressionContextScopePopper() = default;
707 
708  ~ExpressionContextScopePopper()
709  {
710  if ( context )
711  context->popScope();
712  }
713 
714  QgsExpressionContext *context = nullptr;
715 };
716 
720 class GeometryRestorer
721 {
722  public:
723  GeometryRestorer( QgsRenderContext &context )
724  : mContext( context ),
725  mGeometry( context.geometry() )
726  {}
727 
728  ~GeometryRestorer()
729  {
730  mContext.setGeometry( mGeometry );
731  }
732 
733  private:
734  QgsRenderContext &mContext;
735  const QgsAbstractGeometry *mGeometry;
736 };
738 
739 void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, int currentVertexMarkerSize )
740 {
741  const QgsGeometry geom = feature.geometry();
742  if ( geom.isNull() )
743  {
744  return;
745  }
746 
747  GeometryRestorer geomRestorer( context );
748  QgsGeometry segmentizedGeometry = geom;
749  bool usingSegmentizedGeometry = false;
750  context.setGeometry( geom.constGet() );
751 
752  bool tileMapRendering = context.testFlag( QgsRenderContext::RenderMapTile );
753 
754  //convert curve types to normal point/line/polygon ones
755  if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) )
756  {
758  if ( !g )
759  {
760  return;
761  }
762  segmentizedGeometry = QgsGeometry( g );
763  usingSegmentizedGeometry = true;
764  }
765 
766  mSymbolRenderContext->setGeometryPartCount( segmentizedGeometry.constGet()->partCount() );
767  mSymbolRenderContext->setGeometryPartNum( 1 );
768 
769  bool needsExpressionContext = hasDataDefinedProperties();
770  ExpressionContextScopePopper scopePopper;
771  if ( mSymbolRenderContext->expressionContextScope() )
772  {
773  if ( needsExpressionContext )
774  {
775  // this is somewhat nasty - by appending this scope here it's now owned
776  // by both mSymbolRenderContext AND context.expressionContext()
777  // the RAII scopePopper is required to make sure it always has ownership transferred back
778  // from context.expressionContext(), even if exceptions of other early exits occur in this
779  // function
780  context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
781  scopePopper.context = &context.expressionContext();
782 
783  QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
784  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount(), true ) );
785  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1, true ) );
786  }
787  }
788 
789  // Collection of markers to paint, only used for no curve types.
790  QPolygonF markers;
791 
792  // Simplify the geometry, if needed.
794  {
795  const int simplifyHints = context.vectorSimplifyMethod().simplifyHints();
796  const QgsMapToPixelSimplifier simplifier( simplifyHints, context.vectorSimplifyMethod().tolerance(),
798  segmentizedGeometry = simplifier.simplify( segmentizedGeometry );
799  }
800 
801  switch ( QgsWkbTypes::flatType( segmentizedGeometry.constGet()->wkbType() ) )
802  {
803  case QgsWkbTypes::Point:
804  {
805  if ( mType != QgsSymbol::Marker )
806  {
807  QgsDebugMsg( QStringLiteral( "point can be drawn only with marker symbol!" ) );
808  break;
809  }
810 
811  const QgsPoint *point = static_cast< const QgsPoint * >( segmentizedGeometry.constGet() );
812  const QPointF pt = _getPoint( context, *point );
813  static_cast<QgsMarkerSymbol *>( this )->renderPoint( pt, &feature, context, layer, selected );
814 
816  {
817  //draw debugging rect
818  context.painter()->setPen( Qt::red );
819  context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
820  context.painter()->drawRect( static_cast<QgsMarkerSymbol *>( this )->bounds( pt, context, feature ) );
821  }
822 
823  if ( drawVertexMarker && !usingSegmentizedGeometry )
824  {
825  markers << pt;
826  }
827  }
828  break;
830  {
831  if ( mType != QgsSymbol::Line )
832  {
833  QgsDebugMsg( QStringLiteral( "linestring can be drawn only with line symbol!" ) );
834  break;
835  }
836  const QgsCurve &curve = dynamic_cast<const QgsCurve &>( *segmentizedGeometry.constGet() );
837  const QPolygonF pts = _getLineString( context, curve, !tileMapRendering && clipFeaturesToExtent() );
838  static_cast<QgsLineSymbol *>( this )->renderPolyline( pts, &feature, context, layer, selected );
839 
840  if ( drawVertexMarker && !usingSegmentizedGeometry )
841  {
842  markers = pts;
843  }
844  }
845  break;
848  {
849  QPolygonF pts;
850  QList<QPolygonF> holes;
851  if ( mType != QgsSymbol::Fill )
852  {
853  QgsDebugMsg( QStringLiteral( "polygon can be drawn only with fill symbol!" ) );
854  break;
855  }
856  const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *segmentizedGeometry.constGet() );
857  if ( !polygon.exteriorRing() )
858  {
859  QgsDebugMsg( QStringLiteral( "cannot render polygon with no exterior ring" ) );
860  break;
861  }
862  _getPolygon( pts, holes, context, polygon, !tileMapRendering && clipFeaturesToExtent(), mForceRHR );
863  static_cast<QgsFillSymbol *>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
864 
865  if ( drawVertexMarker && !usingSegmentizedGeometry )
866  {
867  markers = pts;
868 
869  Q_FOREACH ( const QPolygonF &hole, holes )
870  {
871  markers << hole;
872  }
873  }
874  }
875  break;
876 
878  {
879  if ( mType != QgsSymbol::Marker )
880  {
881  QgsDebugMsg( QStringLiteral( "multi-point can be drawn only with marker symbol!" ) );
882  break;
883  }
884 
885  const QgsMultiPoint &mp = static_cast< const QgsMultiPoint & >( *segmentizedGeometry.constGet() );
886 
887  if ( drawVertexMarker && !usingSegmentizedGeometry )
888  {
889  markers.reserve( mp.numGeometries() );
890  }
891 
892  for ( int i = 0; i < mp.numGeometries(); ++i )
893  {
894  mSymbolRenderContext->setGeometryPartNum( i + 1 );
895  if ( needsExpressionContext )
896  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
897 
898  const QgsPoint &point = static_cast< const QgsPoint & >( *mp.geometryN( i ) );
899  const QPointF pt = _getPoint( context, point );
900  static_cast<QgsMarkerSymbol *>( this )->renderPoint( pt, &feature, context, layer, selected );
901 
902  if ( drawVertexMarker && !usingSegmentizedGeometry )
903  {
904  markers.append( pt );
905  }
906  }
907  }
908  break;
909 
912  {
913  if ( mType != QgsSymbol::Line )
914  {
915  QgsDebugMsg( QStringLiteral( "multi-linestring can be drawn only with line symbol!" ) );
916  break;
917  }
918 
919  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
920 
921  const unsigned int num = geomCollection.numGeometries();
922  for ( unsigned int i = 0; i < num; ++i )
923  {
924  mSymbolRenderContext->setGeometryPartNum( i + 1 );
925  if ( needsExpressionContext )
926  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
927 
928  context.setGeometry( geomCollection.geometryN( i ) );
929  const QgsCurve &curve = dynamic_cast<const QgsCurve &>( *geomCollection.geometryN( i ) );
930  const QPolygonF pts = _getLineString( context, curve, !tileMapRendering && clipFeaturesToExtent() );
931  static_cast<QgsLineSymbol *>( this )->renderPolyline( pts, &feature, context, layer, selected );
932 
933  if ( drawVertexMarker && !usingSegmentizedGeometry )
934  {
935  if ( i == 0 )
936  {
937  markers = pts;
938  }
939  else
940  {
941  markers << pts;
942  }
943  }
944  }
945  }
946  break;
947 
950  {
951  if ( mType != QgsSymbol::Fill )
952  {
953  QgsDebugMsg( QStringLiteral( "multi-polygon can be drawn only with fill symbol!" ) );
954  break;
955  }
956 
957  QPolygonF pts;
958  QList<QPolygonF> holes;
959 
960  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
961  const unsigned int num = geomCollection.numGeometries();
962 
963  // Sort components by approximate area (probably a bit faster than using
964  // area() )
965  std::map<double, QList<unsigned int> > mapAreaToPartNum;
966  for ( unsigned int i = 0; i < num; ++i )
967  {
968  const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *geomCollection.geometryN( i ) );
969  const QgsRectangle r( polygon.boundingBox() );
970  mapAreaToPartNum[ r.width() * r.height()] << i;
971  }
972 
973  // Draw starting with larger parts down to smaller parts, so that in
974  // case of a part being incorrectly inside another part, it is drawn
975  // on top of it (#15419)
976  std::map<double, QList<unsigned int> >::const_reverse_iterator iter = mapAreaToPartNum.rbegin();
977  for ( ; iter != mapAreaToPartNum.rend(); ++iter )
978  {
979  const QList<unsigned int> &listPartIndex = iter->second;
980  for ( int idx = 0; idx < listPartIndex.size(); ++idx )
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  if ( i == 0 )
998  {
999  markers = pts;
1000  }
1001  else
1002  {
1003  markers << pts;
1004  }
1005 
1006  Q_FOREACH ( const QPolygonF &hole, holes )
1007  {
1008  markers << hole;
1009  }
1010  }
1011  }
1012  }
1013  break;
1014  }
1016  {
1017  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
1018  if ( geomCollection.numGeometries() == 0 )
1019  {
1020  // skip noise from empty geometry collections from simplification
1021  break;
1022  }
1023 
1024  FALLTHROUGH
1025  }
1026  default:
1027  QgsDebugMsg( QStringLiteral( "feature %1: unsupported wkb type %2/%3 for rendering" )
1028  .arg( feature.id() )
1029  .arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
1030  .arg( geom.wkbType(), 0, 16 ) );
1031  }
1032 
1033  if ( drawVertexMarker )
1034  {
1035  if ( !markers.isEmpty() )
1036  {
1037  Q_FOREACH ( QPointF marker, markers )
1038  {
1039  renderVertexMarker( marker, context, currentVertexMarkerType, currentVertexMarkerSize );
1040  }
1041  }
1042  else
1043  {
1045  const QgsMapToPixel &mtp = context.mapToPixel();
1046 
1047  QgsPoint vertexPoint;
1048  QgsVertexId vertexId;
1049  double x, y, z;
1050  QPointF mapPoint;
1051  while ( geom.constGet()->nextVertex( vertexId, vertexPoint ) )
1052  {
1053  //transform
1054  x = vertexPoint.x();
1055  y = vertexPoint.y();
1056  z = 0.0;
1057  if ( ct.isValid() )
1058  {
1059  ct.transformInPlace( x, y, z );
1060  }
1061  mapPoint.setX( x );
1062  mapPoint.setY( y );
1063  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1064  renderVertexMarker( mapPoint, context, currentVertexMarkerType, currentVertexMarkerSize );
1065  }
1066  }
1067  }
1068 }
1069 
1071 {
1072  return mSymbolRenderContext.get();
1073 }
1074 
1075 void QgsSymbol::renderVertexMarker( QPointF pt, QgsRenderContext &context, int currentVertexMarkerType, int currentVertexMarkerSize )
1076 {
1077  QgsVectorLayer::drawVertexMarker( pt.x(), pt.y(), *context.painter(), static_cast< QgsVectorLayer::VertexMarkerType >( currentVertexMarkerType ), currentVertexMarkerSize );
1078 }
1079 
1081 
1082 
1084  : mRenderContext( c )
1085  , mOutputUnit( u )
1086  , mMapUnitScale( mapUnitScale )
1087  , mOpacity( opacity )
1088  , mSelected( selected )
1089  , mRenderHints( renderHints )
1090  , mFeature( f )
1091  , mFields( fields )
1092  , mGeometryPartCount( 0 )
1093  , mGeometryPartNum( 0 )
1094 {
1095 }
1096 
1098 {
1099  mRenderContext.expressionContext().setOriginalValueVariable( value );
1100 }
1101 
1102 double QgsSymbolRenderContext::outputLineWidth( double width ) const
1103 {
1104  return mRenderContext.convertToPainterUnits( width, mOutputUnit, mMapUnitScale );
1105 }
1106 
1107 double QgsSymbolRenderContext::outputPixelSize( double size ) const
1108 {
1109  return mRenderContext.convertToPainterUnits( size, mOutputUnit, mMapUnitScale );
1110 }
1111 
1113 {
1114  // This is just a dummy implementation of assignment.
1115  // sip 4.7 generates a piece of code that needs this function to exist.
1116  // It's not generated automatically by the compiler because of
1117  // mRenderContext member which is a reference (and thus can't be changed).
1118  Q_ASSERT( false );
1119  return *this;
1120 }
1121 
1123 {
1124  return mExpressionContextScope.get();
1125 }
1126 
1128 {
1129  mExpressionContextScope.reset( contextScope );
1130 }
1131 
1133 
1135 {
1137  if ( !sl )
1138  return nullptr;
1139 
1140  QgsSymbolLayerList layers;
1141  layers.append( sl );
1142  return new QgsMarkerSymbol( layers );
1143 }
1144 
1146 {
1148  if ( !sl )
1149  return nullptr;
1150 
1151  QgsSymbolLayerList layers;
1152  layers.append( sl );
1153  return new QgsLineSymbol( layers );
1154 }
1155 
1157 {
1159  if ( !sl )
1160  return nullptr;
1161 
1162  QgsSymbolLayerList layers;
1163  layers.append( sl );
1164  return new QgsFillSymbol( layers );
1165 }
1166 
1168 
1170  : QgsSymbol( Marker, layers )
1171 {
1172  if ( mLayers.isEmpty() )
1173  mLayers.append( new QgsSimpleMarkerSymbolLayer() );
1174 }
1175 
1176 void QgsMarkerSymbol::setAngle( double symbolAngle )
1177 {
1178  double origAngle = angle();
1179  double angleDiff = symbolAngle - origAngle;
1180  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1181  {
1182  QgsMarkerSymbolLayer *markerLayer = dynamic_cast<QgsMarkerSymbolLayer *>( layer );
1183  if ( markerLayer )
1184  markerLayer->setAngle( markerLayer->angle() + angleDiff );
1185  }
1186 }
1187 
1189 {
1190  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1191  {
1192  if ( layer->type() != QgsSymbol::Marker )
1193  continue;
1194  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1195  return markerLayer->angle();
1196  }
1197  return 0;
1198 }
1199 
1200 void QgsMarkerSymbol::setLineAngle( double lineAng )
1201 {
1202  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1203  {
1204  if ( layer->type() != QgsSymbol::Marker )
1205  continue;
1206  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1207  markerLayer->setLineAngle( lineAng );
1208  }
1209 }
1210 
1212 {
1213  const double symbolRotation = angle();
1214 
1215  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1216  {
1217  if ( layer->type() != QgsSymbol::Marker )
1218  continue;
1219  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1220  if ( !property )
1221  {
1223  }
1224  else
1225  {
1226  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1227  {
1229  }
1230  else
1231  {
1232  QgsProperty rotatedDD = rotateWholeSymbol( markerLayer->angle() - symbolRotation, property );
1234  }
1235  }
1236  }
1237 }
1238 
1240 {
1241  const double symbolRotation = angle();
1242  QgsProperty symbolDD;
1243 
1244  // find the base of the "en masse" pattern
1245  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1246  {
1247  if ( layer->type() != QgsSymbol::Marker )
1248  continue;
1249  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1250  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) && markerLayer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertyAngle ) )
1251  {
1252  symbolDD = markerLayer->dataDefinedProperties().property( QgsSymbolLayer::PropertyAngle );
1253  break;
1254  }
1255  }
1256 
1257  if ( !symbolDD )
1258  return QgsProperty();
1259 
1260  // check that all layer's angle expressions match the "en masse" pattern
1261  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1262  {
1263  if ( layer->type() != QgsSymbol::Marker )
1264  continue;
1265  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1266 
1268 
1269  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1270  {
1271  if ( !layerAngleDD || layerAngleDD != symbolDD )
1272  return QgsProperty();
1273  }
1274  else
1275  {
1276  QgsProperty rotatedDD( rotateWholeSymbol( markerLayer->angle() - symbolRotation, symbolDD ) );
1277  if ( !layerAngleDD || layerAngleDD != rotatedDD )
1278  return QgsProperty();
1279  }
1280  }
1281  return symbolDD;
1282 }
1283 
1284 
1286 {
1287  double origSize = size();
1288 
1289  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1290  {
1291  if ( layer->type() != QgsSymbol::Marker )
1292  continue;
1293  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1294  if ( qgsDoubleNear( markerLayer->size(), origSize ) )
1295  markerLayer->setSize( s );
1296  else if ( !qgsDoubleNear( origSize, 0.0 ) )
1297  {
1298  // proportionally scale size
1299  markerLayer->setSize( markerLayer->size() * s / origSize );
1300  }
1301  // also scale offset to maintain relative position
1302  if ( !qgsDoubleNear( origSize, 0.0 ) && ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) ) )
1303  markerLayer->setOffset( QPointF( markerLayer->offset().x() * s / origSize,
1304  markerLayer->offset().y() * s / origSize ) );
1305  }
1306 }
1307 
1309 {
1310  // return size of the largest symbol
1311  double maxSize = 0;
1312  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1313  {
1314  if ( layer->type() != QgsSymbol::Marker )
1315  continue;
1316  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1317  double lsize = markerLayer->size();
1318  if ( lsize > maxSize )
1319  maxSize = lsize;
1320  }
1321  return maxSize;
1322 }
1323 
1325 {
1326  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1327  {
1328  if ( layer->type() != QgsSymbol::Marker )
1329  continue;
1330 
1331  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1332  markerLayer->setSizeUnit( unit );
1333  }
1334 }
1335 
1337 {
1338  bool first = true;
1340 
1341  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1342  {
1343  if ( layer->type() != QgsSymbol::Marker )
1344  continue;
1345  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1346 
1347  if ( first )
1348  unit = markerLayer->sizeUnit();
1349  else
1350  {
1351  if ( unit != markerLayer->sizeUnit() )
1353  }
1354 
1355  first = false;
1356  }
1357  return unit;
1358 }
1359 
1361 {
1362  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1363  {
1364  if ( layer->type() != QgsSymbol::Marker )
1365  continue;
1366 
1367  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1368  markerLayer->setSizeMapUnitScale( scale );
1369  }
1370 }
1371 
1373 {
1374  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1375  {
1376  if ( layer->type() != QgsSymbol::Marker )
1377  continue;
1378 
1379  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1380  return markerLayer->sizeMapUnitScale();
1381  }
1382  return QgsMapUnitScale();
1383 }
1384 
1386 {
1387  const double symbolSize = size();
1388 
1389  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1390  {
1391  if ( layer->type() != QgsSymbol::Marker )
1392  continue;
1393  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1394 
1395  if ( !property )
1396  {
1399  }
1400  else
1401  {
1402  if ( qgsDoubleNear( symbolSize, 0.0 ) || qgsDoubleNear( markerLayer->size(), symbolSize ) )
1403  {
1404  markerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, property );
1405  }
1406  else
1407  {
1408  markerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, scaleWholeSymbol( markerLayer->size() / symbolSize, property ) );
1409  }
1410 
1411  if ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) )
1412  {
1414  markerLayer->offset().x() / symbolSize,
1415  markerLayer->offset().y() / symbolSize, property ) );
1416  }
1417  }
1418  }
1419 }
1420 
1422 {
1423  const double symbolSize = size();
1424 
1425  QgsProperty symbolDD;
1426 
1427  // find the base of the "en masse" pattern
1428  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1429  {
1430  if ( layer->type() != QgsSymbol::Marker )
1431  continue;
1432  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1433  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) && markerLayer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertySize ) )
1434  {
1435  symbolDD = markerLayer->dataDefinedProperties().property( QgsSymbolLayer::PropertySize );
1436  break;
1437  }
1438  }
1439 
1440  if ( !symbolDD )
1441  return QgsProperty();
1442 
1443  // check that all layers size expressions match the "en masse" pattern
1444  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1445  {
1446  if ( layer->type() != QgsSymbol::Marker )
1447  continue;
1448  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1449 
1452 
1453  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) )
1454  {
1455  if ( !layerSizeDD || layerSizeDD != symbolDD )
1456  return QgsProperty();
1457  }
1458  else
1459  {
1460  if ( qgsDoubleNear( symbolSize, 0.0 ) )
1461  return QgsProperty();
1462 
1463  QgsProperty scaledDD( scaleWholeSymbol( markerLayer->size() / symbolSize, symbolDD ) );
1464  if ( !layerSizeDD || layerSizeDD != scaledDD )
1465  return QgsProperty();
1466  }
1467 
1468  QgsProperty scaledOffsetDD( scaleWholeSymbol( markerLayer->offset().x() / symbolSize, markerLayer->offset().y() / symbolSize, symbolDD ) );
1469  if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
1470  return QgsProperty();
1471  }
1472 
1473  return symbolDD;
1474 }
1475 
1477 {
1478  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1479  {
1480  if ( layer->type() != QgsSymbol::Marker )
1481  continue;
1482  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1483  markerLayer->setScaleMethod( scaleMethod );
1484  }
1485 }
1486 
1488 {
1489  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1490  {
1491  if ( layer->type() != QgsSymbol::Marker )
1492  continue;
1493  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1494  // return scale method of the first symbol layer
1495  return markerLayer->scaleMethod();
1496  }
1497 
1498  return DEFAULT_SCALE_METHOD;
1499 }
1500 
1501 void QgsMarkerSymbol::renderPointUsingLayer( QgsMarkerSymbolLayer *layer, QPointF point, QgsSymbolRenderContext &context )
1502 {
1503  static QPointF nullPoint( 0, 0 );
1504 
1506  return;
1507 
1508  QgsPaintEffect *effect = layer->paintEffect();
1509  if ( effect && effect->enabled() )
1510  {
1511  QgsEffectPainter p( context.renderContext() );
1512  p->translate( point );
1513  p.setEffect( effect );
1514  layer->renderPoint( nullPoint, context );
1515  }
1516  else
1517  {
1518  layer->renderPoint( point, context );
1519  }
1520 }
1521 
1522 void QgsMarkerSymbol::renderPoint( QPointF point, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1523 {
1524  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, selected, mRenderHints, f, QgsFields(), mapUnitScale() );
1525  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1526  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1527 
1528  if ( layerIdx != -1 )
1529  {
1530  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1531  if ( symbolLayer && symbolLayer->enabled() )
1532  {
1533  if ( symbolLayer->type() == QgsSymbol::Marker )
1534  {
1535  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( symbolLayer );
1536  renderPointUsingLayer( markerLayer, point, symbolContext );
1537  }
1538  else
1539  renderUsingLayer( symbolLayer, symbolContext );
1540  }
1541  return;
1542  }
1543 
1544  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1545  {
1546  if ( !symbolLayer->enabled() )
1547  continue;
1548 
1549  if ( symbolLayer->type() == QgsSymbol::Marker )
1550  {
1551  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( symbolLayer );
1552  renderPointUsingLayer( markerLayer, point, symbolContext );
1553  }
1554  else
1555  renderUsingLayer( symbolLayer, symbolContext );
1556  }
1557 }
1558 
1559 QRectF QgsMarkerSymbol::bounds( QPointF point, QgsRenderContext &context, const QgsFeature &feature ) const
1560 {
1561  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, false, mRenderHints, &feature, feature.fields(), mapUnitScale() );
1562 
1563  QRectF bound;
1564  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1565  {
1566  if ( layer->type() == QgsSymbol::Marker )
1567  {
1569  if ( bound.isNull() )
1570  bound = symbolLayer->bounds( point, symbolContext );
1571  else
1572  bound = bound.united( symbolLayer->bounds( point, symbolContext ) );
1573  }
1574  }
1575  return bound;
1576 }
1577 
1579 {
1580  QgsMarkerSymbol *cloneSymbol = new QgsMarkerSymbol( cloneLayers() );
1581  cloneSymbol->setOpacity( mOpacity );
1583  cloneSymbol->setLayer( mLayer );
1586  cloneSymbol->setForceRHR( mForceRHR );
1587  return cloneSymbol;
1588 }
1589 
1590 
1592 // LINE
1593 
1595  : QgsSymbol( Line, layers )
1596 {
1597  if ( mLayers.isEmpty() )
1598  mLayers.append( new QgsSimpleLineSymbolLayer() );
1599 }
1600 
1601 void QgsLineSymbol::setWidth( double w )
1602 {
1603  double origWidth = width();
1604 
1605  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1606  {
1607  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
1608 
1609  if ( lineLayer )
1610  {
1611  if ( qgsDoubleNear( lineLayer->width(), origWidth ) )
1612  {
1613  lineLayer->setWidth( w );
1614  }
1615  else if ( !qgsDoubleNear( origWidth, 0.0 ) )
1616  {
1617  // proportionally scale the width
1618  lineLayer->setWidth( lineLayer->width() * w / origWidth );
1619  }
1620  // also scale offset to maintain relative position
1621  if ( !qgsDoubleNear( origWidth, 0.0 ) && !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1622  lineLayer->setOffset( lineLayer->offset() * w / origWidth );
1623  }
1624  }
1625 }
1626 
1627 double QgsLineSymbol::width() const
1628 {
1629  double maxWidth = 0;
1630  if ( mLayers.isEmpty() )
1631  return maxWidth;
1632 
1633  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1634  {
1635  const QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( symbolLayer );
1636  if ( lineLayer )
1637  {
1638  double width = lineLayer->width();
1639  if ( width > maxWidth )
1640  maxWidth = width;
1641  }
1642  }
1643  return maxWidth;
1644 }
1645 
1647 {
1648  const double symbolWidth = width();
1649 
1650  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1651  {
1652  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
1653 
1654  if ( lineLayer )
1655  {
1656  if ( !property )
1657  {
1660  }
1661  else
1662  {
1663  if ( qgsDoubleNear( symbolWidth, 0.0 ) || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1664  {
1666  }
1667  else
1668  {
1669  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyStrokeWidth, scaleWholeSymbol( lineLayer->width() / symbolWidth, property ) );
1670  }
1671 
1672  if ( !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1673  {
1674  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyOffset, scaleWholeSymbol( lineLayer->offset() / symbolWidth, property ) );
1675  }
1676  }
1677  }
1678  }
1679 }
1680 
1682 {
1683  const double symbolWidth = width();
1684 
1685  QgsProperty symbolDD;
1686 
1687  // find the base of the "en masse" pattern
1688  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1689  {
1690  const QgsLineSymbolLayer *layer = dynamic_cast<const QgsLineSymbolLayer *>( *it );
1691  if ( layer && qgsDoubleNear( layer->width(), symbolWidth ) && layer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
1692  {
1694  break;
1695  }
1696  }
1697 
1698  if ( !symbolDD )
1699  return QgsProperty();
1700 
1701  // check that all layers width expressions match the "en masse" pattern
1702  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1703  {
1704  if ( layer->type() != QgsSymbol::Line )
1705  continue;
1706  const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
1707 
1710 
1711  if ( qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1712  {
1713  if ( !layerWidthDD || layerWidthDD != symbolDD )
1714  return QgsProperty();
1715  }
1716  else
1717  {
1718  if ( qgsDoubleNear( symbolWidth, 0.0 ) )
1719  return QgsProperty();
1720 
1721  QgsProperty scaledDD( scaleWholeSymbol( lineLayer->width() / symbolWidth, symbolDD ) );
1722  if ( !layerWidthDD || layerWidthDD != scaledDD )
1723  return QgsProperty();
1724  }
1725 
1726  QgsProperty scaledOffsetDD( scaleWholeSymbol( lineLayer->offset() / symbolWidth, symbolDD ) );
1727  if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
1728  return QgsProperty();
1729  }
1730 
1731  return symbolDD;
1732 }
1733 
1734 void QgsLineSymbol::renderPolyline( const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1735 {
1736  //save old painter
1737  QPainter *renderPainter = context.painter();
1738  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, selected, mRenderHints, f, QgsFields(), mapUnitScale() );
1740  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1741  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1742 
1743  if ( layerIdx != -1 )
1744  {
1745  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1746  if ( symbolLayer && symbolLayer->enabled() )
1747  {
1748  if ( symbolLayer->type() == QgsSymbol::Line )
1749  {
1750  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
1751  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1752  }
1753  else
1754  renderUsingLayer( symbolLayer, symbolContext );
1755  }
1756  return;
1757  }
1758 
1759  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1760  {
1761  if ( !symbolLayer->enabled() )
1762  continue;
1763 
1764  if ( symbolLayer->type() == QgsSymbol::Line )
1765  {
1766  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
1767  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1768  }
1769  else
1770  {
1771  renderUsingLayer( symbolLayer, symbolContext );
1772  }
1773  }
1774 
1775  context.setPainter( renderPainter );
1776 }
1777 
1778 void QgsLineSymbol::renderPolylineUsingLayer( QgsLineSymbolLayer *layer, const QPolygonF &points, QgsSymbolRenderContext &context )
1779 {
1781  return;
1782 
1783  QgsPaintEffect *effect = layer->paintEffect();
1784  if ( effect && effect->enabled() )
1785  {
1786  QgsEffectPainter p( context.renderContext() );
1787  p->translate( points.boundingRect().topLeft() );
1788  p.setEffect( effect );
1789  layer->renderPolyline( points.translated( -points.boundingRect().topLeft() ), context );
1790  }
1791  else
1792  {
1793  layer->renderPolyline( points, context );
1794  }
1795 }
1796 
1797 
1799 {
1800  QgsLineSymbol *cloneSymbol = new QgsLineSymbol( cloneLayers() );
1801  cloneSymbol->setOpacity( mOpacity );
1803  cloneSymbol->setLayer( mLayer );
1806  cloneSymbol->setForceRHR( mForceRHR );
1807  return cloneSymbol;
1808 }
1809 
1811 // FILL
1812 
1814  : QgsSymbol( Fill, layers )
1815 {
1816  if ( mLayers.isEmpty() )
1817  mLayers.append( new QgsSimpleFillSymbolLayer() );
1818 }
1819 
1820 void QgsFillSymbol::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1821 {
1822  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, selected, mRenderHints, f, QgsFields(), mapUnitScale() );
1824  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1825  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1826 
1827  if ( layerIdx != -1 )
1828  {
1829  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1830  if ( symbolLayer && symbolLayer->enabled() )
1831  {
1832  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1833  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1834  else
1835  renderUsingLayer( symbolLayer, symbolContext );
1836  }
1837  return;
1838  }
1839 
1840  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1841  {
1842  if ( !symbolLayer->enabled() )
1843  continue;
1844 
1845  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1846  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1847  else
1848  renderUsingLayer( symbolLayer, symbolContext );
1849  }
1850 }
1851 
1852 void QgsFillSymbol::renderPolygonUsingLayer( QgsSymbolLayer *layer, const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
1853 {
1855  return;
1856 
1857  QgsSymbol::SymbolType layertype = layer->type();
1858 
1859  QgsPaintEffect *effect = layer->paintEffect();
1860  if ( effect && effect->enabled() )
1861  {
1862  QRectF bounds = polygonBounds( points, rings );
1863  QList<QPolygonF> *translatedRings = translateRings( rings, -bounds.left(), -bounds.top() );
1864 
1865  QgsEffectPainter p( context.renderContext() );
1866  p->translate( bounds.topLeft() );
1867  p.setEffect( effect );
1868  if ( layertype == QgsSymbol::Fill )
1869  {
1870  ( static_cast<QgsFillSymbolLayer *>( layer ) )->renderPolygon( points.translated( -bounds.topLeft() ), translatedRings, context );
1871  }
1872  else if ( layertype == QgsSymbol::Line )
1873  {
1874  ( static_cast<QgsLineSymbolLayer *>( layer ) )->renderPolygonStroke( points.translated( -bounds.topLeft() ), translatedRings, context );
1875  }
1876  delete translatedRings;
1877  }
1878  else
1879  {
1880  if ( layertype == QgsSymbol::Fill )
1881  {
1882  ( static_cast<QgsFillSymbolLayer *>( layer ) )->renderPolygon( points, rings, context );
1883  }
1884  else if ( layertype == QgsSymbol::Line )
1885  {
1886  ( static_cast<QgsLineSymbolLayer *>( layer ) )->renderPolygonStroke( points, rings, context );
1887  }
1888  }
1889 }
1890 
1891 QRectF QgsFillSymbol::polygonBounds( const QPolygonF &points, const QList<QPolygonF> *rings ) const
1892 {
1893  QRectF bounds = points.boundingRect();
1894  if ( rings )
1895  {
1896  QList<QPolygonF>::const_iterator it = rings->constBegin();
1897  for ( ; it != rings->constEnd(); ++it )
1898  {
1899  bounds = bounds.united( ( *it ).boundingRect() );
1900  }
1901  }
1902  return bounds;
1903 }
1904 
1905 QList<QPolygonF> *QgsFillSymbol::translateRings( const QList<QPolygonF> *rings, double dx, double dy ) const
1906 {
1907  if ( !rings )
1908  return nullptr;
1909 
1910  QList<QPolygonF> *translatedRings = new QList<QPolygonF>;
1911  QList<QPolygonF>::const_iterator it = rings->constBegin();
1912  for ( ; it != rings->constEnd(); ++it )
1913  {
1914  translatedRings->append( ( *it ).translated( dx, dy ) );
1915  }
1916  return translatedRings;
1917 }
1918 
1920 {
1921  QgsFillSymbol *cloneSymbol = new QgsFillSymbol( cloneLayers() );
1922  cloneSymbol->setOpacity( mOpacity );
1924  cloneSymbol->setLayer( mLayer );
1927  cloneSymbol->setForceRHR( mForceRHR );
1928  return cloneSymbol;
1929 }
1930 
1932 {
1933  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1934  {
1935  if ( layer->type() != QgsSymbol::Fill )
1936  continue;
1937 
1938  QgsFillSymbolLayer *fillLayer = static_cast<QgsFillSymbolLayer *>( layer );
1939 
1940  if ( fillLayer )
1941  fillLayer->setAngle( angle );
1942  }
1943 }
1944 
1945 
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:1083
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:341
Single variable definition for use within a QgsExpressionContextScope.
A rectangle specified with double values.
Definition: qgsrectangle.h:40
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:144
void setMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol.
Definition: qgssymbol.cpp:267
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.
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 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:358
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:1145
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
ScaleMethod scaleMethod()
Definition: qgssymbol.cpp:1487
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:1156
QgsMapUnitScale mapUnitScale() const
Returns the map unit scale for the symbol.
Definition: qgssymbol.cpp:235
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:1127
void setAngle(double angle)
const QgsCurve * interiorRing(int i) const
VertexMarkerType
Editing vertex markers.
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Definition: qgssymbol.cpp:1734
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
Converts the symbol to a SLD representation.
Definition: qgssymbol.cpp:606
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:607
void setSize(double size)
Sets the size for the whole symbol.
Definition: qgssymbol.cpp:1285
Base class for visual effects which can be applied to QPicture drawings.
void renderVertexMarker(QPointF pt, QgsRenderContext &context, int currentVertexMarkerType, int currentVertexMarkerSize)
Render editing vertex marker at specified point.
Definition: qgssymbol.cpp:1075
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:1360
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:1102
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
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:1211
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:1176
QgsFields fields
Definition: qgsfeature.h:66
SimplifyAlgorithm
Types of simplification algorithms that can be used.
void setScaleMethod(QgsSymbol::ScaleMethod scaleMethod)
Sets the method to use for scaling the marker&#39;s size.
QgsAbstractGeometry::SegmentationToleranceType segmentationToleranceType() const
Gets segmentation tolerance type (maximum angle or maximum difference between curve and approximation...
QMap< QString, QString > QgsStringMap
Definition: qgis.h:570
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
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
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.
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:214
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:1112
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:1522
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
Definition: qgssymbol.cpp:1097
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
QgsProperty dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1239
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
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 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:639
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:580
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:1559
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Definition: qgssymbol.cpp:1820
double outputPixelSize(double size) const
Definition: qgssymbol.cpp:1107
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:1919
void setGeometryPartNum(int num)
Sets the part number of current geometry.
Definition: qgssymbol.h:677
void setWidth(double width)
Definition: qgssymbol.cpp:1601
double width() const
Definition: qgssymbol.cpp:1627
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:201
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...
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: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.
void renderFeature(const QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false, int currentVertexMarkerType=0, int currentVertexMarkerSize=0)
Render a feature.
Definition: qgssymbol.cpp:739
QgsMapUnitScale sizeMapUnitScale() const
Returns the size map unit scale for the whole symbol.
Definition: qgssymbol.cpp:1372
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
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:459
virtual void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size)=0
QgsSymbolRenderContext * symbolRenderContext()
Returns the symbol render context.
Definition: qgssymbol.cpp:1070
QgsSymbol::SymbolType type() const
void setScaleMethod(QgsSymbol::ScaleMethod scaleMethod)
Definition: qgssymbol.cpp:1476
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
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:1931
A store for object properties.
Definition: qgsproperty.h:229
QgsMarkerSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Definition: qgssymbol.cpp:1169
QgsRenderContext & renderContext()
Returns a reference to the context&#39;s render context.
Definition: qgssymbol.h:572
static void drawVertexMarker(double x, double y, QPainter &p, QgsVectorLayer::VertexMarkerType type, int vertexSize)
Draws a vertex symbol at (screen) coordinates x, y. (Useful to assist vertex editing.)
Implementation of GeometrySimplifier using the "MapToPixel" algorithm.
QgsSymbolLayer * symbolLayer(int layer)
Returns a specific symbol layer contained in the symbol.
Definition: qgssymbol.cpp:340
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Counter-clockwise orientation.
Definition: qgscurve.h:220
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:1646
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the size units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1324
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:176
QgsSymbol::ScaleMethod scaleMethod() const
Returns the method to use for scaling the marker&#39;s size.
Clockwise orientation.
Definition: qgscurve.h:219
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:1336
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
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1421
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
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:608
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. ...
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
Definition: qgssymbol.cpp:654
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:208
QgsSymbolLayerList cloneLayers() const
Retrieve a cloned list of all layers that make up this symbol.
Definition: qgssymbol.cpp:619
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:668
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:52
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:683
double size() const
Returns the size for the whole symbol, which is the maximum size of all marker symbol layers in the s...
Definition: qgssymbol.cpp:1308
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:196
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:411
QgsSymbol(SymbolType type, const QgsSymbolLayerList &layers)
Definition: qgssymbol.cpp:79
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:166
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:1200
QgsLineSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Definition: qgssymbol.cpp:1594
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:171
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:379
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:1134
void setDataDefinedSize(const QgsProperty &property)
Set data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1385
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
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
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:690
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:426
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:1681
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:1188
QgsFillSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Definition: qgssymbol.cpp:1813
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:1578
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:1798
virtual QString layerType() const =0
Returns a string that represents this layer type.
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:450
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:1122