QGIS API Documentation  2.14.11-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, const QgsStringMap& props ) const
637 {
638  QgsStringMap locProps( props );
639  locProps[ "alpha" ] = QString::number( alpha() );
640  double scaleFactor = 1.0;
641  locProps[ "uom" ] = QgsSymbolLayerV2Utils::encodeSldUom( outputUnit(), &scaleFactor );
642  locProps[ "uomScale" ] = ( !qgsDoubleNear( scaleFactor, 1.0 ) ? qgsDoubleToString( scaleFactor ) : "" );
643 
644  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
645  {
646  ( *it )->toSld( doc, element, locProps );
647  }
648 }
649 
651 {
653  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
654  {
655  QgsSymbolLayerV2* layer = ( *it )->clone();
656  layer->setLocked(( *it )->isLocked() );
657  layer->setRenderingPass(( *it )->renderingPass() );
658  lst.append( layer );
659  }
660  return lst;
661 }
662 
664 {
665  Q_ASSERT( layer->type() == Hybrid );
666 
668 
669  QgsPaintEffect* effect = generatorLayer->paintEffect();
670  if ( effect && effect->enabled() )
671  {
672  QPainter* p = context.renderContext().painter();
673  p->save();
674 
675  effect->begin( context.renderContext() );
676  generatorLayer->render( context );
677  effect->end( context.renderContext() );
678 
679  p->restore();
680  }
681  else
682  {
683  generatorLayer->render( context );
684  }
685 }
686 
688 {
689  QSet<QString> attributes;
691  for ( ; sIt != mLayers.constEnd(); ++sIt )
692  {
693  if ( *sIt )
694  {
695  attributes.unite(( *sIt )->usedAttributes() );
696  }
697  }
698  return attributes;
699 }
700 
702 {
703  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
704  {
705  if ( layer->hasDataDefinedProperties() )
706  return true;
707  }
708  return false;
709 }
710 
711 void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, int currentVertexMarkerSize )
712 {
713  const QgsGeometry* geom = feature.constGeometry();
714  if ( !geom || !geom->geometry() )
715  {
716  return;
717  }
718 
719  const QgsGeometry *segmentizedGeometry = geom;
720  bool deleteSegmentizedGeometry = false;
721  context.setGeometry( geom->geometry() );
722 
723  bool tileMapRendering = context.testFlag( QgsRenderContext::RenderMapTile );
724 
725  //convert curve types to normal point/line/polygon ones
726  if ( QgsWKBTypes::isCurvedType( geom->geometry()->wkbType() ) )
727  {
728  QgsAbstractGeometryV2 *g = geom->geometry()->segmentize();
729  if ( !g )
730  {
731  return;
732  }
733  segmentizedGeometry = new QgsGeometry( g );
734  deleteSegmentizedGeometry = true;
735  }
736 
737  if ( mSymbolRenderContext->expressionContextScope() )
738  {
739  context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
743  }
744 
745  switch ( QgsWKBTypes::flatType( segmentizedGeometry->geometry()->wkbType() ) )
746  {
747  case QgsWKBTypes::Point:
748  {
749  QPointF pt;
750  if ( mType != QgsSymbolV2::Marker )
751  {
752  QgsDebugMsg( "point can be drawn only with marker symbol!" );
753  break;
754  }
755 
756  const QgsPointV2* point = static_cast< const QgsPointV2* >( segmentizedGeometry->geometry() );
757  _getPoint( pt, context, point );
758  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( pt, &feature, context, layer, selected );
759 
761  {
762  //draw debugging rect
763  context.painter()->setPen( Qt::red );
764  context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
765  context.painter()->drawRect( static_cast<QgsMarkerSymbolV2*>( this )->bounds( pt, context, feature ) );
766  }
767  }
768  break;
770  {
771  QPolygonF pts;
772  if ( mType != QgsSymbolV2::Line )
773  {
774  QgsDebugMsg( "linestring can be drawn only with line symbol!" );
775  break;
776  }
777  _getLineString( pts, context, QgsConstWkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() ), !tileMapRendering && clipFeaturesToExtent() );
778  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( pts, &feature, context, layer, selected );
779  }
780  break;
782  {
783  QPolygonF pts;
784  QList<QPolygonF> holes;
785  if ( mType != QgsSymbolV2::Fill )
786  {
787  QgsDebugMsg( "polygon can be drawn only with fill symbol!" );
788  break;
789  }
790  _getPolygon( pts, holes, context, QgsConstWkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() ), !tileMapRendering && clipFeaturesToExtent() );
791  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
792  }
793  break;
794 
796  {
797  QPointF pt;
798 
799  if ( mType != QgsSymbolV2::Marker )
800  {
801  QgsDebugMsg( "multi-point can be drawn only with marker symbol!" );
802  break;
803  }
804 
805  QgsMultiPointV2* mp = static_cast< QgsMultiPointV2* >( segmentizedGeometry->geometry() );
806 
807  for ( int i = 0; i < mp->numGeometries(); ++i )
808  {
810 
811  const QgsPointV2* point = static_cast< const QgsPointV2* >( mp->geometryN( i ) );
812  _getPoint( pt, context, point );
813  static_cast<QgsMarkerSymbolV2*>( this )->renderPoint( pt, &feature, context, layer, selected );
814  }
815  }
816  break;
817 
820  {
821  QPolygonF pts;
822 
823  if ( mType != QgsSymbolV2::Line )
824  {
825  QgsDebugMsg( "multi-linestring can be drawn only with line symbol!" );
826  break;
827  }
828 
829  QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() );
830  wkbPtr.readHeader();
831 
832  unsigned int num;
833  wkbPtr >> num;
834 
835  const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
836 
837  for ( unsigned int i = 0; i < num && wkbPtr; ++i )
838  {
840 
841  if ( geomCollection )
842  {
843  context.setGeometry( geomCollection->geometryN( i ) );
844  }
845  wkbPtr = _getLineString( pts, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() );
846  static_cast<QgsLineSymbolV2*>( this )->renderPolyline( pts, &feature, context, layer, selected );
847  }
848  }
849  break;
850 
853  {
854  if ( mType != QgsSymbolV2::Fill )
855  {
856  QgsDebugMsg( "multi-polygon can be drawn only with fill symbol!" );
857  break;
858  }
859 
860  QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() );
861  wkbPtr.readHeader();
862 
863  unsigned int num;
864  wkbPtr >> num;
865 
866  QPolygonF pts;
867  QList<QPolygonF> holes;
868 
869  const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
870 
871  for ( unsigned int i = 0; i < num && wkbPtr; ++i )
872  {
874 
875  if ( geomCollection )
876  {
877  context.setGeometry( geomCollection->geometryN( i ) );
878  }
879 
880  wkbPtr = _getPolygon( pts, holes, context, wkbPtr, !tileMapRendering && clipFeaturesToExtent() );
881  static_cast<QgsFillSymbolV2*>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
882  }
883  break;
884  }
886  {
887  QgsConstWkbPtr wkbPtr( segmentizedGeometry->asWkb(), segmentizedGeometry->wkbSize() );
888  wkbPtr.readHeader();
889 
890  int nGeometries;
891  wkbPtr >> nGeometries;
892 
893  if ( nGeometries == 0 )
894  {
895  // skip noise from empty geometry collections from simplification
896  break;
897  }
898 
899  FALLTHROUGH;
900  }
901  default:
902  QgsDebugMsg( QString( "feature %1: unsupported wkb type %2/%3 for rendering" )
903  .arg( feature.id() )
904  .arg( QgsWKBTypes::displayString( geom->geometry()->wkbType() ) )
905  .arg( geom->wkbType(), 0, 16 ) );
906  }
907 
908  if ( drawVertexMarker )
909  {
910  const QgsCoordinateTransform* ct = context.coordinateTransform();
911  const QgsMapToPixel& mtp = context.mapToPixel();
912 
913  QgsPointV2 vertexPoint;
914  QgsVertexId vertexId;
915  double x, y, z;
916  QPointF mapPoint;
917  while ( geom->geometry()->nextVertex( vertexId, vertexPoint ) )
918  {
919  //transform
920  x = vertexPoint.x();
921  y = vertexPoint.y();
922  z = vertexPoint.z();
923  if ( ct )
924  {
925  ct->transformInPlace( x, y, z );
926  }
927  mapPoint.setX( x );
928  mapPoint.setY( y );
929  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
930  QgsVectorLayer::drawVertexMarker( mapPoint.x(), mapPoint.y(), *context.painter(),
931  static_cast< QgsVectorLayer::VertexMarkerType >( currentVertexMarkerType ),
932  currentVertexMarkerSize );
933  }
934  }
935 
936  if ( deleteSegmentizedGeometry )
937  {
938  delete segmentizedGeometry;
939  }
940 
941  if ( mSymbolRenderContext->expressionContextScope() )
942  context.expressionContext().popScope();
943 }
944 
946 {
947  return mSymbolRenderContext;
948 }
949 
951 
952 
954  : mRenderContext( c ),
955  mExpressionContextScope( nullptr ),
956  mOutputUnit( u ),
957  mMapUnitScale( mapUnitScale ),
958  mAlpha( alpha ),
959  mSelected( selected ),
960  mRenderHints( renderHints ),
961  mFeature( f ),
962  mFields( fields )
963 {
964 }
965 
967 {
968  delete mExpressionContextScope;
969 }
970 
972 {
973  mRenderContext.expressionContext().setOriginalValueVariable( value );
974 }
975 
976 double QgsSymbolV2RenderContext::outputLineWidth( double width ) const
977 {
978  return QgsSymbolLayerV2Utils::convertToPainterUnits( mRenderContext, width, mOutputUnit, mMapUnitScale );
979 }
980 
981 double QgsSymbolV2RenderContext::outputPixelSize( double size ) const
982 {
983  return size * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( mRenderContext, mOutputUnit, mMapUnitScale );
984 }
985 
987 {
988  // This is just a dummy implementation of assignment.
989  // sip 4.7 generates a piece of code that needs this function to exist.
990  // It's not generated automatically by the compiler because of
991  // mRenderContext member which is a reference (and thus can't be changed).
992  Q_ASSERT( false );
993  return *this;
994 }
995 
997 {
998  return mExpressionContextScope;
999 }
1000 
1002 {
1003  mExpressionContextScope = contextScope;
1004 }
1005 
1007 
1009 {
1011  if ( !sl )
1012  return nullptr;
1013 
1014  QgsSymbolLayerV2List layers;
1015  layers.append( sl );
1016  return new QgsMarkerSymbolV2( layers );
1017 }
1018 
1020 {
1022  if ( !sl )
1023  return nullptr;
1024 
1025  QgsSymbolLayerV2List layers;
1026  layers.append( sl );
1027  return new QgsLineSymbolV2( layers );
1028 }
1029 
1031 {
1033  if ( !sl )
1034  return nullptr;
1035 
1036  QgsSymbolLayerV2List layers;
1037  layers.append( sl );
1038  return new QgsFillSymbolV2( layers );
1039 }
1040 
1042 
1044  : QgsSymbolV2( Marker, layers )
1045 {
1046  if ( mLayers.isEmpty() )
1048 }
1049 
1051 {
1052  double origAngle = angle();
1053  double angleDiff = ang - origAngle;
1054  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1055  {
1056  QgsMarkerSymbolLayerV2* markerLayer = dynamic_cast<QgsMarkerSymbolLayerV2*>( layer );
1057  if ( markerLayer )
1058  markerLayer->setAngle( markerLayer->angle() + angleDiff );
1059  }
1060 }
1061 
1063 {
1064  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1065  {
1066  if ( layer->type() != QgsSymbolV2::Marker )
1067  continue;
1068  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1069  return markerLayer->angle();
1070  }
1071  return 0;
1072 }
1073 
1074 void QgsMarkerSymbolV2::setLineAngle( double lineAng )
1075 {
1076  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1077  {
1078  if ( layer->type() != QgsSymbolV2::Marker )
1079  continue;
1080  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1081  markerLayer->setLineAngle( lineAng );
1082  }
1083 }
1084 
1086 {
1087  const double symbolRotation = angle();
1088 
1089  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1090  {
1091  if ( layer->type() != QgsSymbolV2::Marker )
1092  continue;
1093  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1094  if ( dd.hasDefaultValues() )
1095  {
1096  layer->removeDataDefinedProperty( "angle" );
1097  }
1098  else
1099  {
1100  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1101  {
1102  layer->setDataDefinedProperty( "angle", new QgsDataDefined( dd ) );
1103  }
1104  else
1105  {
1106  QgsDataDefined* rotatedDD = rotateWholeSymbol( markerLayer->angle() - symbolRotation, dd );
1107  layer->setDataDefinedProperty( "angle", rotatedDD );
1108  }
1109  }
1110  }
1111 }
1112 
1114 {
1115  const double symbolRotation = angle();
1116  QgsDataDefined* symbolDD = nullptr;
1117 
1118  // find the base of the "en masse" pattern
1119  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1120  {
1121  if ( layer->type() != QgsSymbolV2::Marker )
1122  continue;
1123  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1124  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) && markerLayer->getDataDefinedProperty( "angle" ) )
1125  {
1126  symbolDD = markerLayer->getDataDefinedProperty( "angle" );
1127  break;
1128  }
1129  }
1130 
1131  if ( !symbolDD )
1132  return QgsDataDefined();
1133 
1134  // check that all layer's angle expressions match the "en masse" pattern
1135  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1136  {
1137  if ( layer->type() != QgsSymbolV2::Marker )
1138  continue;
1139  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1140  QgsDataDefined* layerAngleDD = markerLayer->getDataDefinedProperty( "angle" );
1141 
1142  if ( qgsDoubleNear( markerLayer->angle(), symbolRotation ) )
1143  {
1144  if ( !layerAngleDD || *layerAngleDD != *symbolDD )
1145  return QgsDataDefined();
1146  }
1147  else
1148  {
1149  QScopedPointer< QgsDataDefined > rotatedDD( rotateWholeSymbol( markerLayer->angle() - symbolRotation, *symbolDD ) );
1150  if ( !layerAngleDD || *layerAngleDD != *( rotatedDD.data() ) )
1151  return QgsDataDefined();
1152  }
1153  }
1154  return QgsDataDefined( *symbolDD );
1155 }
1156 
1157 
1159 {
1160  double origSize = size();
1161 
1162  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1163  {
1164  if ( layer->type() != QgsSymbolV2::Marker )
1165  continue;
1166  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1167  if ( qgsDoubleNear( markerLayer->size(), origSize ) )
1168  markerLayer->setSize( s );
1169  else if ( !qgsDoubleNear( origSize, 0.0 ) )
1170  {
1171  // proportionally scale size
1172  markerLayer->setSize( markerLayer->size() * s / origSize );
1173  }
1174  // also scale offset to maintain relative position
1175  if ( !qgsDoubleNear( origSize, 0.0 ) && ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) ) )
1176  markerLayer->setOffset( QPointF( markerLayer->offset().x() * s / origSize,
1177  markerLayer->offset().y() * s / origSize ) );
1178  }
1179 }
1180 
1182 {
1183  // return size of the largest symbol
1184  double maxSize = 0;
1185  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1186  {
1187  if ( layer->type() != QgsSymbolV2::Marker )
1188  continue;
1189  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1190  double lsize = markerLayer->size();
1191  if ( lsize > maxSize )
1192  maxSize = lsize;
1193  }
1194  return maxSize;
1195 }
1196 
1198 {
1199  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1200  {
1201  if ( layer->type() != QgsSymbolV2::Marker )
1202  continue;
1203 
1204  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1205  markerLayer->setSizeUnit( unit );
1206  }
1207 }
1208 
1210 {
1211  bool first = true;
1212  OutputUnit unit = Mixed;
1213 
1214  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1215  {
1216  if ( layer->type() != QgsSymbolV2::Marker )
1217  continue;
1218  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1219 
1220  if ( first )
1221  unit = markerLayer->sizeUnit();
1222  else
1223  {
1224  if ( unit != markerLayer->sizeUnit() )
1225  return Mixed;
1226  }
1227 
1228  first = false;
1229  }
1230  return unit;
1231 }
1232 
1234 {
1235  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1236  {
1237  if ( layer->type() != QgsSymbolV2::Marker )
1238  continue;
1239 
1240  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1241  markerLayer->setSizeMapUnitScale( scale );
1242  }
1243 }
1244 
1246 {
1247  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1248  {
1249  if ( layer->type() != QgsSymbolV2::Marker )
1250  continue;
1251 
1252  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1253  return markerLayer->sizeMapUnitScale();
1254  }
1255  return QgsMapUnitScale();
1256 }
1257 
1259 {
1260  const double symbolSize = size();
1261 
1262  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1263  {
1264  if ( layer->type() != QgsSymbolV2::Marker )
1265  continue;
1266  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1267 
1268  if ( dd.hasDefaultValues() )
1269  {
1270  markerLayer->removeDataDefinedProperty( "size" );
1271  markerLayer->removeDataDefinedProperty( "offset" );
1272  }
1273  else
1274  {
1275  if ( qgsDoubleNear( symbolSize, 0.0 ) || qgsDoubleNear( markerLayer->size(), symbolSize ) )
1276  {
1277  markerLayer->setDataDefinedProperty( "size", new QgsDataDefined( dd ) );
1278  }
1279  else
1280  {
1281  markerLayer->setDataDefinedProperty( "size", scaleWholeSymbol( markerLayer->size() / symbolSize, dd ) );
1282  }
1283 
1284  if ( !qgsDoubleNear( markerLayer->offset().x(), 0.0 ) || !qgsDoubleNear( markerLayer->offset().y(), 0.0 ) )
1285  {
1286  markerLayer->setDataDefinedProperty( "offset", scaleWholeSymbol(
1287  markerLayer->offset().x() / symbolSize,
1288  markerLayer->offset().y() / symbolSize, dd ) );
1289  }
1290  }
1291  }
1292 }
1293 
1295 {
1296  const double symbolSize = size();
1297 
1298  QgsDataDefined* symbolDD = nullptr;
1299 
1300  // find the base of the "en masse" pattern
1301  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1302  {
1303  if ( layer->type() != QgsSymbolV2::Marker )
1304  continue;
1305  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1306  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) && markerLayer->getDataDefinedProperty( "size" ) )
1307  {
1308  symbolDD = markerLayer->getDataDefinedProperty( "size" );
1309  break;
1310  }
1311  }
1312 
1313  if ( !symbolDD )
1314  return QgsDataDefined();
1315 
1316  // check that all layers size expressions match the "en masse" pattern
1317  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1318  {
1319  if ( layer->type() != QgsSymbolV2::Marker )
1320  continue;
1321  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1322 
1323  QgsDataDefined* layerSizeDD = markerLayer->getDataDefinedProperty( "size" );
1324  QgsDataDefined* layerOffsetDD = markerLayer->getDataDefinedProperty( "offset" );
1325 
1326  if ( qgsDoubleNear( markerLayer->size(), symbolSize ) )
1327  {
1328  if ( !layerSizeDD || *layerSizeDD != *symbolDD )
1329  return QgsDataDefined();
1330  }
1331  else
1332  {
1333  if ( qgsDoubleNear( symbolSize, 0.0 ) )
1334  return QgsDataDefined();
1335 
1336  QScopedPointer< QgsDataDefined > scaledDD( scaleWholeSymbol( markerLayer->size() / symbolSize, *symbolDD ) );
1337  if ( !layerSizeDD || *layerSizeDD != *( scaledDD.data() ) )
1338  return QgsDataDefined();
1339  }
1340 
1341  QScopedPointer< QgsDataDefined > scaledOffsetDD( scaleWholeSymbol( markerLayer->offset().x() / symbolSize, markerLayer->offset().y() / symbolSize, *symbolDD ) );
1342  if ( layerOffsetDD && *layerOffsetDD != *( scaledOffsetDD.data() ) )
1343  return QgsDataDefined();
1344  }
1345 
1346  return QgsDataDefined( *symbolDD );
1347 }
1348 
1350 {
1351  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1352  {
1353  if ( layer->type() != QgsSymbolV2::Marker )
1354  continue;
1355  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( layer );
1356  markerLayer->setScaleMethod( scaleMethod );
1357  }
1358 }
1359 
1361 {
1362  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1363  {
1364  if ( layer->type() != QgsSymbolV2::Marker )
1365  continue;
1366  const QgsMarkerSymbolLayerV2* markerLayer = static_cast<const QgsMarkerSymbolLayerV2*>( layer );
1367  // return scale method of the first symbol layer
1368  return markerLayer->scaleMethod();
1369  }
1370 
1371  return DEFAULT_SCALE_METHOD;
1372 }
1373 
1374 void QgsMarkerSymbolV2::renderPointUsingLayer( QgsMarkerSymbolLayerV2* layer, QPointF point, QgsSymbolV2RenderContext& context )
1375 {
1376  static QPointF nullPoint( 0, 0 );
1377 
1378  QgsPaintEffect* effect = layer->paintEffect();
1379  if ( effect && effect->enabled() )
1380  {
1381  QPainter* p = context.renderContext().painter();
1382  p->save();
1383  p->translate( point );
1384 
1385  effect->begin( context.renderContext() );
1386  layer->renderPoint( nullPoint, context );
1387  effect->end( context.renderContext() );
1388 
1389  p->restore();
1390  }
1391  else
1392  {
1393  layer->renderPoint( point, context );
1394  }
1395 }
1396 
1397 void QgsMarkerSymbolV2::renderPoint( QPointF point, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1398 {
1399  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1400 
1401  if ( layerIdx != -1 )
1402  {
1403  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1404  if ( symbolLayer )
1405  {
1406  if ( symbolLayer->type() == QgsSymbolV2::Marker )
1407  {
1408  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( symbolLayer );
1409  renderPointUsingLayer( markerLayer, point, symbolContext );
1410  }
1411  else
1412  renderUsingLayer( symbolLayer, symbolContext );
1413  }
1414  return;
1415  }
1416 
1417  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1418  {
1419  if ( symbolLayer->type() == QgsSymbolV2::Marker )
1420  {
1421  QgsMarkerSymbolLayerV2* markerLayer = static_cast<QgsMarkerSymbolLayerV2*>( symbolLayer );
1422  renderPointUsingLayer( markerLayer, point, symbolContext );
1423  }
1424  else
1425  renderUsingLayer( symbolLayer, symbolContext );
1426  }
1427 }
1428 
1429 QRectF QgsMarkerSymbolV2::bounds( QPointF point, QgsRenderContext& context, const QgsFeature& feature ) const
1430 {
1431  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, &feature, feature.fields(), mapUnitScale() );
1432 
1433  QRectF bound;
1434  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1435  {
1436  if ( layer->type() == QgsSymbolV2::Marker )
1437  {
1439  if ( bound.isNull() )
1440  bound = symbolLayer->bounds( point, symbolContext );
1441  else
1442  bound = bound.united( symbolLayer->bounds( point, symbolContext ) );
1443  }
1444  }
1445  return bound;
1446 }
1447 
1449 {
1450  QgsMarkerSymbolV2* cloneSymbol = new QgsMarkerSymbolV2( cloneLayers() );
1451  cloneSymbol->setAlpha( mAlpha );
1452  cloneSymbol->setLayer( mLayer );
1454  return cloneSymbol;
1455 }
1456 
1457 
1459 // LINE
1460 
1462  : QgsSymbolV2( Line, layers )
1463 {
1464  if ( mLayers.isEmpty() )
1466 }
1467 
1469 {
1470  double origWidth = width();
1471 
1472  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1473  {
1474  QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
1475 
1476  if ( lineLayer )
1477  {
1478  if ( qgsDoubleNear( lineLayer->width(), origWidth ) )
1479  {
1480  lineLayer->setWidth( w );
1481  }
1482  else if ( !qgsDoubleNear( origWidth, 0.0 ) )
1483  {
1484  // proportionally scale the width
1485  lineLayer->setWidth( lineLayer->width() * w / origWidth );
1486  }
1487  // also scale offset to maintain relative position
1488  if ( !qgsDoubleNear( origWidth, 0.0 ) && !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1489  lineLayer->setOffset( lineLayer->offset() * w / origWidth );
1490  }
1491  }
1492 }
1493 
1495 {
1496  double maxWidth = 0;
1497  if ( mLayers.isEmpty() )
1498  return maxWidth;
1499 
1500  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1501  {
1502  const QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1503  if ( lineLayer )
1504  {
1505  double width = lineLayer->width();
1506  if ( width > maxWidth )
1507  maxWidth = width;
1508  }
1509  }
1510  return maxWidth;
1511 }
1512 
1514 {
1515  const double symbolWidth = width();
1516 
1517  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1518  {
1519  QgsLineSymbolLayerV2* lineLayer = dynamic_cast<QgsLineSymbolLayerV2*>( layer );
1520 
1521  if ( lineLayer )
1522  {
1523  if ( dd.hasDefaultValues() )
1524  {
1525  lineLayer->removeDataDefinedProperty( "width" );
1526  lineLayer->removeDataDefinedProperty( "offset" );
1527  }
1528  else
1529  {
1530  if ( qgsDoubleNear( symbolWidth, 0.0 ) || qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1531  {
1532  lineLayer->setDataDefinedProperty( "width", new QgsDataDefined( dd ) );
1533  }
1534  else
1535  {
1536  lineLayer->setDataDefinedProperty( "width", scaleWholeSymbol( lineLayer->width() / symbolWidth, dd ) );
1537  }
1538 
1539  if ( !qgsDoubleNear( lineLayer->offset(), 0.0 ) )
1540  {
1541  lineLayer->setDataDefinedProperty( "offset", scaleWholeSymbol( lineLayer->offset() / symbolWidth, dd ) );
1542  }
1543  }
1544  }
1545  }
1546 }
1547 
1549 {
1550  const double symbolWidth = width();
1551 
1552  QgsDataDefined* symbolDD = nullptr;
1553 
1554  // find the base of the "en masse" pattern
1555  for ( QgsSymbolLayerV2List::const_iterator it = mLayers.begin(); it != mLayers.end(); ++it )
1556  {
1557  const QgsLineSymbolLayerV2* layer = dynamic_cast<const QgsLineSymbolLayerV2*>( *it );
1558  if ( layer && qgsDoubleNear( layer->width(), symbolWidth ) && layer->getDataDefinedProperty( "width" ) )
1559  {
1560  symbolDD = layer->getDataDefinedProperty( "width" );
1561  break;
1562  }
1563  }
1564 
1565  if ( !symbolDD )
1566  return QgsDataDefined();
1567 
1568  // check that all layers width expressions match the "en masse" pattern
1569  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1570  {
1571  if ( layer->type() != QgsSymbolV2::Line )
1572  continue;
1573  const QgsLineSymbolLayerV2* lineLayer = static_cast<const QgsLineSymbolLayerV2*>( layer );
1574 
1575  QgsDataDefined* layerWidthDD = lineLayer->getDataDefinedProperty( "width" );
1576  QgsDataDefined* layerOffsetDD = lineLayer->getDataDefinedProperty( "offset" );
1577 
1578  if ( qgsDoubleNear( lineLayer->width(), symbolWidth ) )
1579  {
1580  if ( !layerWidthDD || *layerWidthDD != *symbolDD )
1581  return QgsDataDefined();
1582  }
1583  else
1584  {
1585  if ( qgsDoubleNear( symbolWidth, 0.0 ) )
1586  return QgsDataDefined();
1587 
1588  QScopedPointer< QgsDataDefined > scaledDD( scaleWholeSymbol( lineLayer->width() / symbolWidth, *symbolDD ) );
1589  if ( !layerWidthDD || *layerWidthDD != *( scaledDD.data() ) )
1590  return QgsDataDefined();
1591  }
1592 
1593  QScopedPointer< QgsDataDefined > scaledOffsetDD( scaleWholeSymbol( lineLayer->offset() / symbolWidth, *symbolDD ) );
1594  if ( layerOffsetDD && *layerOffsetDD != *( scaledOffsetDD.data() ) )
1595  return QgsDataDefined();
1596  }
1597 
1598  return QgsDataDefined( *symbolDD );
1599 }
1600 
1601 void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1602 {
1603  //save old painter
1604  QPainter* renderPainter = context.painter();
1605  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1606 
1607  if ( layerIdx != -1 )
1608  {
1609  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1610  if ( symbolLayer )
1611  {
1612  if ( symbolLayer->type() == QgsSymbolV2::Line )
1613  {
1614  QgsLineSymbolLayerV2* lineLayer = static_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1615  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1616  }
1617  else
1618  renderUsingLayer( symbolLayer, symbolContext );
1619  }
1620  return;
1621  }
1622 
1623  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1624  {
1625  if ( symbolLayer->type() == QgsSymbolV2::Line )
1626  {
1627  QgsLineSymbolLayerV2* lineLayer = static_cast<QgsLineSymbolLayerV2*>( symbolLayer );
1628  renderPolylineUsingLayer( lineLayer, points, symbolContext );
1629  }
1630  else
1631  {
1632  renderUsingLayer( symbolLayer, symbolContext );
1633  }
1634  }
1635 
1636  context.setPainter( renderPainter );
1637 }
1638 
1639 void QgsLineSymbolV2::renderPolylineUsingLayer( QgsLineSymbolLayerV2 *layer, const QPolygonF &points, QgsSymbolV2RenderContext &context )
1640 {
1641  QgsPaintEffect* effect = layer->paintEffect();
1642  if ( effect && effect->enabled() )
1643  {
1644  QPainter* p = context.renderContext().painter();
1645  p->save();
1646  p->translate( points.boundingRect().topLeft() );
1647 
1648  effect->begin( context.renderContext() );
1649  layer->renderPolyline( points.translated( -points.boundingRect().topLeft() ), context );
1650  effect->end( context.renderContext() );
1651 
1652  p->restore();
1653  }
1654  else
1655  {
1656  layer->renderPolyline( points, context );
1657  }
1658 }
1659 
1660 
1662 {
1663  QgsLineSymbolV2* cloneSymbol = new QgsLineSymbolV2( cloneLayers() );
1664  cloneSymbol->setAlpha( mAlpha );
1665  cloneSymbol->setLayer( mLayer );
1667  return cloneSymbol;
1668 }
1669 
1671 // FILL
1672 
1674  : QgsSymbolV2( Fill, layers )
1675 {
1676  if ( mLayers.isEmpty() )
1678 }
1679 
1680 void QgsFillSymbolV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
1681 {
1682  QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1683 
1684  if ( layerIdx != -1 )
1685  {
1686  QgsSymbolLayerV2* symbolLayer = mLayers.value( layerIdx );
1687  if ( symbolLayer )
1688  {
1689  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1690  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1691  else
1692  renderUsingLayer( symbolLayer, symbolContext );
1693  }
1694  return;
1695  }
1696 
1697  Q_FOREACH ( QgsSymbolLayerV2* symbolLayer, mLayers )
1698  {
1699  if ( symbolLayer->type() == Fill || symbolLayer->type() == Line )
1700  renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
1701  else
1702  renderUsingLayer( symbolLayer, symbolContext );
1703  }
1704 }
1705 
1706 void QgsFillSymbolV2::renderPolygonUsingLayer( QgsSymbolLayerV2* layer, const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
1707 {
1708  QgsSymbolV2::SymbolType layertype = layer->type();
1709 
1710  QgsPaintEffect* effect = layer->paintEffect();
1711  if ( effect && effect->enabled() )
1712  {
1713  QRectF bounds = polygonBounds( points, rings );
1714  QList<QPolygonF>* translatedRings = translateRings( rings, -bounds.left(), -bounds.top() );
1715 
1716  QPainter* p = context.renderContext().painter();
1717  p->save();
1718  p->translate( bounds.topLeft() );
1719 
1720  effect->begin( context.renderContext() );
1721  if ( layertype == QgsSymbolV2::Fill )
1722  {
1723  ( static_cast<QgsFillSymbolLayerV2*>( layer ) )->renderPolygon( points.translated( -bounds.topLeft() ), translatedRings, context );
1724  }
1725  else if ( layertype == QgsSymbolV2::Line )
1726  {
1727  ( static_cast<QgsLineSymbolLayerV2*>( layer ) )->renderPolygonOutline( points.translated( -bounds.topLeft() ), translatedRings, context );
1728  }
1729  delete translatedRings;
1730 
1731  effect->end( context.renderContext() );
1732  p->restore();
1733  }
1734  else
1735  {
1736  if ( layertype == QgsSymbolV2::Fill )
1737  {
1738  ( static_cast<QgsFillSymbolLayerV2*>( layer ) )->renderPolygon( points, rings, context );
1739  }
1740  else if ( layertype == QgsSymbolV2::Line )
1741  {
1742  ( static_cast<QgsLineSymbolLayerV2*>( layer ) )->renderPolygonOutline( points, rings, context );
1743  }
1744  }
1745 }
1746 
1747 QRectF QgsFillSymbolV2::polygonBounds( const QPolygonF& points, const QList<QPolygonF>* rings ) const
1748 {
1749  QRectF bounds = points.boundingRect();
1750  if ( rings )
1751  {
1753  for ( ; it != rings->constEnd(); ++it )
1754  {
1755  bounds = bounds.united(( *it ).boundingRect() );
1756  }
1757  }
1758  return bounds;
1759 }
1760 
1761 QList<QPolygonF>* QgsFillSymbolV2::translateRings( const QList<QPolygonF>* rings, double dx, double dy ) const
1762 {
1763  if ( !rings )
1764  return nullptr;
1765 
1766  QList<QPolygonF>* translatedRings = new QList<QPolygonF>;
1768  for ( ; it != rings->constEnd(); ++it )
1769  {
1770  translatedRings->append(( *it ).translated( dx, dy ) );
1771  }
1772  return translatedRings;
1773 }
1774 
1776 {
1777  QgsFillSymbolV2* cloneSymbol = new QgsFillSymbolV2( cloneLayers() );
1778  cloneSymbol->setAlpha( mAlpha );
1779  cloneSymbol->setLayer( mLayer );
1781  return cloneSymbol;
1782 }
1783 
1785 {
1786  Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
1787  {
1788  if ( layer->type() != QgsSymbolV2::Fill )
1789  continue;
1790 
1791  QgsFillSymbolLayerV2* fillLayer = static_cast<QgsFillSymbolLayerV2*>( layer );
1792 
1793  if ( fillLayer )
1794  fillLayer->setAngle( angle );
1795  }
1796 }
1797 
1798 
QgsDataDefined dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
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 contains(const QgsRectangle &rect) const
return true when rectangle contains other rectangle
bool deleteSymbolLayer(int index)
delete symbol layer at specified index
Single variable definition for use within a QgsExpressionContextScope.
static unsigned index
void setViewBox(const QRect &viewBox)
A rectangle specified with double values.
Definition: qgsrectangle.h:35
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
static QgsMarkerSymbolV2 * createSimple(const QgsStringMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
void setClipFeaturesToExtent(bool clipFeaturesToExtent)
Sets whether features drawn by the symbol should be clipped to the render context&#39;s extent...
Definition: qgssymbolv2.h:216
int numGeometries() const
Returns the number of geometries within the collection.
double angle() const
Returns the marker angle for the whole symbol.
OutputUnit
The unit of the output.
Definition: qgssymbolv2.h:62
virtual void setOutputUnit(QgsSymbolV2::OutputUnit unit)
QString readEntry(const QString &scope, const QString &key, const QString &def=QString::null, bool *ok=nullptr) const
QGis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
int width() const
QString dump() const
bool mClipFeaturesToExtent
Definition: qgssymbolv2.h:326
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 QgsLineSymbolV2 * clone() const override
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:328
virtual QRectF bounds(QPointF point, QgsSymbolV2RenderContext &context)
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
QgsSymbolV2::OutputUnit sizeUnit() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setDataDefinedSize(const QgsDataDefined &dd)
Set data defined size for whole symbol (including all symbol layers).
bool save(const QString &fileName, const char *format, int quality) const
static QString encodeColor(const QColor &color)
static QString encodeSldUom(QgsSymbolV2::OutputUnit unit, double *scaleFactor)
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
const QgsMapUnitScale & sizeMapUnitScale() const
static QgsFillSymbolV2 * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
const T & at(int i) const
VertexMarkerType
Editing vertex markers.
void setOffset(QPointF offset)
void removeAt(int i)
QPolygonF translated(qreal dx, qreal dy) const
Base class for visual effects which can be applied to QPicture drawings.
bool changeSymbolLayer(int index, QgsSymbolLayerV2 *layer)
delete layer at specified index and set a new one
QgsSymbolV2RenderContext(QgsRenderContext &c, QgsSymbolV2::OutputUnit u, qreal alpha=1.0, bool selected=false, int renderHints=0, const QgsFeature *f=nullptr, const QgsFields *fields=nullptr, const QgsMapUnitScale &mapUnitScale=QgsMapUnitScale())
ScaleMethod scaleMethod()
virtual bool hasDataDefinedProperties() const
Checks whether the layer has any associated data defined properties.
void save()
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
static void _getPoint(QPointF &pt, QgsRenderContext &context, const QgsPointV2 *point)
Creates a point in screen coordinates from a QgsPointV2 in map coordinates.
Definition: qgssymbolv2.h:262
Abstract base class for all geometries.
Container of fields for a vector layer.
Definition: qgsfield.h:187
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
SymbolType type() const
Definition: qgssymbolv2.h:104
qreal top() const
Line symbol.
Definition: qgssymbolv2.h:79
T takeAt(int i)
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
double size() const
Returns the size for the whole symbol, which is the maximum size of all marker symbol layers in the s...
QgsSymbolLayerV2List cloneLayers() const
Retrieve a cloned list of all layers that make up this symbol.
Multi point geometry collection.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
double z() const
Returns the point&#39;s z-coordinate.
Definition: qgspointv2.h:80
void drawLine(const QLineF &line)
void renderFeature(const QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false, int currentVertexMarkerType=0, int currentVertexMarkerSize=0)
Render a feature.
virtual QgsDataDefined * getDataDefinedProperty(const QString &property) const
Returns the data defined property corresponding to the specified property key.
double y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
void setExpressionContextScope(QgsExpressionContextScope *contextScope)
Set an expression scope for this symbol.
SymbolType mType
Definition: qgssymbolv2.h:319
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
int wkbSize() const
Returns the size of the WKB in asWkb().
virtual void removeDataDefinedProperty(const QString &property)
Removes a data defined property from the layer.
void drawPreviewIcon(QPainter *painter, QSize size, QgsRenderContext *customContext=nullptr)
Draw icon of the symbol that occupyies area given by size using the painter.
qreal left() const
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:285
void setSizeUnit(OutputUnit unit)
Sets the size units for the whole symbol (including all symbol layers).
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
static double pixelSizeScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns scale factor painter units -> pixel dimensions.
void setWidth(double width)
QgsDataDefined * scaleWholeSymbol(double scaleFactor, const QgsDataDefined &dd)
Definition: qgssymbolv2.cpp: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).
int renderHints() const
Definition: qgssymbolv2.h:206
void setMapUnitScale(const QgsMapUnitScale &scale)
void setAngle(double angle)
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const
Writes the SLD element following the SLD v1.1 specs.
virtual void startRender(QgsSymbolV2RenderContext &context)=0
bool useExpression() const
Returns if the field or the expression part is active.
T value(int i) const
QColor fromHsv(int h, int s, int v, int a)
void transformInPlace(double &x, double &y) const
Transform device coordinates to map coordinates.
T * data()
void drawRect(const QRectF &rectangle)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
void setUseExpression(bool use)
Controls if the field or the expression part is active.
void setColor(const QColor &color)
virtual double width() const
QgsDataDefined dataDefinedWidth() const
Returns data defined size for whole symbol (including all symbol layers).
Mixed units in symbol layers.
Definition: qgssymbolv2.h:66
static QgsRenderContext createRenderContext(QPainter *p)
Creates a render context for a pixel based device.
QString number(int n, int base)
QgsSymbolLayerV2List mLayers
Definition: qgssymbolv2.h:320
int count(const T &value) const
qreal x() const
qreal y() const
const QgsAbstractGeometryV2 * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
void append(const T &value)
const QgsFields * fields() const
Returns the field map associated with the feature.
Definition: qgsfeature.cpp:188
void setOffset(double offset)
bool appendSymbolLayer(QgsSymbolLayerV2 *layer)
Append symbol layer at the end of the list Ownership will be transferred.
#define FALLTHROUGH
Definition: qgis.h:439
void resize(int size)
QRectF bounds(QPointF point, QgsRenderContext &context, const QgsFeature &feature=QgsFeature()) const
Returns the approximate bounding box of the marker symbol, which includes the bounding box of all sym...
bool empty() const
void startRender(QgsRenderContext &context, const QgsFields *fields=nullptr)
const QgsVectorLayer * layer() const
Definition: qgssymbolv2.h:242
void fill(uint pixelValue)
double outputLineWidth(double width) const
static double convertToPainterUnits(const QgsRenderContext &c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale())
Converts a size from the specied units to painter units.
void setLineAngle(double lineAngle)
Sets the line angle modification for the symbol&#39;s angle.
Utility class for identifying a unique vertex within a geometry.
const QgsRectangle & extent() const
static QgsLineSymbolV2 * createSimple(const QgsStringMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties. ...
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
static bool isCurvedType(Type type)
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h: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 setRenderingPass(int renderingPass)
#define DEFAULT_SCALE_METHOD
void setLayer(const QgsVectorLayer *layer)
Definition: qgssymbolv2.h:241
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:207
QString expressionString() const
Returns the expression string of this QgsDataDefined.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:34
QString qgsDoubleToString(double a, int precision=17)
Definition: qgis.h:274
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)
void setAngle(double angle)
Sets the angle for the whole symbol.
void setSizeUnit(QgsSymbolV2::OutputUnit unit)
const QgsCoordinateTransform * coordinateTransform() const
Draw bounds of symbols (for debugging/testing)
OutputUnit sizeUnit() const
Returns the size units for the whole symbol (including all symbol layers).
void setBrush(const QBrush &brush)
void setPainter(QPainter *p)
void setSize(double size)
Sets the size for the whole symbol.
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
qreal mAlpha
Symbol opacity (in the range 0 - 1)
Definition: qgssymbolv2.h:323
virtual int partCount() const =0
Returns count of parts contained in the geometry.
QgsSymbolV2RenderContext & operator=(const QgsSymbolV2RenderContext &)
bool enabled() const
Returns whether the effect is enabled.
QRectF united(const QRectF &rectangle) const
virtual void renderPolygonOutline(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
QgsSymbolV2(SymbolType type, const QgsSymbolLayerV2List &layers)
Definition: qgssymbolv2.cpp:84
virtual bool nextVertex(QgsVertexId &id, QgsPointV2 &vertex) const =0
Returns next vertex id and coordinates.
bool hasDataDefinedProperties() const
Returns whether the symbol utilises any data defined properties.
QgsDataDefined * rotateWholeSymbol(double additionalRotation, const QgsDataDefined &dd)
Definition: qgssymbolv2.cpp:49
Single scope for storing variables and functions for use within a QgsExpressionContext.
QgsMapUnitScale mapUnitScale() const
static void drawVertexMarker(double x, double y, QPainter &p, QgsVectorLayer::VertexMarkerType type, int vertexSize)
Draws a vertex symbol at (screen) coordinates x, y.
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:201
void setLineAngle(double lineAngle)
Sets the line angle modification for the symbol&#39;s angle.
double outputPixelSize(double size) const
T * data() const
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
iterator end()
QString toLower() const
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
virtual ~QgsSymbolV2()
virtual void renderPolyline(const QPolygonF &points, QgsSymbolV2RenderContext &context)=0
QgsSymbolV2 * symbol(const QString &name)
return a NEW copy of symbol
Definition: qgsstylev2.cpp:164
virtual QgsFillSymbolV2 * clone() const override
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:202
QImage bigSymbolPreviewImage(QgsExpressionContext *expressionContext=nullptr)
Returns a large (roughly 100x100 pixel) preview image for the symbol.
void setFileName(const QString &fileName)
void exportImage(const QString &path, const QString &format, QSize size)
export symbol as image format. PNG and SVG supported
QgsExpressionContext & expressionContext()
Gets the expression context.
QString field() const
Get the field which this QgsDataDefined represents.
bool clipFeaturesToExtent() const
Returns whether features drawn by the symbol will be clipped to the render context&#39;s extent...
Definition: qgssymbolv2.h:226
void renderUsingLayer(QgsSymbolLayerV2 *layer, QgsSymbolV2RenderContext &context)
Renders a context using a particular symbol layer without passing in a geometry.
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:187
SymbolType
Type of the symbol.
Definition: qgssymbolv2.h:76
void restore()
QgsSymbolV2::OutputUnit outputUnit() const
void setDataDefinedWidth(const QgsDataDefined &dd)
Set data defined width for whole symbol (including all symbol layers).
Hybrid symbol.
Definition: qgssymbolv2.h:81
QgsExpressionContextScope * expressionContextScope()
This scope is always available when a symbol of this type is being rendered.
int remaining() const
Definition: qgswkbptr.h:121
Contains information about the context of a rendering operation.
QgsMapUnitScale sizeMapUnitScale() const
Returns the size map unit scale for the whole symbol.
QgsSymbolV2::ScaleMethod scaleMethod() const
QRectF boundingRect() const
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
QPainter * painter()
const QgsMapToPixel & mapToPixel() const
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.
QgsDataDefined dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
void insert(int i, const T &value)
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
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.
QColor color() const
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:346
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
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
qreal & rx()
qreal & ry()
Class for doing transforms between two map coordinate systems.
virtual QgsAbstractGeometryV2 * segmentize() const
Returns a version of the geometry without curves.
void renderPoint(QPointF point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
void translate(const QPointF &offset)
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:192
virtual void setColor(const QColor &color)
The fill color.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:366
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:197
QgsSymbolLayerV2 * takeSymbolLayer(int index)
Remove symbol layer from the list and return pointer to it.
QgsWKBTypes::Type readHeader() const
Definition: qgswkbptr.cpp:37
double width() const
void transformPolygon(QPolygonF &poly, TransformDirection direction=ForwardTransform) const
QgsSymbolLayerV2 * symbolLayer(int layer)
Returns a specific symbol layers contained in the symbol.
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
const_iterator constEnd() const
virtual void drawPreviewIcon(QgsSymbolV2RenderContext &context, QSize size)=0
const_iterator constBegin() const
QSet< QString > usedAttributes() const
Return a list of attributes required to render this feature.
static QString displayString(Type type)
Returns a display string type for a WKB type, eg the geometry name used in WKT geometry representatio...
Definition: qgswkbtypes.cpp:48
Draw map such that there are no problems between adjacent tiles.
bool hasDefaultValues() const
Returns whether the data defined container is set to all the default values, ie, disabled, with empty expression and no assigned field.
static void trimPolygon(QPolygonF &pts, const QgsRectangle &clipRect)
Definition: qgsclipper.h:181
static const QString EXPR_GEOMETRY_PART_NUM
Inbuilt variable name for geometry part number variable.
void setSize(double size)
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) const
int size() const
void setAngle(double angle)
static const QString EXPR_GEOMETRY_PART_COUNT
Inbuilt variable name for geometry part count variable.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
virtual void end(QgsRenderContext &context)
Ends interception of paint operations to a render context, and draws the result to the render context...
QgsSymbolV2::SymbolType type() const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbolV2 *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbolV2 to an expression context.
virtual void stopRender(QgsSymbolV2RenderContext &context)=0
virtual bool isCompatibleWithSymbol(QgsSymbolV2 *symbol) const
Returns if the layer can be used below the specified symbol.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
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:203
iterator begin()
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
void setGeometry(const QgsAbstractGeometryV2 *geometry)
Sets pointer to original (unsegmentized) geometry.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
virtual void begin(QgsRenderContext &context)
Begins intercepting paint operations to a render context.
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
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:212
bool isLocked() const
int mRenderHints
Definition: qgssymbolv2.h:325
virtual Q_DECL_DEPRECATED void setDataDefinedProperty(const QString &property, const QString &expressionString)
Sets a data defined expression for a property.