QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgssymbolv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssymbolv2.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 "qgssymbolv2.h"
17 #include "qgssymbollayerv2.h"
18 
19 #include "qgslinesymbollayerv2.h"
20 #include "qgsmarkersymbollayerv2.h"
21 #include "qgsfillsymbollayerv2.h"
23 
24 #include "qgslogger.h"
25 #include "qgsrendercontext.h" // for bigSymbolPreview
26 
27 #include "qgsproject.h"
28 #include "qgsstylev2.h"
29 #include "qgspainteffect.h"
30 #include "qgseffectstack.h"
31 
32 #include "qgsdatadefined.h"
33 
34 #include "qgsgeometry.h"
35 #include "qgsmultipointv2.h"
36 #include "qgswkbptr.h"
37 #include "qgswkbsimplifierptr.h"
39 #include "qgsclipper.h"
40 
41 #include <QColor>
42 #include <QImage>
43 #include <QPainter>
44 #include <QSize>
45 #include <QSvgGenerator>
46 
47 #include <cmath>
48 
49 inline
50 QgsDataDefined* rotateWholeSymbol( double additionalRotation, const QgsDataDefined& dd )
51 {
52  QgsDataDefined* rotatedDD = new QgsDataDefined( dd );
53  QString exprString = dd.useExpression() ? dd.expressionString() : dd.field();
54  rotatedDD->setExpressionString( QString::number( additionalRotation ) + " + (" + exprString + ')' );
55  rotatedDD->setUseExpression( true );
56  return rotatedDD;
57 }
58 
59 inline
60 QgsDataDefined* scaleWholeSymbol( double scaleFactor, const QgsDataDefined& dd )
61 {
62  QgsDataDefined* scaledDD = new QgsDataDefined( dd );
63  QString exprString = dd.useExpression() ? dd.expressionString() : dd.field();
64  scaledDD->setExpressionString( QString::number( scaleFactor ) + "*(" + exprString + ')' );
65  scaledDD->setUseExpression( true );
66  return scaledDD;
67 }
68 
69 inline
70 QgsDataDefined* scaleWholeSymbol( double scaleFactorX, double scaleFactorY, const QgsDataDefined& dd )
71 {
72  QgsDataDefined* scaledDD = new QgsDataDefined( dd );
73  QString exprString = dd.useExpression() ? dd.expressionString() : dd.field();
74  scaledDD->setExpressionString(
75  ( !qgsDoubleNear( scaleFactorX, 0.0 ) ? "tostring(" + QString::number( scaleFactorX ) + "*(" + exprString + "))" : "'0'" ) +
76  "|| ',' || " +
77  ( !qgsDoubleNear( scaleFactorY, 0.0 ) ? "tostring(" + QString::number( scaleFactorY ) + "*(" + exprString + "))" : "'0'" ) );
78  scaledDD->setUseExpression( true );
79  return scaledDD;
80 }
81 
82 
84 
86  : mType( type )
87  , mLayers( layers )
88  , mAlpha( 1.0 )
89  , mRenderHints( 0 )
90  , mClipFeaturesToExtent( true )
91  , mLayer( nullptr )
92  , mStarted( false )
93  , mSymbolRenderContext( nullptr )
94 {
95  // check they're all correct symbol layers
96  for ( int i = 0; i < mLayers.count(); i++ )
97  {
98  if ( !mLayers.at( i ) )
99  {
100  mLayers.removeAt( i-- );
101  }
102  else if ( !mLayers.at( i )->isCompatibleWithSymbol( this ) )
103  {
104  delete mLayers.at( i );
105  mLayers.removeAt( i-- );
106  }
107  }
108 }
109 
111 {
112  QgsWKBTypes::Type type = wkbPtr.readHeader();
113  wkbPtr >> pt.rx() >> pt.ry();
114  wkbPtr += ( QgsWKBTypes::coordDimensions( type ) - 2 ) * sizeof( double );
115 
116  if ( context.coordinateTransform() )
117  {
118  double z = 0; // dummy variable for coordinate transform
119  context.coordinateTransform()->transformInPlace( pt.rx(), pt.ry(), z );
120  }
121 
122  context.mapToPixel().transformInPlace( pt.rx(), pt.ry() );
123 
124  return wkbPtr;
125 }
126 
128 {
129  QgsWKBTypes::Type wkbType = wkbPtr.readHeader();
130  unsigned int nPoints;
131  wkbPtr >> nPoints;
132 
133  const QgsCoordinateTransform* ct = context.coordinateTransform();
134  const QgsMapToPixel& mtp = context.mapToPixel();
135 
136  //apply clipping for large lines to achieve a better rendering performance
137  if ( clipToExtent && nPoints > 1 )
138  {
139  const QgsRectangle& e = context.extent();
140  double cw = e.width() / 10;
141  double ch = e.height() / 10;
142  QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
143  wkbPtr -= 1 + 2 * sizeof( int );
144  wkbPtr = QgsClipper::clippedLineWKB( wkbPtr, clipRect, pts );
145  }
146  else
147  {
148  int skipZM = ( QgsWKBTypes::coordDimensions( wkbType ) - 2 ) * sizeof( double );
149  Q_ASSERT( skipZM >= 0 );
150 
151  if ( static_cast<int>( nPoints * ( 2 * sizeof( double ) + skipZM ) ) > wkbPtr.remaining() )
152  {
153  QgsDebugMsg( QString( "%1 points exceed wkb length (%2>%3)" ).arg( nPoints ).arg( nPoints * ( 2 * sizeof( double ) + skipZM ) ).arg( wkbPtr.remaining() ) );
154  return QgsConstWkbPtr( nullptr, 0 );
155  }
156 
157  wkbPtr -= sizeof( unsigned int );
158  wkbPtr >> pts;
159  nPoints = pts.size();
160  }
161 
162  //transform the QPolygonF to screen coordinates
163  if ( ct )
164  {
165  ct->transformPolygon( pts );
166  }
167 
168  QPointF *ptr = pts.data();
169  for ( int i = 0; i < pts.size(); ++i, ++ptr )
170  {
171  mtp.transformInPlace( ptr->rx(), ptr->ry() );
172  }
173 
174  return wkbPtr;
175 }
176 
178 {
179  QgsWKBTypes::Type wkbType = wkbPtr.readHeader();
180  unsigned int numRings;
181  wkbPtr >> numRings;
182 
183  if ( numRings == 0 ) // sanity check for zero rings in polygon
184  return wkbPtr;
185 
186  holes.clear();
187 
188  const QgsCoordinateTransform* ct = context.coordinateTransform();
189  const QgsMapToPixel& mtp = context.mapToPixel();
190  const QgsRectangle& e = context.extent();
191  double cw = e.width() / 10;
192  double ch = e.height() / 10;
193  QgsRectangle clipRect( e.xMinimum() - cw, e.yMinimum() - ch, e.xMaximum() + cw, e.yMaximum() + ch );
194 
195  int skipZM = ( QgsWKBTypes::coordDimensions( wkbType ) - 2 ) * sizeof( double );
196  Q_ASSERT( skipZM >= 0 );
197 
198  for ( unsigned int idx = 0; idx < numRings; idx++ )
199  {
200  unsigned int nPoints;
201  wkbPtr >> nPoints;
202 
203  if ( static_cast<int>( nPoints * ( 2 * sizeof( double ) + skipZM ) ) > wkbPtr.remaining() )
204  {
205  QgsDebugMsg( QString( "%1 points exceed wkb length (%2>%3)" ).arg( nPoints ).arg( nPoints * ( 2 * sizeof( double ) + skipZM ) ).arg( wkbPtr.remaining() ) );
206  return QgsConstWkbPtr( nullptr, 0 );
207  }
208 
209  QPolygonF poly;
210  wkbPtr -= sizeof( unsigned int );
211  wkbPtr >> poly;
212  nPoints = poly.size();
213 
214  if ( nPoints < 1 )
215  continue;
216 
217  //clip close to view extent, if needed
218  QRectF ptsRect = poly.boundingRect();
219  if ( clipToExtent && !context.extent().contains( ptsRect ) )
220  {
221  QgsClipper::trimPolygon( poly, clipRect );
222  }
223 
224  //transform the QPolygonF to screen coordinates
225  if ( ct )
226  {
227  ct->transformPolygon( poly );
228  }
229 
230  QPointF *ptr = poly.data();
231  for ( int i = 0; i < poly.size(); ++i, ++ptr )
232  {
233  mtp.transformInPlace( ptr->rx(), ptr->ry() );
234  }
235 
236  if ( idx == 0 )
237  pts = poly;
238  else
239  holes.append( poly );
240  }
241 
242  return wkbPtr;
243 }
244 
246 {
247  delete mSymbolRenderContext;
248  // delete all symbol layers (we own them, so it's okay)
249  qDeleteAll( mLayers );
250 }
251 
253 {
254  if ( mLayers.empty() )
255  {
256  return QgsSymbolV2::Mixed;
257  }
258 
260 
261  QgsSymbolV2::OutputUnit unit = ( *it )->outputUnit();
262 
263  for ( ; it != mLayers.constEnd(); ++it )
264  {
265  if (( *it )->outputUnit() != unit )
266  {
267  return QgsSymbolV2::Mixed;
268  }
269  }
270  return unit;
271 }
272 
274 {
275  if ( mLayers.empty() )
276  {
277  return QgsMapUnitScale();
278  }
279 
281  if ( it == mLayers.constEnd() )
282  return QgsMapUnitScale();
283 
284  QgsMapUnitScale scale = ( *it )->mapUnitScale();
285  ++it;
286 
287  for ( ; it != mLayers.constEnd(); ++it )
288  {
289  if (( *it )->mapUnitScale() != scale )
290  {
291  return QgsMapUnitScale();
292  }
293  }
294  return scale;
295 }
296 
298 {
299  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
300  {
301  layer->setOutputUnit( u );
302  }
303 }
304 
306 {
307  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
308  {
309  layer->setMapUnitScale( scale );
310  }
311 }
312 
314 {
315  QgsSymbolV2* s = nullptr;
316 
317  // override global default if project has a default for this type
319  switch ( geomType )
320  {
321  case QGis::Point :
322  defaultSymbol = QgsProject::instance()->readEntry( "DefaultStyles", "/Marker", "" );
323  break;
324  case QGis::Line :
325  defaultSymbol = QgsProject::instance()->readEntry( "DefaultStyles", "/Line", "" );
326  break;
327  case QGis::Polygon :
328  defaultSymbol = QgsProject::instance()->readEntry( "DefaultStyles", "/Fill", "" );
329  break;
330  default:
331  defaultSymbol = "";
332  break;
333  }
334  if ( defaultSymbol != "" )
335  s = QgsStyleV2::defaultStyle()->symbol( defaultSymbol );
336 
337  // if no default found for this type, get global default (as previously)
338  if ( ! s )
339  {
340  switch ( geomType )
341  {
342  case QGis::Point:
343  s = new QgsMarkerSymbolV2();
344  break;
345  case QGis::Line:
346  s = new QgsLineSymbolV2();
347  break;
348  case QGis::Polygon:
349  s = new QgsFillSymbolV2();
350  break;
351  default:
352  QgsDebugMsg( "unknown layer's geometry type" );
353  return nullptr;
354  }
355  }
356 
357  // set alpha transparency
358  s->setAlpha( QgsProject::instance()->readDoubleEntry( "DefaultStyles", "/AlphaInt", 255 ) / 255.0 );
359 
360  // set random color, it project prefs allow
361  if ( defaultSymbol == "" ||
362  QgsProject::instance()->readBoolEntry( "DefaultStyles", "/RandomColors", true ) )
363  {
364  s->setColor( QColor::fromHsv( qrand() % 360, 64 + qrand() % 192, 128 + qrand() % 128 ) );
365  }
366 
367  return s;
368 }
369 
371 {
372  return mLayers.value( layer );
373 }
374 
375 
377 {
378  // fill symbol can contain also line symbol layers for drawing of outlines
379  if ( mType == Fill && layerType == Line )
380  return true;
381 
382  return mType == layerType;
383 }
384 
385 
387 {
388  if ( index < 0 || index > mLayers.count() ) // can be added also after the last index
389  return false;
390 
391  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
392  return false;
393 
394  mLayers.insert( index, layer );
395  return true;
396 }
397 
398 
400 {
401  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
402  return false;
403 
404  mLayers.append( layer );
405  return true;
406 }
407 
408 
410 {
411  if ( index < 0 || index >= mLayers.count() )
412  return false;
413 
414  delete mLayers.at( index );
415  mLayers.removeAt( index );
416  return true;
417 }
418 
419 
421 {
422  if ( index < 0 || index >= mLayers.count() )
423  return nullptr;
424 
425  return mLayers.takeAt( index );
426 }
427 
428 
430 {
431  QgsSymbolLayerV2* oldLayer = mLayers.value( index );
432 
433  if ( oldLayer == layer )
434  return false;
435 
436  if ( !layer || !layer->isCompatibleWithSymbol( this ) )
437  return false;
438 
439  delete oldLayer; // first delete the original layer
440  mLayers[index] = layer; // set new layer
441  return true;
442 }
443 
444 
445 void QgsSymbolV2::startRender( QgsRenderContext& context, const QgsFields* fields )
446 {
447  Q_ASSERT_X( !mStarted, "startRender", "Rendering has already been started for this symbol instance!" );
448 
449  mStarted = true;
450  delete mSymbolRenderContext;
451  mSymbolRenderContext = new QgsSymbolV2RenderContext( context, outputUnit(), mAlpha, false, mRenderHints, nullptr, fields, mapUnitScale() );
452 
453  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, nullptr, fields, mapUnitScale() );
454 
456 
457  mSymbolRenderContext->setExpressionContextScope( scope );
458 
459  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
460  layer->startRender( symbolContext );
461 }
462 
464 {
465  Q_ASSERT_X( mStarted, "startRender", "startRender was not called for this symbol instance!" );
466  mStarted = false;
467 
468  Q_UNUSED( context )
469  if ( mSymbolRenderContext )
470  {
471  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
472  layer->stopRender( *mSymbolRenderContext );
473  }
474 
475  delete mSymbolRenderContext;
476  mSymbolRenderContext = nullptr;
477 
478  mLayer = nullptr;
479 }
480 
482 {
483  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
484  {
485  if ( !layer->isLocked() )
486  layer->setColor( color );
487  }
488 }
489 
491 {
492  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
493  {
494  // return color of the first unlocked layer
495  if ( !( *it )->isLocked() )
496  return ( *it )->color();
497  }
498  return QColor( 0, 0, 0 );
499 }
500 
501 void QgsSymbolV2::drawPreviewIcon( QPainter* painter, QSize size, QgsRenderContext* customContext )
502 {
503  QgsRenderContext context = customContext ? *customContext : QgsSymbolLayerV2Utils::createRenderContext( painter );
504  context.setForceVectorOutput( true );
505  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, nullptr, nullptr, mapUnitScale() );
506 
507  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
508  {
509  if ( mType == Fill && layer->type() == Line )
510  {
511  // line symbol layer would normally draw just a line
512  // so we override this case to force it to draw a polygon outline
513  QgsLineSymbolLayerV2* lsl = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
514 
515  if ( lsl )
516  {
517  // from QgsFillSymbolLayerV2::drawPreviewIcon()
518  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
519  lsl->startRender( symbolContext );
520  lsl->renderPolygonOutline( poly, nullptr, symbolContext );
521  lsl->stopRender( symbolContext );
522  }
523  }
524  else
525  layer->drawPreviewIcon( symbolContext, size );
526  }
527 }
528 
529 void QgsSymbolV2::exportImage( const QString& path, const QString& format, QSize size )
530 {
531  if ( format.toLower() == "svg" )
532  {
533  QSvgGenerator generator;
534  generator.setFileName( path );
535  generator.setSize( size );
536  generator.setViewBox( QRect( 0, 0, size.height(), size.height() ) );
537 
538  QPainter painter( &generator );
539  drawPreviewIcon( &painter, size );
540  painter.end();
541  }
542  else
543  {
544  QImage image = asImage( size );
545  image.save( path );
546  }
547 }
548 
550 {
551  QImage image( size, QImage::Format_ARGB32_Premultiplied );
552  image.fill( 0 );
553 
554  QPainter p( &image );
555  p.setRenderHint( QPainter::Antialiasing );
556 
557  drawPreviewIcon( &p, size, customContext );
558 
559  return image;
560 }
561 
562 
564 {
565  QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
566  preview.fill( 0 );
567 
568  QPainter p( &preview );
569  p.setRenderHint( QPainter::Antialiasing );
570  p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialising
571 
572  if ( mType == QgsSymbolV2::Marker )
573  {
574  p.setPen( QPen( Qt::gray ) );
575  p.drawLine( 0, 50, 100, 50 );
576  p.drawLine( 50, 0, 50, 100 );
577  }
578 
580  if ( expressionContext )
581  context.setExpressionContext( *expressionContext );
582 
583  startRender( context );
584 
585  if ( mType == QgsSymbolV2::Line )
586  {
587  QPolygonF poly;
588  poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
589  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( poly, nullptr, context );
590  }
591  else if ( mType == QgsSymbolV2::Fill )
592  {
593  QPolygonF polygon;
594  polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
595  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( polygon, nullptr, nullptr, context );
596  }
597  else // marker
598  {
599  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( QPointF( 50, 50 ), nullptr, context );
600  }
601 
602  stopRender( context );
603  return preview;
604 }
605 
606 
608 {
609  QString t;
610  switch ( type() )
611  {
612  case QgsSymbolV2::Marker:
613  t = "MARKER";
614  break;
615  case QgsSymbolV2::Line:
616  t = "LINE";
617  break;
618  case QgsSymbolV2::Fill:
619  t = "FILL";
620  break;
621  default:
622  Q_ASSERT( 0 && "unknown symbol type" );
623  }
624  QString s = QString( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerV2Utils::encodeColor( color() ) );
625 
626  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
627  {
628  // TODO:
629  }
630  return s;
631 }
632 
633 void QgsSymbolV2::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const
634 {
635  QgsStringMap locProps( props );
636  locProps[ "alpha" ] = QString::number( alpha() );
637  double scaleFactor = 1.0;
638  locProps[ "uom" ] = QgsSymbolLayerV2Utils::encodeSldUom( outputUnit(), &scaleFactor );
639  locProps[ "uomScale" ] = ( !qgsDoubleNear( scaleFactor, 1.0 ) ? qgsDoubleToString( scaleFactor ) : "" );
640 
641  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
642  {
643  ( *it )->toSld( doc, element, locProps );
644  }
645 }
646 
648 {
650  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
651  {
652  QgsSymbolLayerV2* layer = ( *it )->clone();
653  layer->setLocked(( *it )->isLocked() );
654  layer->setRenderingPass(( *it )->renderingPass() );
655  lst.append( layer );
656  }
657  return lst;
658 }
659 
661 {
662  Q_ASSERT( layer->type() == Hybrid );
663 
665 
666  QgsPaintEffect* effect = generatorLayer->paintEffect();
667  if ( effect && effect->enabled() )
668  {
669  QPainter* p = context.renderContext().painter();
670  p->save();
671 
672  effect->begin( context.renderContext() );
673  generatorLayer->render( context );
674  effect->end( context.renderContext() );
675 
676  p->restore();
677  }
678  else
679  {
680  generatorLayer->render( context );
681  }
682 }
683 
685 {
686  QSet<QString> attributes;
688  for ( ; sIt != mLayers.constEnd(); ++sIt )
689  {
690  if ( *sIt )
691  {
692  attributes.unite(( *sIt )->usedAttributes() );
693  }
694  }
695  return attributes;
696 }
697 
699 {
700  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
701  {
702  if ( layer->hasDataDefinedProperties() )
703  return true;
704  }
705  return false;
706 }
707 
709 
713 class ExpressionContextScopePopper
714 {
715  public:
716 
717  ExpressionContextScopePopper() : context( nullptr )
718  {}
719 
720  ~ExpressionContextScopePopper()
721  {
722  if ( context )
723  context->popScope();
724  }
725 
726  QgsExpressionContext *context;
727 };
729 
730 void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, int currentVertexMarkerSize )
731 {
732  const QgsGeometry* geom = feature.constGeometry();
733  if ( !geom || !geom->geometry() )
734  {
735  return;
736  }
737 
738  const QgsGeometry *segmentizedGeometry = geom;
739  bool deleteSegmentizedGeometry = false;
740  context.setGeometry( geom->geometry() );
741 
742  bool tileMapRendering = context.testFlag( QgsRenderContext::RenderMapTile );
743 
744  //convert curve types to normal point/line/polygon ones
745  if ( QgsWKBTypes::isCurvedType( geom->geometry()->wkbType() ) )
746  {
748  if ( !g )
749  {
750  return;
751  }
752  segmentizedGeometry = new QgsGeometry( g );
753  deleteSegmentizedGeometry = true;
754  }
755 
756  ExpressionContextScopePopper scopePopper;
757  if ( mSymbolRenderContext )
758  {
759  mSymbolRenderContext->setGeometryPartCount( segmentizedGeometry->geometry()->partCount() );
760  mSymbolRenderContext->setGeometryPartNum( 1 );
761 
762  if ( mSymbolRenderContext->expressionContextScope() )
763  {
764  // this is somewhat nasty - by appending this scope here it's now owned
765  // by both mSymbolRenderContext AND context.expressionContext()
766  // the RAII scopePopper is required to make sure it always has ownership transferred back
767  // from context.expressionContext(), even if exceptions of other early exits occur in this
768  // function
769  context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
770  scopePopper.context = &context.expressionContext();
771 
772  QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
773  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount(), true ) );
774  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1, true ) );
775  }
776  }
777 
778  // Collection of markers to paint, only used for no curve types.
779  QPolygonF markers;
780 
781  switch ( QgsWKBTypes::flatType( segmentizedGeometry->geometry()->wkbType() ) )
782  {
783  case QgsWKBTypes::Point:
784  {
785  QPointF pt;
786  if ( mType != QgsSymbolV2::Marker )
787  {
788  QgsDebugMsg( "point can be drawn only with marker symbol!" );
789  break;
790  }
791 
792  const QgsPointV2* point = static_cast< const QgsPointV2* >( segmentizedGeometry->geometry() );
793  _getPoint( pt, context, point );
794  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( pt, &feature, context, layer, selected );
795 
797  {
798  //draw debugging rect
799  context.painter()->setPen( Qt::red );
800  context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
801  context.painter()->drawRect( static_cast<QgsMarkerSymbolV2*>( this )->bounds( pt, context, feature ) );
802  }
803 
804  if ( drawVertexMarker && !deleteSegmentizedGeometry )
805  {
806  markers << pt;
807  }
808  }
809  break;
811  {
812  QPolygonF pts;
813  if ( mType != QgsSymbolV2::Line )
814  {
815  QgsDebugMsg( "linestring can be drawn only with line symbol!" );
816  break;
817  }
818  QgsConstWkbSimplifierPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize(), context.vectorSimplifyMethod() );
819  _getLineString( pts, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() );
820  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( pts, &feature, context, layer, selected );
821 
822  if ( drawVertexMarker && !deleteSegmentizedGeometry )
823  {
824  markers = pts;
825  }
826  }
827  break;
829  {
830  QPolygonF pts;
831  QList<QPolygonF> holes;
832  if ( mType != QgsSymbolV2::Fill )
833  {
834  QgsDebugMsg( "polygon can be drawn only with fill symbol!" );
835  break;
836  }
837  QgsConstWkbSimplifierPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize(), context.vectorSimplifyMethod() );
838  _getPolygon( pts, holes, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() );
839  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
840 
841  if ( drawVertexMarker && !deleteSegmentizedGeometry )
842  {
843  markers = pts;
844 
845  Q_FOREACH ( const QPolygonF& hole, holes )
846  {
847  markers << hole;
848  }
849  }
850  }
851  break;
852 
854  {
855  QPointF pt;
856 
857  if ( mType != QgsSymbolV2::Marker )
858  {
859  QgsDebugMsg( "multi-point can be drawn only with marker symbol!" );
860  break;
861  }
862 
863  QgsMultiPointV2* mp = static_cast< QgsMultiPointV2* >( segmentizedGeometry->geometry() );
864 
865  if ( drawVertexMarker && !deleteSegmentizedGeometry )
866  {
867  markers.reserve( mp->numGeometries() );
868  }
869 
870  for ( int i = 0; i < mp->numGeometries(); ++i )
871  {
872  if ( mSymbolRenderContext )
873  {
874  mSymbolRenderContext->setGeometryPartNum( i + 1 );
875  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
876  }
877 
878  const QgsPointV2* point = static_cast< const QgsPointV2* >( mp->geometryN( i ) );
879  _getPoint( pt, context, point );
880  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( pt, &feature, context, layer, selected );
881 
882  if ( drawVertexMarker && !deleteSegmentizedGeometry )
883  {
884  markers.append( pt );
885  }
886  }
887  }
888  break;
889 
892  {
893  QPolygonF pts;
894 
895  if ( mType != QgsSymbolV2::Line )
896  {
897  QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" );
898  break;
899  }
900 
901  QgsConstWkbSimplifierPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize(), context.vectorSimplifyMethod() );
902  wkbPtr.readHeader();
903 
904  unsigned int num;
905  wkbPtr >> num;
906 
907  const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
908 
909  for ( unsigned int i = 0; i < num && wkbPtr; ++i )
910  {
911  if ( mSymbolRenderContext )
912  {
913  mSymbolRenderContext->setGeometryPartNum( i + 1 );
914  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
915  }
916 
917  if ( geomCollection )
918  {
919  context.setGeometry( geomCollection->geometryN( i ) );
920  }
921  if ( _getLineString( pts, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() ) == nullptr )
922  {
923  break;
924  }
925  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( pts, &feature, context, layer, selected );
926 
927  if ( drawVertexMarker && !deleteSegmentizedGeometry )
928  {
929  if ( i == 0 )
930  {
931  markers = pts;
932  }
933  else
934  {
935  markers << pts;
936  }
937  }
938  }
939  }
940  break;
941 
944  {
945  if ( mType != QgsSymbolV2::Fill )
946  {
947  QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" );
948  break;
949  }
950 
951  QgsConstWkbSimplifierPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize(), context.vectorSimplifyMethod() );
952  wkbPtr.readHeader();
953 
954  unsigned int num;
955  wkbPtr >> num;
956 
957  QPolygonF pts;
958  QList<QPolygonF> holes;
959 
960  const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
961 
962  for ( unsigned int i = 0; i < num && wkbPtr; ++i )
963  {
964  if ( mSymbolRenderContext )
965  {
966  mSymbolRenderContext->setGeometryPartNum( i + 1 );
967  mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
968  }
969 
970  if ( geomCollection )
971  {
972  context.setGeometry( geomCollection->geometryN( i ) );
973  }
974  if ( _getPolygon( pts, holes, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() ) == nullptr )
975  {
976  break;
977  }
978  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
979 
980  if ( drawVertexMarker && !deleteSegmentizedGeometry )
981  {
982  if ( i == 0 )
983  {
984  markers = pts;
985  }
986  else
987  {
988  markers << pts;
989  }
990 
991  Q_FOREACH ( const QPolygonF& hole, holes )
992  {
993  markers << hole;
994  }
995  }
996  }
997  break;
998  }
1000  {
1001  QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() );
1002  wkbPtr.readHeader();
1003 
1004  int nGeometries;
1005  wkbPtr >> nGeometries;
1006 
1007  if ( nGeometries == 0 )
1008  {
1009  // skip noise from empty geometry collections from simplification
1010  break;
1011  }
1012 
1013  FALLTHROUGH;
1014  }
1015  default:
1016  QgsDebugMsg( QString( "feature %1: unsupported wkb type %2/%3 for rendering" )
1017  .arg( feature.id() )
1018  .arg( QgsWKBTypes::displayString( geom->geometry()->wkbType() ) )
1019  .arg( geom->wkbType(), 0, 16 ) );
1020  }
1021 
1022  if ( drawVertexMarker )
1023  {
1024  if ( markers.size() > 0 )
1025  {
1026  Q_FOREACH ( QPointF marker, markers )
1027  {
1028  renderVertexMarker( marker, context, currentVertexMarkerType, currentVertexMarkerSize );
1029  }
1030  }
1031  else
1032  {
1033  const QgsCoordinateTransform* ct = context.coordinateTransform();
1034  const QgsMapToPixel& mtp = context.mapToPixel();
1035 
1036  QgsPointV2 vertexPoint;
1037  QgsVertexId vertexId;
1038  double x, y, z;
1039  QPointF mapPoint;
1040  while ( geom->geometry()->nextVertex( vertexId, vertexPoint ) )
1041  {
1042  //transform
1043  x = vertexPoint.x();
1044  y = vertexPoint.y();
1045  z = 0.0;
1046  if ( ct )
1047  {
1048  ct->transformInPlace( x, y, z );
1049  }
1050  mapPoint.setX( x );
1051  mapPoint.setY( y );
1052  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1053  renderVertexMarker( mapPoint, context, currentVertexMarkerType, currentVertexMarkerSize );
1054  }
1055  }
1056  }
1057 
1058  if ( deleteSegmentizedGeometry )
1059  {
1060  delete segmentizedGeometry;
1061  }
1062 }
1063 
1065 {
1066  return mSymbolRenderContext;
1067 }
1068 
1069 void QgsSymbolV2::renderVertexMarker( QPointF pt, QgsRenderContext& context, int currentVertexMarkerType, int currentVertexMarkerSize )
1070 {
1071  QgsVectorLayer::drawVertexMarker( pt.x(), pt.y(), *context.painter(), static_cast< QgsVectorLayer::VertexMarkerType >( currentVertexMarkerType ), currentVertexMarkerSize );
1072 }
1073 
1075 
1076 
1078  : mRenderContext( c )
1079  , mExpressionContextScope( nullptr )
1080  , mOutputUnit( u )
1081  , mMapUnitScale( mapUnitScale )
1082  , mAlpha( alpha )
1083  , mSelected( selected )
1084  , mRenderHints( renderHints )
1085  , mFeature( f )
1086  , mFields( fields )
1087  , mGeometryPartCount( 0 )
1088  , mGeometryPartNum( 0 )
1089 {
1090 }
1091 
1093 {
1094  delete mExpressionContextScope;
1095 }
1096 
1098 {
1099  mRenderContext.expressionContext().setOriginalValueVariable( value );
1100 }
1101 
1102 double QgsSymbolV2RenderContext::outputLineWidth( double width ) const
1103 {
1104  return QgsSymbolLayerV2Utils::convertToPainterUnits( mRenderContext, width, mOutputUnit, mMapUnitScale );
1105 }
1106 
1108 {
1109  return size * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( mRenderContext, mOutputUnit, mMapUnitScale );
1110 }
1111 
1113 {
1114  // This is just a dummy implementation of assignment.
1115  // sip 4.7 generates a piece of code that needs this function to exist.
1116  // It's not generated automatically by the compiler because of
1117  // mRenderContext member which is a reference (and thus can't be changed).
1118  Q_ASSERT( false );
1119  return *this;
1120 }
1121 
1123 {
1124  return mExpressionContextScope;
1125 }
1126 
1128 {
1129  mExpressionContextScope = contextScope;
1130 }
1131 
1133 
1135 {
1137  if ( !sl )
1138  return nullptr;
1139 
1140  QgsSymbolLayerV2List layers;
1141  layers.append( sl );
1142  return new QgsMarkerSymbolV2( layers );
1143 }
1144 
1146 {
1148  if ( !sl )
1149  return nullptr;
1150 
1151  QgsSymbolLayerV2List layers;
1152  layers.append( sl );
1153  return new QgsLineSymbolV2( layers );
1154 }
1155 
1157 {
1159  if ( !sl )
1160  return nullptr;
1161 
1162  QgsSymbolLayerV2List layers;
1163  layers.append( sl );
1164  return new QgsFillSymbolV2( layers );
1165 }
1166 
1168 
1170  : QgsSymbolV2( Marker, layers )
1171 {
1172  if ( mLayers.isEmpty() )
1174 }
1175 
1176 void QgsMarkerSymbolV2::setAngle( double angle0 )
1177 {
1178  double origAngle = angle();
1179  double angleDiff = angle0 - origAngle;
1180  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1181  {
1182  QgsMarkerSymbolLayerV2* markerLayer = dynamic_cast<QgsMarkerSymbolLayerV2*>( layer );
1183  if ( markerLayer )
1184  markerLayer->setAngle( markerLayer->angle() + angleDiff );
1185  }
1186 }
1187 
1189 {
1190  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1191  {
1192  if ( layer->type() != QgsSymbolV2::Marker )
1193  continue;
1194  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1195  return markerLayer->angle();
1196  }
1197  return 0;
1198 }
1199 
1200 void QgsMarkerSymbolV2::setLineAngle( double lineAng )
1201 {
1202  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1203  {
1204  if ( layer->type() != QgsSymbolV2::Marker )
1205  continue;
1206  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1207  markerLayer->setLineAngle( lineAng );
1208  }
1209 }
1210 
1212 {
1213  const double symbolRotation = angle();
1214 
1215  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1216  {
1217  if ( layer->type() != QgsSymbolV2::Marker )
1218  continue;
1219  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1220  if ( dd.hasDefaultValues() )
1221  {
1222  layer->removeDataDefinedProperty( "angle" );
1223  }
1224  else
1225  {
1226  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1227  {
1228  layer->setDataDefinedProperty( "angle", new QgsDataDefined( dd ) );
1229  }
1230  else
1231  {
1232  QgsDataDefined* rotatedDD = rotateWholeSymbol( markerLayer->angle() - symbolRotation, dd );
1233  layer->setDataDefinedProperty( "angle", rotatedDD );
1234  }
1235  }
1236  }
1237 }
1238 
1240 {
1241  const double symbolRotation = angle();
1242  QgsDataDefined* symbolDD = nullptr;
1243 
1244  // find the base of the "en masse" pattern
1245  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1246  {
1247  if ( layer->type() != QgsSymbolV2::Marker )
1248  continue;
1249  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1250  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) && markerLayer->getDataDefinedProperty( "angle" ) )
1251  {
1252  symbolDD = markerLayer->getDataDefinedProperty( "angle" );
1253  break;
1254  }
1255  }
1256 
1257  if ( !symbolDD )
1258  return QgsDataDefined();
1259 
1260  // check that all layer's angle expressions match the "en masse" pattern
1261  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1262  {
1263  if ( layer->type() != QgsSymbolV2::Marker )
1264  continue;
1265  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1266  QgsDataDefined* layerAngleDD = markerLayer->getDataDefinedProperty( "angle" );
1267 
1268  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1269  {
1270  if ( !layerAngleDD || *layerAngleDD != *symbolDD )
1271  return QgsDataDefined();
1272  }
1273  else
1274  {
1275  QScopedPointer< QgsDataDefined > rotatedDD( rotateWholeSymbol( markerLayer->angle() - symbolRotation, *symbolDD ) );
1276  if ( !layerAngleDD || *layerAngleDD != *( rotatedDD.data() ) )
1277  return QgsDataDefined();
1278  }
1279  }
1280  return QgsDataDefined( *symbolDD );
1281 }
1282 
1283 
1285 {
1286  double origSize = size();
1287 
1288  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1289  {
1290  if ( layer->type() != QgsSymbolV2::Marker )
1291  continue;
1292  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1293  if ( qgsDoubleNear( markerLayer->size(), origSize ) )
1294  markerLayer->setSize( s );
1295  else if ( !qgsDoubleNear( origSize, 0.0 ) )
1296  {
1297  // proportionally scale size
1298  markerLayer->setSize( markerLayer->size() * s / origSize );
1299  }
1300  // also scale offset to maintain relative position
1301  if ( !qgsDoubleNear( origSize, 0.0 ) && ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) ) )
1302  markerLayer->setOffset( QPointF( markerLayer->offset().x() * s / origSize,
1303  markerLayer->offset().y() * s / origSize ) );
1304  }
1305 }
1306 
1308 {
1309  // return size of the largest symbol
1310  double maxSize = 0;
1311  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1312  {
1313  if ( layer->type() != QgsSymbolV2::Marker )
1314  continue;
1315  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1316  double lsize = markerLayer->size();
1317  if ( lsize > maxSize )
1318  maxSize = lsize;
1319  }
1320  return maxSize;
1321 }
1322 
1324 {
1325  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1326  {
1327  if ( layer->type() != QgsSymbolV2::Marker )
1328  continue;
1329 
1330  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1331  markerLayer->setSizeUnit( unit );
1332  }
1333 }
1334 
1336 {
1337  bool first = true;
1338  OutputUnit unit = Mixed;
1339 
1340  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1341  {
1342  if ( layer->type() != QgsSymbolV2::Marker )
1343  continue;
1344  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1345 
1346  if ( first )
1347  unit = markerLayer->sizeUnit();
1348  else
1349  {
1350  if ( unit != markerLayer->sizeUnit() )
1351  return Mixed;
1352  }
1353 
1354  first = false;
1355  }
1356  return unit;
1357 }
1358 
1360 {
1361  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1362  {
1363  if ( layer->type() != QgsSymbolV2::Marker )
1364  continue;
1365 
1366  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1367  markerLayer->setSizeMapUnitScale( scale );
1368  }
1369 }
1370 
1372 {
1373  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1374  {
1375  if ( layer->type() != QgsSymbolV2::Marker )
1376  continue;
1377 
1378  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1379  return markerLayer->sizeMapUnitScale();
1380  }
1381  return QgsMapUnitScale();
1382 }
1383 
1385 {
1386  const double symbolSize = size();
1387 
1388  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1389  {
1390  if ( layer->type() != QgsSymbolV2::Marker )
1391  continue;
1392  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1393 
1394  if ( dd.hasDefaultValues() )
1395  {
1396  markerLayer->removeDataDefinedProperty( "size" );
1397  markerLayer->removeDataDefinedProperty( "offset" );
1398  }
1399  else
1400  {
1401  if ( qgsDoubleNear( symbolSize, 0.0 ) || qgsDoubleNear( markerLayer->size(), symbolSize ) )
1402  {
1403  markerLayer->setDataDefinedProperty( "size", new QgsDataDefined( dd ) );
1404  }
1405  else
1406  {
1407  markerLayer->setDataDefinedProperty( "size", scaleWholeSymbol( markerLayer->size() / symbolSize, dd ) );
1408  }
1409 
1410  if ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) )
1411  {
1412  markerLayer->setDataDefinedProperty( "offset", scaleWholeSymbol(
1413  markerLayer->offset().x() / symbolSize,
1414  markerLayer->offset().y() / symbolSize, dd ) );
1415  }
1416  }
1417  }
1418 }
1419 
1421 {
1422  const double symbolSize = size();
1423 
1424  QgsDataDefined* symbolDD = nullptr;
1425 
1426  // find the base of the "en masse" pattern
1427  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1428  {
1429  if ( layer->type() != QgsSymbolV2::Marker )
1430  continue;
1431  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1432  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) && markerLayer->getDataDefinedProperty( "size" ) )
1433  {
1434  symbolDD = markerLayer->getDataDefinedProperty( "size" );
1435  break;
1436  }
1437  }
1438 
1439  if ( !symbolDD )
1440  return QgsDataDefined();
1441 
1442  // check that all layers size expressions match the "en masse" pattern
1443  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1444  {
1445  if ( layer->type() != QgsSymbolV2::Marker )
1446  continue;
1447  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1448 
1449  QgsDataDefined* layerSizeDD = markerLayer->getDataDefinedProperty( "size" );
1450  QgsDataDefined* layerOffsetDD = markerLayer->getDataDefinedProperty( "offset" );
1451 
1452  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) )
1453  {
1454  if ( !layerSizeDD || *layerSizeDD != *symbolDD )
1455  return QgsDataDefined();
1456  }
1457  else
1458  {
1459  if ( qgsDoubleNear( symbolSize, 0.0 ) )
1460  return QgsDataDefined();
1461 
1462  QScopedPointer< QgsDataDefined > scaledDD( scaleWholeSymbol( markerLayer->size() / symbolSize, *symbolDD ) );
1463  if ( !layerSizeDD || *layerSizeDD != *( scaledDD.data() ) )
1464  return QgsDataDefined();
1465  }
1466 
1467  QScopedPointer< QgsDataDefined > scaledOffsetDD( scaleWholeSymbol( markerLayer->offset().x() / symbolSize, markerLayer->offset().y() / symbolSize, *symbolDD ) );
1468  if ( layerOffsetDD && *layerOffsetDD != *( scaledOffsetDD.data() ) )
1469  return QgsDataDefined();
1470  }
1471 
1472  return QgsDataDefined( *symbolDD );
1473 }
1474 
1476 {
1477  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1478  {
1479  if ( layer->type() != QgsSymbolV2::Marker )
1480  continue;
1481  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1482  markerLayer->setScaleMethod( scaleMethod );
1483  }
1484 }
1485 
1487 {
1488  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1489  {
1490  if ( layer->type() != QgsSymbolV2::Marker )
1491  continue;
1492  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1493  // return scale method of the first symbol layer
1494  return markerLayer->scaleMethod();
1495  }
1496 
1497  return DEFAULT_SCALE_METHOD;
1498 }
1499 
1500 void QgsMarkerSymbolV2::renderPointUsingLayer( QgsMarkerSymbolLayerV2* layer, QPointF point, QgsSymbolV2RenderContext& context )
1501 {
1502  static QPointF nullPoint( 0, 0 );
1503 
1504  QgsPaintEffect* effect = layer->paintEffect();
1505  if ( effect && effect->enabled() )
1506  {
1507  QPainter* p = context.renderContext().painter();
1508  p->save();
1509  p->translate( point );
1510 
1511  effect->begin( context.renderContext() );
1512  layer->renderPoint( nullPoint, context );
1513  effect->end( context.renderContext() );
1514 
1515  p->restore();
1516  }
1517  else
1518  {
1519  layer->renderPoint( point, context );
1520  }
1521 }
1522 
1523 void QgsMarkerSymbolV2::renderPoint( QPointF point, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1524 {
1525  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1526  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1527  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1528 
1529  if ( layerIdx != -1 )
1530  {
1531  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1532  if ( symbolLayer )
1533  {
1534  if ( symbolLayer->type() == QgsSymbolV2::Marker )
1535  {
1536  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( symbolLayer );
1537  renderPointUsingLayer( markerLayer, point, symbolContext );
1538  }
1539  else
1540  renderUsingLayer( symbolLayer, symbolContext );
1541  }
1542  return;
1543  }
1544 
1545  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1546  {
1547  if ( symbolLayer->type() == QgsSymbolV2::Marker )
1548  {
1549  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( symbolLayer );
1550  renderPointUsingLayer( markerLayer, point, symbolContext );
1551  }
1552  else
1553  renderUsingLayer( symbolLayer, symbolContext );
1554  }
1555 }
1556 
1557 QRectF QgsMarkerSymbolV2::bounds( QPointF point, QgsRenderContext& context, const QgsFeature& feature ) const
1558 {
1559  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, &feature, feature.fields(), mapUnitScale() );
1560 
1561  QRectF bound;
1562  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1563  {
1564  if ( layer->type() == QgsSymbolV2::Marker )
1565  {
1567  if ( bound.isNull() )
1568  bound = symbolLayer->bounds( point, symbolContext );
1569  else
1570  bound = bound.united( symbolLayer->bounds( point, symbolContext ) );
1571  }
1572  }
1573  return bound;
1574 }
1575 
1577 {
1578  QgsMarkerSymbolV2* cloneSymbol = new QgsMarkerSymbolV2( cloneLayers() );
1579  cloneSymbol->setAlpha( mAlpha );
1580  cloneSymbol->setLayer( mLayer );
1582  return cloneSymbol;
1583 }
1584 
1585 
1587 // LINE
1588 
1590  : QgsSymbolV2( Line, layers )
1591 {
1592  if ( mLayers.isEmpty() )
1594 }
1595 
1597 {
1598  double origWidth = width();
1599 
1600  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1601  {
1602  QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
1603 
1604  if ( lineLayer )
1605  {
1606  if ( qgsDoubleNear( lineLayer->width(), origWidth ) )
1607  {
1608  lineLayer->setWidth( w );
1609  }
1610  else if ( !qgsDoubleNear( origWidth, 0.0 ) )
1611  {
1612  // proportionally scale the width
1613  lineLayer->setWidth( lineLayer->width() * w / origWidth );
1614  }
1615  // also scale offset to maintain relative position
1616  if ( !qgsDoubleNear( origWidth, 0.0 ) && !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1617  lineLayer->setOffset( lineLayer->offset() * w / origWidth );
1618  }
1619  }
1620 }
1621 
1623 {
1624  double maxWidth = 0;
1625  if ( mLayers.isEmpty() )
1626  return maxWidth;
1627 
1628  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1629  {
1630  const QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1631  if ( lineLayer )
1632  {
1633  double width = lineLayer->width();
1634  if ( width > maxWidth )
1635  maxWidth = width;
1636  }
1637  }
1638  return maxWidth;
1639 }
1640 
1642 {
1643  const double symbolWidth = width();
1644 
1645  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1646  {
1647  QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
1648 
1649  if ( lineLayer )
1650  {
1651  if ( dd.hasDefaultValues() )
1652  {
1653  lineLayer->removeDataDefinedProperty( "width" );
1654  lineLayer->removeDataDefinedProperty( "offset" );
1655  }
1656  else
1657  {
1658  if ( qgsDoubleNear( symbolWidth, 0.0 ) || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1659  {
1660  lineLayer->setDataDefinedProperty( "width", new QgsDataDefined( dd ) );
1661  }
1662  else
1663  {
1664  lineLayer->setDataDefinedProperty( "width", scaleWholeSymbol( lineLayer->width() / symbolWidth, dd ) );
1665  }
1666 
1667  if ( !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1668  {
1669  lineLayer->setDataDefinedProperty( "offset", scaleWholeSymbol( lineLayer->offset() / symbolWidth, dd ) );
1670  }
1671  }
1672  }
1673  }
1674 }
1675 
1677 {
1678  const double symbolWidth = width();
1679 
1680  QgsDataDefined* symbolDD = nullptr;
1681 
1682  // find the base of the "en masse" pattern
1683  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1684  {
1685  const QgsLineSymbolLayerV2* layer = dynamic_cast<const QgsLineSymbolLayerV2*>( *it );
1686  if ( layer && qgsDoubleNear( layer->width(), symbolWidth ) && layer->getDataDefinedProperty( "width" ) )
1687  {
1688  symbolDD = layer->getDataDefinedProperty( "width" );
1689  break;
1690  }
1691  }
1692 
1693  if ( !symbolDD )
1694  return QgsDataDefined();
1695 
1696  // check that all layers width expressions match the "en masse" pattern
1697  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1698  {
1699  if ( layer->type() != QgsSymbolV2::Line )
1700  continue;
1701  const QgsLineSymbolLayerV2* lineLayer = static_cast<const QgsLineSymbolLayerV2*>( layer );
1702 
1703  QgsDataDefined* layerWidthDD = lineLayer->getDataDefinedProperty( "width" );
1704  QgsDataDefined* layerOffsetDD = lineLayer->getDataDefinedProperty( "offset" );
1705 
1706  if ( qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1707  {
1708  if ( !layerWidthDD || *layerWidthDD != *symbolDD )
1709  return QgsDataDefined();
1710  }
1711  else
1712  {
1713  if ( qgsDoubleNear( symbolWidth, 0.0 ) )
1714  return QgsDataDefined();
1715 
1716  QScopedPointer< QgsDataDefined > scaledDD( scaleWholeSymbol( lineLayer->width() / symbolWidth, *symbolDD ) );
1717  if ( !layerWidthDD || *layerWidthDD != *( scaledDD.data() ) )
1718  return QgsDataDefined();
1719  }
1720 
1721  QScopedPointer< QgsDataDefined > scaledOffsetDD( scaleWholeSymbol( lineLayer->offset() / symbolWidth, *symbolDD ) );
1722  if ( layerOffsetDD && *layerOffsetDD != *( scaledOffsetDD.data() ) )
1723  return QgsDataDefined();
1724  }
1725 
1726  return QgsDataDefined( *symbolDD );
1727 }
1728 
1729 void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1730 {
1731  //save old painter
1732  QPainter* renderPainter = context.painter();
1733  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1734  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1735  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1736 
1737  if ( layerIdx != -1 )
1738  {
1739  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1740  if ( symbolLayer )
1741  {
1742  if ( symbolLayer->type() == QgsSymbolV2::Line )
1743  {
1744  QgsLineSymbolLayerV2* lineLayer = static_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1745  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1746  }
1747  else
1748  renderUsingLayer( symbolLayer, symbolContext );
1749  }
1750  return;
1751  }
1752 
1753  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1754  {
1755  if ( symbolLayer->type() == QgsSymbolV2::Line )
1756  {
1757  QgsLineSymbolLayerV2* lineLayer = static_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1758  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1759  }
1760  else
1761  {
1762  renderUsingLayer( symbolLayer, symbolContext );
1763  }
1764  }
1765 
1766  context.setPainter( renderPainter );
1767 }
1768 
1769 void QgsLineSymbolV2::renderPolylineUsingLayer( QgsLineSymbolLayerV2 *layer, const QPolygonF &points, QgsSymbolV2RenderContext &context )
1770 {
1771  QgsPaintEffect* effect = layer->paintEffect();
1772  if ( effect && effect->enabled() )
1773  {
1774  QPainter* p = context.renderContext().painter();
1775  p->save();
1776  p->translate( points.boundingRect().topLeft() );
1777 
1778  effect->begin( context.renderContext() );
1779  layer->renderPolyline( points.translated( -points.boundingRect().topLeft() ), context );
1780  effect->end( context.renderContext() );
1781 
1782  p->restore();
1783  }
1784  else
1785  {
1786  layer->renderPolyline( points, context );
1787  }
1788 }
1789 
1790 
1792 {
1793  QgsLineSymbolV2* cloneSymbol = new QgsLineSymbolV2( cloneLayers() );
1794  cloneSymbol->setAlpha( mAlpha );
1795  cloneSymbol->setLayer( mLayer );
1797  return cloneSymbol;
1798 }
1799 
1801 // FILL
1802 
1804  : QgsSymbolV2( Fill, layers )
1805 {
1806  if ( mLayers.isEmpty() )
1808 }
1809 
1810 void QgsFillSymbolV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1811 {
1812  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1813  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1814  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1815 
1816  if ( layerIdx != -1 )
1817  {
1818  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1819  if ( symbolLayer )
1820  {
1821  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1822  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1823  else
1824  renderUsingLayer( symbolLayer, symbolContext );
1825  }
1826  return;
1827  }
1828 
1829  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1830  {
1831  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1832  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1833  else
1834  renderUsingLayer( symbolLayer, symbolContext );
1835  }
1836 }
1837 
1838 void QgsFillSymbolV2::renderPolygonUsingLayer( QgsSymbolLayerV2* layer, const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
1839 {
1840  QgsSymbolV2::SymbolType layertype = layer->type();
1841 
1842  QgsPaintEffect* effect = layer->paintEffect();
1843  if ( effect && effect->enabled() )
1844  {
1845  QRectF bounds = polygonBounds( points, rings );
1846  QList<QPolygonF>* translatedRings = translateRings( rings, -bounds.left(), -bounds.top() );
1847 
1848  QPainter* p = context.renderContext().painter();
1849  p->save();
1850  p->translate( bounds.topLeft() );
1851 
1852  effect->begin( context.renderContext() );
1853  if ( layertype == QgsSymbolV2::Fill )
1854  {
1855  ( static_cast<QgsFillSymbolLayerV2*>( layer ) )->renderPolygon( points.translated( -bounds.topLeft() ), translatedRings, context );
1856  }
1857  else if ( layertype == QgsSymbolV2::Line )
1858  {
1859  ( static_cast<QgsLineSymbolLayerV2*>( layer ) )->renderPolygonOutline( points.translated( -bounds.topLeft() ), translatedRings, context );
1860  }
1861  delete translatedRings;
1862 
1863  effect->end( context.renderContext() );
1864  p->restore();
1865  }
1866  else
1867  {
1868  if ( layertype == QgsSymbolV2::Fill )
1869  {
1870  ( static_cast<QgsFillSymbolLayerV2*>( layer ) )->renderPolygon( points, rings, context );
1871  }
1872  else if ( layertype == QgsSymbolV2::Line )
1873  {
1874  ( static_cast<QgsLineSymbolLayerV2*>( layer ) )->renderPolygonOutline( points, rings, context );
1875  }
1876  }
1877 }
1878 
1879 QRectF QgsFillSymbolV2::polygonBounds( const QPolygonF& points, const QList<QPolygonF>* rings ) const
1880 {
1881  QRectF bounds = points.boundingRect();
1882  if ( rings )
1883  {
1885  for ( ; it != rings->constEnd(); ++it )
1886  {
1887  bounds = bounds.united(( *it ).boundingRect() );
1888  }
1889  }
1890  return bounds;
1891 }
1892 
1893 QList<QPolygonF>* QgsFillSymbolV2::translateRings( const QList<QPolygonF>* rings, double dx, double dy ) const
1894 {
1895  if ( !rings )
1896  return nullptr;
1897 
1898  QList<QPolygonF>* translatedRings = new QList<QPolygonF>;
1900  for ( ; it != rings->constEnd(); ++it )
1901  {
1902  translatedRings->append(( *it ).translated( dx, dy ) );
1903  }
1904  return translatedRings;
1905 }
1906 
1908 {
1909  QgsFillSymbolV2* cloneSymbol = new QgsFillSymbolV2( cloneLayers() );
1910  cloneSymbol->setAlpha( mAlpha );
1911  cloneSymbol->setLayer( mLayer );
1913  return cloneSymbol;
1914 }
1915 
1917 {
1918  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1919  {
1920  if ( layer->type() != QgsSymbolV2::Fill )
1921  continue;
1922 
1923  QgsFillSymbolLayerV2* fillLayer = static_cast<QgsFillSymbolLayerV2*>( layer );
1924 
1925  if ( fillLayer )
1926  fillLayer->setAngle( angle );
1927  }
1928 }
1929 
1930 
QgsDataDefined dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
virtual void renderPoint(QPointF point, QgsSymbolV2RenderContext &context)=0
Renders a marker at the specified point.
virtual void setMapUnitScale(const QgsMapUnitScale &scale)
QgsFillSymbolV2(const QgsSymbolLayerV2List &layers=QgsSymbolLayerV2List())
void setForceVectorOutput(bool force)
void clear()
void setLocked(bool locked)
static int coordDimensions(Type type)
Returns the coordinate dimension of the geometry type as an integer.
Definition: qgswkbtypes.h:573
bool contains(const QgsRectangle &rect) const
return true when rectangle contains other rectangle
bool deleteSymbolLayer(int index)
delete symbol layer at specified index
Single variable definition for use within a QgsExpressionContextScope.
static unsigned index
void setViewBox(const QRect &viewBox)
A rectangle specified with double values.
Definition: qgsrectangle.h:35
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
static QgsMarkerSymbolV2 * createSimple(const QgsStringMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
void setClipFeaturesToExtent(bool clipFeaturesToExtent)
Sets whether features drawn by the symbol should be clipped to the render context&#39;s extent...
Definition: qgssymbolv2.h:219
int numGeometries() const
Returns the number of geometries within the collection.
double angle() const
Returns the marker angle for the whole symbol.
QPointF offset() const
Returns the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered mar...
OutputUnit
The unit of the output.
Definition: qgssymbolv2.h:65
virtual void setOutputUnit(QgsSymbolV2::OutputUnit unit)
QString readEntry(const QString &scope, const QString &key, const QString &def=QString::null, bool *ok=nullptr) const
QGis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
int width() const
QString dump() const
bool mClipFeaturesToExtent
Definition: qgssymbolv2.h:333
void setDataDefinedAngle(const QgsDataDefined &dd)
Set data defined angle for whole symbol (including all symbol layers).
A container class for data source field mapping or expression.
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Added in QGIS v2.4.
bool end()
GeometryType
Definition: qgis.h:115
void setSize(const QSize &size)
void setGeometryPartCount(int count)
Sets the part count of current geometry.
Definition: qgssymbolv2.h:403
virtual QgsLineSymbolV2 * clone() const override
void setRenderHint(RenderHint hint, bool on)
const QgsVectorLayer * mLayer
Definition: qgssymbolv2.h:335
void append(const T &value)
virtual QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context)
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
QgsSymbolV2::OutputUnit sizeUnit() const
Returns the units for the symbol&#39;s size.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
double size() const
Returns the symbol size.
void setDataDefinedSize(const QgsDataDefined &dd)
Set data defined size for whole symbol (including all symbol layers).
bool save(const QString &fileName, const char *format, int quality) const
static QString encodeColor(const QColor &color)
static QString encodeSldUom(QgsSymbolV2::OutputUnit unit, double *scaleFactor)
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
Sets the method to use for scaling the marker&#39;s size.
const QgsMapUnitScale & sizeMapUnitScale() const
Returns the map unit scale for the symbol&#39;s size.
static QgsFillSymbolV2 * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
const T & at(int i) const
VertexMarkerType
Editing vertex markers.
void setOffset(QPointF offset)
Sets the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered marker...
void removeAt(int i)
QPolygonF translated(qreal dx, qreal dy) const
Base class for visual effects which can be applied to QPicture drawings.
bool changeSymbolLayer(int index, QgsSymbolLayerV2 *layer)
delete layer at specified index and set a new one
QgsSymbolV2RenderContext(QgsRenderContext &c, QgsSymbolV2::OutputUnit u, qreal alpha=1.0, bool selected=false, int renderHints=0, const QgsFeature *f=nullptr, const QgsFields *fields=nullptr, const QgsMapUnitScale &mapUnitScale=QgsMapUnitScale())
ScaleMethod scaleMethod()
virtual bool hasDataDefinedProperties() const
Checks whether the layer has any associated data defined properties.
void save()
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
static void _getPoint(QPointF &pt, QgsRenderContext &context, const QgsPointV2 *point)
Creates a point in screen coordinates from a QgsPointV2 in map coordinates.
Definition: qgssymbolv2.h:265
Abstract base class for all geometries.
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.
Container of fields for a vector layer.
Definition: qgsfield.h:252
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
SymbolType type() const
Definition: qgssymbolv2.h:107
qreal top() const
Line symbol.
Definition: qgssymbolv2.h:82
T takeAt(int i)
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
double size() const
Returns the size for the whole symbol, which is the maximum size of all marker symbol layers in the s...
QgsSymbolLayerV2List cloneLayers() const
Retrieve a cloned list of all layers that make up this symbol.
Multi point geometry collection.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
void drawLine(const QLineF &line)
virtual QgsDataDefined * getDataDefinedProperty(const QString &property) const
Returns the data defined property corresponding to the specified property key.
double y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
void setExpressionContextScope(QgsExpressionContextScope *contextScope)
Set an expression scope for this symbol.
SymbolType mType
Definition: qgssymbolv2.h:326
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsSimpleMarkerSymbolLayerV2.
int wkbSize() const
Returns the size of the WKB in asWkb().
virtual void removeDataDefinedProperty(const QString &property)
Removes a data defined property from the layer.
void drawPreviewIcon(QPainter *painter, QSize size, QgsRenderContext *customContext=nullptr)
Draw icon of the symbol that occupyies area given by size using the painter.
qreal left() const
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:353
void setSizeUnit(OutputUnit unit)
Sets the size units for the whole symbol (including all symbol layers).
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
static double pixelSizeScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns scale factor painter units -> pixel dimensions.
void setWidth(double width)
QgsDataDefined * scaleWholeSymbol(double scaleFactor, const QgsDataDefined &dd)
Definition: qgssymbolv2.cpp:60
Marker symbol.
Definition: qgssymbolv2.h:81
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the size map unit scale for the whole symbol (including all symbol layers).
int renderHints() const
Definition: qgssymbolv2.h:209
void setMapUnitScale(const QgsMapUnitScale &scale)
static QgsConstWkbPtr clippedLineWKB(QgsConstWkbPtr &wkb, const QgsRectangle &clipExtent, QPolygonF &line)
Reads a polyline from WKB and clips it to clipExtent.
Definition: qgsclipper.cpp:41
void setAngle(double angle)
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const
Writes the SLD element following the SLD v1.1 specs.
virtual void startRender(QgsSymbolV2RenderContext &context)=0
bool useExpression() const
Returns if the field or the expression part is active.
T value(int i) const
QColor fromHsv(int h, int s, int v, int a)
void transformInPlace(double &x, double &y) const
Transform device coordinates to map coordinates.
T * data()
void drawRect(const QRectF &rectangle)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
void setUseExpression(bool use)
Controls if the field or the expression part is active.
void setColor(const QColor &color)
virtual double width() const
QgsDataDefined dataDefinedWidth() const
Returns data defined size for whole symbol (including all symbol layers).
Mixed units in symbol layers.
Definition: qgssymbolv2.h:69
static QgsRenderContext createRenderContext(QPainter *p)
Creates a render context for a pixel based device.
QString number(int n, int base)
QgsSymbolLayerV2List mLayers
Definition: qgssymbolv2.h:327
int count(const T &value) const
qreal x() const
qreal y() const
const QgsAbstractGeometryV2 * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
void append(const T &value)
const QgsFields * fields() const
Returns the field map associated with the feature.
Definition: qgsfeature.cpp:188
void setOffset(double offset)
bool appendSymbolLayer(QgsSymbolLayerV2 *layer)
Append symbol layer at the end of the list Ownership will be transferred.
#define FALLTHROUGH
Definition: qgis.h:539
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...
bool empty() const
void startRender(QgsRenderContext &context, const QgsFields *fields=nullptr)
const QgsVectorLayer * layer() const
Definition: qgssymbolv2.h:245
void fill(uint pixelValue)
double outputLineWidth(double width) const
static double convertToPainterUnits(const QgsRenderContext &c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale())
Converts a size from the specied units to painter units.
void setLineAngle(double lineAngle)
Sets the line angle modification for the symbol&#39;s angle.
Utility class for identifying a unique vertex within a geometry.
const QgsRectangle & extent() const
static QgsLineSymbolV2 * createSimple(const QgsStringMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties. ...
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
static bool isCurvedType(Type type)
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:531
void setPen(const QColor &color)
Q_DECL_DEPRECATED bool isSymbolLayerCompatible(SymbolType layerType)
check whether a symbol layer type can be used within the symbol (marker-marker, line-line, fill-fill/line)
void setRenderingPass(int renderingPass)
#define DEFAULT_SCALE_METHOD
void setLayer(const QgsVectorLayer *layer)
Definition: qgssymbolv2.h:244
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:207
QString expressionString() const
Returns the expression string of this QgsDataDefined.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:34
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:341
bool isEmpty() const
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
virtual void setWidth(double width)
static QgsStyleV2 * defaultStyle()
return default application-wide style
Definition: qgsstylev2.cpp:51
QPointF topLeft() const
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
QgsMarkerSymbolV2(const QgsSymbolLayerV2List &layers=QgsSymbolLayerV2List())
void setAngle(double angle)
virtual QgsAbstractGeometryV2 * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
void setAngle(double angle)
Sets the angle for the whole symbol.
void setSizeUnit(QgsSymbolV2::OutputUnit unit)
Sets the units for the symbol&#39;s size.
const QgsCoordinateTransform * coordinateTransform() const
Draw bounds of symbols (for debugging/testing)
OutputUnit sizeUnit() const
Returns the size units for the whole symbol (including all symbol layers).
void setBrush(const QBrush &brush)
void setPainter(QPainter *p)
void setSize(double size)
Sets the size for the whole symbol.
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
qreal mAlpha
Symbol opacity (in the range 0 - 1)
Definition: qgssymbolv2.h:330
virtual int partCount() const =0
Returns count of parts contained in the geometry.
QgsSymbolV2RenderContext & operator=(const QgsSymbolV2RenderContext &)
bool enabled() const
Returns whether the effect is enabled.
QRectF united(const QRectF &rectangle) const
virtual void renderPolygonOutline(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
QgsSymbolV2(SymbolType type, const QgsSymbolLayerV2List &layers)
Definition: qgssymbolv2.cpp:85
virtual bool nextVertex(QgsVertexId &id, QgsPointV2 &vertex) const =0
Returns next vertex id and coordinates.
bool hasDataDefinedProperties() const
Returns whether the symbol utilises any data defined properties.
QgsDataDefined * rotateWholeSymbol(double additionalRotation, const QgsDataDefined &dd)
Definition: qgssymbolv2.cpp:50
Single scope for storing variables and functions for use within a QgsExpressionContext.
QgsMapUnitScale mapUnitScale() const
static void drawVertexMarker(double x, double y, QPainter &p, QgsVectorLayer::VertexMarkerType type, int vertexSize)
Draws a vertex symbol at (screen) coordinates x, y.
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:204
void setLineAngle(double lineAngle)
Sets the line angle modification for the symbol&#39;s angle.
double outputPixelSize(double size) const
T * data() const
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
iterator end()
QString toLower() const
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
virtual ~QgsSymbolV2()
void reserve(int size)
virtual void renderPolyline(const QPolygonF &points, QgsSymbolV2RenderContext &context)=0
QgsSymbolV2 * symbol(const QString &name)
return a NEW copy of symbol
Definition: qgsstylev2.cpp:164
virtual QgsFillSymbolV2 * clone() const override
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:202
QImage bigSymbolPreviewImage(QgsExpressionContext *expressionContext=nullptr)
Returns a large (roughly 100x100 pixel) preview image for the symbol.
void setFileName(const QString &fileName)
void exportImage(const QString &path, const QString &format, QSize size)
export symbol as image format. PNG and SVG supported
QgsExpressionContext & expressionContext()
Gets the expression context.
QString field() const
Get the field which this QgsDataDefined represents.
bool clipFeaturesToExtent() const
Returns whether features drawn by the symbol will be clipped to the render context&#39;s extent...
Definition: qgssymbolv2.h:229
void renderUsingLayer(QgsSymbolLayerV2 *layer, QgsSymbolV2RenderContext &context)
Renders a context using a particular symbol layer without passing in a geometry.
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:187
SymbolType
Type of the symbol.
Definition: qgssymbolv2.h:79
void restore()
QgsSymbolV2::OutputUnit outputUnit() const
void setDataDefinedWidth(const QgsDataDefined &dd)
Set data defined width for whole symbol (including all symbol layers).
Hybrid symbol.
Definition: qgssymbolv2.h:84
QgsExpressionContextScope * expressionContextScope()
This scope is always available when a symbol of this type is being rendered.
int remaining() const
Definition: qgswkbptr.h:133
Contains information about the context of a rendering operation.
QgsMapUnitScale sizeMapUnitScale() const
Returns the size map unit scale for the whole symbol.
double segmentationTolerance() const
Gets the segmentation tolerance applied when rendering curved geometries.
QgsSymbolV2::ScaleMethod scaleMethod() const
Returns the method to use for scaling the marker&#39;s size.
QRectF boundingRect() const
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
QPainter * painter()
const QgsMapToPixel & mapToPixel() const
void stopRender(QgsRenderContext &context)
bool insertSymbolLayer(int index, QgsSymbolLayerV2 *layer)
Insert symbol layer to specified index Ownership will be transferred.
QSet< T > & unite(const QSet< T > &other)
static QgsSymbolV2 * defaultSymbol(QGis::GeometryType geomType)
return new default symbol for specified geometry type
ScaleMethod
Scale method.
Definition: qgssymbolv2.h:90
Struct for storing maximum and minimum scales for measurements in map units.
QgsDataDefined dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
void insert(int i, const T &value)
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
QImage asImage(QSize size, QgsRenderContext *customContext=nullptr)
Generate symbol as image.
QColor color() const
QgsAbstractGeometryV2::SegmentationToleranceType segmentationToleranceType() const
Gets segmentation tolerance type (maximum angle or maximum difference between curve and approximation...
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:359
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setX(qreal x)
void setY(qreal y)
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:382
int height() const
Fill symbol.
Definition: qgssymbolv2.h:83
static QgsConstWkbPtr _getPolygon(QPolygonF &pts, QList< QPolygonF > &holes, QgsRenderContext &context, QgsConstWkbPtr &wkb, bool clipToExtent=true)
Creates a polygon in screen coordinates from a wkb string in map coordinates.
qreal & rx()
qreal & ry()
Class for doing transforms between two map coordinate systems.
void renderPoint(QPointF point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
void translate(const QPointF &offset)
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:192
double angle() const
Returns the rotation angle for the marker, in degrees clockwise from north.
virtual void setColor(const QColor &color)
The fill color.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:366
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:197
void setGeometryPartNum(int num)
Sets the part number of current geometry.
Definition: qgssymbolv2.h:412
Abstract base class for marker symbol layers.
QgsSymbolLayerV2 * takeSymbolLayer(int index)
Remove symbol layer from the list and return pointer to it.
QgsWKBTypes::Type readHeader() const
Definition: qgswkbptr.cpp:38
double width() const
void transformPolygon(QPolygonF &poly, TransformDirection direction=ForwardTransform) const
QgsSymbolLayerV2 * symbolLayer(int layer)
Returns a specific symbol layers contained in the symbol.
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
const_iterator constEnd() const
virtual void drawPreviewIcon(QgsSymbolV2RenderContext &context, QSize size)=0
const_iterator constBegin() const
QSet< QString > usedAttributes() const
Return a list of attributes required to render this feature.
static QString displayString(Type type)
Returns a display string type for a WKB type, eg the geometry name used in WKT geometry representatio...
Definition: qgswkbtypes.cpp:48
Draw map such that there are no problems between adjacent tiles.
bool hasDefaultValues() const
Returns whether the data defined container is set to all the default values, ie, disabled, with empty expression and no assigned field.
static void trimPolygon(QPolygonF &pts, const QgsRectangle &clipRect)
Definition: qgsclipper.h:181
static const QString EXPR_GEOMETRY_PART_NUM
Inbuilt variable name for geometry part number variable.
void setSize(double size)
Sets the symbol size.
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) const
int size() const
void setAngle(double angle)
Sets the rotation angle for the marker.
static const QString EXPR_GEOMETRY_PART_COUNT
Inbuilt variable name for geometry part count variable.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
virtual void end(QgsRenderContext &context)
Ends interception of paint operations to a render context, and draws the result to the render context...
QgsSymbolV2::SymbolType type() const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbolV2 *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbolV2 to an expression context.
virtual void stopRender(QgsSymbolV2RenderContext &context)=0
virtual bool isCompatibleWithSymbol(QgsSymbolV2 *symbol) const
Returns if the layer can be used below the specified symbol.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol&#39;s size.
void renderVertexMarker(QPointF pt, QgsRenderContext &context, int currentVertexMarkerType, int currentVertexMarkerSize)
Render editing vertex marker at specified point.
void setExpressionString(const QString &expr)
Sets the expression for this QgsDataDefined.
void setOutputUnit(QgsSymbolV2::OutputUnit u)
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:206
iterator begin()
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
void setGeometry(const QgsAbstractGeometryV2 *geometry)
Sets pointer to original (unsegmentized) geometry.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
virtual void begin(QgsRenderContext &context)
Begins intercepting paint operations to a render context.
Simple marker symbol layer, consisting of a rendered shape with solid fill color and an outline...
QgsSymbolV2RenderContext * symbolRenderContext()
Returns the symbol render context.
QgsLineSymbolV2(const QgsSymbolLayerV2List &layers=QgsSymbolLayerV2List())
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
virtual QgsMarkerSymbolV2 * clone() const override
static QgsConstWkbPtr _getLineString(QPolygonF &pts, QgsRenderContext &context, QgsConstWkbPtr &wkb, bool clipToExtent=true)
Creates a line string in screen coordinates from a wkb string in map coordinates. ...
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:212
bool isLocked() const
int mRenderHints
Definition: qgssymbolv2.h:332
virtual Q_DECL_DEPRECATED void setDataDefinedProperty(const QString &property, const QString &expressionString)
Sets a data defined expression for a property.