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