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