QGIS API Documentation  2.17.0-Master (00653d2)
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  , mSymbolRenderContext( nullptr )
93 {
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  delete mSymbolRenderContext;
448  mSymbolRenderContext = new QgsSymbolV2RenderContext( context, outputUnit(), mAlpha, false, mRenderHints, nullptr, fields, mapUnitScale() );
449 
450  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, nullptr, fields, mapUnitScale() );
451 
453 
454  mSymbolRenderContext->setExpressionContextScope( scope );
455 
456  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
457  layer->startRender( symbolContext );
458 }
459 
461 {
462  Q_UNUSED( context )
463  if ( mSymbolRenderContext )
464  {
465  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
466  layer->stopRender( *mSymbolRenderContext );
467  }
468 
469  delete mSymbolRenderContext;
470  mSymbolRenderContext = nullptr;
471 
472  mLayer = nullptr;
473 }
474 
476 {
477  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
478  {
479  if ( !layer->isLocked() )
480  layer->setColor( color );
481  }
482 }
483 
485 {
486  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
487  {
488  // return color of the first unlocked layer
489  if ( !( *it )->isLocked() )
490  return ( *it )->color();
491  }
492  return QColor( 0, 0, 0 );
493 }
494 
495 void QgsSymbolV2::drawPreviewIcon( QPainter* painter, QSize size, QgsRenderContext* customContext )
496 {
497  QgsRenderContext context = customContext ? *customContext : QgsSymbolLayerV2Utils::createRenderContext( painter );
498  context.setForceVectorOutput( true );
499  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, nullptr, nullptr, mapUnitScale() );
500 
501  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
502  {
503  if ( mType == Fill && layer->type() == Line )
504  {
505  // line symbol layer would normally draw just a line
506  // so we override this case to force it to draw a polygon outline
507  QgsLineSymbolLayerV2* lsl = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
508 
509  if ( lsl )
510  {
511  // from QgsFillSymbolLayerV2::drawPreviewIcon()
512  QPolygonF poly = QRectF( QPointF( 0, 0 ), QPointF( size.width() - 1, size.height() - 1 ) );
513  lsl->startRender( symbolContext );
514  lsl->renderPolygonOutline( poly, nullptr, symbolContext );
515  lsl->stopRender( symbolContext );
516  }
517  }
518  else
519  layer->drawPreviewIcon( symbolContext, size );
520  }
521 }
522 
523 void QgsSymbolV2::exportImage( const QString& path, const QString& format, QSize size )
524 {
525  if ( format.toLower() == "svg" )
526  {
527  QSvgGenerator generator;
528  generator.setFileName( path );
529  generator.setSize( size );
530  generator.setViewBox( QRect( 0, 0, size.height(), size.height() ) );
531 
532  QPainter painter( &generator );
533  drawPreviewIcon( &painter, size );
534  painter.end();
535  }
536  else
537  {
538  QImage image = asImage( size );
539  image.save( path );
540  }
541 }
542 
544 {
545  QImage image( size, QImage::Format_ARGB32_Premultiplied );
546  image.fill( 0 );
547 
548  QPainter p( &image );
549  p.setRenderHint( QPainter::Antialiasing );
550 
551  drawPreviewIcon( &p, size, customContext );
552 
553  return image;
554 }
555 
556 
558 {
559  QImage preview( QSize( 100, 100 ), QImage::Format_ARGB32_Premultiplied );
560  preview.fill( 0 );
561 
562  QPainter p( &preview );
563  p.setRenderHint( QPainter::Antialiasing );
564  p.translate( 0.5, 0.5 ); // shift by half a pixel to avoid blurring due antialising
565 
566  if ( mType == QgsSymbolV2::Marker )
567  {
568  p.setPen( QPen( Qt::gray ) );
569  p.drawLine( 0, 50, 100, 50 );
570  p.drawLine( 50, 0, 50, 100 );
571  }
572 
574  if ( expressionContext )
575  context.setExpressionContext( *expressionContext );
576 
577  startRender( context );
578 
579  if ( mType == QgsSymbolV2::Line )
580  {
581  QPolygonF poly;
582  poly << QPointF( 0, 50 ) << QPointF( 99, 50 );
583  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( poly, nullptr, context );
584  }
585  else if ( mType == QgsSymbolV2::Fill )
586  {
587  QPolygonF polygon;
588  polygon << QPointF( 20, 20 ) << QPointF( 80, 20 ) << QPointF( 80, 80 ) << QPointF( 20, 80 ) << QPointF( 20, 20 );
589  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( polygon, nullptr, nullptr, context );
590  }
591  else // marker
592  {
593  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( QPointF( 50, 50 ), nullptr, context );
594  }
595 
596  stopRender( context );
597  return preview;
598 }
599 
600 
602 {
603  QString t;
604  switch ( type() )
605  {
606  case QgsSymbolV2::Marker:
607  t = "MARKER";
608  break;
609  case QgsSymbolV2::Line:
610  t = "LINE";
611  break;
612  case QgsSymbolV2::Fill:
613  t = "FILL";
614  break;
615  default:
616  Q_ASSERT( 0 && "unknown symbol type" );
617  }
618  QString s = QString( "%1 SYMBOL (%2 layers) color %3" ).arg( t ).arg( mLayers.count() ).arg( QgsSymbolLayerV2Utils::encodeColor( color() ) );
619 
620  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
621  {
622  // TODO:
623  }
624  return s;
625 }
626 
627 void QgsSymbolV2::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const
628 {
629  QgsStringMap locProps( props );
630  locProps[ "alpha" ] = QString::number( alpha() );
631  double scaleFactor = 1.0;
632  locProps[ "uom" ] = QgsSymbolLayerV2Utils::encodeSldUom( outputUnit(), &scaleFactor );
633  locProps[ "uomScale" ] = ( !qgsDoubleNear( scaleFactor, 1.0 ) ? qgsDoubleToString( scaleFactor ) : "" );
634 
635  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
636  {
637  ( *it )->toSld( doc, element, locProps );
638  }
639 }
640 
642 {
644  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
645  {
646  QgsSymbolLayerV2* layer = ( *it )->clone();
647  layer->setLocked(( *it )->isLocked() );
648  layer->setRenderingPass(( *it )->renderingPass() );
649  lst.append( layer );
650  }
651  return lst;
652 }
653 
655 {
656  Q_ASSERT( layer->type() == Hybrid );
657 
659 
660  QgsPaintEffect* effect = generatorLayer->paintEffect();
661  if ( effect && effect->enabled() )
662  {
663  QPainter* p = context.renderContext().painter();
664  p->save();
665 
666  effect->begin( context.renderContext() );
667  generatorLayer->render( context );
668  effect->end( context.renderContext() );
669 
670  p->restore();
671  }
672  else
673  {
674  generatorLayer->render( context );
675  }
676 }
677 
679 {
680  QSet<QString> attributes;
682  for ( ; sIt != mLayers.constEnd(); ++sIt )
683  {
684  if ( *sIt )
685  {
686  attributes.unite(( *sIt )->usedAttributes() );
687  }
688  }
689  return attributes;
690 }
691 
693 {
694  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
695  {
696  if ( layer->hasDataDefinedProperties() )
697  return true;
698  }
699  return false;
700 }
701 
702 void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, int currentVertexMarkerSize )
703 {
704  const QgsGeometry* geom = feature.constGeometry();
705  if ( !geom || !geom->geometry() )
706  {
707  return;
708  }
709 
710  const QgsGeometry *segmentizedGeometry = geom;
711  bool deleteSegmentizedGeometry = false;
712  context.setGeometry( geom->geometry() );
713 
714  bool tileMapRendering = context.testFlag( QgsRenderContext::RenderMapTile );
715 
716  //convert curve types to normal point/line/polygon ones
717  if ( QgsWKBTypes::isCurvedType( geom->geometry()->wkbType() ) )
718  {
720  if ( !g )
721  {
722  return;
723  }
724  segmentizedGeometry = new QgsGeometry( g );
725  deleteSegmentizedGeometry = true;
726  }
727 
728  mSymbolRenderContext->setGeometryPartCount( segmentizedGeometry->geometry()->partCount() );
729  mSymbolRenderContext->setGeometryPartNum( 1 );
730 
731  if ( mSymbolRenderContext->expressionContextScope() )
732  {
733  context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
735  mSymbolRenderContext->expressionContextScope()->setVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount() );
737  }
738 
739  // Collection of markers to paint, only used for no curve types.
740  QPolygonF markers;
741 
742  switch ( QgsWKBTypes::flatType( segmentizedGeometry->geometry()->wkbType() ) )
743  {
744  case QgsWKBTypes::Point:
745  {
746  QPointF pt;
747  if ( mType != QgsSymbolV2::Marker )
748  {
749  QgsDebugMsg( "point can be drawn only with marker symbol!" );
750  break;
751  }
752 
753  const QgsPointV2* point = static_cast< const QgsPointV2* >( segmentizedGeometry->geometry() );
754  _getPoint( pt, context, point );
755  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( pt, &feature, context, layer, selected );
756 
758  {
759  //draw debugging rect
760  context.painter()->setPen( Qt::red );
761  context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
762  context.painter()->drawRect( static_cast<QgsMarkerSymbolV2*>( this )->bounds( pt, context, feature ) );
763  }
764 
765  if ( drawVertexMarker && !deleteSegmentizedGeometry )
766  {
767  markers << pt;
768  }
769  }
770  break;
772  {
773  QPolygonF pts;
774  if ( mType != QgsSymbolV2::Line )
775  {
776  QgsDebugMsg( "linestring can be drawn only with line symbol!" );
777  break;
778  }
779  QgsConstWkbSimplifierPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize(), context.vectorSimplifyMethod() );
780  _getLineString( pts, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() );
781  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( pts, &feature, context, layer, selected );
782 
783  if ( drawVertexMarker && !deleteSegmentizedGeometry )
784  {
785  markers = pts;
786  }
787  }
788  break;
790  {
791  QPolygonF pts;
792  QList<QPolygonF> holes;
793  if ( mType != QgsSymbolV2::Fill )
794  {
795  QgsDebugMsg( "polygon can be drawn only with fill symbol!" );
796  break;
797  }
798  QgsConstWkbSimplifierPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize(), context.vectorSimplifyMethod() );
799  _getPolygon( pts, holes, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() );
800  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
801 
802  if ( drawVertexMarker && !deleteSegmentizedGeometry )
803  {
804  markers = pts;
805 
806  Q_FOREACH ( const QPolygonF& hole, holes )
807  {
808  markers << hole;
809  }
810  }
811  }
812  break;
813 
815  {
816  QPointF pt;
817 
818  if ( mType != QgsSymbolV2::Marker )
819  {
820  QgsDebugMsg( "multi-point can be drawn only with marker symbol!" );
821  break;
822  }
823 
824  QgsMultiPointV2* mp = static_cast< QgsMultiPointV2* >( segmentizedGeometry->geometry() );
825 
826  if ( drawVertexMarker && !deleteSegmentizedGeometry )
827  {
828  markers.reserve( mp->numGeometries() );
829  }
830 
831  for ( int i = 0; i < mp->numGeometries(); ++i )
832  {
833  mSymbolRenderContext->setGeometryPartNum( i + 1 );
835 
836  const QgsPointV2* point = static_cast< const QgsPointV2* >( mp->geometryN( i ) );
837  _getPoint( pt, context, point );
838  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( pt, &feature, context, layer, selected );
839 
840  if ( drawVertexMarker && !deleteSegmentizedGeometry )
841  {
842  markers.append( pt );
843  }
844  }
845  }
846  break;
847 
850  {
851  QPolygonF pts;
852 
853  if ( mType != QgsSymbolV2::Line )
854  {
855  QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" );
856  break;
857  }
858 
859  QgsConstWkbSimplifierPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize(), context.vectorSimplifyMethod() );
860  wkbPtr.readHeader();
861 
862  unsigned int num;
863  wkbPtr >> num;
864 
865  const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
866 
867  for ( unsigned int i = 0; i < num && wkbPtr; ++i )
868  {
869  mSymbolRenderContext->setGeometryPartNum( i + 1 );
871 
872  if ( geomCollection )
873  {
874  context.setGeometry( geomCollection->geometryN( i ) );
875  }
876  if ( _getLineString( pts, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() ) == nullptr )
877  {
878  break;
879  }
880  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( pts, &feature, context, layer, selected );
881 
882  if ( drawVertexMarker && !deleteSegmentizedGeometry )
883  {
884  if ( i == 0 )
885  {
886  markers = pts;
887  }
888  else
889  {
890  markers << pts;
891  }
892  }
893  }
894  }
895  break;
896 
899  {
900  if ( mType != QgsSymbolV2::Fill )
901  {
902  QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" );
903  break;
904  }
905 
906  QgsConstWkbSimplifierPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize(), context.vectorSimplifyMethod() );
907  wkbPtr.readHeader();
908 
909  unsigned int num;
910  wkbPtr >> num;
911 
912  QPolygonF pts;
913  QList<QPolygonF> holes;
914 
915  const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
916 
917  for ( unsigned int i = 0; i < num && wkbPtr; ++i )
918  {
919  mSymbolRenderContext->setGeometryPartNum( i + 1 );
921 
922  if ( geomCollection )
923  {
924  context.setGeometry( geomCollection->geometryN( i ) );
925  }
926  if ( _getPolygon( pts, holes, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() ) == nullptr )
927  {
928  break;
929  }
930  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
931 
932  if ( drawVertexMarker && !deleteSegmentizedGeometry )
933  {
934  if ( i == 0 )
935  {
936  markers = pts;
937  }
938  else
939  {
940  markers << pts;
941  }
942 
943  Q_FOREACH ( const QPolygonF& hole, holes )
944  {
945  markers << hole;
946  }
947  }
948  }
949  break;
950  }
952  {
953  QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() );
954  wkbPtr.readHeader();
955 
956  int nGeometries;
957  wkbPtr >> nGeometries;
958 
959  if ( nGeometries == 0 )
960  {
961  // skip noise from empty geometry collections from simplification
962  break;
963  }
964 
965  FALLTHROUGH;
966  }
967  default:
968  QgsDebugMsg( QString( "feature %1: unsupported wkb type %2/%3 for rendering" )
969  .arg( feature.id() )
970  .arg( QgsWKBTypes::displayString( geom->geometry()->wkbType() ) )
971  .arg( geom->wkbType(), 0, 16 ) );
972  }
973 
974  if ( drawVertexMarker )
975  {
976  if ( markers.size() > 0 )
977  {
978  Q_FOREACH ( QPointF marker, markers )
979  {
980  renderVertexMarker( marker, context, currentVertexMarkerType, currentVertexMarkerSize );
981  }
982  }
983  else
984  {
985  const QgsCoordinateTransform* ct = context.coordinateTransform();
986  const QgsMapToPixel& mtp = context.mapToPixel();
987 
988  QgsPointV2 vertexPoint;
989  QgsVertexId vertexId;
990  double x, y, z;
991  QPointF mapPoint;
992  while ( geom->geometry()->nextVertex( vertexId, vertexPoint ) )
993  {
994  //transform
995  x = vertexPoint.x();
996  y = vertexPoint.y();
997  z = 0.0;
998  if ( ct )
999  {
1000  ct->transformInPlace( x, y, z );
1001  }
1002  mapPoint.setX( x );
1003  mapPoint.setY( y );
1004  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1005  renderVertexMarker( mapPoint, context, currentVertexMarkerType, currentVertexMarkerSize );
1006  }
1007  }
1008  }
1009 
1010  if ( deleteSegmentizedGeometry )
1011  {
1012  delete segmentizedGeometry;
1013  }
1014 
1015  if ( mSymbolRenderContext->expressionContextScope() )
1016  context.expressionContext().popScope();
1017 }
1018 
1020 {
1021  return mSymbolRenderContext;
1022 }
1023 
1024 void QgsSymbolV2::renderVertexMarker( QPointF pt, QgsRenderContext& context, int currentVertexMarkerType, int currentVertexMarkerSize )
1025 {
1026  QgsVectorLayer::drawVertexMarker( pt.x(), pt.y(), *context.painter(), static_cast< QgsVectorLayer::VertexMarkerType >( currentVertexMarkerType ), currentVertexMarkerSize );
1027 }
1028 
1030 
1031 
1033  : mRenderContext( c )
1034  , mExpressionContextScope( nullptr )
1035  , mOutputUnit( u )
1036  , mMapUnitScale( mapUnitScale )
1037  , mAlpha( alpha )
1038  , mSelected( selected )
1039  , mRenderHints( renderHints )
1040  , mFeature( f )
1041  , mFields( fields )
1042  , mGeometryPartCount( 0 )
1043  , mGeometryPartNum( 0 )
1044 {
1045 }
1046 
1048 {
1049  delete mExpressionContextScope;
1050 }
1051 
1053 {
1054  mRenderContext.expressionContext().setOriginalValueVariable( value );
1055 }
1056 
1057 double QgsSymbolV2RenderContext::outputLineWidth( double width ) const
1058 {
1059  return QgsSymbolLayerV2Utils::convertToPainterUnits( mRenderContext, width, mOutputUnit, mMapUnitScale );
1060 }
1061 
1063 {
1064  return size * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( mRenderContext, mOutputUnit, mMapUnitScale );
1065 }
1066 
1068 {
1069  // This is just a dummy implementation of assignment.
1070  // sip 4.7 generates a piece of code that needs this function to exist.
1071  // It's not generated automatically by the compiler because of
1072  // mRenderContext member which is a reference (and thus can't be changed).
1073  Q_ASSERT( false );
1074  return *this;
1075 }
1076 
1078 {
1079  return mExpressionContextScope;
1080 }
1081 
1083 {
1084  mExpressionContextScope = contextScope;
1085 }
1086 
1088 
1090 {
1092  if ( !sl )
1093  return nullptr;
1094 
1095  QgsSymbolLayerV2List layers;
1096  layers.append( sl );
1097  return new QgsMarkerSymbolV2( layers );
1098 }
1099 
1101 {
1103  if ( !sl )
1104  return nullptr;
1105 
1106  QgsSymbolLayerV2List layers;
1107  layers.append( sl );
1108  return new QgsLineSymbolV2( layers );
1109 }
1110 
1112 {
1114  if ( !sl )
1115  return nullptr;
1116 
1117  QgsSymbolLayerV2List layers;
1118  layers.append( sl );
1119  return new QgsFillSymbolV2( layers );
1120 }
1121 
1123 
1125  : QgsSymbolV2( Marker, layers )
1126 {
1127  if ( mLayers.isEmpty() )
1129 }
1130 
1132 {
1133  double origAngle = angle();
1134  double angleDiff = ang - origAngle;
1135  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1136  {
1137  QgsMarkerSymbolLayerV2* markerLayer = dynamic_cast<QgsMarkerSymbolLayerV2*>( layer );
1138  if ( markerLayer )
1139  markerLayer->setAngle( markerLayer->angle() + angleDiff );
1140  }
1141 }
1142 
1144 {
1145  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1146  {
1147  if ( layer->type() != QgsSymbolV2::Marker )
1148  continue;
1149  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1150  return markerLayer->angle();
1151  }
1152  return 0;
1153 }
1154 
1155 void QgsMarkerSymbolV2::setLineAngle( double lineAng )
1156 {
1157  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1158  {
1159  if ( layer->type() != QgsSymbolV2::Marker )
1160  continue;
1161  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1162  markerLayer->setLineAngle( lineAng );
1163  }
1164 }
1165 
1167 {
1168  const double symbolRotation = angle();
1169 
1170  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1171  {
1172  if ( layer->type() != QgsSymbolV2::Marker )
1173  continue;
1174  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1175  if ( dd.hasDefaultValues() )
1176  {
1177  layer->removeDataDefinedProperty( "angle" );
1178  }
1179  else
1180  {
1181  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1182  {
1183  layer->setDataDefinedProperty( "angle", new QgsDataDefined( dd ) );
1184  }
1185  else
1186  {
1187  QgsDataDefined* rotatedDD = rotateWholeSymbol( markerLayer->angle() - symbolRotation, dd );
1188  layer->setDataDefinedProperty( "angle", rotatedDD );
1189  }
1190  }
1191  }
1192 }
1193 
1195 {
1196  const double symbolRotation = angle();
1197  QgsDataDefined* symbolDD = nullptr;
1198 
1199  // find the base of the "en masse" pattern
1200  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1201  {
1202  if ( layer->type() != QgsSymbolV2::Marker )
1203  continue;
1204  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1205  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) && markerLayer->getDataDefinedProperty( "angle" ) )
1206  {
1207  symbolDD = markerLayer->getDataDefinedProperty( "angle" );
1208  break;
1209  }
1210  }
1211 
1212  if ( !symbolDD )
1213  return QgsDataDefined();
1214 
1215  // check that all layer's angle expressions match the "en masse" pattern
1216  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1217  {
1218  if ( layer->type() != QgsSymbolV2::Marker )
1219  continue;
1220  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1221  QgsDataDefined* layerAngleDD = markerLayer->getDataDefinedProperty( "angle" );
1222 
1223  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1224  {
1225  if ( !layerAngleDD || *layerAngleDD != *symbolDD )
1226  return QgsDataDefined();
1227  }
1228  else
1229  {
1230  QScopedPointer< QgsDataDefined > rotatedDD( rotateWholeSymbol( markerLayer->angle() - symbolRotation, *symbolDD ) );
1231  if ( !layerAngleDD || *layerAngleDD != *( rotatedDD.data() ) )
1232  return QgsDataDefined();
1233  }
1234  }
1235  return QgsDataDefined( *symbolDD );
1236 }
1237 
1238 
1240 {
1241  double origSize = size();
1242 
1243  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1244  {
1245  if ( layer->type() != QgsSymbolV2::Marker )
1246  continue;
1247  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1248  if ( qgsDoubleNear( markerLayer->size(), origSize ) )
1249  markerLayer->setSize( s );
1250  else if ( !qgsDoubleNear( origSize, 0.0 ) )
1251  {
1252  // proportionally scale size
1253  markerLayer->setSize( markerLayer->size() * s / origSize );
1254  }
1255  // also scale offset to maintain relative position
1256  if ( !qgsDoubleNear( origSize, 0.0 ) && ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) ) )
1257  markerLayer->setOffset( QPointF( markerLayer->offset().x() * s / origSize,
1258  markerLayer->offset().y() * s / origSize ) );
1259  }
1260 }
1261 
1263 {
1264  // return size of the largest symbol
1265  double maxSize = 0;
1266  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1267  {
1268  if ( layer->type() != QgsSymbolV2::Marker )
1269  continue;
1270  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1271  double lsize = markerLayer->size();
1272  if ( lsize > maxSize )
1273  maxSize = lsize;
1274  }
1275  return maxSize;
1276 }
1277 
1279 {
1280  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1281  {
1282  if ( layer->type() != QgsSymbolV2::Marker )
1283  continue;
1284 
1285  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1286  markerLayer->setSizeUnit( unit );
1287  }
1288 }
1289 
1291 {
1292  bool first = true;
1293  OutputUnit unit = Mixed;
1294 
1295  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1296  {
1297  if ( layer->type() != QgsSymbolV2::Marker )
1298  continue;
1299  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1300 
1301  if ( first )
1302  unit = markerLayer->sizeUnit();
1303  else
1304  {
1305  if ( unit != markerLayer->sizeUnit() )
1306  return Mixed;
1307  }
1308 
1309  first = false;
1310  }
1311  return unit;
1312 }
1313 
1315 {
1316  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1317  {
1318  if ( layer->type() != QgsSymbolV2::Marker )
1319  continue;
1320 
1321  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1322  markerLayer->setSizeMapUnitScale( scale );
1323  }
1324 }
1325 
1327 {
1328  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1329  {
1330  if ( layer->type() != QgsSymbolV2::Marker )
1331  continue;
1332 
1333  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1334  return markerLayer->sizeMapUnitScale();
1335  }
1336  return QgsMapUnitScale();
1337 }
1338 
1340 {
1341  const double symbolSize = size();
1342 
1343  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1344  {
1345  if ( layer->type() != QgsSymbolV2::Marker )
1346  continue;
1347  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1348 
1349  if ( dd.hasDefaultValues() )
1350  {
1351  markerLayer->removeDataDefinedProperty( "size" );
1352  markerLayer->removeDataDefinedProperty( "offset" );
1353  }
1354  else
1355  {
1356  if ( qgsDoubleNear( symbolSize, 0.0 ) || qgsDoubleNear( markerLayer->size(), symbolSize ) )
1357  {
1358  markerLayer->setDataDefinedProperty( "size", new QgsDataDefined( dd ) );
1359  }
1360  else
1361  {
1362  markerLayer->setDataDefinedProperty( "size", scaleWholeSymbol( markerLayer->size() / symbolSize, dd ) );
1363  }
1364 
1365  if ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) )
1366  {
1367  markerLayer->setDataDefinedProperty( "offset", scaleWholeSymbol(
1368  markerLayer->offset().x() / symbolSize,
1369  markerLayer->offset().y() / symbolSize, dd ) );
1370  }
1371  }
1372  }
1373 }
1374 
1376 {
1377  const double symbolSize = size();
1378 
1379  QgsDataDefined* symbolDD = nullptr;
1380 
1381  // find the base of the "en masse" pattern
1382  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1383  {
1384  if ( layer->type() != QgsSymbolV2::Marker )
1385  continue;
1386  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1387  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) && markerLayer->getDataDefinedProperty( "size" ) )
1388  {
1389  symbolDD = markerLayer->getDataDefinedProperty( "size" );
1390  break;
1391  }
1392  }
1393 
1394  if ( !symbolDD )
1395  return QgsDataDefined();
1396 
1397  // check that all layers size expressions match the "en masse" pattern
1398  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1399  {
1400  if ( layer->type() != QgsSymbolV2::Marker )
1401  continue;
1402  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1403 
1404  QgsDataDefined* layerSizeDD = markerLayer->getDataDefinedProperty( "size" );
1405  QgsDataDefined* layerOffsetDD = markerLayer->getDataDefinedProperty( "offset" );
1406 
1407  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) )
1408  {
1409  if ( !layerSizeDD || *layerSizeDD != *symbolDD )
1410  return QgsDataDefined();
1411  }
1412  else
1413  {
1414  if ( qgsDoubleNear( symbolSize, 0.0 ) )
1415  return QgsDataDefined();
1416 
1417  QScopedPointer< QgsDataDefined > scaledDD( scaleWholeSymbol( markerLayer->size() / symbolSize, *symbolDD ) );
1418  if ( !layerSizeDD || *layerSizeDD != *( scaledDD.data() ) )
1419  return QgsDataDefined();
1420  }
1421 
1422  QScopedPointer< QgsDataDefined > scaledOffsetDD( scaleWholeSymbol( markerLayer->offset().x() / symbolSize, markerLayer->offset().y() / symbolSize, *symbolDD ) );
1423  if ( layerOffsetDD && *layerOffsetDD != *( scaledOffsetDD.data() ) )
1424  return QgsDataDefined();
1425  }
1426 
1427  return QgsDataDefined( *symbolDD );
1428 }
1429 
1431 {
1432  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1433  {
1434  if ( layer->type() != QgsSymbolV2::Marker )
1435  continue;
1436  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1437  markerLayer->setScaleMethod( scaleMethod );
1438  }
1439 }
1440 
1442 {
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  // return scale method of the first symbol layer
1449  return markerLayer->scaleMethod();
1450  }
1451 
1452  return DEFAULT_SCALE_METHOD;
1453 }
1454 
1455 void QgsMarkerSymbolV2::renderPointUsingLayer( QgsMarkerSymbolLayerV2* layer, QPointF point, QgsSymbolV2RenderContext& context )
1456 {
1457  static QPointF nullPoint( 0, 0 );
1458 
1459  QgsPaintEffect* effect = layer->paintEffect();
1460  if ( effect && effect->enabled() )
1461  {
1462  QPainter* p = context.renderContext().painter();
1463  p->save();
1464  p->translate( point );
1465 
1466  effect->begin( context.renderContext() );
1467  layer->renderPoint( nullPoint, context );
1468  effect->end( context.renderContext() );
1469 
1470  p->restore();
1471  }
1472  else
1473  {
1474  layer->renderPoint( point, context );
1475  }
1476 }
1477 
1478 void QgsMarkerSymbolV2::renderPoint( QPointF point, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1479 {
1480  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1481  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1482  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1483 
1484  if ( layerIdx != -1 )
1485  {
1486  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1487  if ( symbolLayer )
1488  {
1489  if ( symbolLayer->type() == QgsSymbolV2::Marker )
1490  {
1491  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( symbolLayer );
1492  renderPointUsingLayer( markerLayer, point, symbolContext );
1493  }
1494  else
1495  renderUsingLayer( symbolLayer, symbolContext );
1496  }
1497  return;
1498  }
1499 
1500  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1501  {
1502  if ( symbolLayer->type() == QgsSymbolV2::Marker )
1503  {
1504  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( symbolLayer );
1505  renderPointUsingLayer( markerLayer, point, symbolContext );
1506  }
1507  else
1508  renderUsingLayer( symbolLayer, symbolContext );
1509  }
1510 }
1511 
1512 QRectF QgsMarkerSymbolV2::bounds( QPointF point, QgsRenderContext& context, const QgsFeature& feature ) const
1513 {
1514  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, &feature, feature.fields(), mapUnitScale() );
1515 
1516  QRectF bound;
1517  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1518  {
1519  if ( layer->type() == QgsSymbolV2::Marker )
1520  {
1522  if ( bound.isNull() )
1523  bound = symbolLayer->bounds( point, symbolContext );
1524  else
1525  bound = bound.united( symbolLayer->bounds( point, symbolContext ) );
1526  }
1527  }
1528  return bound;
1529 }
1530 
1532 {
1533  QgsMarkerSymbolV2* cloneSymbol = new QgsMarkerSymbolV2( cloneLayers() );
1534  cloneSymbol->setAlpha( mAlpha );
1535  cloneSymbol->setLayer( mLayer );
1537  return cloneSymbol;
1538 }
1539 
1540 
1542 // LINE
1543 
1545  : QgsSymbolV2( Line, layers )
1546 {
1547  if ( mLayers.isEmpty() )
1549 }
1550 
1552 {
1553  double origWidth = width();
1554 
1555  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1556  {
1557  QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
1558 
1559  if ( lineLayer )
1560  {
1561  if ( qgsDoubleNear( lineLayer->width(), origWidth ) )
1562  {
1563  lineLayer->setWidth( w );
1564  }
1565  else if ( !qgsDoubleNear( origWidth, 0.0 ) )
1566  {
1567  // proportionally scale the width
1568  lineLayer->setWidth( lineLayer->width() * w / origWidth );
1569  }
1570  // also scale offset to maintain relative position
1571  if ( !qgsDoubleNear( origWidth, 0.0 ) && !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1572  lineLayer->setOffset( lineLayer->offset() * w / origWidth );
1573  }
1574  }
1575 }
1576 
1578 {
1579  double maxWidth = 0;
1580  if ( mLayers.isEmpty() )
1581  return maxWidth;
1582 
1583  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1584  {
1585  const QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1586  if ( lineLayer )
1587  {
1588  double width = lineLayer->width();
1589  if ( width > maxWidth )
1590  maxWidth = width;
1591  }
1592  }
1593  return maxWidth;
1594 }
1595 
1597 {
1598  const double symbolWidth = width();
1599 
1600  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1601  {
1602  QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
1603 
1604  if ( lineLayer )
1605  {
1606  if ( dd.hasDefaultValues() )
1607  {
1608  lineLayer->removeDataDefinedProperty( "width" );
1609  lineLayer->removeDataDefinedProperty( "offset" );
1610  }
1611  else
1612  {
1613  if ( qgsDoubleNear( symbolWidth, 0.0 ) || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1614  {
1615  lineLayer->setDataDefinedProperty( "width", new QgsDataDefined( dd ) );
1616  }
1617  else
1618  {
1619  lineLayer->setDataDefinedProperty( "width", scaleWholeSymbol( lineLayer->width() / symbolWidth, dd ) );
1620  }
1621 
1622  if ( !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1623  {
1624  lineLayer->setDataDefinedProperty( "offset", scaleWholeSymbol( lineLayer->offset() / symbolWidth, dd ) );
1625  }
1626  }
1627  }
1628  }
1629 }
1630 
1632 {
1633  const double symbolWidth = width();
1634 
1635  QgsDataDefined* symbolDD = nullptr;
1636 
1637  // find the base of the "en masse" pattern
1638  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1639  {
1640  const QgsLineSymbolLayerV2* layer = dynamic_cast<const QgsLineSymbolLayerV2*>( *it );
1641  if ( layer && qgsDoubleNear( layer->width(), symbolWidth ) && layer->getDataDefinedProperty( "width" ) )
1642  {
1643  symbolDD = layer->getDataDefinedProperty( "width" );
1644  break;
1645  }
1646  }
1647 
1648  if ( !symbolDD )
1649  return QgsDataDefined();
1650 
1651  // check that all layers width expressions match the "en masse" pattern
1652  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1653  {
1654  if ( layer->type() != QgsSymbolV2::Line )
1655  continue;
1656  const QgsLineSymbolLayerV2* lineLayer = static_cast<const QgsLineSymbolLayerV2*>( layer );
1657 
1658  QgsDataDefined* layerWidthDD = lineLayer->getDataDefinedProperty( "width" );
1659  QgsDataDefined* layerOffsetDD = lineLayer->getDataDefinedProperty( "offset" );
1660 
1661  if ( qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1662  {
1663  if ( !layerWidthDD || *layerWidthDD != *symbolDD )
1664  return QgsDataDefined();
1665  }
1666  else
1667  {
1668  if ( qgsDoubleNear( symbolWidth, 0.0 ) )
1669  return QgsDataDefined();
1670 
1671  QScopedPointer< QgsDataDefined > scaledDD( scaleWholeSymbol( lineLayer->width() / symbolWidth, *symbolDD ) );
1672  if ( !layerWidthDD || *layerWidthDD != *( scaledDD.data() ) )
1673  return QgsDataDefined();
1674  }
1675 
1676  QScopedPointer< QgsDataDefined > scaledOffsetDD( scaleWholeSymbol( lineLayer->offset() / symbolWidth, *symbolDD ) );
1677  if ( layerOffsetDD && *layerOffsetDD != *( scaledOffsetDD.data() ) )
1678  return QgsDataDefined();
1679  }
1680 
1681  return QgsDataDefined( *symbolDD );
1682 }
1683 
1684 void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1685 {
1686  //save old painter
1687  QPainter* renderPainter = context.painter();
1688  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1689  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1690  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1691 
1692  if ( layerIdx != -1 )
1693  {
1694  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1695  if ( symbolLayer )
1696  {
1697  if ( symbolLayer->type() == QgsSymbolV2::Line )
1698  {
1699  QgsLineSymbolLayerV2* lineLayer = static_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1700  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1701  }
1702  else
1703  renderUsingLayer( symbolLayer, symbolContext );
1704  }
1705  return;
1706  }
1707 
1708  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1709  {
1710  if ( symbolLayer->type() == QgsSymbolV2::Line )
1711  {
1712  QgsLineSymbolLayerV2* lineLayer = static_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1713  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1714  }
1715  else
1716  {
1717  renderUsingLayer( symbolLayer, symbolContext );
1718  }
1719  }
1720 
1721  context.setPainter( renderPainter );
1722 }
1723 
1724 void QgsLineSymbolV2::renderPolylineUsingLayer( QgsLineSymbolLayerV2 *layer, const QPolygonF &points, QgsSymbolV2RenderContext &context )
1725 {
1726  QgsPaintEffect* effect = layer->paintEffect();
1727  if ( effect && effect->enabled() )
1728  {
1729  QPainter* p = context.renderContext().painter();
1730  p->save();
1731  p->translate( points.boundingRect().topLeft() );
1732 
1733  effect->begin( context.renderContext() );
1734  layer->renderPolyline( points.translated( -points.boundingRect().topLeft() ), context );
1735  effect->end( context.renderContext() );
1736 
1737  p->restore();
1738  }
1739  else
1740  {
1741  layer->renderPolyline( points, context );
1742  }
1743 }
1744 
1745 
1747 {
1748  QgsLineSymbolV2* cloneSymbol = new QgsLineSymbolV2( cloneLayers() );
1749  cloneSymbol->setAlpha( mAlpha );
1750  cloneSymbol->setLayer( mLayer );
1752  return cloneSymbol;
1753 }
1754 
1756 // FILL
1757 
1759  : QgsSymbolV2( Fill, layers )
1760 {
1761  if ( mLayers.isEmpty() )
1763 }
1764 
1765 void QgsFillSymbolV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1766 {
1767  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1768  symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1769  symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
1770 
1771  if ( layerIdx != -1 )
1772  {
1773  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1774  if ( symbolLayer )
1775  {
1776  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1777  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1778  else
1779  renderUsingLayer( symbolLayer, symbolContext );
1780  }
1781  return;
1782  }
1783 
1784  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1785  {
1786  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1787  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1788  else
1789  renderUsingLayer( symbolLayer, symbolContext );
1790  }
1791 }
1792 
1793 void QgsFillSymbolV2::renderPolygonUsingLayer( QgsSymbolLayerV2* layer, const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
1794 {
1795  QgsSymbolV2::SymbolType layertype = layer->type();
1796 
1797  QgsPaintEffect* effect = layer->paintEffect();
1798  if ( effect && effect->enabled() )
1799  {
1800  QRectF bounds = polygonBounds( points, rings );
1801  QList<QPolygonF>* translatedRings = translateRings( rings, -bounds.left(), -bounds.top() );
1802 
1803  QPainter* p = context.renderContext().painter();
1804  p->save();
1805  p->translate( bounds.topLeft() );
1806 
1807  effect->begin( context.renderContext() );
1808  if ( layertype == QgsSymbolV2::Fill )
1809  {
1810  ( static_cast<QgsFillSymbolLayerV2*>( layer ) )->renderPolygon( points.translated( -bounds.topLeft() ), translatedRings, context );
1811  }
1812  else if ( layertype == QgsSymbolV2::Line )
1813  {
1814  ( static_cast<QgsLineSymbolLayerV2*>( layer ) )->renderPolygonOutline( points.translated( -bounds.topLeft() ), translatedRings, context );
1815  }
1816  delete translatedRings;
1817 
1818  effect->end( context.renderContext() );
1819  p->restore();
1820  }
1821  else
1822  {
1823  if ( layertype == QgsSymbolV2::Fill )
1824  {
1825  ( static_cast<QgsFillSymbolLayerV2*>( layer ) )->renderPolygon( points, rings, context );
1826  }
1827  else if ( layertype == QgsSymbolV2::Line )
1828  {
1829  ( static_cast<QgsLineSymbolLayerV2*>( layer ) )->renderPolygonOutline( points, rings, context );
1830  }
1831  }
1832 }
1833 
1834 QRectF QgsFillSymbolV2::polygonBounds( const QPolygonF& points, const QList<QPolygonF>* rings ) const
1835 {
1836  QRectF bounds = points.boundingRect();
1837  if ( rings )
1838  {
1840  for ( ; it != rings->constEnd(); ++it )
1841  {
1842  bounds = bounds.united(( *it ).boundingRect() );
1843  }
1844  }
1845  return bounds;
1846 }
1847 
1848 QList<QPolygonF>* QgsFillSymbolV2::translateRings( const QList<QPolygonF>* rings, double dx, double dy ) const
1849 {
1850  if ( !rings )
1851  return nullptr;
1852 
1853  QList<QPolygonF>* translatedRings = new QList<QPolygonF>;
1855  for ( ; it != rings->constEnd(); ++it )
1856  {
1857  translatedRings->append(( *it ).translated( dx, dy ) );
1858  }
1859  return translatedRings;
1860 }
1861 
1863 {
1864  QgsFillSymbolV2* cloneSymbol = new QgsFillSymbolV2( cloneLayers() );
1865  cloneSymbol->setAlpha( mAlpha );
1866  cloneSymbol->setLayer( mLayer );
1868  return cloneSymbol;
1869 }
1870 
1872 {
1873  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1874  {
1875  if ( layer->type() != QgsSymbolV2::Fill )
1876  continue;
1877 
1878  QgsFillSymbolLayerV2* fillLayer = static_cast<QgsFillSymbolLayerV2*>( layer );
1879 
1880  if ( fillLayer )
1881  fillLayer->setAngle( angle );
1882  }
1883 }
1884 
1885 
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
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:400
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.
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)
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.
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
void setVariable(const QString &name, const QVariant &value)
Convenience method for setting a variable in the context scope by name and value. ...
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).
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
int geometryPartCount() const
Part count of current geometry.
Definition: qgssymbolv2.h:396
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:356
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:409
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.
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
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.