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