QGIS API Documentation  2.99.0-Master (b058df7)
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 QgsPolygon &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  break;
273  }
274  if ( !defaultSymbol.isEmpty() )
275  s = QgsStyle::defaultStyle()->symbol( defaultSymbol );
276 
277  // if no default found for this type, get global default (as previously)
278  if ( ! s )
279  {
280  switch ( geomType )
281  {
283  s = new QgsMarkerSymbol();
284  break;
286  s = new QgsLineSymbol();
287  break;
289  s = new QgsFillSymbol();
290  break;
291  default:
292  QgsDebugMsg( "unknown layer's geometry type" );
293  return nullptr;
294  }
295  }
296 
297  // set opacity
298  double opacity = 1.0;
299  bool ok = false;
300  // upgrade old setting
301  double alpha = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/AlphaInt" ), 255, &ok );
302  if ( ok )
303  opacity = alpha / 255.0;
304  double newOpacity = QgsProject::instance()->readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Opacity" ), 1.0, &ok );
305  if ( ok )
306  opacity = newOpacity;
307  s->setOpacity( opacity );
308 
309  // set random color, it project prefs allow
310  if ( defaultSymbol.isEmpty() ||
311  QgsProject::instance()->readBoolEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/RandomColors" ), true ) )
312  {
313  s->setColor( QColor::fromHsv( qrand() % 360, 64 + qrand() % 192, 128 + qrand() % 128 ) );
314  }
315 
316  return s;
317 }
318 
320 {
321  return mLayers.value( layer );
322 }
323 
325 {
326  if ( index < 0 || index > mLayers.count() ) // can be added also after the last index
327  return false;
328 
329  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
330  return false;
331 
332  mLayers.insert( index, layer );
333  return true;
334 }
335 
336 
338 {
339  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
340  return false;
341 
342  mLayers.append( layer );
343  return true;
344 }
345 
346 
348 {
349  if ( index < 0 || index >= mLayers.count() )
350  return false;
351 
352  delete mLayers.at( index );
353  mLayers.removeAt( index );
354  return true;
355 }
356 
357 
359 {
360  if ( index < 0 || index >= mLayers.count() )
361  return nullptr;
362 
363  return mLayers.takeAt( index );
364 }
365 
366 
368 {
369  QgsSymbolLayer *oldLayer = mLayers.value( index );
370 
371  if ( oldLayer == layer )
372  return false;
373 
374  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
375  return false;
376 
377  delete oldLayer; // first delete the original layer
378  mLayers[index] = layer; // set new layer
379  return true;
380 }
381 
382 
383 void QgsSymbol::startRender( QgsRenderContext &context, const QgsFields &fields )
384 {
385  Q_ASSERT_X( !mStarted, "startRender", "Rendering has already been started for this symbol instance!" );
386  mStarted = true;
387 
388  mSymbolRenderContext.reset( new QgsSymbolRenderContext( context, outputUnit(), mOpacity, false, mRenderHints, nullptr, fields, mapUnitScale() ) );
389 
390  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, false, mRenderHints, nullptr, fields, mapUnitScale() );
391 
392  std::unique_ptr< QgsExpressionContextScope > scope( QgsExpressionContextUtils::updateSymbolScope( this, new QgsExpressionContextScope() ) );
393  mSymbolRenderContext->setExpressionContextScope( scope.release() );
394 
395  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
396  {
397  if ( !layer->enabled() )
398  continue;
399 
400  layer->prepareExpressions( symbolContext );
401  layer->startRender( symbolContext );
402  }
403 }
404 
406 {
407  Q_ASSERT_X( mStarted, "startRender", "startRender was not called for this symbol instance!" );
408  mStarted = false;
409 
410  Q_UNUSED( context )
411  if ( mSymbolRenderContext )
412  {
413  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
414  {
415  if ( !layer->enabled() )
416  continue;
417 
418  layer->stopRender( *mSymbolRenderContext );
419  }
420  }
421 
422  mSymbolRenderContext.reset( nullptr );
423 
424  mLayer = nullptr;
425 }
426 
427 void QgsSymbol::setColor( const QColor &color )
428 {
429  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
430  {
431  if ( !layer->isLocked() )
432  layer->setColor( color );
433  }
434 }
435 
436 QColor QgsSymbol::color() const
437 {
438  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
439  {
440  // return color of the first unlocked layer
441  if ( !( *it )->isLocked() )
442  return ( *it )->color();
443  }
444  return QColor( 0, 0, 0 );
445 }
446 
447 void QgsSymbol::drawPreviewIcon( QPainter *painter, QSize size, QgsRenderContext *customContext )
448 {
449  QgsRenderContext context = customContext ? *customContext : QgsRenderContext::fromQPainter( painter );
450  context.setForceVectorOutput( true );
451  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, false, mRenderHints, nullptr, QgsFields(), mapUnitScale() );
452 
453  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
454  {
455  if ( !layer->enabled() )
456  continue;
457 
458  if ( mType == Fill && layer->type() == Line )
459  {
460  // line symbol layer would normally draw just a line
461  // so we override this case to force it to draw a polygon stroke
462  QgsLineSymbolLayer *lsl = dynamic_cast<QgsLineSymbolLayer *>( layer );
463 
464  if ( lsl )
465  {
466  // from QgsFillSymbolLayer::drawPreviewIcon()
467  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
468  lsl->startRender( symbolContext );
469  lsl->renderPolygonStroke( poly, nullptr, symbolContext );
470  lsl->stopRender( symbolContext );
471  }
472  }
473  else
474  layer->drawPreviewIcon( symbolContext, size );
475  }
476 }
477 
478 void QgsSymbol::exportImage( const QString &path, const QString &format, QSize size )
479 {
480  if ( format.toLower() == QLatin1String( "svg" ) )
481  {
482  QSvgGenerator generator;
483  generator.setFileName( path );
484  generator.setSize( size );
485  generator.setViewBox( QRect( 0, 0, size.height(), size.height() ) );
486 
487  QPainter painter( &generator );
488  drawPreviewIcon( &painter, size );
489  painter.end();
490  }
491  else
492  {
493  QImage image = asImage( size );
494  image.save( path );
495  }
496 }
497 
498 QImage QgsSymbol::asImage( QSize size, QgsRenderContext *customContext )
499 {
500  QImage image( size, QImage::Format_ARGB32_Premultiplied );
501  image.fill( 0 );
502 
503  QPainter p( &image );
504  p.setRenderHint( QPainter::Antialiasing );
505 
506  drawPreviewIcon( &p, size, customContext );
507 
508  return image;
509 }
510 
511 
513 {
514  QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
515  preview.fill( 0 );
516 
517  QPainter p( &preview );
518  p.setRenderHint( QPainter::Antialiasing );
519  p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialising
520 
521  if ( mType == QgsSymbol::Marker )
522  {
523  p.setPen( QPen( Qt::gray ) );
524  p.drawLine( 0, 50, 100, 50 );
525  p.drawLine( 50, 0, 50, 100 );
526  }
527 
529  if ( expressionContext )
530  context.setExpressionContext( *expressionContext );
531 
532  startRender( context );
533 
534  if ( mType == QgsSymbol::Line )
535  {
536  QPolygonF poly;
537  poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
538  static_cast<QgsLineSymbol *>( this )->renderPolyline( poly, nullptr, context );
539  }
540  else if ( mType == QgsSymbol::Fill )
541  {
542  QPolygonF polygon;
543  polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
544  static_cast<QgsFillSymbol *>( this )->renderPolygon( polygon, nullptr, nullptr, context );
545  }
546  else // marker
547  {
548  static_cast<QgsMarkerSymbol *>( this )->renderPoint( QPointF( 50, 50 ), nullptr, context );
549  }
550 
551  stopRender( context );
552  return preview;
553 }
554 
555 
556 QString QgsSymbol::dump() const
557 {
558  QString t;
559  switch ( type() )
560  {
561  case QgsSymbol::Marker:
562  t = QStringLiteral( "MARKER" );
563  break;
564  case QgsSymbol::Line:
565  t = QStringLiteral( "LINE" );
566  break;
567  case QgsSymbol::Fill:
568  t = QStringLiteral( "FILL" );
569  break;
570  default:
571  Q_ASSERT( false && "unknown symbol type" );
572  }
573  QString s = QStringLiteral( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerUtils::encodeColor( color() ) );
574 
575  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
576  {
577  // TODO:
578  }
579  return s;
580 }
581 
582 void QgsSymbol::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
583 {
584  props[ QStringLiteral( "alpha" )] = QString::number( opacity() );
585  double scaleFactor = 1.0;
586  props[ QStringLiteral( "uom" )] = QgsSymbolLayerUtils::encodeSldUom( outputUnit(), &scaleFactor );
587  props[ QStringLiteral( "uomScale" )] = ( !qgsDoubleNear( scaleFactor, 1.0 ) ? qgsDoubleToString( scaleFactor ) : QLatin1String( "" ) );
588 
589  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
590  {
591  ( *it )->toSld( doc, element, props );
592  }
593 }
594 
596 {
597  QgsSymbolLayerList lst;
598  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
599  {
600  QgsSymbolLayer *layer = ( *it )->clone();
601  layer->setLocked( ( *it )->isLocked() );
602  layer->setRenderingPass( ( *it )->renderingPass() );
603  layer->setEnabled( ( *it )->enabled() );
604  lst.append( layer );
605  }
606  return lst;
607 }
608 
610 {
611  Q_ASSERT( layer->type() == Hybrid );
612 
614  return;
615 
616  QgsGeometryGeneratorSymbolLayer *generatorLayer = static_cast<QgsGeometryGeneratorSymbolLayer *>( layer );
617 
618  QgsPaintEffect *effect = generatorLayer->paintEffect();
619  if ( effect && effect->enabled() )
620  {
621  QgsEffectPainter p( context.renderContext(), effect );
622  generatorLayer->render( context );
623  }
624  else
625  {
626  generatorLayer->render( context );
627  }
628 }
629 
630 QSet<QString> QgsSymbol::usedAttributes( const QgsRenderContext &context ) const
631 {
632  QSet<QString> attributes;
633  QgsSymbolLayerList::const_iterator sIt = mLayers.constBegin();
634  for ( ; sIt != mLayers.constEnd(); ++sIt )
635  {
636  if ( *sIt )
637  {
638  attributes.unite( ( *sIt )->usedAttributes( context ) );
639  }
640  }
641  return attributes;
642 }
643 
645 {
646  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
647  {
649  return true;
650  }
651  return false;
652 }
653 
655 
659 class ExpressionContextScopePopper
660 {
661  public:
662 
663  ExpressionContextScopePopper() = default;
664 
665  ~ExpressionContextScopePopper()
666  {
667  if ( context )
668  context->popScope();
669  }
670 
671  QgsExpressionContext *context = nullptr;
672 };
674 
675 void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, int currentVertexMarkerSize )
676 {
677  const QgsGeometry geom = feature.geometry();
678  if ( geom.isNull() )
679  {
680  return;
681  }
682 
683  QgsGeometry segmentizedGeometry = geom;
684  bool usingSegmentizedGeometry = false;
685  context.setGeometry( geom.constGet() );
686 
687  bool tileMapRendering = context.testFlag( QgsRenderContext::RenderMapTile );
688 
689  //convert curve types to normal point/line/polygon ones
690  if ( QgsWkbTypes::isCurvedType( geom.constGet()->wkbType() ) )
691  {
693  if ( !g )
694  {
695  return;
696  }
697  segmentizedGeometry = QgsGeometry( g );
698  usingSegmentizedGeometry = true;
699  }
700 
701  mSymbolRenderContext->setGeometryPartCount( segmentizedGeometry.constGet()->partCount() );
702  mSymbolRenderContext->setGeometryPartNum( 1 );
703 
704  ExpressionContextScopePopper scopePopper;
705  if ( mSymbolRenderContext->expressionContextScope() )
706  {
707  // this is somewhat nasty - by appending this scope here it's now owned
708  // by both mSymbolRenderContext AND context.expressionContext()
709  // the RAII scopePopper is required to make sure it always has ownership transferred back
710  // from context.expressionContext(), even if exceptions of other early exits occur in this
711  // function
712  context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
713  scopePopper.context = &context.expressionContext();
714 
715  QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
716  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount(), true ) );
717  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1, true ) );
718  }
719 
720  // Collection of markers to paint, only used for no curve types.
721  QPolygonF markers;
722 
723  // Simplify the geometry, if needed.
725  {
726  const int simplifyHints = context.vectorSimplifyMethod().simplifyHints();
727  const QgsMapToPixelSimplifier simplifier( simplifyHints, context.vectorSimplifyMethod().tolerance(),
729  segmentizedGeometry = simplifier.simplify( segmentizedGeometry );
730  }
731 
732  switch ( QgsWkbTypes::flatType( segmentizedGeometry.constGet()->wkbType() ) )
733  {
734  case QgsWkbTypes::Point:
735  {
736  if ( mType != QgsSymbol::Marker )
737  {
738  QgsDebugMsg( "point can be drawn only with marker symbol!" );
739  break;
740  }
741 
742  const QgsPoint *point = static_cast< const QgsPoint * >( segmentizedGeometry.constGet() );
743  const QPointF pt = _getPoint( context, *point );
744  static_cast<QgsMarkerSymbol *>( this )->renderPoint( pt, &feature, context, layer, selected );
745 
747  {
748  //draw debugging rect
749  context.painter()->setPen( Qt::red );
750  context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
751  context.painter()->drawRect( static_cast<QgsMarkerSymbol *>( this )->bounds( pt, context, feature ) );
752  }
753 
754  if ( drawVertexMarker && !usingSegmentizedGeometry )
755  {
756  markers << pt;
757  }
758  }
759  break;
761  {
762  if ( mType != QgsSymbol::Line )
763  {
764  QgsDebugMsg( "linestring can be drawn only with line symbol!" );
765  break;
766  }
767  const QgsCurve &curve = dynamic_cast<const QgsCurve &>( *segmentizedGeometry.constGet() );
768  const QPolygonF pts = _getLineString( context, curve, !tileMapRendering && clipFeaturesToExtent() );
769  static_cast<QgsLineSymbol *>( this )->renderPolyline( pts, &feature, context, layer, selected );
770 
771  if ( drawVertexMarker && !usingSegmentizedGeometry )
772  {
773  markers = pts;
774  }
775  }
776  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 QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *segmentizedGeometry.constGet() );
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 QgsMultiPoint &mp = static_cast< const QgsMultiPoint & >( *segmentizedGeometry.constGet() );
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.constGet() );
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.constGet() );
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 QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *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 QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *geomCollection.geometryN( i ) );
917  if ( !polygon.exteriorRing() )
918  break;
919 
920  _getPolygon( pts, holes, context, polygon, !tileMapRendering && clipFeaturesToExtent() );
921  static_cast<QgsFillSymbol *>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
922 
923  if ( drawVertexMarker && !usingSegmentizedGeometry )
924  {
925  if ( i == 0 )
926  {
927  markers = pts;
928  }
929  else
930  {
931  markers << pts;
932  }
933 
934  Q_FOREACH ( const QPolygonF &hole, holes )
935  {
936  markers << hole;
937  }
938  }
939  }
940  }
941  break;
942  }
944  {
945  const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
946  if ( geomCollection.numGeometries() == 0 )
947  {
948  // skip noise from empty geometry collections from simplification
949  break;
950  }
951 
952  FALLTHROUGH;
953  }
954  default:
955  QgsDebugMsg( QString( "feature %1: unsupported wkb type %2/%3 for rendering" )
956  .arg( feature.id() )
957  .arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
958  .arg( geom.wkbType(), 0, 16 ) );
959  }
960 
961  if ( drawVertexMarker )
962  {
963  if ( !markers.isEmpty() )
964  {
965  Q_FOREACH ( QPointF marker, markers )
966  {
967  renderVertexMarker( marker, context, currentVertexMarkerType, currentVertexMarkerSize );
968  }
969  }
970  else
971  {
973  const QgsMapToPixel &mtp = context.mapToPixel();
974 
975  QgsPoint vertexPoint;
976  QgsVertexId vertexId;
977  double x, y, z;
978  QPointF mapPoint;
979  while ( geom.constGet()->nextVertex( vertexId, vertexPoint ) )
980  {
981  //transform
982  x = vertexPoint.x();
983  y = vertexPoint.y();
984  z = 0.0;
985  if ( ct.isValid() )
986  {
987  ct.transformInPlace( x, y, z );
988  }
989  mapPoint.setX( x );
990  mapPoint.setY( y );
991  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
992  renderVertexMarker( mapPoint, context, currentVertexMarkerType, currentVertexMarkerSize );
993  }
994  }
995  }
996 }
997 
999 {
1000  return mSymbolRenderContext.get();
1001 }
1002 
1003 void QgsSymbol::renderVertexMarker( QPointF pt, QgsRenderContext &context, int currentVertexMarkerType, int currentVertexMarkerSize )
1004 {
1005  QgsVectorLayer::drawVertexMarker( pt.x(), pt.y(), *context.painter(), static_cast< QgsVectorLayer::VertexMarkerType >( currentVertexMarkerType ), currentVertexMarkerSize );
1006 }
1007 
1009 
1010 
1012  : mRenderContext( c )
1013  , mOutputUnit( u )
1014  , mMapUnitScale( mapUnitScale )
1015  , mOpacity( opacity )
1016  , mSelected( selected )
1017  , mRenderHints( renderHints )
1018  , mFeature( f )
1019  , mFields( fields )
1020  , mGeometryPartCount( 0 )
1021  , mGeometryPartNum( 0 )
1022 {
1023 }
1024 
1026 {
1027  mRenderContext.expressionContext().setOriginalValueVariable( value );
1028 }
1029 
1030 double QgsSymbolRenderContext::outputLineWidth( double width ) const
1031 {
1032  return mRenderContext.convertToPainterUnits( width, mOutputUnit, mMapUnitScale );
1033 }
1034 
1035 double QgsSymbolRenderContext::outputPixelSize( double size ) const
1036 {
1037  return mRenderContext.convertToPainterUnits( size, mOutputUnit, mMapUnitScale );
1038 }
1039 
1041 {
1042  // This is just a dummy implementation of assignment.
1043  // sip 4.7 generates a piece of code that needs this function to exist.
1044  // It's not generated automatically by the compiler because of
1045  // mRenderContext member which is a reference (and thus can't be changed).
1046  Q_ASSERT( false );
1047  return *this;
1048 }
1049 
1051 {
1052  return mExpressionContextScope.get();
1053 }
1054 
1056 {
1057  mExpressionContextScope.reset( contextScope );
1058 }
1059 
1061 
1063 {
1065  if ( !sl )
1066  return nullptr;
1067 
1068  QgsSymbolLayerList layers;
1069  layers.append( sl );
1070  return new QgsMarkerSymbol( layers );
1071 }
1072 
1074 {
1076  if ( !sl )
1077  return nullptr;
1078 
1079  QgsSymbolLayerList layers;
1080  layers.append( sl );
1081  return new QgsLineSymbol( layers );
1082 }
1083 
1085 {
1087  if ( !sl )
1088  return nullptr;
1089 
1090  QgsSymbolLayerList layers;
1091  layers.append( sl );
1092  return new QgsFillSymbol( layers );
1093 }
1094 
1096 
1098  : QgsSymbol( Marker, layers )
1099 {
1100  if ( mLayers.isEmpty() )
1101  mLayers.append( new QgsSimpleMarkerSymbolLayer() );
1102 }
1103 
1104 void QgsMarkerSymbol::setAngle( double symbolAngle )
1105 {
1106  double origAngle = angle();
1107  double angleDiff = symbolAngle - origAngle;
1108  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1109  {
1110  QgsMarkerSymbolLayer *markerLayer = dynamic_cast<QgsMarkerSymbolLayer *>( layer );
1111  if ( markerLayer )
1112  markerLayer->setAngle( markerLayer->angle() + angleDiff );
1113  }
1114 }
1115 
1117 {
1118  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1119  {
1120  if ( layer->type() != QgsSymbol::Marker )
1121  continue;
1122  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1123  return markerLayer->angle();
1124  }
1125  return 0;
1126 }
1127 
1128 void QgsMarkerSymbol::setLineAngle( double lineAng )
1129 {
1130  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1131  {
1132  if ( layer->type() != QgsSymbol::Marker )
1133  continue;
1134  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1135  markerLayer->setLineAngle( lineAng );
1136  }
1137 }
1138 
1140 {
1141  const double symbolRotation = angle();
1142 
1143  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1144  {
1145  if ( layer->type() != QgsSymbol::Marker )
1146  continue;
1147  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1148  if ( !property )
1149  {
1151  }
1152  else
1153  {
1154  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1155  {
1157  }
1158  else
1159  {
1160  QgsProperty rotatedDD = rotateWholeSymbol( markerLayer->angle() - symbolRotation, property );
1162  }
1163  }
1164  }
1165 }
1166 
1168 {
1169  const double symbolRotation = angle();
1170  QgsProperty symbolDD;
1171 
1172  // find the base of the "en masse" pattern
1173  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1174  {
1175  if ( layer->type() != QgsSymbol::Marker )
1176  continue;
1177  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1178  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) && markerLayer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertyAngle ) )
1179  {
1180  symbolDD = markerLayer->dataDefinedProperties().property( QgsSymbolLayer::PropertyAngle );
1181  break;
1182  }
1183  }
1184 
1185  if ( !symbolDD )
1186  return QgsProperty();
1187 
1188  // check that all layer's angle expressions match 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 
1196 
1197  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1198  {
1199  if ( !layerAngleDD || layerAngleDD != symbolDD )
1200  return QgsProperty();
1201  }
1202  else
1203  {
1204  QgsProperty rotatedDD( rotateWholeSymbol( markerLayer->angle() - symbolRotation, symbolDD ) );
1205  if ( !layerAngleDD || layerAngleDD != rotatedDD )
1206  return QgsProperty();
1207  }
1208  }
1209  return symbolDD;
1210 }
1211 
1212 
1214 {
1215  double origSize = size();
1216 
1217  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1218  {
1219  if ( layer->type() != QgsSymbol::Marker )
1220  continue;
1221  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1222  if ( qgsDoubleNear( markerLayer->size(), origSize ) )
1223  markerLayer->setSize( s );
1224  else if ( !qgsDoubleNear( origSize, 0.0 ) )
1225  {
1226  // proportionally scale size
1227  markerLayer->setSize( markerLayer->size() * s / origSize );
1228  }
1229  // also scale offset to maintain relative position
1230  if ( !qgsDoubleNear( origSize, 0.0 ) && ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) ) )
1231  markerLayer->setOffset( QPointF( markerLayer->offset().x() * s / origSize,
1232  markerLayer->offset().y() * s / origSize ) );
1233  }
1234 }
1235 
1237 {
1238  // return size of the largest symbol
1239  double maxSize = 0;
1240  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1241  {
1242  if ( layer->type() != QgsSymbol::Marker )
1243  continue;
1244  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1245  double lsize = markerLayer->size();
1246  if ( lsize > maxSize )
1247  maxSize = lsize;
1248  }
1249  return maxSize;
1250 }
1251 
1253 {
1254  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1255  {
1256  if ( layer->type() != QgsSymbol::Marker )
1257  continue;
1258 
1259  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1260  markerLayer->setSizeUnit( unit );
1261  }
1262 }
1263 
1265 {
1266  bool first = true;
1268 
1269  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1270  {
1271  if ( layer->type() != QgsSymbol::Marker )
1272  continue;
1273  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1274 
1275  if ( first )
1276  unit = markerLayer->sizeUnit();
1277  else
1278  {
1279  if ( unit != markerLayer->sizeUnit() )
1281  }
1282 
1283  first = false;
1284  }
1285  return unit;
1286 }
1287 
1289 {
1290  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1291  {
1292  if ( layer->type() != QgsSymbol::Marker )
1293  continue;
1294 
1295  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1296  markerLayer->setSizeMapUnitScale( scale );
1297  }
1298 }
1299 
1301 {
1302  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1303  {
1304  if ( layer->type() != QgsSymbol::Marker )
1305  continue;
1306 
1307  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1308  return markerLayer->sizeMapUnitScale();
1309  }
1310  return QgsMapUnitScale();
1311 }
1312 
1314 {
1315  const double symbolSize = size();
1316 
1317  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1318  {
1319  if ( layer->type() != QgsSymbol::Marker )
1320  continue;
1321  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1322 
1323  if ( !property )
1324  {
1327  }
1328  else
1329  {
1330  if ( qgsDoubleNear( symbolSize, 0.0 ) || qgsDoubleNear( markerLayer->size(), symbolSize ) )
1331  {
1332  markerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, property );
1333  }
1334  else
1335  {
1336  markerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, scaleWholeSymbol( markerLayer->size() / symbolSize, property ) );
1337  }
1338 
1339  if ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) )
1340  {
1342  markerLayer->offset().x() / symbolSize,
1343  markerLayer->offset().y() / symbolSize, property ) );
1344  }
1345  }
1346  }
1347 }
1348 
1350 {
1351  const double symbolSize = size();
1352 
1353  QgsProperty symbolDD;
1354 
1355  // find the base of the "en masse" pattern
1356  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1357  {
1358  if ( layer->type() != QgsSymbol::Marker )
1359  continue;
1360  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1361  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) && markerLayer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertySize ) )
1362  {
1363  symbolDD = markerLayer->dataDefinedProperties().property( QgsSymbolLayer::PropertySize );
1364  break;
1365  }
1366  }
1367 
1368  if ( !symbolDD )
1369  return QgsProperty();
1370 
1371  // check that all layers size expressions match 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 
1380 
1381  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) )
1382  {
1383  if ( !layerSizeDD || layerSizeDD != symbolDD )
1384  return QgsProperty();
1385  }
1386  else
1387  {
1388  if ( qgsDoubleNear( symbolSize, 0.0 ) )
1389  return QgsProperty();
1390 
1391  QgsProperty scaledDD( scaleWholeSymbol( markerLayer->size() / symbolSize, symbolDD ) );
1392  if ( !layerSizeDD || layerSizeDD != scaledDD )
1393  return QgsProperty();
1394  }
1395 
1396  QgsProperty scaledOffsetDD( scaleWholeSymbol( markerLayer->offset().x() / symbolSize, markerLayer->offset().y() / symbolSize, symbolDD ) );
1397  if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
1398  return QgsProperty();
1399  }
1400 
1401  return symbolDD;
1402 }
1403 
1405 {
1406  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1407  {
1408  if ( layer->type() != QgsSymbol::Marker )
1409  continue;
1410  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1411  markerLayer->setScaleMethod( scaleMethod );
1412  }
1413 }
1414 
1416 {
1417  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1418  {
1419  if ( layer->type() != QgsSymbol::Marker )
1420  continue;
1421  const QgsMarkerSymbolLayer *markerLayer = static_cast<const QgsMarkerSymbolLayer *>( layer );
1422  // return scale method of the first symbol layer
1423  return markerLayer->scaleMethod();
1424  }
1425 
1426  return DEFAULT_SCALE_METHOD;
1427 }
1428 
1429 void QgsMarkerSymbol::renderPointUsingLayer( QgsMarkerSymbolLayer *layer, QPointF point, QgsSymbolRenderContext &context )
1430 {
1431  static QPointF nullPoint( 0, 0 );
1432 
1434  return;
1435 
1436  QgsPaintEffect *effect = layer->paintEffect();
1437  if ( effect && effect->enabled() )
1438  {
1439  QgsEffectPainter p( context.renderContext() );
1440  p->translate( point );
1441  p.setEffect( effect );
1442  layer->renderPoint( nullPoint, context );
1443  }
1444  else
1445  {
1446  layer->renderPoint( point, context );
1447  }
1448 }
1449 
1450 void QgsMarkerSymbol::renderPoint( QPointF point, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1451 {
1452  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, selected, mRenderHints, f, QgsFields(), mapUnitScale() );
1453  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1454  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1455 
1456  if ( layerIdx != -1 )
1457  {
1458  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1459  if ( symbolLayer && symbolLayer->enabled() )
1460  {
1461  if ( symbolLayer->type() == QgsSymbol::Marker )
1462  {
1463  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( symbolLayer );
1464  renderPointUsingLayer( markerLayer, point, symbolContext );
1465  }
1466  else
1467  renderUsingLayer( symbolLayer, symbolContext );
1468  }
1469  return;
1470  }
1471 
1472  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1473  {
1474  if ( !symbolLayer->enabled() )
1475  continue;
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 }
1486 
1487 QRectF QgsMarkerSymbol::bounds( QPointF point, QgsRenderContext &context, const QgsFeature &feature ) const
1488 {
1489  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, false, mRenderHints, &feature, feature.fields(), mapUnitScale() );
1490 
1491  QRectF bound;
1492  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1493  {
1494  if ( layer->type() == QgsSymbol::Marker )
1495  {
1497  if ( bound.isNull() )
1498  bound = symbolLayer->bounds( point, symbolContext );
1499  else
1500  bound = bound.united( symbolLayer->bounds( point, symbolContext ) );
1501  }
1502  }
1503  return bound;
1504 }
1505 
1507 {
1508  QgsMarkerSymbol *cloneSymbol = new QgsMarkerSymbol( cloneLayers() );
1509  cloneSymbol->setOpacity( mOpacity );
1510  cloneSymbol->setLayer( mLayer );
1512  return cloneSymbol;
1513 }
1514 
1515 
1517 // LINE
1518 
1520  : QgsSymbol( Line, layers )
1521 {
1522  if ( mLayers.isEmpty() )
1523  mLayers.append( new QgsSimpleLineSymbolLayer() );
1524 }
1525 
1526 void QgsLineSymbol::setWidth( double w )
1527 {
1528  double origWidth = width();
1529 
1530  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1531  {
1532  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
1533 
1534  if ( lineLayer )
1535  {
1536  if ( qgsDoubleNear( lineLayer->width(), origWidth ) )
1537  {
1538  lineLayer->setWidth( w );
1539  }
1540  else if ( !qgsDoubleNear( origWidth, 0.0 ) )
1541  {
1542  // proportionally scale the width
1543  lineLayer->setWidth( lineLayer->width() * w / origWidth );
1544  }
1545  // also scale offset to maintain relative position
1546  if ( !qgsDoubleNear( origWidth, 0.0 ) && !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1547  lineLayer->setOffset( lineLayer->offset() * w / origWidth );
1548  }
1549  }
1550 }
1551 
1552 double QgsLineSymbol::width() const
1553 {
1554  double maxWidth = 0;
1555  if ( mLayers.isEmpty() )
1556  return maxWidth;
1557 
1558  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1559  {
1560  const QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( symbolLayer );
1561  if ( lineLayer )
1562  {
1563  double width = lineLayer->width();
1564  if ( width > maxWidth )
1565  maxWidth = width;
1566  }
1567  }
1568  return maxWidth;
1569 }
1570 
1572 {
1573  const double symbolWidth = width();
1574 
1575  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1576  {
1577  QgsLineSymbolLayer *lineLayer = dynamic_cast<QgsLineSymbolLayer *>( layer );
1578 
1579  if ( lineLayer )
1580  {
1581  if ( !property )
1582  {
1585  }
1586  else
1587  {
1588  if ( qgsDoubleNear( symbolWidth, 0.0 ) || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1589  {
1591  }
1592  else
1593  {
1594  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyStrokeWidth, scaleWholeSymbol( lineLayer->width() / symbolWidth, property ) );
1595  }
1596 
1597  if ( !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1598  {
1599  lineLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyOffset, scaleWholeSymbol( lineLayer->offset() / symbolWidth, property ) );
1600  }
1601  }
1602  }
1603  }
1604 }
1605 
1607 {
1608  const double symbolWidth = width();
1609 
1610  QgsProperty symbolDD;
1611 
1612  // find the base of the "en masse" pattern
1613  for ( QgsSymbolLayerList::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1614  {
1615  const QgsLineSymbolLayer *layer = dynamic_cast<const QgsLineSymbolLayer *>( *it );
1616  if ( layer && qgsDoubleNear( layer->width(), symbolWidth ) && layer->dataDefinedProperties().isActive( QgsSymbolLayer::PropertyStrokeWidth ) )
1617  {
1619  break;
1620  }
1621  }
1622 
1623  if ( !symbolDD )
1624  return QgsProperty();
1625 
1626  // check that all layers width expressions match the "en masse" pattern
1627  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1628  {
1629  if ( layer->type() != QgsSymbol::Line )
1630  continue;
1631  const QgsLineSymbolLayer *lineLayer = static_cast<const QgsLineSymbolLayer *>( layer );
1632 
1635 
1636  if ( qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1637  {
1638  if ( !layerWidthDD || layerWidthDD != symbolDD )
1639  return QgsProperty();
1640  }
1641  else
1642  {
1643  if ( qgsDoubleNear( symbolWidth, 0.0 ) )
1644  return QgsProperty();
1645 
1646  QgsProperty scaledDD( scaleWholeSymbol( lineLayer->width() / symbolWidth, symbolDD ) );
1647  if ( !layerWidthDD || layerWidthDD != scaledDD )
1648  return QgsProperty();
1649  }
1650 
1651  QgsProperty scaledOffsetDD( scaleWholeSymbol( lineLayer->offset() / symbolWidth, symbolDD ) );
1652  if ( layerOffsetDD && layerOffsetDD != scaledOffsetDD )
1653  return QgsProperty();
1654  }
1655 
1656  return symbolDD;
1657 }
1658 
1659 void QgsLineSymbol::renderPolyline( const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1660 {
1661  //save old painter
1662  QPainter *renderPainter = context.painter();
1663  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, selected, mRenderHints, f, QgsFields(), mapUnitScale() );
1665  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1666  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1667 
1668  if ( layerIdx != -1 )
1669  {
1670  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1671  if ( symbolLayer && symbolLayer->enabled() )
1672  {
1673  if ( symbolLayer->type() == QgsSymbol::Line )
1674  {
1675  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
1676  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1677  }
1678  else
1679  renderUsingLayer( symbolLayer, symbolContext );
1680  }
1681  return;
1682  }
1683 
1684  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1685  {
1686  if ( !symbolLayer->enabled() )
1687  continue;
1688 
1689  if ( symbolLayer->type() == QgsSymbol::Line )
1690  {
1691  QgsLineSymbolLayer *lineLayer = static_cast<QgsLineSymbolLayer *>( symbolLayer );
1692  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1693  }
1694  else
1695  {
1696  renderUsingLayer( symbolLayer, symbolContext );
1697  }
1698  }
1699 
1700  context.setPainter( renderPainter );
1701 }
1702 
1703 void QgsLineSymbol::renderPolylineUsingLayer( QgsLineSymbolLayer *layer, const QPolygonF &points, QgsSymbolRenderContext &context )
1704 {
1706  return;
1707 
1708  QgsPaintEffect *effect = layer->paintEffect();
1709  if ( effect && effect->enabled() )
1710  {
1711  QgsEffectPainter p( context.renderContext() );
1712  p->translate( points.boundingRect().topLeft() );
1713  p.setEffect( effect );
1714  layer->renderPolyline( points.translated( -points.boundingRect().topLeft() ), context );
1715  }
1716  else
1717  {
1718  layer->renderPolyline( points, context );
1719  }
1720 }
1721 
1722 
1724 {
1725  QgsLineSymbol *cloneSymbol = new QgsLineSymbol( cloneLayers() );
1726  cloneSymbol->setOpacity( mOpacity );
1727  cloneSymbol->setLayer( mLayer );
1729  return cloneSymbol;
1730 }
1731 
1733 // FILL
1734 
1736  : QgsSymbol( Fill, layers )
1737 {
1738  if ( mLayers.isEmpty() )
1739  mLayers.append( new QgsSimpleFillSymbolLayer() );
1740 }
1741 
1742 void QgsFillSymbol::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
1743 {
1744  QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, selected, mRenderHints, f, QgsFields(), mapUnitScale() );
1746  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1747  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1748 
1749  if ( layerIdx != -1 )
1750  {
1751  QgsSymbolLayer *symbolLayer = mLayers.value( layerIdx );
1752  if ( symbolLayer && symbolLayer->enabled() )
1753  {
1754  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1755  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1756  else
1757  renderUsingLayer( symbolLayer, symbolContext );
1758  }
1759  return;
1760  }
1761 
1762  Q_FOREACH ( QgsSymbolLayer *symbolLayer, mLayers )
1763  {
1764  if ( !symbolLayer->enabled() )
1765  continue;
1766 
1767  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1768  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1769  else
1770  renderUsingLayer( symbolLayer, symbolContext );
1771  }
1772 }
1773 
1774 void QgsFillSymbol::renderPolygonUsingLayer( QgsSymbolLayer *layer, const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
1775 {
1777  return;
1778 
1779  QgsSymbol::SymbolType layertype = layer->type();
1780 
1781  QgsPaintEffect *effect = layer->paintEffect();
1782  if ( effect && effect->enabled() )
1783  {
1784  QRectF bounds = polygonBounds( points, rings );
1785  QList<QPolygonF> *translatedRings = translateRings( rings, -bounds.left(), -bounds.top() );
1786 
1787  QgsEffectPainter p( context.renderContext() );
1788  p->translate( bounds.topLeft() );
1789  p.setEffect( effect );
1790  if ( layertype == QgsSymbol::Fill )
1791  {
1792  ( static_cast<QgsFillSymbolLayer *>( layer ) )->renderPolygon( points.translated( -bounds.topLeft() ), translatedRings, context );
1793  }
1794  else if ( layertype == QgsSymbol::Line )
1795  {
1796  ( static_cast<QgsLineSymbolLayer *>( layer ) )->renderPolygonStroke( points.translated( -bounds.topLeft() ), translatedRings, context );
1797  }
1798  delete translatedRings;
1799  }
1800  else
1801  {
1802  if ( layertype == QgsSymbol::Fill )
1803  {
1804  ( static_cast<QgsFillSymbolLayer *>( layer ) )->renderPolygon( points, rings, context );
1805  }
1806  else if ( layertype == QgsSymbol::Line )
1807  {
1808  ( static_cast<QgsLineSymbolLayer *>( layer ) )->renderPolygonStroke( points, rings, context );
1809  }
1810  }
1811 }
1812 
1813 QRectF QgsFillSymbol::polygonBounds( const QPolygonF &points, const QList<QPolygonF> *rings ) const
1814 {
1815  QRectF bounds = points.boundingRect();
1816  if ( rings )
1817  {
1818  QList<QPolygonF>::const_iterator it = rings->constBegin();
1819  for ( ; it != rings->constEnd(); ++it )
1820  {
1821  bounds = bounds.united( ( *it ).boundingRect() );
1822  }
1823  }
1824  return bounds;
1825 }
1826 
1827 QList<QPolygonF> *QgsFillSymbol::translateRings( const QList<QPolygonF> *rings, double dx, double dy ) const
1828 {
1829  if ( !rings )
1830  return nullptr;
1831 
1832  QList<QPolygonF> *translatedRings = new QList<QPolygonF>;
1833  QList<QPolygonF>::const_iterator it = rings->constBegin();
1834  for ( ; it != rings->constEnd(); ++it )
1835  {
1836  translatedRings->append( ( *it ).translated( dx, dy ) );
1837  }
1838  return translatedRings;
1839 }
1840 
1842 {
1843  QgsFillSymbol *cloneSymbol = new QgsFillSymbol( cloneLayers() );
1844  cloneSymbol->setOpacity( mOpacity );
1845  cloneSymbol->setLayer( mLayer );
1847  return cloneSymbol;
1848 }
1849 
1851 {
1852  Q_FOREACH ( QgsSymbolLayer *layer, mLayers )
1853  {
1854  if ( layer->type() != QgsSymbol::Fill )
1855  continue;
1856 
1857  QgsFillSymbolLayer *fillLayer = static_cast<QgsFillSymbolLayer *>( layer );
1858 
1859  if ( fillLayer )
1860  fillLayer->setAngle( angle );
1861  }
1862 }
1863 
1864 
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:324
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)
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:1011
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 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:337
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:1073
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
ScaleMethod scaleMethod()
Definition: qgssymbol.cpp:1415
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:1084
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:1055
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:1659
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
Definition: qgssymbol.cpp:582
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:1213
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:1003
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:1288
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:1030
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:347
void setDataDefinedAngle(const QgsProperty &property)
Set data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1139
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:1104
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:443
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:227
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:383
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: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:1040
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:1450
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
Definition: qgssymbol.cpp:1025
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:1167
SymbolType mType
Definition: qgssymbol.h:393
QPolygonF asQPolygonF() const
Returns a QPolygonF representing the points.
Definition: qgscurve.cpp:177
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:498
void exportImage(const QString &path, const QString &format, QSize size)
export symbol as image format. PNG and SVG supported
Definition: qgssymbol.cpp:478
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:508
#define FALLTHROUGH
Definition: qgis.h:512
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:556
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:1487
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Definition: qgssymbol.cpp:1742
double outputPixelSize(double size) const
Definition: qgssymbol.cpp:1035
void renderUsingLayer(QgsSymbolLayer *layer, QgsSymbolRenderContext &context)
Renders a context using a particular symbol layer without passing in a geometry.
Definition: qgssymbol.cpp:609
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:264
virtual QgsFillSymbol * clone() const override
Get a deep copy of this symbol.
Definition: qgssymbol.cpp:1841
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:175
void setWidth(double width)
Definition: qgssymbol.cpp:1526
double width() const
Definition: qgssymbol.cpp:1552
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:138
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:213
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:675
QgsMapUnitScale sizeMapUnitScale() const
Returns the size map unit scale for the whole symbol.
Definition: qgssymbol.cpp:1300
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:447
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:436
virtual void drawPreviewIcon(QgsSymbolRenderContext &context, QSize size)=0
QgsSymbolRenderContext * symbolRenderContext()
Returns the symbol render context.
Definition: qgssymbol.cpp:998
QgsSymbol::SymbolType type() const
void setScaleMethod(QgsSymbol::ScaleMethod scaleMethod)
Definition: qgssymbol.cpp:1404
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:1850
A store for object properties.
Definition: qgsproperty.h:229
QgsMarkerSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Definition: qgssymbol.cpp:1097
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:319
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:1571
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the size units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1252
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
virtual QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Definition: qgssurface.h:45
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:126
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:1264
QgsExpressionContext & expressionContext()
Gets the expression context.
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1349
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:111
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:137
bool changeSymbolLayer(int index, QgsSymbolLayer *layer)
delete layer at specified index and set a new one
Definition: qgssymbol.cpp:367
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:630
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:187
QgsSymbolLayerList cloneLayers() const
Retrieve a cloned list of all layers that make up this symbol.
Definition: qgssymbol.cpp:595
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:644
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:53
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:1236
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:116
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:1128
QgsLineSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Definition: qgssymbol.cpp:1519
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:121
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:358
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:164
static QgsMarkerSymbol * createSimple(const QgsStringMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
Definition: qgssymbol.cpp:1062
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:1313
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:512
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:405
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:1606
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:1116
QgsFillSymbol(const QgsSymbolLayerList &layers=QgsSymbolLayerList())
Definition: qgssymbol.cpp:1735
virtual QgsMarkerSymbol * clone() const override
Get a deep copy of this symbol.
Definition: qgssymbol.cpp:1506
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: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:145
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:1723
void setColor(const QColor &color)
Definition: qgssymbol.cpp:427
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:1050