QGIS API Documentation  2.14.5-Essen
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  if ( mSymbolRenderContext->expressionContextScope() )
737  {
738  context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
740  mSymbolRenderContext->expressionContextScope()->setVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, segmentizedGeometry->geometry()->partCount() );
742  }
743 
744  switch ( QgsWKBTypes::flatType( segmentizedGeometry->geometry()->wkbType() ) )
745  {
746  case QgsWKBTypes::Point:
747  {
748  QPointF pt;
749  if ( mType != QgsSymbolV2::Marker )
750  {
751  QgsDebugMsg( "point can be drawn only with marker symbol!" );
752  break;
753  }
754 
755  const QgsPointV2* point = static_cast< const QgsPointV2* >( segmentizedGeometry->geometry() );
756  _getPoint( pt, context, point );
757  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( pt, &feature, context, layer, selected );
758 
760  {
761  //draw debugging rect
762  context.painter()->setPen( Qt::red );
763  context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
764  context.painter()->drawRect( static_cast<QgsMarkerSymbolV2*>( this )->bounds( pt, context, feature ) );
765  }
766  }
767  break;
769  {
770  QPolygonF pts;
771  if ( mType != QgsSymbolV2::Line )
772  {
773  QgsDebugMsg( "linestring can be drawn only with line symbol!" );
774  break;
775  }
776  _getLineString( pts, context, QgsConstWkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() ), !tileMapRendering && clipFeaturesToExtent() );
777  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( pts, &feature, context, layer, selected );
778  }
779  break;
781  {
782  QPolygonF pts;
783  QList<QPolygonF> holes;
784  if ( mType != QgsSymbolV2::Fill )
785  {
786  QgsDebugMsg( "polygon can be drawn only with fill symbol!" );
787  break;
788  }
789  _getPolygon( pts, holes, context, QgsConstWkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() ), !tileMapRendering && clipFeaturesToExtent() );
790  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
791  }
792  break;
793 
795  {
796  QPointF pt;
797 
798  if ( mType != QgsSymbolV2::Marker )
799  {
800  QgsDebugMsg( "multi-point can be drawn only with marker symbol!" );
801  break;
802  }
803 
804  QgsMultiPointV2* mp = static_cast< QgsMultiPointV2* >( segmentizedGeometry->geometry() );
805 
806  for ( int i = 0; i < mp->numGeometries(); ++i )
807  {
809 
810  const QgsPointV2* point = static_cast< const QgsPointV2* >( mp->geometryN( i ) );
811  _getPoint( pt, context, point );
812  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( pt, &feature, context, layer, selected );
813  }
814  }
815  break;
816 
819  {
820  QPolygonF pts;
821 
822  if ( mType != QgsSymbolV2::Line )
823  {
824  QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" );
825  break;
826  }
827 
828  QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() );
829  wkbPtr.readHeader();
830 
831  unsigned int num;
832  wkbPtr >> num;
833 
834  const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
835 
836  for ( unsigned int i = 0; i < num && wkbPtr; ++i )
837  {
839 
840  if ( geomCollection )
841  {
842  context.setGeometry( geomCollection->geometryN( i ) );
843  }
844  wkbPtr = _getLineString( pts, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() );
845  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( pts, &feature, context, layer, selected );
846  }
847  }
848  break;
849 
852  {
853  if ( mType != QgsSymbolV2::Fill )
854  {
855  QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" );
856  break;
857  }
858 
859  QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() );
860  wkbPtr.readHeader();
861 
862  unsigned int num;
863  wkbPtr >> num;
864 
865  QPolygonF pts;
866  QList<QPolygonF> holes;
867 
868  const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
869 
870  for ( unsigned int i = 0; i < num && wkbPtr; ++i )
871  {
873 
874  if ( geomCollection )
875  {
876  context.setGeometry( geomCollection->geometryN( i ) );
877  }
878 
879  wkbPtr = _getPolygon( pts, holes, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() );
880  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
881  }
882  break;
883  }
885  {
886  QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() );
887  wkbPtr.readHeader();
888 
889  int nGeometries;
890  wkbPtr >> nGeometries;
891 
892  if ( nGeometries == 0 )
893  {
894  // skip noise from empty geometry collections from simplification
895  break;
896  }
897 
898  FALLTHROUGH;
899  }
900  default:
901  QgsDebugMsg( QString( "feature %1: unsupported wkb type %2/%3 for rendering" )
902  .arg( feature.id() )
903  .arg( QgsWKBTypes::displayString( geom->geometry()->wkbType() ) )
904  .arg( geom->wkbType(), 0, 16 ) );
905  }
906 
907  if ( drawVertexMarker )
908  {
909  const QgsCoordinateTransform* ct = context.coordinateTransform();
910  const QgsMapToPixel& mtp = context.mapToPixel();
911 
912  QgsPointV2 vertexPoint;
913  QgsVertexId vertexId;
914  double x, y, z;
915  QPointF mapPoint;
916  while ( geom->geometry()->nextVertex( vertexId, vertexPoint ) )
917  {
918  //transform
919  x = vertexPoint.x();
920  y = vertexPoint.y();
921  z = vertexPoint.z();
922  if ( ct )
923  {
924  ct->transformInPlace( x, y, z );
925  }
926  mapPoint.setX( x );
927  mapPoint.setY( y );
928  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
929  QgsVectorLayer::drawVertexMarker( mapPoint.x(), mapPoint.y(), *context.painter(),
930  static_cast< QgsVectorLayer::VertexMarkerType >( currentVertexMarkerType ),
931  currentVertexMarkerSize );
932  }
933  }
934 
935  if ( deleteSegmentizedGeometry )
936  {
937  delete segmentizedGeometry;
938  }
939 
940  if ( mSymbolRenderContext->expressionContextScope() )
941  context.expressionContext().popScope();
942 }
943 
945 {
946  return mSymbolRenderContext;
947 }
948 
950 
951 
953  : mRenderContext( c ),
954  mExpressionContextScope( nullptr ),
955  mOutputUnit( u ),
956  mMapUnitScale( mapUnitScale ),
957  mAlpha( alpha ),
958  mSelected( selected ),
959  mRenderHints( renderHints ),
960  mFeature( f ),
961  mFields( fields )
962 {
963 }
964 
966 {
967  delete mExpressionContextScope;
968 }
969 
971 {
972  mRenderContext.expressionContext().setOriginalValueVariable( value );
973 }
974 
975 double QgsSymbolV2RenderContext::outputLineWidth( double width ) const
976 {
977  return QgsSymbolLayerV2Utils::convertToPainterUnits( mRenderContext, width, mOutputUnit, mMapUnitScale );
978 }
979 
980 double QgsSymbolV2RenderContext::outputPixelSize( double size ) const
981 {
982  return size * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( mRenderContext, mOutputUnit, mMapUnitScale );
983 }
984 
986 {
987  // This is just a dummy implementation of assignment.
988  // sip 4.7 generates a piece of code that needs this function to exist.
989  // It's not generated automatically by the compiler because of
990  // mRenderContext member which is a reference (and thus can't be changed).
991  Q_ASSERT( false );
992  return *this;
993 }
994 
996 {
997  return mExpressionContextScope;
998 }
999 
1001 {
1002  mExpressionContextScope = contextScope;
1003 }
1004 
1006 
1008 {
1010  if ( !sl )
1011  return nullptr;
1012 
1013  QgsSymbolLayerV2List layers;
1014  layers.append( sl );
1015  return new QgsMarkerSymbolV2( layers );
1016 }
1017 
1019 {
1021  if ( !sl )
1022  return nullptr;
1023 
1024  QgsSymbolLayerV2List layers;
1025  layers.append( sl );
1026  return new QgsLineSymbolV2( layers );
1027 }
1028 
1030 {
1032  if ( !sl )
1033  return nullptr;
1034 
1035  QgsSymbolLayerV2List layers;
1036  layers.append( sl );
1037  return new QgsFillSymbolV2( layers );
1038 }
1039 
1041 
1043  : QgsSymbolV2( Marker, layers )
1044 {
1045  if ( mLayers.isEmpty() )
1047 }
1048 
1050 {
1051  double origAngle = angle();
1052  double angleDiff = ang - origAngle;
1053  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1054  {
1055  QgsMarkerSymbolLayerV2* markerLayer = dynamic_cast<QgsMarkerSymbolLayerV2*>( layer );
1056  if ( markerLayer )
1057  markerLayer->setAngle( markerLayer->angle() + angleDiff );
1058  }
1059 }
1060 
1062 {
1063  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1064  {
1065  if ( layer->type() != QgsSymbolV2::Marker )
1066  continue;
1067  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1068  return markerLayer->angle();
1069  }
1070  return 0;
1071 }
1072 
1073 void QgsMarkerSymbolV2::setLineAngle( double lineAng )
1074 {
1075  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1076  {
1077  if ( layer->type() != QgsSymbolV2::Marker )
1078  continue;
1079  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1080  markerLayer->setLineAngle( lineAng );
1081  }
1082 }
1083 
1085 {
1086  const double symbolRotation = angle();
1087 
1088  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1089  {
1090  if ( layer->type() != QgsSymbolV2::Marker )
1091  continue;
1092  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1093  if ( dd.hasDefaultValues() )
1094  {
1095  layer->removeDataDefinedProperty( "angle" );
1096  }
1097  else
1098  {
1099  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1100  {
1101  layer->setDataDefinedProperty( "angle", new QgsDataDefined( dd ) );
1102  }
1103  else
1104  {
1105  QgsDataDefined* rotatedDD = rotateWholeSymbol( markerLayer->angle() - symbolRotation, dd );
1106  layer->setDataDefinedProperty( "angle", rotatedDD );
1107  }
1108  }
1109  }
1110 }
1111 
1113 {
1114  const double symbolRotation = angle();
1115  QgsDataDefined* symbolDD = nullptr;
1116 
1117  // find the base of the "en masse" pattern
1118  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1119  {
1120  if ( layer->type() != QgsSymbolV2::Marker )
1121  continue;
1122  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1123  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) && markerLayer->getDataDefinedProperty( "angle" ) )
1124  {
1125  symbolDD = markerLayer->getDataDefinedProperty( "angle" );
1126  break;
1127  }
1128  }
1129 
1130  if ( !symbolDD )
1131  return QgsDataDefined();
1132 
1133  // check that all layer's angle expressions match the "en masse" pattern
1134  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1135  {
1136  if ( layer->type() != QgsSymbolV2::Marker )
1137  continue;
1138  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1139  QgsDataDefined* layerAngleDD = markerLayer->getDataDefinedProperty( "angle" );
1140 
1141  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1142  {
1143  if ( !layerAngleDD || *layerAngleDD != *symbolDD )
1144  return QgsDataDefined();
1145  }
1146  else
1147  {
1148  QScopedPointer< QgsDataDefined > rotatedDD( rotateWholeSymbol( markerLayer->angle() - symbolRotation, *symbolDD ) );
1149  if ( !layerAngleDD || *layerAngleDD != *( rotatedDD.data() ) )
1150  return QgsDataDefined();
1151  }
1152  }
1153  return QgsDataDefined( *symbolDD );
1154 }
1155 
1156 
1158 {
1159  double origSize = size();
1160 
1161  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1162  {
1163  if ( layer->type() != QgsSymbolV2::Marker )
1164  continue;
1165  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1166  if ( qgsDoubleNear( markerLayer->size(), origSize ) )
1167  markerLayer->setSize( s );
1168  else if ( !qgsDoubleNear( origSize, 0.0 ) )
1169  {
1170  // proportionally scale size
1171  markerLayer->setSize( markerLayer->size() * s / origSize );
1172  }
1173  // also scale offset to maintain relative position
1174  if ( !qgsDoubleNear( origSize, 0.0 ) && ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) ) )
1175  markerLayer->setOffset( QPointF( markerLayer->offset().x() * s / origSize,
1176  markerLayer->offset().y() * s / origSize ) );
1177  }
1178 }
1179 
1181 {
1182  // return size of the largest symbol
1183  double maxSize = 0;
1184  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1185  {
1186  if ( layer->type() != QgsSymbolV2::Marker )
1187  continue;
1188  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1189  double lsize = markerLayer->size();
1190  if ( lsize > maxSize )
1191  maxSize = lsize;
1192  }
1193  return maxSize;
1194 }
1195 
1197 {
1198  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1199  {
1200  if ( layer->type() != QgsSymbolV2::Marker )
1201  continue;
1202 
1203  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1204  markerLayer->setSizeUnit( unit );
1205  }
1206 }
1207 
1209 {
1210  bool first = true;
1211  OutputUnit unit = Mixed;
1212 
1213  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1214  {
1215  if ( layer->type() != QgsSymbolV2::Marker )
1216  continue;
1217  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1218 
1219  if ( first )
1220  unit = markerLayer->sizeUnit();
1221  else
1222  {
1223  if ( unit != markerLayer->sizeUnit() )
1224  return Mixed;
1225  }
1226 
1227  first = false;
1228  }
1229  return unit;
1230 }
1231 
1233 {
1234  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1235  {
1236  if ( layer->type() != QgsSymbolV2::Marker )
1237  continue;
1238 
1239  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1240  markerLayer->setSizeMapUnitScale( scale );
1241  }
1242 }
1243 
1245 {
1246  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1247  {
1248  if ( layer->type() != QgsSymbolV2::Marker )
1249  continue;
1250 
1251  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1252  return markerLayer->sizeMapUnitScale();
1253  }
1254  return QgsMapUnitScale();
1255 }
1256 
1258 {
1259  const double symbolSize = size();
1260 
1261  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1262  {
1263  if ( layer->type() != QgsSymbolV2::Marker )
1264  continue;
1265  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1266 
1267  if ( dd.hasDefaultValues() )
1268  {
1269  markerLayer->removeDataDefinedProperty( "size" );
1270  markerLayer->removeDataDefinedProperty( "offset" );
1271  }
1272  else
1273  {
1274  if ( qgsDoubleNear( symbolSize, 0.0 ) || qgsDoubleNear( markerLayer->size(), symbolSize ) )
1275  {
1276  markerLayer->setDataDefinedProperty( "size", new QgsDataDefined( dd ) );
1277  }
1278  else
1279  {
1280  markerLayer->setDataDefinedProperty( "size", scaleWholeSymbol( markerLayer->size() / symbolSize, dd ) );
1281  }
1282 
1283  if ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) )
1284  {
1285  markerLayer->setDataDefinedProperty( "offset", scaleWholeSymbol(
1286  markerLayer->offset().x() / symbolSize,
1287  markerLayer->offset().y() / symbolSize, dd ) );
1288  }
1289  }
1290  }
1291 }
1292 
1294 {
1295  const double symbolSize = size();
1296 
1297  QgsDataDefined* symbolDD = nullptr;
1298 
1299  // find the base of the "en masse" pattern
1300  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1301  {
1302  if ( layer->type() != QgsSymbolV2::Marker )
1303  continue;
1304  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1305  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) && markerLayer->getDataDefinedProperty( "size" ) )
1306  {
1307  symbolDD = markerLayer->getDataDefinedProperty( "size" );
1308  break;
1309  }
1310  }
1311 
1312  if ( !symbolDD )
1313  return QgsDataDefined();
1314 
1315  // check that all layers size expressions match the "en masse" pattern
1316  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1317  {
1318  if ( layer->type() != QgsSymbolV2::Marker )
1319  continue;
1320  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1321 
1322  QgsDataDefined* layerSizeDD = markerLayer->getDataDefinedProperty( "size" );
1323  QgsDataDefined* layerOffsetDD = markerLayer->getDataDefinedProperty( "offset" );
1324 
1325  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) )
1326  {
1327  if ( !layerSizeDD || *layerSizeDD != *symbolDD )
1328  return QgsDataDefined();
1329  }
1330  else
1331  {
1332  if ( qgsDoubleNear( symbolSize, 0.0 ) )
1333  return QgsDataDefined();
1334 
1335  QScopedPointer< QgsDataDefined > scaledDD( scaleWholeSymbol( markerLayer->size() / symbolSize, *symbolDD ) );
1336  if ( !layerSizeDD || *layerSizeDD != *( scaledDD.data() ) )
1337  return QgsDataDefined();
1338  }
1339 
1340  QScopedPointer< QgsDataDefined > scaledOffsetDD( scaleWholeSymbol( markerLayer->offset().x() / symbolSize, markerLayer->offset().y() / symbolSize, *symbolDD ) );
1341  if ( layerOffsetDD && *layerOffsetDD != *( scaledOffsetDD.data() ) )
1342  return QgsDataDefined();
1343  }
1344 
1345  return QgsDataDefined( *symbolDD );
1346 }
1347 
1349 {
1350  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1351  {
1352  if ( layer->type() != QgsSymbolV2::Marker )
1353  continue;
1354  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1355  markerLayer->setScaleMethod( scaleMethod );
1356  }
1357 }
1358 
1360 {
1361  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1362  {
1363  if ( layer->type() != QgsSymbolV2::Marker )
1364  continue;
1365  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1366  // return scale method of the first symbol layer
1367  return markerLayer->scaleMethod();
1368  }
1369 
1370  return DEFAULT_SCALE_METHOD;
1371 }
1372 
1373 void QgsMarkerSymbolV2::renderPointUsingLayer( QgsMarkerSymbolLayerV2* layer, QPointF point, QgsSymbolV2RenderContext& context )
1374 {
1375  static QPointF nullPoint( 0, 0 );
1376 
1377  QgsPaintEffect* effect = layer->paintEffect();
1378  if ( effect && effect->enabled() )
1379  {
1380  QPainter* p = context.renderContext().painter();
1381  p->save();
1382  p->translate( point );
1383 
1384  effect->begin( context.renderContext() );
1385  layer->renderPoint( nullPoint, context );
1386  effect->end( context.renderContext() );
1387 
1388  p->restore();
1389  }
1390  else
1391  {
1392  layer->renderPoint( point, context );
1393  }
1394 }
1395 
1396 void QgsMarkerSymbolV2::renderPoint( QPointF point, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1397 {
1398  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1399 
1400  if ( layerIdx != -1 )
1401  {
1402  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1403  if ( symbolLayer )
1404  {
1405  if ( symbolLayer->type() == QgsSymbolV2::Marker )
1406  {
1407  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( symbolLayer );
1408  renderPointUsingLayer( markerLayer, point, symbolContext );
1409  }
1410  else
1411  renderUsingLayer( symbolLayer, symbolContext );
1412  }
1413  return;
1414  }
1415 
1416  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1417  {
1418  if ( symbolLayer->type() == QgsSymbolV2::Marker )
1419  {
1420  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( symbolLayer );
1421  renderPointUsingLayer( markerLayer, point, symbolContext );
1422  }
1423  else
1424  renderUsingLayer( symbolLayer, symbolContext );
1425  }
1426 }
1427 
1428 QRectF QgsMarkerSymbolV2::bounds( QPointF point, QgsRenderContext& context, const QgsFeature& feature ) const
1429 {
1430  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, &feature, feature.fields(), mapUnitScale() );
1431 
1432  QRectF bound;
1433  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1434  {
1435  if ( layer->type() == QgsSymbolV2::Marker )
1436  {
1438  if ( bound.isNull() )
1439  bound = symbolLayer->bounds( point, symbolContext );
1440  else
1441  bound = bound.united( symbolLayer->bounds( point, symbolContext ) );
1442  }
1443  }
1444  return bound;
1445 }
1446 
1448 {
1449  QgsMarkerSymbolV2* cloneSymbol = new QgsMarkerSymbolV2( cloneLayers() );
1450  cloneSymbol->setAlpha( mAlpha );
1451  cloneSymbol->setLayer( mLayer );
1453  return cloneSymbol;
1454 }
1455 
1456 
1458 // LINE
1459 
1461  : QgsSymbolV2( Line, layers )
1462 {
1463  if ( mLayers.isEmpty() )
1465 }
1466 
1468 {
1469  double origWidth = width();
1470 
1471  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1472  {
1473  QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
1474 
1475  if ( lineLayer )
1476  {
1477  if ( qgsDoubleNear( lineLayer->width(), origWidth ) )
1478  {
1479  lineLayer->setWidth( w );
1480  }
1481  else if ( !qgsDoubleNear( origWidth, 0.0 ) )
1482  {
1483  // proportionally scale the width
1484  lineLayer->setWidth( lineLayer->width() * w / origWidth );
1485  }
1486  // also scale offset to maintain relative position
1487  if ( !qgsDoubleNear( origWidth, 0.0 ) && !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1488  lineLayer->setOffset( lineLayer->offset() * w / origWidth );
1489  }
1490  }
1491 }
1492 
1494 {
1495  double maxWidth = 0;
1496  if ( mLayers.isEmpty() )
1497  return maxWidth;
1498 
1499  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1500  {
1501  const QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1502  if ( lineLayer )
1503  {
1504  double width = lineLayer->width();
1505  if ( width > maxWidth )
1506  maxWidth = width;
1507  }
1508  }
1509  return maxWidth;
1510 }
1511 
1513 {
1514  const double symbolWidth = width();
1515 
1516  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1517  {
1518  QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
1519 
1520  if ( lineLayer )
1521  {
1522  if ( dd.hasDefaultValues() )
1523  {
1524  lineLayer->removeDataDefinedProperty( "width" );
1525  lineLayer->removeDataDefinedProperty( "offset" );
1526  }
1527  else
1528  {
1529  if ( qgsDoubleNear( symbolWidth, 0.0 ) || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1530  {
1531  lineLayer->setDataDefinedProperty( "width", new QgsDataDefined( dd ) );
1532  }
1533  else
1534  {
1535  lineLayer->setDataDefinedProperty( "width", scaleWholeSymbol( lineLayer->width() / symbolWidth, dd ) );
1536  }
1537 
1538  if ( !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1539  {
1540  lineLayer->setDataDefinedProperty( "offset", scaleWholeSymbol( lineLayer->offset() / symbolWidth, dd ) );
1541  }
1542  }
1543  }
1544  }
1545 }
1546 
1548 {
1549  const double symbolWidth = width();
1550 
1551  QgsDataDefined* symbolDD = nullptr;
1552 
1553  // find the base of the "en masse" pattern
1554  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1555  {
1556  const QgsLineSymbolLayerV2* layer = dynamic_cast<const QgsLineSymbolLayerV2*>( *it );
1557  if ( layer && qgsDoubleNear( layer->width(), symbolWidth ) && layer->getDataDefinedProperty( "width" ) )
1558  {
1559  symbolDD = layer->getDataDefinedProperty( "width" );
1560  break;
1561  }
1562  }
1563 
1564  if ( !symbolDD )
1565  return QgsDataDefined();
1566 
1567  // check that all layers width expressions match the "en masse" pattern
1568  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1569  {
1570  if ( layer->type() != QgsSymbolV2::Line )
1571  continue;
1572  const QgsLineSymbolLayerV2* lineLayer = static_cast<const QgsLineSymbolLayerV2*>( layer );
1573 
1574  QgsDataDefined* layerWidthDD = lineLayer->getDataDefinedProperty( "width" );
1575  QgsDataDefined* layerOffsetDD = lineLayer->getDataDefinedProperty( "offset" );
1576 
1577  if ( qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1578  {
1579  if ( !layerWidthDD || *layerWidthDD != *symbolDD )
1580  return QgsDataDefined();
1581  }
1582  else
1583  {
1584  if ( qgsDoubleNear( symbolWidth, 0.0 ) )
1585  return QgsDataDefined();
1586 
1587  QScopedPointer< QgsDataDefined > scaledDD( scaleWholeSymbol( lineLayer->width() / symbolWidth, *symbolDD ) );
1588  if ( !layerWidthDD || *layerWidthDD != *( scaledDD.data() ) )
1589  return QgsDataDefined();
1590  }
1591 
1592  QScopedPointer< QgsDataDefined > scaledOffsetDD( scaleWholeSymbol( lineLayer->offset() / symbolWidth, *symbolDD ) );
1593  if ( layerOffsetDD && *layerOffsetDD != *( scaledOffsetDD.data() ) )
1594  return QgsDataDefined();
1595  }
1596 
1597  return QgsDataDefined( *symbolDD );
1598 }
1599 
1600 void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1601 {
1602  //save old painter
1603  QPainter* renderPainter = context.painter();
1604  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1605 
1606  if ( layerIdx != -1 )
1607  {
1608  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1609  if ( symbolLayer )
1610  {
1611  if ( symbolLayer->type() == QgsSymbolV2::Line )
1612  {
1613  QgsLineSymbolLayerV2* lineLayer = static_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1614  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1615  }
1616  else
1617  renderUsingLayer( symbolLayer, symbolContext );
1618  }
1619  return;
1620  }
1621 
1622  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1623  {
1624  if ( symbolLayer->type() == QgsSymbolV2::Line )
1625  {
1626  QgsLineSymbolLayerV2* lineLayer = static_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1627  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1628  }
1629  else
1630  {
1631  renderUsingLayer( symbolLayer, symbolContext );
1632  }
1633  }
1634 
1635  context.setPainter( renderPainter );
1636 }
1637 
1638 void QgsLineSymbolV2::renderPolylineUsingLayer( QgsLineSymbolLayerV2 *layer, const QPolygonF &points, QgsSymbolV2RenderContext &context )
1639 {
1640  QgsPaintEffect* effect = layer->paintEffect();
1641  if ( effect && effect->enabled() )
1642  {
1643  QPainter* p = context.renderContext().painter();
1644  p->save();
1645  p->translate( points.boundingRect().topLeft() );
1646 
1647  effect->begin( context.renderContext() );
1648  layer->renderPolyline( points.translated( -points.boundingRect().topLeft() ), context );
1649  effect->end( context.renderContext() );
1650 
1651  p->restore();
1652  }
1653  else
1654  {
1655  layer->renderPolyline( points, context );
1656  }
1657 }
1658 
1659 
1661 {
1662  QgsLineSymbolV2* cloneSymbol = new QgsLineSymbolV2( cloneLayers() );
1663  cloneSymbol->setAlpha( mAlpha );
1664  cloneSymbol->setLayer( mLayer );
1666  return cloneSymbol;
1667 }
1668 
1670 // FILL
1671 
1673  : QgsSymbolV2( Fill, layers )
1674 {
1675  if ( mLayers.isEmpty() )
1677 }
1678 
1679 void QgsFillSymbolV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1680 {
1681  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1682 
1683  if ( layerIdx != -1 )
1684  {
1685  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1686  if ( symbolLayer )
1687  {
1688  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1689  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1690  else
1691  renderUsingLayer( symbolLayer, symbolContext );
1692  }
1693  return;
1694  }
1695 
1696  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1697  {
1698  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1699  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1700  else
1701  renderUsingLayer( symbolLayer, symbolContext );
1702  }
1703 }
1704 
1705 void QgsFillSymbolV2::renderPolygonUsingLayer( QgsSymbolLayerV2* layer, const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
1706 {
1707  QgsSymbolV2::SymbolType layertype = layer->type();
1708 
1709  QgsPaintEffect* effect = layer->paintEffect();
1710  if ( effect && effect->enabled() )
1711  {
1712  QRectF bounds = polygonBounds( points, rings );
1713  QList<QPolygonF>* translatedRings = translateRings( rings, -bounds.left(), -bounds.top() );
1714 
1715  QPainter* p = context.renderContext().painter();
1716  p->save();
1717  p->translate( bounds.topLeft() );
1718 
1719  effect->begin( context.renderContext() );
1720  if ( layertype == QgsSymbolV2::Fill )
1721  {
1722  ( static_cast<QgsFillSymbolLayerV2*>( layer ) )->renderPolygon( points.translated( -bounds.topLeft() ), translatedRings, context );
1723  }
1724  else if ( layertype == QgsSymbolV2::Line )
1725  {
1726  ( static_cast<QgsLineSymbolLayerV2*>( layer ) )->renderPolygonOutline( points.translated( -bounds.topLeft() ), translatedRings, context );
1727  }
1728  delete translatedRings;
1729 
1730  effect->end( context.renderContext() );
1731  p->restore();
1732  }
1733  else
1734  {
1735  if ( layertype == QgsSymbolV2::Fill )
1736  {
1737  ( static_cast<QgsFillSymbolLayerV2*>( layer ) )->renderPolygon( points, rings, context );
1738  }
1739  else if ( layertype == QgsSymbolV2::Line )
1740  {
1741  ( static_cast<QgsLineSymbolLayerV2*>( layer ) )->renderPolygonOutline( points, rings, context );
1742  }
1743  }
1744 }
1745 
1746 QRectF QgsFillSymbolV2::polygonBounds( const QPolygonF& points, const QList<QPolygonF>* rings ) const
1747 {
1748  QRectF bounds = points.boundingRect();
1749  if ( rings )
1750  {
1752  for ( ; it != rings->constEnd(); ++it )
1753  {
1754  bounds = bounds.united(( *it ).boundingRect() );
1755  }
1756  }
1757  return bounds;
1758 }
1759 
1760 QList<QPolygonF>* QgsFillSymbolV2::translateRings( const QList<QPolygonF>* rings, double dx, double dy ) const
1761 {
1762  if ( !rings )
1763  return nullptr;
1764 
1765  QList<QPolygonF>* translatedRings = new QList<QPolygonF>;
1767  for ( ; it != rings->constEnd(); ++it )
1768  {
1769  translatedRings->append(( *it ).translated( dx, dy ) );
1770  }
1771  return translatedRings;
1772 }
1773 
1775 {
1776  QgsFillSymbolV2* cloneSymbol = new QgsFillSymbolV2( cloneLayers() );
1777  cloneSymbol->setAlpha( mAlpha );
1778  cloneSymbol->setLayer( mLayer );
1780  return cloneSymbol;
1781 }
1782 
1784 {
1785  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1786  {
1787  if ( layer->type() != QgsSymbolV2::Fill )
1788  continue;
1789 
1790  QgsFillSymbolLayerV2* fillLayer = static_cast<QgsFillSymbolLayerV2*>( layer );
1791 
1792  if ( fillLayer )
1793  fillLayer->setAngle( angle );
1794  }
1795 }
1796 
1797 
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
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
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
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)
Definition: qgis.h:285
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
double y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
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:439
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.
Utility class for identifying a unique vertex within a geometry.
double z() const
Returns the point&#39;s z-coordinate.
Definition: qgspointv2.h:80
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
virtual bool nextVertex(QgsVertexId &id, QgsPointV2 &vertex) const =0
Returns next vertex id and coordinates.
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()
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.
void setX(qreal x)
void setY(qreal y)
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:381
int height() const
Fill symbol.
Definition: qgssymbolv2.h:80
QgsSymbolV2::OutputUnit outputUnit() const
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
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