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