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