QGIS API Documentation  2.14.11-Essen
qgsfillsymbollayerv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfillsymbollayerv2.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 "qgsfillsymbollayerv2.h"
17 #include "qgslinesymbollayerv2.h"
18 #include "qgsmarkersymbollayerv2.h"
19 #include "qgssymbollayerv2utils.h"
20 #include "qgsdxfexport.h"
21 #include "qgsexpression.h"
22 #include "qgsrendercontext.h"
23 #include "qgsproject.h"
24 #include "qgssvgcache.h"
25 #include "qgslogger.h"
26 #include "qgsvectorcolorrampv2.h"
27 #include "qgsunittypes.h"
28 
29 #include <QPainter>
30 #include <QFile>
31 #include <QSvgRenderer>
32 #include <QDomDocument>
33 #include <QDomElement>
34 
35 QgsSimpleFillSymbolLayerV2::QgsSimpleFillSymbolLayerV2( const QColor& color, Qt::BrushStyle style, const QColor& borderColor, Qt::PenStyle borderStyle, double borderWidth,
36  Qt::PenJoinStyle penJoinStyle )
37  : mBrushStyle( style )
38  , mBorderColor( borderColor )
39  , mBorderStyle( borderStyle )
40  , mBorderWidth( borderWidth )
41  , mBorderWidthUnit( QgsSymbolV2::MM )
42  , mPenJoinStyle( penJoinStyle )
43  , mOffsetUnit( QgsSymbolV2::MM )
44 {
45  mColor = color;
46 }
47 
49 {
50  mBorderWidthUnit = unit;
51  mOffsetUnit = unit;
52 }
53 
55 {
57  if ( mOffsetUnit != unit )
58  {
59  return QgsSymbolV2::Mixed;
60  }
61  return unit;
62 }
63 
65 {
67  mOffsetMapUnitScale = scale;
68 }
69 
71 {
73  {
75  }
76  return QgsMapUnitScale();
77 }
78 
79 void QgsSimpleFillSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QBrush& brush, QPen& pen, QPen& selPen )
80 {
81  if ( !hasDataDefinedProperties() )
82  return; // shortcut
83 
84  bool ok;
85 
87  {
90  if ( ok )
92  }
94  {
97  if ( ok )
99  }
101  {
104  if ( ok )
106  }
108  {
112  pen.setWidthF( width );
113  selPen.setWidthF( width );
114  }
116  {
119  if ( ok )
120  {
123  }
124  }
126  {
129  if ( ok )
130  {
133  }
134  }
135 }
136 
137 
139 {
141  Qt::BrushStyle style = DEFAULT_SIMPLEFILL_STYLE;
145  Qt::PenJoinStyle penJoinStyle = DEFAULT_SIMPLEFILL_JOINSTYLE;
146  QPointF offset;
147 
148  if ( props.contains( "color" ) )
149  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
150  if ( props.contains( "style" ) )
151  style = QgsSymbolLayerV2Utils::decodeBrushStyle( props["style"] );
152  if ( props.contains( "color_border" ) )
153  {
154  //pre 2.5 projects used "color_border"
155  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
156  }
157  else if ( props.contains( "outline_color" ) )
158  {
159  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["outline_color"] );
160  }
161  else if ( props.contains( "line_color" ) )
162  {
163  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["line_color"] );
164  }
165 
166  if ( props.contains( "style_border" ) )
167  {
168  //pre 2.5 projects used "style_border"
169  borderStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["style_border"] );
170  }
171  else if ( props.contains( "outline_style" ) )
172  {
173  borderStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["outline_style"] );
174  }
175  else if ( props.contains( "line_style" ) )
176  {
177  borderStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["line_style"] );
178  }
179  if ( props.contains( "width_border" ) )
180  {
181  //pre 2.5 projects used "width_border"
182  borderWidth = props["width_border"].toDouble();
183  }
184  else if ( props.contains( "outline_width" ) )
185  {
186  borderWidth = props["outline_width"].toDouble();
187  }
188  else if ( props.contains( "line_width" ) )
189  {
190  borderWidth = props["line_width"].toDouble();
191  }
192  if ( props.contains( "offset" ) )
193  offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
194  if ( props.contains( "joinstyle" ) )
195  penJoinStyle = QgsSymbolLayerV2Utils::decodePenJoinStyle( props["joinstyle"] );
196 
197  QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, style, borderColor, borderStyle, borderWidth, penJoinStyle );
198  sl->setOffset( offset );
199  if ( props.contains( "border_width_unit" ) )
200  {
201  sl->setBorderWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["border_width_unit"] ) );
202  }
203  else if ( props.contains( "outline_width_unit" ) )
204  {
205  sl->setBorderWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
206  }
207  else if ( props.contains( "line_width_unit" ) )
208  {
209  sl->setBorderWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["line_width_unit"] ) );
210  }
211  if ( props.contains( "offset_unit" ) )
212  sl->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
213 
214  if ( props.contains( "border_width_map_unit_scale" ) )
215  sl->setBorderWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["border_width_map_unit_scale"] ) );
216  if ( props.contains( "offset_map_unit_scale" ) )
217  sl->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
218 
219  sl->restoreDataDefinedProperties( props );
220 
221  return sl;
222 }
223 
224 
226 {
227  return "SimpleFill";
228 }
229 
231 {
233  fillColor.setAlphaF( context.alpha() * mColor.alphaF() );
234  mBrush = QBrush( fillColor, mBrushStyle );
235 
236  // scale brush content for printout
237  double rasterScaleFactor = context.renderContext().rasterScaleFactor();
238  if ( rasterScaleFactor != 1.0 )
239  {
240  mBrush.setMatrix( QMatrix().scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor ) );
241  }
242 
243  QColor selColor = context.renderContext().selectionColor();
244  QColor selPenColor = selColor == mColor ? selColor : mBorderColor;
245  if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() );
246  mSelBrush = QBrush( selColor );
247  // N.B. unless a "selection line color" is implemented in addition to the "selection color" option
248  // this would mean symbols with "no fill" look the same whether or not they are selected
249  if ( selectFillStyle )
251 
253  borderColor.setAlphaF( context.alpha() * mBorderColor.alphaF() );
254  mPen = QPen( borderColor );
255  mSelPen = QPen( selPenColor );
259  prepareExpressions( context );
260 }
261 
263 {
264  Q_UNUSED( context );
265 }
266 
268 {
269  QPainter* p = context.renderContext().painter();
270  if ( !p )
271  {
272  return;
273  }
274 
275  applyDataDefinedSymbology( context, mBrush, mPen, mSelPen );
276 
277  p->setBrush( context.selected() ? mSelBrush : mBrush );
278  p->setPen( context.selected() ? mSelPen : mPen );
279 
280  QPointF offset;
281  if ( !mOffset.isNull() )
282  {
285  p->translate( offset );
286  }
287 
288  _renderPolygon( p, points, rings, context );
289 
290  if ( !mOffset.isNull() )
291  {
292  p->translate( -offset );
293  }
294 }
295 
297 {
298  QgsStringMap map;
299  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
301  map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
302  map["outline_style"] = QgsSymbolLayerV2Utils::encodePenStyle( mBorderStyle );
303  map["outline_width"] = QString::number( mBorderWidth );
304  map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mBorderWidthUnit );
305  map["border_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mBorderWidthMapUnitScale );
307  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
309  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
311  return map;
312 }
313 
315 {
317  sl->setOffset( mOffset );
318  sl->setOffsetUnit( mOffsetUnit );
323  copyPaintEffect( sl );
324  return sl;
325 }
326 
327 void QgsSimpleFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const
328 {
329  if ( mBrushStyle == Qt::NoBrush && mBorderStyle == Qt::NoPen )
330  return;
331 
332  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
333  if ( !props.value( "uom", "" ).isEmpty() )
334  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
335  element.appendChild( symbolizerElem );
336 
337  // <Geometry>
338  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
339 
340  if ( mBrushStyle != Qt::NoBrush )
341  {
342  // <Fill>
343  QDomElement fillElem = doc.createElement( "se:Fill" );
344  symbolizerElem.appendChild( fillElem );
346  }
347 
348  if ( mBorderStyle != Qt::NoPen )
349  {
350  // <Stroke>
351  QDomElement strokeElem = doc.createElement( "se:Stroke" );
352  symbolizerElem.appendChild( strokeElem );
354  QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, mBorderStyle, borderWidth, borderWidth, &mPenJoinStyle );
355  }
356 
357  // <se:Displacement>
359  QgsSymbolLayerV2Utils::createDisplacementElement( doc, symbolizerElem, offset );
360 }
361 
362 QString QgsSimpleFillSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
363 {
364  //brush
365  QString symbolStyle;
367  symbolStyle.append( ';' );
368  //pen
369  symbolStyle.append( QgsSymbolLayerV2Utils::ogrFeatureStylePen( mBorderWidth, mmScaleFactor, mapUnitScaleFactor, mBorderColor, mPenJoinStyle ) );
370  return symbolStyle;
371 }
372 
374 {
375  QgsDebugMsg( "Entered." );
376 
378  Qt::BrushStyle fillStyle;
379  Qt::PenStyle borderStyle;
380  double borderWidth;
381 
382  QDomElement fillElem = element.firstChildElement( "Fill" );
383  QgsSymbolLayerV2Utils::fillFromSld( fillElem, fillStyle, color );
384 
385  QDomElement strokeElem = element.firstChildElement( "Stroke" );
386  QgsSymbolLayerV2Utils::lineFromSld( strokeElem, borderStyle, borderColor, borderWidth );
387 
388  QPointF offset;
390 
391  QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, fillStyle, borderColor, borderStyle, borderWidth );
392  sl->setOffset( offset );
393  return sl;
394 }
395 
397 {
398  double penBleed = mBorderStyle == Qt::NoPen ? 0 : ( mBorderWidth / 2.0 );
399  double offsetBleed = mOffset.x() > mOffset.y() ? mOffset.x() : mOffset.y();
400  return penBleed + offsetBleed;
401 }
402 
404 {
405  double width = mBorderWidth;
407  {
410  }
412 }
413 
415 {
417  {
418  bool ok;
421  if ( ok )
422  return QgsSymbolLayerV2Utils::decodeColor( color );
423  }
424  return mBorderColor;
425 }
426 
428 {
429  double angle = mAngle;
431  {
432  context.setOriginalValueVariable( mAngle );
434  }
435  return angle;
436 }
437 
439 {
440  return mBorderStyle;
441 }
442 
444 {
446  {
447  bool ok;
450  if ( ok )
451  return QgsSymbolLayerV2Utils::decodeColor( color );
452  }
453  return mColor;
454 }
455 
457 {
458  return mBrushStyle;
459 }
460 
461 //QgsGradientFillSymbolLayer
462 
464  GradientColorType colorType, GradientType gradientType,
465  GradientCoordinateMode coordinateMode, GradientSpread spread )
466  : mGradientColorType( colorType )
467  , mGradientRamp( nullptr )
468  , mGradientType( gradientType )
469  , mCoordinateMode( coordinateMode )
470  , mGradientSpread( spread )
471  , mReferencePoint1( QPointF( 0.5, 0 ) )
472  , mReferencePoint1IsCentroid( false )
473  , mReferencePoint2( QPointF( 0.5, 1 ) )
474  , mReferencePoint2IsCentroid( false )
475  , mOffsetUnit( QgsSymbolV2::MM )
476 {
477  mColor = color;
478  mColor2 = color2;
479 }
480 
482 {
483  delete mGradientRamp;
484 }
485 
487 {
488  //default to a two-color, linear gradient with feature mode and pad spreading
493  //default to gradient from the default fill color to white
495  QPointF referencePoint1 = QPointF( 0.5, 0 );
496  bool refPoint1IsCentroid = false;
497  QPointF referencePoint2 = QPointF( 0.5, 1 );
498  bool refPoint2IsCentroid = false;
499  double angle = 0;
500  QPointF offset;
501 
502  //update gradient properties from props
503  if ( props.contains( "type" ) )
504  type = static_cast< GradientType >( props["type"].toInt() );
505  if ( props.contains( "coordinate_mode" ) )
506  coordinateMode = static_cast< GradientCoordinateMode >( props["coordinate_mode"].toInt() );
507  if ( props.contains( "spread" ) )
508  gradientSpread = static_cast< GradientSpread >( props["spread"].toInt() );
509  if ( props.contains( "color_type" ) )
510  colorType = static_cast< GradientColorType >( props["color_type"].toInt() );
511  if ( props.contains( "gradient_color" ) )
512  {
513  //pre 2.5 projects used "gradient_color"
514  color = QgsSymbolLayerV2Utils::decodeColor( props["gradient_color"] );
515  }
516  else if ( props.contains( "color" ) )
517  {
518  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
519  }
520  if ( props.contains( "gradient_color2" ) )
521  {
522  color2 = QgsSymbolLayerV2Utils::decodeColor( props["gradient_color2"] );
523  }
524 
525  if ( props.contains( "reference_point1" ) )
526  referencePoint1 = QgsSymbolLayerV2Utils::decodePoint( props["reference_point1"] );
527  if ( props.contains( "reference_point1_iscentroid" ) )
528  refPoint1IsCentroid = props["reference_point1_iscentroid"].toInt();
529  if ( props.contains( "reference_point2" ) )
530  referencePoint2 = QgsSymbolLayerV2Utils::decodePoint( props["reference_point2"] );
531  if ( props.contains( "reference_point2_iscentroid" ) )
532  refPoint2IsCentroid = props["reference_point2_iscentroid"].toInt();
533  if ( props.contains( "angle" ) )
534  angle = props["angle"].toDouble();
535 
536  if ( props.contains( "offset" ) )
537  offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
538 
539  //attempt to create color ramp from props
541 
542  //create a new gradient fill layer with desired properties
543  QgsGradientFillSymbolLayerV2* sl = new QgsGradientFillSymbolLayerV2( color, color2, colorType, type, coordinateMode, gradientSpread );
544  sl->setOffset( offset );
545  if ( props.contains( "offset_unit" ) )
546  sl->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
547  if ( props.contains( "offset_map_unit_scale" ) )
548  sl->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
549  sl->setReferencePoint1( referencePoint1 );
550  sl->setReferencePoint1IsCentroid( refPoint1IsCentroid );
551  sl->setReferencePoint2( referencePoint2 );
552  sl->setReferencePoint2IsCentroid( refPoint2IsCentroid );
553  sl->setAngle( angle );
554  if ( gradientRamp )
555  sl->setColorRamp( gradientRamp );
556 
557  sl->restoreDataDefinedProperties( props );
558 
559  return sl;
560 }
561 
563 {
564  delete mGradientRamp;
565  mGradientRamp = ramp;
566 }
567 
569 {
570  return "GradientFill";
571 }
572 
573 void QgsGradientFillSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, const QPolygonF& points )
574 {
576  {
577  //shortcut
580  return;
581  }
582 
583  bool ok;
584 
585  //first gradient color
586  QColor color = mColor;
588  {
591  if ( ok )
592  color = QgsSymbolLayerV2Utils::decodeColor( colorString );
593  }
594 
595  //second gradient color
598  {
601  if ( ok )
602  color2 = QgsSymbolLayerV2Utils::decodeColor( colorString );
603  }
604 
605  //gradient rotation angle
606  double angle = mAngle;
608  {
609  context.setOriginalValueVariable( mAngle );
611  }
612 
613  //gradient type
616  {
618  if ( ok )
619  {
620  if ( currentType == QObject::tr( "linear" ) )
621  {
623  }
624  else if ( currentType == QObject::tr( "radial" ) )
625  {
627  }
628  else if ( currentType == QObject::tr( "conical" ) )
629  {
631  }
632  }
633  }
634 
635  //coordinate mode
638  {
640  if ( ok )
641  {
642  if ( currentCoordMode == QObject::tr( "feature" ) )
643  {
644  coordinateMode = QgsGradientFillSymbolLayerV2::Feature;
645  }
646  else if ( currentCoordMode == QObject::tr( "viewport" ) )
647  {
649  }
650  }
651  }
652 
653  //gradient spread
656  {
658  if ( ok )
659  {
660  if ( currentSpread == QObject::tr( "pad" ) )
661  {
663  }
664  else if ( currentSpread == QObject::tr( "repeat" ) )
665  {
667  }
668  else if ( currentSpread == QObject::tr( "reflect" ) )
669  {
671  }
672  }
673  }
674 
675  //reference point 1 x & y
676  double refPoint1X = mReferencePoint1.x();
678  {
679  context.setOriginalValueVariable( refPoint1X );
680  refPoint1X = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE1_X, context, refPoint1X ).toDouble();
681  }
682  double refPoint1Y = mReferencePoint1.y();
684  {
685  context.setOriginalValueVariable( refPoint1Y );
686  refPoint1Y = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE1_Y, context, refPoint1Y ).toDouble();
687  }
688  bool refPoint1IsCentroid = mReferencePoint1IsCentroid;
690  {
691  context.setOriginalValueVariable( refPoint1IsCentroid );
692  refPoint1IsCentroid = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE1_ISCENTROID, context, refPoint1IsCentroid ).toBool();
693  }
694 
695  //reference point 2 x & y
696  double refPoint2X = mReferencePoint2.x();
698  {
699  context.setOriginalValueVariable( refPoint2X );
700  refPoint2X = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE2_X, context, refPoint2X ).toDouble();
701  }
702  double refPoint2Y = mReferencePoint2.y();
704  {
705  context.setOriginalValueVariable( refPoint2Y );
706  refPoint2Y = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE2_Y, context, refPoint2Y ).toDouble();
707  }
708  bool refPoint2IsCentroid = mReferencePoint2IsCentroid;
710  {
711  context.setOriginalValueVariable( refPoint2IsCentroid );
712  refPoint2IsCentroid = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE2_ISCENTROID, context, refPoint2IsCentroid ).toBool();
713  }
714 
715  if ( refPoint1IsCentroid || refPoint2IsCentroid )
716  {
717  //either the gradient is starting or ending at a centroid, so calculate it
718  QPointF centroid = QgsSymbolLayerV2Utils::polygonCentroid( points );
719  //centroid coordinates need to be scaled to a range [0, 1] relative to polygon bounds
720  QRectF bbox = points.boundingRect();
721  double centroidX = ( centroid.x() - bbox.left() ) / bbox.width();
722  double centroidY = ( centroid.y() - bbox.top() ) / bbox.height();
723 
724  if ( refPoint1IsCentroid )
725  {
726  refPoint1X = centroidX;
727  refPoint1Y = centroidY;
728  }
729  if ( refPoint2IsCentroid )
730  {
731  refPoint2X = centroidX;
732  refPoint2Y = centroidY;
733  }
734  }
735 
736  //update gradient with data defined values
737  applyGradient( context, mBrush, color, color2, mGradientColorType, mGradientRamp, gradientType, coordinateMode,
738  spread, QPointF( refPoint1X, refPoint1Y ), QPointF( refPoint2X, refPoint2Y ), angle );
739 }
740 
741 QPointF QgsGradientFillSymbolLayerV2::rotateReferencePoint( QPointF refPoint, double angle )
742 {
743  //rotate a reference point by a specified angle around the point (0.5, 0.5)
744 
745  //create a line from the centrepoint of a rectangle bounded by (0, 0) and (1, 1) to the reference point
746  QLineF refLine = QLineF( QPointF( 0.5, 0.5 ), refPoint );
747  //rotate this line by the current rotation angle
748  refLine.setAngle( refLine.angle() + angle );
749  //get new end point of line
750  QPointF rotatedReferencePoint = refLine.p2();
751  //make sure coords of new end point is within [0, 1]
752  if ( rotatedReferencePoint.x() > 1 )
753  rotatedReferencePoint.setX( 1 );
754  if ( rotatedReferencePoint.x() < 0 )
755  rotatedReferencePoint.setX( 0 );
756  if ( rotatedReferencePoint.y() > 1 )
757  rotatedReferencePoint.setY( 1 );
758  if ( rotatedReferencePoint.y() < 0 )
759  rotatedReferencePoint.setY( 0 );
760 
761  return rotatedReferencePoint;
762 }
763 
764 void QgsGradientFillSymbolLayerV2::applyGradient( const QgsSymbolV2RenderContext &context, QBrush &brush,
769 {
770  //update alpha of gradient colors
772  fillColor.setAlphaF( context.alpha() * fillColor.alphaF() );
773  QColor fillColor2 = color2;
774  fillColor2.setAlphaF( context.alpha() * fillColor2.alphaF() );
775 
776  //rotate reference points
777  QPointF rotatedReferencePoint1 = !qgsDoubleNear( angle, 0.0 ) ? rotateReferencePoint( referencePoint1, angle ) : referencePoint1;
778  QPointF rotatedReferencePoint2 = !qgsDoubleNear( angle, 0.0 ) ? rotateReferencePoint( referencePoint2, angle ) : referencePoint2;
779 
780  //create a QGradient with the desired properties
781  QGradient gradient;
782  switch ( gradientType )
783  {
785  gradient = QLinearGradient( rotatedReferencePoint1, rotatedReferencePoint2 );
786  break;
788  gradient = QRadialGradient( rotatedReferencePoint1, QLineF( rotatedReferencePoint1, rotatedReferencePoint2 ).length() );
789  break;
791  gradient = QConicalGradient( rotatedReferencePoint1, QLineF( rotatedReferencePoint1, rotatedReferencePoint2 ).angle() );
792  break;
793  }
794  switch ( coordinateMode )
795  {
797  gradient.setCoordinateMode( QGradient::ObjectBoundingMode );
798  break;
800  gradient.setCoordinateMode( QGradient::StretchToDeviceMode );
801  break;
802  }
803  switch ( gradientSpread )
804  {
806  gradient.setSpread( QGradient::PadSpread );
807  break;
809  gradient.setSpread( QGradient::ReflectSpread );
810  break;
812  gradient.setSpread( QGradient::RepeatSpread );
813  break;
814  }
815 
816  //add stops to gradient
817  if ( gradientColorType == QgsGradientFillSymbolLayerV2::ColorRamp && gradientRamp && gradientRamp->type() == "gradient" )
818  {
819  //color ramp gradient
820  QgsVectorGradientColorRampV2* gradRamp = static_cast<QgsVectorGradientColorRampV2*>( gradientRamp );
821  gradRamp->addStopsToGradient( &gradient, context.alpha() );
822  }
823  else
824  {
825  //two color gradient
826  gradient.setColorAt( 0.0, fillColor );
827  gradient.setColorAt( 1.0, fillColor2 );
828  }
829 
830  //update QBrush use gradient
831  brush = QBrush( gradient );
832 }
833 
835 {
836  QColor selColor = context.renderContext().selectionColor();
837  if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() );
838  mSelBrush = QBrush( selColor );
839 
840  //update mBrush to use a gradient fill with specified properties
841  prepareExpressions( context );
842 }
843 
845 {
846  Q_UNUSED( context );
847 }
848 
850 {
851  QPainter* p = context.renderContext().painter();
852  if ( !p )
853  {
854  return;
855  }
856 
857  applyDataDefinedSymbology( context, points );
858 
859  p->setBrush( context.selected() ? mSelBrush : mBrush );
860  p->setPen( Qt::NoPen );
861 
862  QPointF offset;
863  if ( !mOffset.isNull() )
864  {
867  p->translate( offset );
868  }
869 
870  _renderPolygon( p, points, rings, context );
871 
872  if ( !mOffset.isNull() )
873  {
874  p->translate( -offset );
875  }
876 }
877 
879 {
880  QgsStringMap map;
881  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
882  map["gradient_color2"] = QgsSymbolLayerV2Utils::encodeColor( mColor2 );
883  map["color_type"] = QString::number( mGradientColorType );
884  map["type"] = QString::number( mGradientType );
885  map["coordinate_mode"] = QString::number( mCoordinateMode );
886  map["spread"] = QString::number( mGradientSpread );
887  map["reference_point1"] = QgsSymbolLayerV2Utils::encodePoint( mReferencePoint1 );
888  map["reference_point1_iscentroid"] = QString::number( mReferencePoint1IsCentroid );
889  map["reference_point2"] = QgsSymbolLayerV2Utils::encodePoint( mReferencePoint2 );
890  map["reference_point2_iscentroid"] = QString::number( mReferencePoint2IsCentroid );
891  map["angle"] = QString::number( mAngle );
892  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
894  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
896  if ( mGradientRamp )
897  {
898  map.unite( mGradientRamp->properties() );
899  }
900  return map;
901 }
902 
904 {
906  if ( mGradientRamp )
907  sl->setColorRamp( mGradientRamp->clone() );
912  sl->setAngle( mAngle );
913  sl->setOffset( mOffset );
914  sl->setOffsetUnit( mOffsetUnit );
917  copyPaintEffect( sl );
918  return sl;
919 }
920 
922 {
923  double offsetBleed = mOffset.x() > mOffset.y() ? mOffset.x() : mOffset.y();
924  return offsetBleed;
925 }
926 
928 {
929  mOffsetUnit = unit;
930 }
931 
933 {
934  return mOffsetUnit;
935 }
936 
938 {
939  mOffsetMapUnitScale = scale;
940 }
941 
943 {
944  return mOffsetMapUnitScale;
945 }
946 
947 //QgsShapeburstFillSymbolLayer
948 
950  int blurRadius, bool useWholeShape, double maxDistance ) :
951 
952  mBlurRadius( blurRadius ),
953  mUseWholeShape( useWholeShape ),
954  mMaxDistance( maxDistance ),
955  mDistanceUnit( QgsSymbolV2::MM ),
956  mColorType( colorType ),
957  mColor2( color2 ),
958  mGradientRamp( nullptr ),
959  mTwoColorGradientRamp( nullptr ),
960  mIgnoreRings( false ),
961  mOffsetUnit( QgsSymbolV2::MM )
962 {
963  mColor = color;
964 }
965 
967 {
968  delete mGradientRamp;
969 }
970 
972 {
973  //default to a two-color gradient
975  QColor color = DEFAULT_SIMPLEFILL_COLOR, color2 = Qt::white;
976  int blurRadius = 0;
977  bool useWholeShape = true;
978  double maxDistance = 5;
979  QPointF offset;
980 
981  //update fill properties from props
982  if ( props.contains( "color_type" ) )
983  {
984  colorType = static_cast< ShapeburstColorType >( props["color_type"].toInt() );
985  }
986  if ( props.contains( "shapeburst_color" ) )
987  {
988  //pre 2.5 projects used "shapeburst_color"
989  color = QgsSymbolLayerV2Utils::decodeColor( props["shapeburst_color"] );
990  }
991  else if ( props.contains( "color" ) )
992  {
993  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
994  }
995 
996  if ( props.contains( "shapeburst_color2" ) )
997  {
998  //pre 2.5 projects used "shapeburst_color2"
999  color2 = QgsSymbolLayerV2Utils::decodeColor( props["shapeburst_color2"] );
1000  }
1001  else if ( props.contains( "gradient_color2" ) )
1002  {
1003  color2 = QgsSymbolLayerV2Utils::decodeColor( props["gradient_color2"] );
1004  }
1005  if ( props.contains( "blur_radius" ) )
1006  {
1007  blurRadius = props["blur_radius"].toInt();
1008  }
1009  if ( props.contains( "use_whole_shape" ) )
1010  {
1011  useWholeShape = props["use_whole_shape"].toInt();
1012  }
1013  if ( props.contains( "max_distance" ) )
1014  {
1015  maxDistance = props["max_distance"].toDouble();
1016  }
1017  if ( props.contains( "offset" ) )
1018  {
1019  offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
1020  }
1021 
1022  //attempt to create color ramp from props
1024 
1025  //create a new shapeburst fill layer with desired properties
1026  QgsShapeburstFillSymbolLayerV2* sl = new QgsShapeburstFillSymbolLayerV2( color, color2, colorType, blurRadius, useWholeShape, maxDistance );
1027  sl->setOffset( offset );
1028  if ( props.contains( "offset_unit" ) )
1029  {
1030  sl->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1031  }
1032  if ( props.contains( "distance_unit" ) )
1033  {
1034  sl->setDistanceUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["distance_unit"] ) );
1035  }
1036  if ( props.contains( "offset_map_unit_scale" ) )
1037  {
1038  sl->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1039  }
1040  if ( props.contains( "distance_map_unit_scale" ) )
1041  {
1042  sl->setDistanceMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["distance_map_unit_scale"] ) );
1043  }
1044  if ( props.contains( "ignore_rings" ) )
1045  {
1046  sl->setIgnoreRings( props["ignore_rings"].toInt() );
1047  }
1048  if ( gradientRamp )
1049  {
1050  sl->setColorRamp( gradientRamp );
1051  }
1052 
1053  sl->restoreDataDefinedProperties( props );
1054 
1055  return sl;
1056 }
1057 
1059 {
1060  return "ShapeburstFill";
1061 }
1062 
1064 {
1065  delete mGradientRamp;
1066  mGradientRamp = ramp;
1067 }
1068 
1069 void QgsShapeburstFillSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QColor& color, QColor& color2, int& blurRadius, bool& useWholeShape,
1070  double& maxDistance, bool& ignoreRings )
1071 {
1072  bool ok;
1073 
1074  //first gradient color
1075  color = mColor;
1077  {
1080  if ( ok )
1081  color = QgsSymbolLayerV2Utils::decodeColor( colorString );
1082  }
1083 
1084  //second gradient color
1085  color2 = mColor2;
1087  {
1090  if ( ok )
1091  color2 = QgsSymbolLayerV2Utils::decodeColor( colorString );
1092  }
1093 
1094  //blur radius
1097  {
1100  }
1101 
1102  //use whole shape
1105  {
1108  }
1109 
1110  //max distance
1113  {
1116  }
1117 
1118  //ignore rings
1119  ignoreRings = mIgnoreRings;
1121  {
1124  }
1125 
1126 }
1127 
1129 {
1130  //TODO - check this
1131  QColor selColor = context.renderContext().selectionColor();
1132  if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() );
1133  mSelBrush = QBrush( selColor );
1134 
1135  prepareExpressions( context );
1136 }
1137 
1139 {
1140  Q_UNUSED( context );
1141 }
1142 
1144 {
1145  QPainter* p = context.renderContext().painter();
1146  if ( !p )
1147  {
1148  return;
1149  }
1150 
1151  if ( context.selected() )
1152  {
1153  //feature is selected, draw using selection style
1154  p->setBrush( mSelBrush );
1155  QPointF offset;
1156  if ( !mOffset.isNull() )
1157  {
1160  p->translate( offset );
1161  }
1162  _renderPolygon( p, points, rings, context );
1163  if ( !mOffset.isNull() )
1164  {
1165  p->translate( -offset );
1166  }
1167  return;
1168  }
1169 
1170  QColor color1, color2;
1171  int blurRadius;
1172  bool useWholeShape;
1173  double maxDistance;
1174  bool ignoreRings;
1175  //calculate data defined symbology
1176  applyDataDefinedSymbology( context, color1, color2, blurRadius, useWholeShape, maxDistance, ignoreRings );
1177 
1178  //calculate max distance for shapeburst fill to extend from polygon boundary, in pixels
1179  int outputPixelMaxDist = 0;
1180  if ( !useWholeShape && !qgsDoubleNear( maxDistance, 0.0 ) )
1181  {
1182  //convert max distance to pixels
1183  const QgsRenderContext& ctx = context.renderContext();
1184  outputPixelMaxDist = maxDistance * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceUnit, mDistanceMapUnitScale );
1185  }
1186 
1187  //if we are using the two color mode, create a gradient ramp
1189  {
1190  mTwoColorGradientRamp = new QgsVectorGradientColorRampV2( color1, color2 );
1191  }
1192 
1193  //no border for shapeburst fills
1194  p->setPen( QPen( Qt::NoPen ) );
1195 
1196  //calculate margin size in pixels so that QImage of polygon has sufficient space to draw the full blur effect
1197  int sideBuffer = 4 + ( blurRadius + 2 ) * 4;
1198  //create a QImage to draw shapeburst in
1199  double imWidth = points.boundingRect().width() + ( sideBuffer * 2 );
1200  double imHeight = points.boundingRect().height() + ( sideBuffer * 2 );
1201  QImage * fillImage = new QImage( imWidth * context.renderContext().rasterScaleFactor(),
1202  imHeight * context.renderContext().rasterScaleFactor(), QImage::Format_ARGB32_Premultiplied );
1203  //Fill this image with black. Initially the distance transform is drawn in greyscale, where black pixels have zero distance from the
1204  //polygon boundary. Since we don't care about pixels which fall outside the polygon, we start with a black image and then draw over it the
1205  //polygon in white. The distance transform function then fills in the correct distance values for the white pixels.
1206  fillImage->fill( Qt::black );
1207 
1208  //also create an image to store the alpha channel
1209  QImage * alphaImage = new QImage( fillImage->width(), fillImage->height(), QImage::Format_ARGB32_Premultiplied );
1210  //initially fill the alpha channel image with a transparent color
1211  alphaImage->fill( Qt::transparent );
1212 
1213  //now, draw the polygon in the alpha channel image
1214  QPainter imgPainter;
1215  imgPainter.begin( alphaImage );
1216  imgPainter.setRenderHint( QPainter::Antialiasing, true );
1217  imgPainter.setBrush( QBrush( Qt::white ) );
1218  imgPainter.setPen( QPen( Qt::black ) );
1219  imgPainter.translate( -points.boundingRect().left() + sideBuffer, - points.boundingRect().top() + sideBuffer );
1220  imgPainter.scale( context.renderContext().rasterScaleFactor(), context.renderContext().rasterScaleFactor() );
1221  _renderPolygon( &imgPainter, points, rings, context );
1222  imgPainter.end();
1223 
1224  //now that we have a render of the polygon in white, draw this onto the shapeburst fill image too
1225  //(this avoids calling _renderPolygon twice, since that can be slow)
1226  imgPainter.begin( fillImage );
1227  if ( !ignoreRings )
1228  {
1229  imgPainter.drawImage( 0, 0, *alphaImage );
1230  }
1231  else
1232  {
1233  //using ignore rings mode, so the alpha image can't be used
1234  //directly as the alpha channel contains polygon rings and we need
1235  //to draw now without any rings
1236  imgPainter.setBrush( QBrush( Qt::white ) );
1237  imgPainter.setPen( QPen( Qt::black ) );
1238  imgPainter.translate( -points.boundingRect().left() + sideBuffer, - points.boundingRect().top() + sideBuffer );
1239  imgPainter.scale( context.renderContext().rasterScaleFactor(), context.renderContext().rasterScaleFactor() );
1240  _renderPolygon( &imgPainter, points, nullptr, context );
1241  }
1242  imgPainter.end();
1243 
1244  //apply distance transform to image, uses the current color ramp to calculate final pixel colors
1245  double * dtArray = distanceTransform( fillImage );
1246 
1247  //copy distance transform values back to QImage, shading by appropriate color ramp
1249  context.alpha(), useWholeShape, outputPixelMaxDist );
1250 
1251  //clean up some variables
1252  delete [] dtArray;
1254  {
1255  delete mTwoColorGradientRamp;
1256  }
1257 
1258  //apply blur if desired
1259  if ( blurRadius > 0 )
1260  {
1261  QgsSymbolLayerV2Utils::blurImageInPlace( *fillImage, QRect( 0, 0, fillImage->width(), fillImage->height() ), blurRadius, false );
1262  }
1263 
1264  //apply alpha channel to distance transform image, so that areas outside the polygon are transparent
1265  imgPainter.begin( fillImage );
1266  imgPainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
1267  imgPainter.drawImage( 0, 0, *alphaImage );
1268  imgPainter.end();
1269  //we're finished with the alpha channel image now
1270  delete alphaImage;
1271 
1272  //draw shapeburst image in correct place in the destination painter
1273 
1274  p->save();
1275  QPointF offset;
1276  if ( !mOffset.isNull() )
1277  {
1280  p->translate( offset );
1281  }
1282 
1283  p->scale( 1 / context.renderContext().rasterScaleFactor(), 1 / context.renderContext().rasterScaleFactor() );
1284  p->drawImage( points.boundingRect().left() - sideBuffer, points.boundingRect().top() - sideBuffer, *fillImage );
1285 
1286  delete fillImage;
1287 
1288  if ( !mOffset.isNull() )
1289  {
1290  p->translate( -offset );
1291  }
1292  p->restore();
1293 
1294 }
1295 
1296 //fast distance transform code, adapted from http://cs.brown.edu/~pff/dt/
1297 
1298 /* distance transform of a 1d function using squared distance */
1299 void QgsShapeburstFillSymbolLayerV2::distanceTransform1d( double *f, int n, int *v, double *z, double *d )
1300 {
1301  int k = 0;
1302  v[0] = 0;
1303  z[0] = -INF;
1304  z[1] = + INF;
1305  for ( int q = 1; q <= n - 1; q++ )
1306  {
1307  double s = (( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
1308  while ( s <= z[k] )
1309  {
1310  k--;
1311  s = (( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
1312  }
1313  k++;
1314  v[k] = q;
1315  z[k] = s;
1316  z[k+1] = + INF;
1317  }
1318 
1319  k = 0;
1320  for ( int q = 0; q <= n - 1; q++ )
1321  {
1322  while ( z[k+1] < q )
1323  k++;
1324  d[q] = ( q - v[k] ) * ( q - v[k] ) + f[v[k]];
1325  }
1326 }
1327 
1328 /* distance transform of 2d function using squared distance */
1329 void QgsShapeburstFillSymbolLayerV2::distanceTransform2d( double * im, int width, int height )
1330 {
1331  int maxDimension = qMax( width, height );
1332  double *f = new double[ maxDimension ];
1333  int *v = new int[ maxDimension ];
1334  double *z = new double[ maxDimension + 1 ];
1335  double *d = new double[ maxDimension ];
1336 
1337  // transform along columns
1338  for ( int x = 0; x < width; x++ )
1339  {
1340  for ( int y = 0; y < height; y++ )
1341  {
1342  f[y] = im[ x + y * width ];
1343  }
1344  distanceTransform1d( f, height, v, z, d );
1345  for ( int y = 0; y < height; y++ )
1346  {
1347  im[ x + y * width ] = d[y];
1348  }
1349  }
1350 
1351  // transform along rows
1352  for ( int y = 0; y < height; y++ )
1353  {
1354  for ( int x = 0; x < width; x++ )
1355  {
1356  f[x] = im[ x + y*width ];
1357  }
1358  distanceTransform1d( f, width, v, z, d );
1359  for ( int x = 0; x < width; x++ )
1360  {
1361  im[ x + y*width ] = d[x];
1362  }
1363  }
1364 
1365  delete [] d;
1366  delete [] f;
1367  delete [] v;
1368  delete [] z;
1369 }
1370 
1371 /* distance transform of a binary QImage */
1372 double * QgsShapeburstFillSymbolLayerV2::distanceTransform( QImage *im )
1373 {
1374  int width = im->width();
1375  int height = im->height();
1376 
1377  double * dtArray = new double[width * height];
1378 
1379  //load qImage to array
1380  QRgb tmpRgb;
1381  int idx = 0;
1382  for ( int heightIndex = 0; heightIndex < height; ++heightIndex )
1383  {
1384  const QRgb* scanLine = reinterpret_cast< const QRgb* >( im->constScanLine( heightIndex ) );
1385  for ( int widthIndex = 0; widthIndex < width; ++widthIndex )
1386  {
1387  tmpRgb = scanLine[widthIndex];
1388  if ( qRed( tmpRgb ) == 0 )
1389  {
1390  //black pixel, so zero distance
1391  dtArray[ idx ] = 0;
1392  }
1393  else
1394  {
1395  //white pixel, so initially set distance as infinite
1396  dtArray[ idx ] = INF;
1397  }
1398  idx++;
1399  }
1400  }
1401 
1402  //calculate squared distance transform
1403  distanceTransform2d( dtArray, width, height );
1404 
1405  return dtArray;
1406 }
1407 
1408 void QgsShapeburstFillSymbolLayerV2::dtArrayToQImage( double * array, QImage *im, QgsVectorColorRampV2* ramp, double layerAlpha, bool useWholeShape, int maxPixelDistance )
1409 {
1410  int width = im->width();
1411  int height = im->height();
1412 
1413  //find maximum distance value
1414  double maxDistanceValue;
1415 
1416  if ( useWholeShape )
1417  {
1418  //no max distance specified in symbol properties, so calculate from maximum value in distance transform results
1419  double dtMaxValue = array[0];
1420  for ( int i = 1; i < ( width * height ); ++i )
1421  {
1422  if ( array[i] > dtMaxValue )
1423  {
1424  dtMaxValue = array[i];
1425  }
1426  }
1427 
1428  //values in distance transform are squared
1429  maxDistanceValue = sqrt( dtMaxValue );
1430  }
1431  else
1432  {
1433  //use max distance set in symbol properties
1434  maxDistanceValue = maxPixelDistance;
1435  }
1436 
1437  //update the pixels in the provided QImage
1438  int idx = 0;
1439  double squaredVal = 0;
1440  double pixVal = 0;
1441  QColor pixColor;
1442  bool layerHasAlpha = layerAlpha < 1.0;
1443 
1444  for ( int heightIndex = 0; heightIndex < height; ++heightIndex )
1445  {
1446  QRgb* scanLine = reinterpret_cast< QRgb* >( im->scanLine( heightIndex ) );
1447  for ( int widthIndex = 0; widthIndex < width; ++widthIndex )
1448  {
1449  //result of distance transform
1450  squaredVal = array[idx];
1451 
1452  //scale result to fit in the range [0, 1]
1453  if ( maxDistanceValue > 0 )
1454  {
1455  pixVal = squaredVal > 0 ? qMin(( sqrt( squaredVal ) / maxDistanceValue ), 1.0 ) : 0;
1456  }
1457  else
1458  {
1459  pixVal = 1.0;
1460  }
1461 
1462  //convert value to color from ramp
1463  pixColor = ramp->color( pixVal );
1464 
1465  int pixAlpha = pixColor.alpha();
1466  if (( layerHasAlpha ) || ( pixAlpha != 255 ) )
1467  {
1468  //apply layer's transparency to alpha value
1469  double alpha = pixAlpha * layerAlpha;
1470  //premultiply ramp color since we are storing this in a ARGB32_Premultiplied QImage
1471  QgsSymbolLayerV2Utils::premultiplyColor( pixColor, alpha );
1472  }
1473 
1474  scanLine[widthIndex] = pixColor.rgba();
1475  idx++;
1476  }
1477  }
1478 }
1479 
1481 {
1482  QgsStringMap map;
1483  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
1484  map["gradient_color2"] = QgsSymbolLayerV2Utils::encodeColor( mColor2 );
1485  map["color_type"] = QString::number( mColorType );
1486  map["blur_radius"] = QString::number( mBlurRadius );
1487  map["use_whole_shape"] = QString::number( mUseWholeShape );
1488  map["max_distance"] = QString::number( mMaxDistance );
1489  map["distance_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceUnit );
1490  map["distance_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceMapUnitScale );
1491  map["ignore_rings"] = QString::number( mIgnoreRings );
1492  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1493  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1494  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1495 
1497 
1498  if ( mGradientRamp )
1499  {
1500  map.unite( mGradientRamp->properties() );
1501  }
1502 
1503  return map;
1504 }
1505 
1507 {
1509  if ( mGradientRamp )
1510  {
1511  sl->setColorRamp( mGradientRamp->clone() );
1512  }
1516  sl->setOffset( mOffset );
1517  sl->setOffsetUnit( mOffsetUnit );
1520  copyPaintEffect( sl );
1521  return sl;
1522 }
1523 
1525 {
1526  double offsetBleed = qMax( mOffset.x(), mOffset.y() );
1527  return offsetBleed;
1528 }
1529 
1531 {
1532  mDistanceUnit = unit;
1533  mOffsetUnit = unit;
1534 }
1535 
1537 {
1538  if ( mDistanceUnit == mOffsetUnit )
1539  {
1540  return mDistanceUnit;
1541  }
1542  return QgsSymbolV2::Mixed;
1543 }
1544 
1546 {
1547  mDistanceMapUnitScale = scale;
1548  mOffsetMapUnitScale = scale;
1549 }
1550 
1552 {
1554  {
1555  return mDistanceMapUnitScale;
1556  }
1557  return QgsMapUnitScale();
1558 }
1559 
1560 
1561 //QgsImageFillSymbolLayer
1562 
1564  : mNextAngle( 0.0 )
1565  , mOutlineWidth( 0.0 )
1566  , mOutlineWidthUnit( QgsSymbolV2::MM )
1567  , mOutline( nullptr )
1568 {
1569  setSubSymbol( new QgsLineSymbolV2() );
1570 }
1571 
1573 {
1574 }
1575 
1577 {
1578  QPainter* p = context.renderContext().painter();
1579  if ( !p )
1580  {
1581  return;
1582  }
1583 
1584  mNextAngle = mAngle;
1585  applyDataDefinedSettings( context );
1586 
1587  p->setPen( QPen( Qt::NoPen ) );
1588 
1589  QTransform bkTransform = mBrush.transform();
1591  {
1592  //transform brush to upper left corner of geometry bbox
1593  QPointF leftCorner = points.boundingRect().topLeft();
1594  QTransform t = mBrush.transform();
1595  t.translate( leftCorner.x(), leftCorner.y() );
1596  mBrush.setTransform( t );
1597  }
1598 
1599  if ( context.selected() )
1600  {
1601  QColor selColor = context.renderContext().selectionColor();
1602  // Alister - this doesn't seem to work here
1603  //if ( ! selectionIsOpaque )
1604  // selColor.setAlphaF( context.alpha() );
1605  p->setBrush( QBrush( selColor ) );
1606  _renderPolygon( p, points, rings, context );
1607  }
1608 
1609  if ( !qgsDoubleNear( mNextAngle, 0.0 ) )
1610  {
1611  QTransform t = mBrush.transform();
1612  t.rotate( mNextAngle );
1613  mBrush.setTransform( t );
1614  }
1615  p->setBrush( mBrush );
1616  _renderPolygon( p, points, rings, context );
1617  if ( mOutline )
1618  {
1619  mOutline->renderPolyline( points, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
1620  if ( rings )
1621  {
1622  QList<QPolygonF>::const_iterator ringIt = rings->constBegin();
1623  for ( ; ringIt != rings->constEnd(); ++ringIt )
1624  {
1625  mOutline->renderPolyline( *ringIt, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
1626  }
1627  }
1628  }
1629 
1630  mBrush.setTransform( bkTransform );
1631 }
1632 
1634 {
1635  if ( !symbol ) //unset current outline
1636  {
1637  delete mOutline;
1638  mOutline = nullptr;
1639  return true;
1640  }
1641 
1642  if ( symbol->type() != QgsSymbolV2::Line )
1643  {
1644  delete symbol;
1645  return false;
1646  }
1647 
1648  QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
1649  if ( lineSymbol )
1650  {
1651  delete mOutline;
1652  mOutline = lineSymbol;
1653  return true;
1654  }
1655 
1656  delete symbol;
1657  return false;
1658 }
1659 
1661 {
1662  mOutlineWidthUnit = unit;
1663 }
1664 
1666 {
1667  return mOutlineWidthUnit;
1668 }
1669 
1671 {
1672  mOutlineWidthMapUnitScale = scale;
1673 }
1674 
1676 {
1678 }
1679 
1681 {
1682  if ( mOutline && mOutline->symbolLayer( 0 ) )
1683  {
1684  double subLayerBleed = mOutline->symbolLayer( 0 )->estimateMaxBleed();
1685  return subLayerBleed;
1686  }
1687  return 0;
1688 }
1689 
1691 {
1692  double width = mOutlineWidth;
1694  {
1697  }
1699 }
1700 
1702 {
1703  Q_UNUSED( context );
1704  if ( !mOutline )
1705  {
1706  return QColor( Qt::black );
1707  }
1708  return mOutline->color();
1709 }
1710 
1712 {
1713  return Qt::SolidLine;
1714 #if 0
1715  if ( !mOutline )
1716  {
1717  return Qt::SolidLine;
1718  }
1719  else
1720  {
1721  return mOutline->dxfPenStyle();
1722  }
1723 #endif //0
1724 }
1725 
1727 {
1729  if ( mOutline )
1730  attr.unite( mOutline->usedAttributes() );
1731  return attr;
1732 }
1733 
1734 
1735 //QgsSVGFillSymbolLayer
1736 
1738  mPatternWidth( width ),
1739  mPatternWidthUnit( QgsSymbolV2::MM ),
1740  mSvgOutlineWidthUnit( QgsSymbolV2::MM )
1741 {
1742  setSvgFilePath( svgFilePath );
1743  mOutlineWidth = 0.3;
1744  mAngle = angle;
1745  mColor = QColor( 255, 255, 255 );
1746  mSvgOutlineColor = QColor( 0, 0, 0 );
1747  mSvgOutlineWidth = 0.2;
1748  setDefaultSvgParams();
1749  mSvgPattern = nullptr;
1750 }
1751 
1753  mPatternWidth( width ),
1755  mSvgData( svgData ),
1757 {
1758  storeViewBox();
1759  mOutlineWidth = 0.3;
1760  mAngle = angle;
1761  mColor = QColor( 255, 255, 255 );
1762  mSvgOutlineColor = QColor( 0, 0, 0 );
1763  mSvgOutlineWidth = 0.2;
1764  setSubSymbol( new QgsLineSymbolV2() );
1765  setDefaultSvgParams();
1766  mSvgPattern = nullptr;
1767 }
1768 
1770 {
1771  delete mSvgPattern;
1772 }
1773 
1775 {
1777  mPatternWidthUnit = unit;
1778  mSvgOutlineWidthUnit = unit;
1779  mOutlineWidthUnit = unit;
1780  mOutline->setOutputUnit( unit );
1781 }
1782 
1784 {
1786  if ( mPatternWidthUnit != unit || mSvgOutlineWidthUnit != unit || mOutlineWidthUnit != unit )
1787  {
1788  return QgsSymbolV2::Mixed;
1789  }
1790  return unit;
1791 }
1792 
1794 {
1796  mPatternWidthMapUnitScale = scale;
1798  mOutlineWidthMapUnitScale = scale;
1799 }
1800 
1802 {
1806  {
1808  }
1809  return QgsMapUnitScale();
1810 }
1811 
1813 {
1815  storeViewBox();
1816 
1817  mSvgFilePath = svgPath;
1818  setDefaultSvgParams();
1819 }
1820 
1822 {
1823  QByteArray data;
1824  double width = 20;
1826  double angle = 0.0;
1827 
1828  if ( properties.contains( "width" ) )
1829  {
1830  width = properties["width"].toDouble();
1831  }
1832  if ( properties.contains( "svgFile" ) )
1833  {
1834  QString svgName = properties["svgFile"];
1835  QString savePath = QgsSymbolLayerV2Utils::symbolNameToPath( svgName );
1836  svgFilePath = ( savePath.isEmpty() ? svgName : savePath );
1837  }
1838  if ( properties.contains( "angle" ) )
1839  {
1840  angle = properties["angle"].toDouble();
1841  }
1842 
1843  QgsSVGFillSymbolLayer* symbolLayer = nullptr;
1844  if ( !svgFilePath.isEmpty() )
1845  {
1846  symbolLayer = new QgsSVGFillSymbolLayer( svgFilePath, width, angle );
1847  }
1848  else
1849  {
1850  if ( properties.contains( "data" ) )
1851  {
1852  data = QByteArray::fromHex( properties["data"].toLocal8Bit() );
1853  }
1854  symbolLayer = new QgsSVGFillSymbolLayer( data, width, angle );
1855  }
1856 
1857  //svg parameters
1858  if ( properties.contains( "svgFillColor" ) )
1859  {
1860  //pre 2.5 projects used "svgFillColor"
1861  symbolLayer->setSvgFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["svgFillColor"] ) );
1862  }
1863  else if ( properties.contains( "color" ) )
1864  {
1865  symbolLayer->setSvgFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["color"] ) );
1866  }
1867  if ( properties.contains( "svgOutlineColor" ) )
1868  {
1869  //pre 2.5 projects used "svgOutlineColor"
1870  symbolLayer->setSvgOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["svgOutlineColor"] ) );
1871  }
1872  else if ( properties.contains( "outline_color" ) )
1873  {
1874  symbolLayer->setSvgOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["outline_color"] ) );
1875  }
1876  else if ( properties.contains( "line_color" ) )
1877  {
1878  symbolLayer->setSvgOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["line_color"] ) );
1879  }
1880  if ( properties.contains( "svgOutlineWidth" ) )
1881  {
1882  //pre 2.5 projects used "svgOutlineWidth"
1883  symbolLayer->setSvgOutlineWidth( properties["svgOutlineWidth"].toDouble() );
1884  }
1885  else if ( properties.contains( "outline_width" ) )
1886  {
1887  symbolLayer->setSvgOutlineWidth( properties["outline_width"].toDouble() );
1888  }
1889  else if ( properties.contains( "line_width" ) )
1890  {
1891  symbolLayer->setSvgOutlineWidth( properties["line_width"].toDouble() );
1892  }
1893 
1894  //units
1895  if ( properties.contains( "pattern_width_unit" ) )
1896  {
1897  symbolLayer->setPatternWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["pattern_width_unit"] ) );
1898  }
1899  if ( properties.contains( "pattern_width_map_unit_scale" ) )
1900  {
1901  symbolLayer->setPatternWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["pattern_width_map_unit_scale"] ) );
1902  }
1903  if ( properties.contains( "svg_outline_width_unit" ) )
1904  {
1905  symbolLayer->setSvgOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["svg_outline_width_unit"] ) );
1906  }
1907  if ( properties.contains( "svg_outline_width_map_unit_scale" ) )
1908  {
1909  symbolLayer->setSvgOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["svg_outline_width_map_unit_scale"] ) );
1910  }
1911  if ( properties.contains( "outline_width_unit" ) )
1912  {
1913  symbolLayer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
1914  }
1915  if ( properties.contains( "outline_width_map_unit_scale" ) )
1916  {
1917  symbolLayer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
1918  }
1919 
1920  symbolLayer->restoreDataDefinedProperties( properties );
1921 
1922  return symbolLayer;
1923 }
1924 
1926 {
1927  return "SVGFill";
1928 }
1929 
1930 void QgsSVGFillSymbolLayer::applyPattern( QBrush& brush, const QString& svgFilePath, double patternWidth, QgsSymbolV2::OutputUnit patternWidthUnit,
1931  const QColor& svgFillColor, const QColor& svgOutlineColor, double svgOutlineWidth,
1934 {
1935  if ( mSvgViewBox.isNull() )
1936  {
1937  return;
1938  }
1939 
1940  delete mSvgPattern;
1941  mSvgPattern = nullptr;
1943 
1944  if ( static_cast< int >( size ) < 1.0 || 10000.0 < size )
1945  {
1946  mSvgPattern = new QImage();
1947  brush.setTextureImage( *mSvgPattern );
1948  }
1949  else
1950  {
1951  bool fitsInCache = true;
1953  const QImage& patternImage = QgsSvgCache::instance()->svgAsImage( svgFilePath, size, svgFillColor, svgOutlineColor, outlineWidth,
1954  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
1955  if ( !fitsInCache )
1956  {
1957  const QPicture& patternPict = QgsSvgCache::instance()->svgAsPicture( svgFilePath, size, svgFillColor, svgOutlineColor, outlineWidth,
1958  context.renderContext().scaleFactor(), 1.0 );
1959  double hwRatio = 1.0;
1960  if ( patternPict.width() > 0 )
1961  {
1962  hwRatio = static_cast< double >( patternPict.height() ) / static_cast< double >( patternPict.width() );
1963  }
1964  mSvgPattern = new QImage( static_cast< int >( size ), static_cast< int >( size * hwRatio ), QImage::Format_ARGB32_Premultiplied );
1965  mSvgPattern->fill( 0 ); // transparent background
1966 
1967  QPainter p( mSvgPattern );
1968  p.drawPicture( QPointF( size / 2, size * hwRatio / 2 ), patternPict );
1969  }
1970 
1971  QTransform brushTransform;
1972  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
1973  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1974  {
1975  QImage transparentImage = fitsInCache ? patternImage.copy() : mSvgPattern->copy();
1976  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
1977  brush.setTextureImage( transparentImage );
1978  }
1979  else
1980  {
1981  brush.setTextureImage( fitsInCache ? patternImage : *mSvgPattern );
1982  }
1983  brush.setTransform( brushTransform );
1984  }
1985 }
1986 
1988 {
1989 
1991 
1992  if ( mOutline )
1993  {
1994  mOutline->startRender( context.renderContext(), context.fields() );
1995  }
1996 
1997  prepareExpressions( context );
1998 }
1999 
2001 {
2002  if ( mOutline )
2003  {
2004  mOutline->stopRender( context.renderContext() );
2005  }
2006 }
2007 
2009 {
2010  QgsStringMap map;
2011  if ( !mSvgFilePath.isEmpty() )
2012  {
2014  }
2015  else
2016  {
2017  map.insert( "data", QString( mSvgData.toHex() ) );
2018  }
2019 
2020  map.insert( "width", QString::number( mPatternWidth ) );
2021  map.insert( "angle", QString::number( mAngle ) );
2022 
2023  //svg parameters
2025  map.insert( "outline_color", QgsSymbolLayerV2Utils::encodeColor( mSvgOutlineColor ) );
2026  map.insert( "outline_width", QString::number( mSvgOutlineWidth ) );
2027 
2028  //units
2029  map.insert( "pattern_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mPatternWidthUnit ) );
2030  map.insert( "pattern_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mPatternWidthMapUnitScale ) );
2031  map.insert( "svg_outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mSvgOutlineWidthUnit ) );
2032  map.insert( "svg_outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mSvgOutlineWidthMapUnitScale ) );
2033  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
2034  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
2035 
2037  return map;
2038 }
2039 
2041 {
2042  QgsSVGFillSymbolLayer* clonedLayer = nullptr;
2043  if ( !mSvgFilePath.isEmpty() )
2044  {
2045  clonedLayer = new QgsSVGFillSymbolLayer( mSvgFilePath, mPatternWidth, mAngle );
2046  clonedLayer->setSvgFillColor( mColor );
2047  clonedLayer->setSvgOutlineColor( mSvgOutlineColor );
2048  clonedLayer->setSvgOutlineWidth( mSvgOutlineWidth );
2049  }
2050  else
2051  {
2052  clonedLayer = new QgsSVGFillSymbolLayer( mSvgData, mPatternWidth, mAngle );
2053  }
2054 
2055  clonedLayer->setPatternWidthUnit( mPatternWidthUnit );
2059  clonedLayer->setOutlineWidthUnit( mOutlineWidthUnit );
2061 
2062  if ( mOutline )
2063  {
2064  clonedLayer->setSubSymbol( mOutline->clone() );
2065  }
2066  copyDataDefinedProperties( clonedLayer );
2067  copyPaintEffect( clonedLayer );
2068  return clonedLayer;
2069 }
2070 
2071 void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const
2072 {
2073  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
2074  if ( !props.value( "uom", "" ).isEmpty() )
2075  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
2076  element.appendChild( symbolizerElem );
2077 
2078  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
2079 
2080  QDomElement fillElem = doc.createElement( "se:Fill" );
2081  symbolizerElem.appendChild( fillElem );
2082 
2083  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
2084  fillElem.appendChild( graphicFillElem );
2085 
2086  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2087  graphicFillElem.appendChild( graphicElem );
2088 
2089  if ( !mSvgFilePath.isEmpty() )
2090  {
2091  double partternWidth = QgsSymbolLayerV2Utils::rescaleUom( mPatternWidth, mPatternWidthUnit, props );
2092  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mSvgFilePath, "image/svg+xml", mColor, partternWidth );
2093  }
2094  else
2095  {
2096  // TODO: create svg from data
2097  // <se:InlineContent>
2098  symbolizerElem.appendChild( doc.createComment( "SVG from data not implemented yet" ) );
2099  }
2100 
2101  if ( mSvgOutlineColor.isValid() || mSvgOutlineWidth >= 0 )
2102  {
2104  QgsSymbolLayerV2Utils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, svgOutlineWidth );
2105  }
2106 
2107  // <Rotation>
2108  QString angleFunc;
2109  bool ok;
2110  double angle = props.value( "angle", "0" ).toDouble( &ok );
2111  if ( !ok )
2112  {
2113  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2114  }
2115  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2116  {
2117  angleFunc = QString::number( angle + mAngle );
2118  }
2119  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2120 
2121  if ( mOutline )
2122  {
2123  // the outline sub symbol should be stored within the Stroke element,
2124  // but it will be stored in a separated LineSymbolizer because it could
2125  // have more than one layer
2126  mOutline->toSld( doc, element, props );
2127  }
2128 }
2129 
2131 {
2132  QgsDebugMsg( "Entered." );
2133 
2134  QString path, mimeType;
2135  QColor fillColor, borderColor;
2136  Qt::PenStyle penStyle;
2137  double size, borderWidth;
2138 
2139  QDomElement fillElem = element.firstChildElement( "Fill" );
2140  if ( fillElem.isNull() )
2141  return nullptr;
2142 
2143  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
2144  if ( graphicFillElem.isNull() )
2145  return nullptr;
2146 
2147  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
2148  if ( graphicElem.isNull() )
2149  return nullptr;
2150 
2151  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
2152  return nullptr;
2153 
2154  if ( mimeType != "image/svg+xml" )
2155  return nullptr;
2156 
2157  QgsSymbolLayerV2Utils::lineFromSld( graphicElem, penStyle, borderColor, borderWidth );
2158 
2159  double angle = 0.0;
2160  QString angleFunc;
2161  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2162  {
2163  bool ok;
2164  double d = angleFunc.toDouble( &ok );
2165  if ( ok )
2166  angle = d;
2167  }
2168 
2169  QgsSVGFillSymbolLayer* sl = new QgsSVGFillSymbolLayer( path, size, angle );
2170  sl->setSvgFillColor( fillColor );
2171  sl->setSvgOutlineColor( borderColor );
2172  sl->setSvgOutlineWidth( borderWidth );
2173 
2174  // try to get the outline
2175  QDomElement strokeElem = element.firstChildElement( "Stroke" );
2176  if ( !strokeElem.isNull() )
2177  {
2179  if ( l )
2180  {
2181  QgsSymbolLayerV2List layers;
2182  layers.append( l );
2183  sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
2184  }
2185  }
2186 
2187  return sl;
2188 }
2189 
2191 {
2195  {
2196  return; //no data defined settings
2197  }
2198 
2199  bool ok;
2200 
2202  {
2203  context.setOriginalValueVariable( mAngle );
2204  double nextAngle = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_ANGLE, context, QVariant(), &ok ).toDouble();
2205  if ( ok )
2206  mNextAngle = nextAngle;
2207  }
2208 
2209  double width = mPatternWidth;
2211  {
2214  }
2215  QString svgFile = mSvgFilePath;
2217  {
2220  }
2221  QColor svgFillColor = mColor;
2223  {
2226  if ( ok )
2227  svgFillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2228  }
2229  QColor svgOutlineColor = mSvgOutlineColor;
2231  {
2234  if ( ok )
2235  svgOutlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2236  }
2237  double outlineWidth = mSvgOutlineWidth;
2239  {
2242  }
2243  applyPattern( mBrush, svgFile, width, mPatternWidthUnit, svgFillColor, svgOutlineColor, outlineWidth,
2245 
2246 }
2247 
2248 void QgsSVGFillSymbolLayer::storeViewBox()
2249 {
2250  if ( !mSvgData.isEmpty() )
2251  {
2252  QSvgRenderer r( mSvgData );
2253  if ( r.isValid() )
2254  {
2255  mSvgViewBox = r.viewBoxF();
2256  return;
2257  }
2258  }
2259 
2260  mSvgViewBox = QRectF();
2261  return;
2262 }
2263 
2264 void QgsSVGFillSymbolLayer::setDefaultSvgParams()
2265 {
2266  if ( mSvgFilePath.isEmpty() )
2267  {
2268  return;
2269  }
2270 
2271  bool hasFillParam, hasFillOpacityParam, hasOutlineParam, hasOutlineWidthParam, hasOutlineOpacityParam;
2272  bool hasDefaultFillColor, hasDefaultFillOpacity, hasDefaultOutlineColor, hasDefaultOutlineWidth, hasDefaultOutlineOpacity;
2273  QColor defaultFillColor, defaultOutlineColor;
2274  double defaultOutlineWidth, defaultFillOpacity, defaultOutlineOpacity;
2275  QgsSvgCache::instance()->containsParams( mSvgFilePath, hasFillParam, hasDefaultFillColor, defaultFillColor,
2276  hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
2277  hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
2278  hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth,
2279  hasOutlineOpacityParam, hasDefaultOutlineOpacity, defaultOutlineOpacity );
2280 
2281  double newFillOpacity = hasFillOpacityParam ? mColor.alphaF() : 1.0;
2282  double newOutlineOpacity = hasOutlineOpacityParam ? mSvgOutlineColor.alphaF() : 1.0;
2283 
2284  if ( hasDefaultFillColor )
2285  {
2286  mColor = defaultFillColor;
2287  mColor.setAlphaF( newFillOpacity );
2288  }
2289  if ( hasDefaultFillOpacity )
2290  {
2291  mColor.setAlphaF( defaultFillOpacity );
2292  }
2293  if ( hasDefaultOutlineColor )
2294  {
2295  mSvgOutlineColor = defaultOutlineColor;
2296  mSvgOutlineColor.setAlphaF( newOutlineOpacity );
2297  }
2298  if ( hasDefaultOutlineOpacity )
2299  {
2300  mSvgOutlineColor.setAlphaF( defaultOutlineOpacity );
2301  }
2302  if ( hasDefaultOutlineWidth )
2303  {
2304  mSvgOutlineWidth = defaultOutlineWidth;
2305  }
2306 }
2307 
2308 
2311  , mDistance( 5.0 )
2312  , mDistanceUnit( QgsSymbolV2::MM )
2313  , mLineWidth( 0 )
2314  , mLineWidthUnit( QgsSymbolV2::MM )
2315  , mLineAngle( 45.0 )
2316  , mOffset( 0.0 )
2317  , mOffsetUnit( QgsSymbolV2::MM )
2318  , mFillLineSymbol( nullptr )
2319 {
2320  setSubSymbol( new QgsLineSymbolV2() );
2321  QgsImageFillSymbolLayer::setSubSymbol( nullptr ); //no outline
2322 }
2323 
2325 {
2326  mFillLineSymbol->setWidth( w );
2327  mLineWidth = w;
2328 }
2329 
2331 {
2332  mFillLineSymbol->setColor( c );
2333  mColor = c;
2334 }
2335 
2337 {
2338  return mFillLineSymbol ? mFillLineSymbol->color() : mColor;
2339 }
2340 
2342 {
2343  delete mFillLineSymbol;
2344 }
2345 
2347 {
2348  if ( !symbol )
2349  {
2350  return false;
2351  }
2352 
2353  if ( symbol->type() == QgsSymbolV2::Line )
2354  {
2355  QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
2356  if ( lineSymbol )
2357  {
2358  delete mFillLineSymbol;
2359  mFillLineSymbol = lineSymbol;
2360 
2361  return true;
2362  }
2363  }
2364  delete symbol;
2365  return false;
2366 }
2367 
2369 {
2370  return mFillLineSymbol;
2371 }
2372 
2374 {
2376  if ( mFillLineSymbol )
2377  attr.unite( mFillLineSymbol->usedAttributes() );
2378  return attr;
2379 }
2380 
2382 {
2383  return 0;
2384 }
2385 
2387 {
2389  mDistanceUnit = unit;
2390  mLineWidthUnit = unit;
2391  mOffsetUnit = unit;
2392 }
2393 
2395 {
2397  if ( mDistanceUnit != unit || mLineWidthUnit != unit || mOffsetUnit != unit )
2398  {
2399  return QgsSymbolV2::Mixed;
2400  }
2401  return unit;
2402 }
2403 
2405 {
2407  mDistanceMapUnitScale = scale;
2408  mLineWidthMapUnitScale = scale;
2409  mOffsetMapUnitScale = scale;
2410 }
2411 
2413 {
2417  {
2418  return mDistanceMapUnitScale;
2419  }
2420  return QgsMapUnitScale();
2421 }
2422 
2424 {
2426 
2427  //default values
2428  double lineAngle = 45;
2429  double distance = 5;
2430  double lineWidth = 0.5;
2431  QColor color( Qt::black );
2432  double offset = 0.0;
2433 
2434  if ( properties.contains( "lineangle" ) )
2435  {
2436  //pre 2.5 projects used "lineangle"
2437  lineAngle = properties["lineangle"].toDouble();
2438  }
2439  else if ( properties.contains( "angle" ) )
2440  {
2441  lineAngle = properties["angle"].toDouble();
2442  }
2443  patternLayer->setLineAngle( lineAngle );
2444 
2445  if ( properties.contains( "distance" ) )
2446  {
2447  distance = properties["distance"].toDouble();
2448  }
2449  patternLayer->setDistance( distance );
2450 
2451  if ( properties.contains( "linewidth" ) )
2452  {
2453  //pre 2.5 projects used "linewidth"
2454  lineWidth = properties["linewidth"].toDouble();
2455  }
2456  else if ( properties.contains( "outline_width" ) )
2457  {
2458  lineWidth = properties["outline_width"].toDouble();
2459  }
2460  else if ( properties.contains( "line_width" ) )
2461  {
2462  lineWidth = properties["line_width"].toDouble();
2463  }
2464  patternLayer->setLineWidth( lineWidth );
2465 
2466  if ( properties.contains( "color" ) )
2467  {
2468  color = QgsSymbolLayerV2Utils::decodeColor( properties["color"] );
2469  }
2470  else if ( properties.contains( "outline_color" ) )
2471  {
2472  color = QgsSymbolLayerV2Utils::decodeColor( properties["outline_color"] );
2473  }
2474  else if ( properties.contains( "line_color" ) )
2475  {
2476  color = QgsSymbolLayerV2Utils::decodeColor( properties["line_color"] );
2477  }
2478  patternLayer->setColor( color );
2479 
2480  if ( properties.contains( "offset" ) )
2481  {
2482  offset = properties["offset"].toDouble();
2483  }
2484  patternLayer->setOffset( offset );
2485 
2486 
2487  if ( properties.contains( "distance_unit" ) )
2488  {
2489  patternLayer->setDistanceUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_unit"] ) );
2490  }
2491  if ( properties.contains( "distance_map_unit_scale" ) )
2492  {
2493  patternLayer->setDistanceMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_map_unit_scale"] ) );
2494  }
2495  if ( properties.contains( "line_width_unit" ) )
2496  {
2497  patternLayer->setLineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["line_width_unit"] ) );
2498  }
2499  else if ( properties.contains( "outline_width_unit" ) )
2500  {
2501  patternLayer->setLineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
2502  }
2503  if ( properties.contains( "line_width_map_unit_scale" ) )
2504  {
2505  patternLayer->setLineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["line_width_map_unit_scale"] ) );
2506  }
2507  if ( properties.contains( "offset_unit" ) )
2508  {
2509  patternLayer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
2510  }
2511  if ( properties.contains( "offset_map_unit_scale" ) )
2512  {
2513  patternLayer->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["offset_map_unit_scale"] ) );
2514  }
2515  if ( properties.contains( "outline_width_unit" ) )
2516  {
2517  patternLayer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
2518  }
2519  if ( properties.contains( "outline_width_map_unit_scale" ) )
2520  {
2521  patternLayer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
2522  }
2523 
2524  patternLayer->restoreDataDefinedProperties( properties );
2525 
2526  return patternLayer;
2527 }
2528 
2530 {
2531  return "LinePatternFill";
2532 }
2533 
2534 void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double lineAngle, double distance,
2535  double lineWidth, const QColor& color )
2536 {
2537  Q_UNUSED( lineWidth );
2538  Q_UNUSED( color );
2539 
2540  mBrush.setTextureImage( QImage() ); // set empty in case we have to return
2541 
2542  if ( !mFillLineSymbol )
2543  {
2544  return;
2545  }
2546  // We have to make a copy because marker intervals will have to be adjusted
2547  QgsLineSymbolV2* fillLineSymbol = mFillLineSymbol->clone();
2548  if ( !fillLineSymbol )
2549  {
2550  return;
2551  }
2552 
2553  const QgsRenderContext& ctx = context.renderContext();
2554  //double outlinePixelWidth = lineWidth * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mLineWidthUnit, mLineWidthMapUnitScale );
2557 
2558  // To get all patterns into image, we have to consider symbols size (estimateMaxBleed()).
2559  // For marker lines we have to get markers interval.
2560  double outputPixelBleed = 0;
2561  double outputPixelInterval = 0; // maximum interval
2562  for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2563  {
2564  QgsSymbolLayerV2 *layer = fillLineSymbol->symbolLayer( i );
2565  double layerBleed = layer->estimateMaxBleed();
2566  // TODO: to get real bleed we have to scale it using context and units,
2567  // unfortunately estimateMaxBleed() ignore units completely, e.g.
2568  // QgsMarkerLineSymbolLayerV2::estimateMaxBleed() is mixing marker size and
2569  // offset regardless units. This has to be fixed especially
2570  // in estimateMaxBleed(), context probably has to be used.
2571  // For now, we only support millimeters
2572  double outputPixelLayerBleed = layerBleed * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, QgsSymbolV2::MM );
2573  outputPixelBleed = qMax( outputPixelBleed, outputPixelLayerBleed );
2574 
2575  QgsMarkerLineSymbolLayerV2 *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayerV2 *>( layer );
2576  if ( markerLineLayer )
2577  {
2578  double outputPixelLayerInterval = markerLineLayer->interval() * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, markerLineLayer->intervalUnit(), markerLineLayer->intervalMapUnitScale() );
2579 
2580  // There may be multiple marker lines with different intervals.
2581  // In theory we should find the least common multiple, but that could be too
2582  // big (multiplication of intervals in the worst case).
2583  // Because patterns without small common interval would look strange, we
2584  // believe that the longest interval should usually be sufficient.
2585  outputPixelInterval = qMax( outputPixelInterval, outputPixelLayerInterval );
2586  }
2587  }
2588 
2589  if ( outputPixelInterval > 0 )
2590  {
2591  // We have to adjust marker intervals to integer pixel size to get
2592  // repeatable pattern.
2593  double intervalScale = qRound( outputPixelInterval ) / outputPixelInterval;
2594  outputPixelInterval = qRound( outputPixelInterval );
2595 
2596  for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2597  {
2598  QgsSymbolLayerV2 *layer = fillLineSymbol->symbolLayer( i );
2599 
2600  QgsMarkerLineSymbolLayerV2 *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayerV2 *>( layer );
2601  if ( markerLineLayer )
2602  {
2603  markerLineLayer->setInterval( intervalScale * markerLineLayer->interval() );
2604  }
2605  }
2606  }
2607 
2608  //create image
2609  int height, width;
2610  if ( qgsDoubleNear( lineAngle, 0 ) || qgsDoubleNear( lineAngle, 360 ) || qgsDoubleNear( lineAngle, 180 ) )
2611  {
2612  height = outputPixelDist;
2613  width = outputPixelInterval > 0 ? outputPixelInterval : height;
2614  }
2615  else if ( qgsDoubleNear( lineAngle, 90 ) || qgsDoubleNear( lineAngle, 270 ) )
2616  {
2617  width = outputPixelDist;
2618  height = outputPixelInterval > 0 ? outputPixelInterval : width;
2619  }
2620  else
2621  {
2622  height = outputPixelDist / cos( lineAngle * M_PI / 180 ); //keep perpendicular distance between lines constant
2623  width = outputPixelDist / sin( lineAngle * M_PI / 180 );
2624 
2625  // recalculate real angle and distance after rounding to pixels
2626  lineAngle = 180 * atan2( static_cast< double >( height ), static_cast< double >( width ) ) / M_PI;
2627  if ( lineAngle < 0 )
2628  {
2629  lineAngle += 360.;
2630  }
2631 
2632  height = qAbs( height );
2633  width = qAbs( width );
2634 
2635  outputPixelDist = height * cos( lineAngle * M_PI / 180 );
2636 
2637  // Round offset to correspond to one pixel height, otherwise lines may
2638  // be shifted on tile border if offset falls close to pixel center
2639  int offsetHeight = qRound( qAbs( outputPixelOffset / cos( lineAngle * M_PI / 180 ) ) );
2640  outputPixelOffset = offsetHeight * cos( lineAngle * M_PI / 180 );
2641  }
2642 
2643  //depending on the angle, we might need to render into a larger image and use a subset of it
2644  double dx = 0;
2645  double dy = 0;
2646 
2647  // Add buffer based on bleed but keep precisely the height/width ratio (angle)
2648  // thus we add integer multiplications of width and height covering the bleed
2649  int bufferMulti = qMax( qCeil( outputPixelBleed / width ), qCeil( outputPixelBleed / width ) );
2650 
2651  // Always buffer at least once so that center of line marker in upper right corner
2652  // does not fall outside due to representation error
2653  bufferMulti = qMax( bufferMulti, 1 );
2654 
2655  int xBuffer = width * bufferMulti;
2656  int yBuffer = height * bufferMulti;
2657  int innerWidth = width;
2658  int innerHeight = height;
2659  width += 2 * xBuffer;
2660  height += 2 * yBuffer;
2661 
2662  if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
2663  {
2664  return;
2665  }
2666 
2667  QImage patternImage( width, height, QImage::Format_ARGB32 );
2668  patternImage.fill( 0 );
2669 
2670  QPointF p1, p2, p3, p4, p5, p6;
2671  if ( qgsDoubleNear( lineAngle, 0.0 ) || qgsDoubleNear( lineAngle, 360.0 ) || qgsDoubleNear( lineAngle, 180.0 ) )
2672  {
2673  p1 = QPointF( 0, yBuffer );
2674  p2 = QPointF( width, yBuffer );
2675  p3 = QPointF( 0, yBuffer + innerHeight );
2676  p4 = QPointF( width, yBuffer + innerHeight );
2677  }
2678  else if ( qgsDoubleNear( lineAngle, 90.0 ) || qgsDoubleNear( lineAngle, 270.0 ) )
2679  {
2680  p1 = QPointF( xBuffer, height );
2681  p2 = QPointF( xBuffer, 0 );
2682  p3 = QPointF( xBuffer + innerWidth, height );
2683  p4 = QPointF( xBuffer + innerWidth, 0 );
2684  }
2685  else if ( lineAngle > 0 && lineAngle < 90 )
2686  {
2687  dx = outputPixelDist * cos(( 90 - lineAngle ) * M_PI / 180.0 );
2688  dy = outputPixelDist * sin(( 90 - lineAngle ) * M_PI / 180.0 );
2689  p1 = QPointF( 0, height );
2690  p2 = QPointF( width, 0 );
2691  p3 = QPointF( -dx, height - dy );
2692  p4 = QPointF( width - dx, -dy );
2693  p5 = QPointF( dx, height + dy );
2694  p6 = QPointF( width + dx, dy );
2695  }
2696  else if ( lineAngle > 180 && lineAngle < 270 )
2697  {
2698  dx = outputPixelDist * cos(( 90 - lineAngle ) * M_PI / 180.0 );
2699  dy = outputPixelDist * sin(( 90 - lineAngle ) * M_PI / 180.0 );
2700  p1 = QPointF( width, 0 );
2701  p2 = QPointF( 0, height );
2702  p3 = QPointF( width - dx, -dy );
2703  p4 = QPointF( -dx, height - dy );
2704  p5 = QPointF( width + dx, dy );
2705  p6 = QPointF( dx, height + dy );
2706  }
2707  else if ( lineAngle > 90 && lineAngle < 180 )
2708  {
2709  dy = outputPixelDist * cos(( 180 - lineAngle ) * M_PI / 180 );
2710  dx = outputPixelDist * sin(( 180 - lineAngle ) * M_PI / 180 );
2711  p1 = QPointF( 0, 0 );
2712  p2 = QPointF( width, height );
2713  p5 = QPointF( dx, -dy );
2714  p6 = QPointF( width + dx, height - dy );
2715  p3 = QPointF( -dx, dy );
2716  p4 = QPointF( width - dx, height + dy );
2717  }
2718  else if ( lineAngle > 270 && lineAngle < 360 )
2719  {
2720  dy = outputPixelDist * cos(( 180 - lineAngle ) * M_PI / 180 );
2721  dx = outputPixelDist * sin(( 180 - lineAngle ) * M_PI / 180 );
2722  p1 = QPointF( width, height );
2723  p2 = QPointF( 0, 0 );
2724  p5 = QPointF( width + dx, height - dy );
2725  p6 = QPointF( dx, -dy );
2726  p3 = QPointF( width - dx, height + dy );
2727  p4 = QPointF( -dx, dy );
2728  }
2729 
2730  if ( !qgsDoubleNear( mOffset, 0.0 ) ) //shift everything
2731  {
2732  QPointF tempPt;
2733  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelDist + outputPixelOffset );
2734  p3 = QPointF( tempPt.x(), tempPt.y() );
2735  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelDist + outputPixelOffset );
2736  p4 = QPointF( tempPt.x(), tempPt.y() );
2737  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p5, outputPixelDist - outputPixelOffset );
2738  p5 = QPointF( tempPt.x(), tempPt.y() );
2739  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p6, outputPixelDist - outputPixelOffset );
2740  p6 = QPointF( tempPt.x(), tempPt.y() );
2741 
2742  //update p1, p2 last
2743  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelOffset );
2744  p1 = QPointF( tempPt.x(), tempPt.y() );
2745  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelOffset );
2746  p2 = QPointF( tempPt.x(), tempPt.y() );
2747  }
2748 
2749  QPainter p( &patternImage );
2750 
2751 #if 0
2752  // DEBUG: Draw rectangle
2753  p.setRenderHint( QPainter::Antialiasing, false ); // get true rect
2754  QPen pen( QColor( Qt::black ) );
2755  pen.setWidthF( 0.1 );
2756  pen.setCapStyle( Qt::FlatCap );
2757  p.setPen( pen );
2758 
2759  // To see this rectangle, comment buffer cut below.
2760  // Subtract 1 because not antialiased are rendered to the right/down by 1 pixel
2761  QPolygon polygon = QPolygon() << QPoint( 0, 0 ) << QPoint( width - 1, 0 ) << QPoint( width - 1, height - 1 ) << QPoint( 0, height - 1 ) << QPoint( 0, 0 );
2762  p.drawPolygon( polygon );
2763 
2764  polygon = QPolygon() << QPoint( xBuffer, yBuffer ) << QPoint( width - xBuffer - 1, yBuffer ) << QPoint( width - xBuffer - 1, height - yBuffer - 1 ) << QPoint( xBuffer, height - yBuffer - 1 ) << QPoint( xBuffer, yBuffer );
2765  p.drawPolygon( polygon );
2766 #endif
2767 
2768  // Use antialiasing because without antialiasing lines are rendered to the
2769  // right and below the mathematically defined points (not symmetrical)
2770  // and such tiles become useless for are filling
2771  p.setRenderHint( QPainter::Antialiasing, true );
2772 
2773  // line rendering needs context for drawing on patternImage
2774  QgsRenderContext lineRenderContext;
2775  lineRenderContext.setPainter( &p );
2776  lineRenderContext.setRasterScaleFactor( 1.0 );
2777  lineRenderContext.setScaleFactor( context.renderContext().scaleFactor() * context.renderContext().rasterScaleFactor() );
2779  lineRenderContext.setMapToPixel( mtp );
2780  lineRenderContext.setForceVectorOutput( false );
2781  lineRenderContext.setExpressionContext( context.renderContext().expressionContext() );
2782 
2783  fillLineSymbol->startRender( lineRenderContext, context.fields() );
2784 
2785  QVector<QPolygonF> polygons;
2786  polygons.append( QPolygonF() << p1 << p2 );
2787  polygons.append( QPolygonF() << p3 << p4 );
2788  if ( !qgsDoubleNear( lineAngle, 0 ) && !qgsDoubleNear( lineAngle, 360 ) && !qgsDoubleNear( lineAngle, 90 ) && !qgsDoubleNear( lineAngle, 180 ) && !qgsDoubleNear( lineAngle, 270 ) )
2789  {
2790  polygons.append( QPolygonF() << p5 << p6 );
2791  }
2792 
2793  Q_FOREACH ( const QPolygonF& polygon, polygons )
2794  {
2795  fillLineSymbol->renderPolyline( polygon, context.feature(), lineRenderContext, -1, context.selected() );
2796  }
2797 
2798  fillLineSymbol->stopRender( lineRenderContext );
2799  p.end();
2800 
2801  // Cut off the buffer
2802  patternImage = patternImage.copy( xBuffer, yBuffer, patternImage.width() - 2 * xBuffer, patternImage.height() - 2 * yBuffer );
2803 
2804  //set image to mBrush
2805  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
2806  {
2807  QImage transparentImage = patternImage.copy();
2808  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
2809  brush.setTextureImage( transparentImage );
2810  }
2811  else
2812  {
2813  brush.setTextureImage( patternImage );
2814  }
2815 
2816  QTransform brushTransform;
2817  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
2818  brush.setTransform( brushTransform );
2819 
2820  delete fillLineSymbol;
2821 }
2822 
2824 {
2825  applyPattern( context, mBrush, mLineAngle, mDistance, mLineWidth, mColor );
2826 
2827  if ( mFillLineSymbol )
2828  {
2829  mFillLineSymbol->startRender( context.renderContext(), context.fields() );
2830  }
2831 
2832  prepareExpressions( context );
2833 }
2834 
2836 {
2837 }
2838 
2840 {
2841  QgsStringMap map;
2842  map.insert( "angle", QString::number( mLineAngle ) );
2843  map.insert( "distance", QString::number( mDistance ) );
2844  map.insert( "line_width", QString::number( mLineWidth ) );
2846  map.insert( "offset", QString::number( mOffset ) );
2848  map.insert( "line_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mLineWidthUnit ) );
2850  map.insert( "distance_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceMapUnitScale ) );
2851  map.insert( "line_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mLineWidthMapUnitScale ) );
2852  map.insert( "offset_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale ) );
2853  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
2854  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
2856  return map;
2857 }
2858 
2860 {
2862  if ( mFillLineSymbol )
2863  {
2864  clonedLayer->setSubSymbol( mFillLineSymbol->clone() );
2865  }
2866  copyPaintEffect( clonedLayer );
2867  return clonedLayer;
2868 }
2869 
2871 {
2872  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
2873  if ( !props.value( "uom", "" ).isEmpty() )
2874  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
2875  element.appendChild( symbolizerElem );
2876 
2877  // <Geometry>
2878  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
2879 
2880  QDomElement fillElem = doc.createElement( "se:Fill" );
2881  symbolizerElem.appendChild( fillElem );
2882 
2883  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
2884  fillElem.appendChild( graphicFillElem );
2885 
2886  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2887  graphicFillElem.appendChild( graphicElem );
2888 
2889  //line properties must be inside the graphic definition
2890  QColor lineColor = mFillLineSymbol ? mFillLineSymbol->color() : QColor();
2891  double lineWidth = mFillLineSymbol ? mFillLineSymbol->width() : 0.0;
2892  lineWidth = QgsSymbolLayerV2Utils::rescaleUom( lineWidth, mLineWidthUnit, props );
2894  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), lineColor, Qt::SolidLine, lineWidth, distance );
2895 
2896  // <Rotation>
2897  QString angleFunc;
2898  bool ok;
2899  double angle = props.value( "angle", "0" ).toDouble( &ok );
2900  if ( !ok )
2901  {
2902  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mLineAngle );
2903  }
2904  else if ( !qgsDoubleNear( angle + mLineAngle, 0.0 ) )
2905  {
2906  angleFunc = QString::number( angle + mLineAngle );
2907  }
2908  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2909 
2910  // <se:Displacement>
2911  QPointF lineOffset( sin( mLineAngle ) * mOffset, cos( mLineAngle ) * mOffset );
2912  lineOffset = QgsSymbolLayerV2Utils::rescaleUom( lineOffset, mOffsetUnit, props );
2913  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, lineOffset );
2914 }
2915 
2917 {
2918  QString featureStyle;
2919  featureStyle.append( "Brush(" );
2920  featureStyle.append( QString( "fc:%1" ).arg( mColor.name() ) );
2921  featureStyle.append( QString( ",bc:%1" ).arg( "#00000000" ) ); //transparent background
2922  featureStyle.append( ",id:\"ogr-brush-2\"" );
2923  featureStyle.append( QString( ",a:%1" ).arg( mLineAngle ) );
2924  featureStyle.append( QString( ",s:%1" ).arg( mLineWidth * widthScaleFactor ) );
2925  featureStyle.append( ",dx:0mm" );
2926  featureStyle.append( QString( ",dy:%1mm" ).arg( mDistance * widthScaleFactor ) );
2927  featureStyle.append( ')' );
2928  return featureStyle;
2929 }
2930 
2932 {
2935  && ( !mFillLineSymbol || !mFillLineSymbol->hasDataDefinedProperties() ) )
2936  {
2937  return; //no data defined settings
2938  }
2939 
2940  bool ok;
2941  double lineAngle = mLineAngle;
2943  {
2946  }
2947  double distance = mDistance;
2949  {
2952  }
2953  double lineWidth = mLineWidth;
2955  {
2958  }
2959  QColor color = mColor;
2961  {
2964  if ( ok )
2965  color = QgsSymbolLayerV2Utils::decodeColor( colorString );
2966  }
2967  applyPattern( context, mBrush, lineAngle, distance, lineWidth, color );
2968 }
2969 
2971 {
2972  QgsDebugMsg( "Entered." );
2973 
2974  QString name;
2975  QColor fillColor, lineColor;
2976  double size, lineWidth;
2977  Qt::PenStyle lineStyle;
2978 
2979  QDomElement fillElem = element.firstChildElement( "Fill" );
2980  if ( fillElem.isNull() )
2981  return nullptr;
2982 
2983  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
2984  if ( graphicFillElem.isNull() )
2985  return nullptr;
2986 
2987  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
2988  if ( graphicElem.isNull() )
2989  return nullptr;
2990 
2991  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, lineColor, lineStyle, lineWidth, size ) )
2992  return nullptr;
2993 
2994  if ( name != "horline" )
2995  return nullptr;
2996 
2997  double angle = 0.0;
2998  QString angleFunc;
2999  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
3000  {
3001  bool ok;
3002  double d = angleFunc.toDouble( &ok );
3003  if ( ok )
3004  angle = d;
3005  }
3006 
3007  double offset = 0.0;
3008  QPointF vectOffset;
3009  if ( QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, vectOffset ) )
3010  {
3011  offset = sqrt( pow( vectOffset.x(), 2 ) + pow( vectOffset.y(), 2 ) );
3012  }
3013 
3015  sl->setColor( lineColor );
3016  sl->setLineWidth( lineWidth );
3017  sl->setLineAngle( angle );
3018  sl->setOffset( offset );
3019  sl->setDistance( size );
3020 
3021  // try to get the outline
3022  QDomElement strokeElem = element.firstChildElement( "Stroke" );
3023  if ( !strokeElem.isNull() )
3024  {
3026  if ( l )
3027  {
3028  QgsSymbolLayerV2List layers;
3029  layers.append( l );
3030  sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
3031  }
3032  }
3033 
3034  return sl;
3035 }
3036 
3037 
3039 
3041  mDistanceXUnit( QgsSymbolV2::MM ), mDistanceY( 15 ), mDistanceYUnit( QgsSymbolV2::MM ), mDisplacementX( 0 ), mDisplacementXUnit( QgsSymbolV2::MM ),
3042  mDisplacementY( 0 ), mDisplacementYUnit( QgsSymbolV2::MM )
3043 {
3044  mDistanceX = 15;
3045  mDistanceY = 15;
3046  mDisplacementX = 0;
3047  mDisplacementY = 0;
3049  QgsImageFillSymbolLayer::setSubSymbol( nullptr ); //no outline
3050 }
3051 
3053 {
3054  delete mMarkerSymbol;
3055 }
3056 
3058 {
3060  mDistanceXUnit = unit;
3061  mDistanceYUnit = unit;
3062  mDisplacementXUnit = unit;
3063  mDisplacementYUnit = unit;
3064  if ( mMarkerSymbol )
3065  {
3066  mMarkerSymbol->setOutputUnit( unit );
3067  }
3068 
3069 }
3070 
3072 {
3074  if ( mDistanceXUnit != unit || mDistanceYUnit != unit || mDisplacementXUnit != unit || mDisplacementYUnit != unit )
3075  {
3076  return QgsSymbolV2::Mixed;
3077  }
3078  return unit;
3079 }
3080 
3082 {
3084  mDistanceXMapUnitScale = scale;
3085  mDistanceYMapUnitScale = scale;
3088 }
3089 
3091 {
3096  {
3097  return mDistanceXMapUnitScale;
3098  }
3099  return QgsMapUnitScale();
3100 }
3101 
3103 {
3105  if ( properties.contains( "distance_x" ) )
3106  {
3107  layer->setDistanceX( properties["distance_x"].toDouble() );
3108  }
3109  if ( properties.contains( "distance_y" ) )
3110  {
3111  layer->setDistanceY( properties["distance_y"].toDouble() );
3112  }
3113  if ( properties.contains( "displacement_x" ) )
3114  {
3115  layer->setDisplacementX( properties["displacement_x"].toDouble() );
3116  }
3117  if ( properties.contains( "displacement_y" ) )
3118  {
3119  layer->setDisplacementY( properties["displacement_y"].toDouble() );
3120  }
3121 
3122  if ( properties.contains( "distance_x_unit" ) )
3123  {
3124  layer->setDistanceXUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_x_unit"] ) );
3125  }
3126  if ( properties.contains( "distance_x_map_unit_scale" ) )
3127  {
3128  layer->setDistanceXMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_x_map_unit_scale"] ) );
3129  }
3130  if ( properties.contains( "distance_y_unit" ) )
3131  {
3132  layer->setDistanceYUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_y_unit"] ) );
3133  }
3134  if ( properties.contains( "distance_y_map_unit_scale" ) )
3135  {
3136  layer->setDistanceYMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_y_map_unit_scale"] ) );
3137  }
3138  if ( properties.contains( "displacement_x_unit" ) )
3139  {
3140  layer->setDisplacementXUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["displacement_x_unit"] ) );
3141  }
3142  if ( properties.contains( "displacement_x_map_unit_scale" ) )
3143  {
3144  layer->setDisplacementXMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["displacement_x_map_unit_scale"] ) );
3145  }
3146  if ( properties.contains( "displacement_y_unit" ) )
3147  {
3148  layer->setDisplacementYUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["displacement_y_unit"] ) );
3149  }
3150  if ( properties.contains( "displacement_y_map_unit_scale" ) )
3151  {
3152  layer->setDisplacementYMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["displacement_y_map_unit_scale"] ) );
3153  }
3154  if ( properties.contains( "outline_width_unit" ) )
3155  {
3156  layer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
3157  }
3158  if ( properties.contains( "outline_width_map_unit_scale" ) )
3159  {
3160  layer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
3161  }
3162 
3163  layer->restoreDataDefinedProperties( properties );
3164 
3165  return layer;
3166 }
3167 
3169 {
3170  return "PointPatternFill";
3171 }
3172 
3173 void QgsPointPatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double distanceX, double distanceY,
3174  double displacementX, double displacementY )
3175 {
3176  //render 3 rows and columns in one go to easily incorporate displacement
3177  const QgsRenderContext& ctx = context.renderContext();
3180 
3181  if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
3182  {
3183  QImage img;
3184  brush.setTextureImage( img );
3185  return;
3186  }
3187 
3188  QImage patternImage( width, height, QImage::Format_ARGB32 );
3189  patternImage.fill( 0 );
3190 
3191  if ( mMarkerSymbol )
3192  {
3193  QPainter p( &patternImage );
3194 
3195  //marker rendering needs context for drawing on patternImage
3196  QgsRenderContext pointRenderContext;
3197  pointRenderContext.setRendererScale( context.renderContext().rendererScale() );
3198  pointRenderContext.setPainter( &p );
3199  pointRenderContext.setRasterScaleFactor( 1.0 );
3200  pointRenderContext.setScaleFactor( context.renderContext().scaleFactor() * context.renderContext().rasterScaleFactor() );
3202  pointRenderContext.setMapToPixel( mtp );
3203  pointRenderContext.setForceVectorOutput( false );
3204  pointRenderContext.setExpressionContext( context.renderContext().expressionContext() );
3205 
3206  mMarkerSymbol->startRender( pointRenderContext, context.fields() );
3207 
3208  //render corner points
3209  mMarkerSymbol->renderPoint( QPointF( 0, 0 ), context.feature(), pointRenderContext );
3210  mMarkerSymbol->renderPoint( QPointF( width, 0 ), context.feature(), pointRenderContext );
3211  mMarkerSymbol->renderPoint( QPointF( 0, height ), context.feature(), pointRenderContext );
3212  mMarkerSymbol->renderPoint( QPointF( width, height ), context.feature(), pointRenderContext );
3213 
3214  //render displaced points
3216  double displacementPixelY = displacementY * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDisplacementYUnit, mDisplacementYMapUnitScale );
3217  mMarkerSymbol->renderPoint( QPointF( width / 2.0, -displacementPixelY ), context.feature(), pointRenderContext );
3218  mMarkerSymbol->renderPoint( QPointF( displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
3219  mMarkerSymbol->renderPoint( QPointF( width / 2.0 + displacementPixelX, height / 2.0 - displacementPixelY ), context.feature(), pointRenderContext );
3220  mMarkerSymbol->renderPoint( QPointF( width + displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
3221  mMarkerSymbol->renderPoint( QPointF( width / 2.0, height - displacementPixelY ), context.feature(), pointRenderContext );
3222 
3223  mMarkerSymbol->stopRender( pointRenderContext );
3224  }
3225 
3226  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
3227  {
3228  QImage transparentImage = patternImage.copy();
3229  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
3230  brush.setTextureImage( transparentImage );
3231  }
3232  else
3233  {
3234  brush.setTextureImage( patternImage );
3235  }
3236  QTransform brushTransform;
3237  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
3238  brush.setTransform( brushTransform );
3239 }
3240 
3242 {
3243  applyPattern( context, mBrush, mDistanceX, mDistanceY, mDisplacementX, mDisplacementY );
3244 
3245  if ( mOutline )
3246  {
3247  mOutline->startRender( context.renderContext(), context.fields() );
3248  }
3249  prepareExpressions( context );
3250 }
3251 
3253 {
3254  if ( mOutline )
3255  {
3256  mOutline->stopRender( context.renderContext() );
3257  }
3258 }
3259 
3261 {
3262  QgsStringMap map;
3263  map.insert( "distance_x", QString::number( mDistanceX ) );
3264  map.insert( "distance_y", QString::number( mDistanceY ) );
3265  map.insert( "displacement_x", QString::number( mDisplacementX ) );
3266  map.insert( "displacement_y", QString::number( mDisplacementY ) );
3267  map.insert( "distance_x_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceXUnit ) );
3268  map.insert( "distance_y_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceYUnit ) );
3269  map.insert( "displacement_x_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementXUnit ) );
3270  map.insert( "displacement_y_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementYUnit ) );
3271  map.insert( "distance_x_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceXMapUnitScale ) );
3272  map.insert( "distance_y_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceYMapUnitScale ) );
3273  map.insert( "displacement_x_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDisplacementXMapUnitScale ) );
3274  map.insert( "displacement_y_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDisplacementYMapUnitScale ) );
3275  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
3276  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
3278  return map;
3279 }
3280 
3282 {
3284  if ( mMarkerSymbol )
3285  {
3286  clonedLayer->setSubSymbol( mMarkerSymbol->clone() );
3287  }
3288  copyPaintEffect( clonedLayer );
3289  return clonedLayer;
3290 }
3291 
3293 {
3294  for ( int i = 0; i < mMarkerSymbol->symbolLayerCount(); i++ )
3295  {
3296  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
3297  if ( !props.value( "uom", "" ).isEmpty() )
3298  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
3299  element.appendChild( symbolizerElem );
3300 
3301  // <Geometry>
3302  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
3303 
3304  QDomElement fillElem = doc.createElement( "se:Fill" );
3305  symbolizerElem.appendChild( fillElem );
3306 
3307  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
3308  fillElem.appendChild( graphicFillElem );
3309 
3310  // store distanceX, distanceY, displacementX, displacementY in a <VendorOption>
3314  QDomElement distanceElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "distance", dist );
3315  symbolizerElem.appendChild( distanceElem );
3316 
3318  QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
3319  if ( !markerLayer )
3320  {
3321  QString errorMsg = QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() );
3322  graphicFillElem.appendChild( doc.createComment( errorMsg ) );
3323  }
3324  else
3325  {
3326  markerLayer->writeSldMarker( doc, graphicFillElem, props );
3327  }
3328  }
3329 }
3330 
3332 {
3333  Q_UNUSED( element );
3334  return nullptr;
3335 }
3336 
3338 {
3339  if ( !symbol )
3340  {
3341  return false;
3342  }
3343 
3344  if ( symbol->type() == QgsSymbolV2::Marker )
3345  {
3346  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( symbol );
3347  delete mMarkerSymbol;
3348  mMarkerSymbol = markerSymbol;
3349  }
3350  return true;
3351 }
3352 
3354 {
3358  {
3359  return;
3360  }
3361 
3362  double distanceX = mDistanceX;
3364  {
3367  }
3368  double distanceY = mDistanceY;
3370  {
3373  }
3374  double displacementX = mDisplacementX;
3376  {
3379  }
3380  double displacementY = mDisplacementY;
3382  {
3385  }
3386  applyPattern( context, mBrush, distanceX, distanceY, displacementX, displacementY );
3387 }
3388 
3390 {
3391  return 0;
3392 }
3393 
3395 {
3397 
3398  if ( mMarkerSymbol )
3399  attributes.unite( mMarkerSymbol->usedAttributes() );
3400 
3401  return attributes;
3402 }
3403 
3405 {
3406  mColor = c;
3407  if ( mMarkerSymbol )
3408  mMarkerSymbol->setColor( c );
3409 }
3410 
3412 {
3413  return mMarkerSymbol ? mMarkerSymbol->color() : mColor;
3414 }
3415 
3417 
3418 
3419 QgsCentroidFillSymbolLayerV2::QgsCentroidFillSymbolLayerV2(): mMarker( nullptr ), mPointOnSurface( false )
3420 {
3422 }
3423 
3425 {
3426  delete mMarker;
3427 }
3428 
3430 {
3432 
3433  if ( properties.contains( "point_on_surface" ) )
3434  sl->setPointOnSurface( properties["point_on_surface"].toInt() != 0 );
3435 
3436  return sl;
3437 }
3438 
3440 {
3441  return "CentroidFill";
3442 }
3443 
3445 {
3446  mMarker->setColor( color );
3447  mColor = color;
3448 }
3449 
3451 {
3452  return mMarker ? mMarker->color() : mColor;
3453 }
3454 
3456 {
3457  mMarker->setAlpha( context.alpha() );
3458  mMarker->startRender( context.renderContext(), context.fields() );
3459 }
3460 
3462 {
3463  mMarker->stopRender( context.renderContext() );
3464 }
3465 
3467 {
3468  Q_UNUSED( rings );
3469 
3471  mMarker->renderPoint( centroid, context.feature(), context.renderContext(), -1, context.selected() );
3472 }
3473 
3475 {
3476  QgsStringMap map;
3477  map["point_on_surface"] = QString::number( mPointOnSurface );
3478  return map;
3479 }
3480 
3482 {
3484  x->mAngle = mAngle;
3485  x->mColor = mColor;
3486  x->setSubSymbol( mMarker->clone() );
3488  copyPaintEffect( x );
3489  return x;
3490 }
3491 
3493 {
3494  // SLD 1.0 specs says: "if a line, polygon, or raster geometry is
3495  // used with PointSymbolizer, then the semantic is to use the centroid
3496  // of the geometry, or any similar representative point.
3497  mMarker->toSld( doc, element, props );
3498 }
3499 
3501 {
3502  QgsDebugMsg( "Entered." );
3503 
3505  if ( !l )
3506  return nullptr;
3507 
3508  QgsSymbolLayerV2List layers;
3509  layers.append( l );
3510  QgsMarkerSymbolV2 *marker = new QgsMarkerSymbolV2( layers );
3511 
3513  sl->setSubSymbol( marker );
3514  return sl;
3515 }
3516 
3517 
3519 {
3520  return mMarker;
3521 }
3522 
3524 {
3525  if ( !symbol || symbol->type() != QgsSymbolV2::Marker )
3526  {
3527  delete symbol;
3528  return false;
3529  }
3530 
3531  delete mMarker;
3532  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
3533  mColor = mMarker->color();
3534  return true;
3535 }
3536 
3538 {
3540 
3541  if ( mMarker )
3542  attributes.unite( mMarker->usedAttributes() );
3543 
3544  return attributes;
3545 }
3546 
3548 {
3549  if ( mMarker )
3550  {
3551  mMarker->setOutputUnit( unit );
3552  }
3553 }
3554 
3556 {
3557  if ( mMarker )
3558  {
3559  return mMarker->outputUnit();
3560  }
3561  return QgsSymbolV2::Mixed; //mOutputUnit;
3562 }
3563 
3565 {
3566  if ( mMarker )
3567  {
3568  mMarker->setMapUnitScale( scale );
3569  }
3570 }
3571 
3573 {
3574  if ( mMarker )
3575  {
3576  return mMarker->mapUnitScale();
3577  }
3578  return QgsMapUnitScale();
3579 }
3580 
3581 
3582 
3583 
3586  , mImageFilePath( imageFilePath )
3587  , mCoordinateMode( QgsRasterFillSymbolLayer::Feature )
3588  , mAlpha( 1.0 )
3589  , mOffsetUnit( QgsSymbolV2::MM )
3590  , mWidth( 0.0 )
3591  , mWidthUnit( QgsSymbolV2::Pixel )
3592 {
3593  QgsImageFillSymbolLayer::setSubSymbol( nullptr ); //disable sub symbol
3594 }
3595 
3597 {
3598 
3599 }
3600 
3602 {
3604  double alpha = 1.0;
3605  QPointF offset;
3606  double angle = 0.0;
3607  double width = 0.0;
3608 
3609  QString imagePath;
3610  if ( properties.contains( "imageFile" ) )
3611  {
3612  imagePath = properties["imageFile"];
3613  }
3614  if ( properties.contains( "coordinate_mode" ) )
3615  {
3616  mode = static_cast< FillCoordinateMode >( properties["coordinate_mode"].toInt() );
3617  }
3618  if ( properties.contains( "alpha" ) )
3619  {
3620  alpha = properties["alpha"].toDouble();
3621  }
3622  if ( properties.contains( "offset" ) )
3623  {
3624  offset = QgsSymbolLayerV2Utils::decodePoint( properties["offset"] );
3625  }
3626  if ( properties.contains( "angle" ) )
3627  {
3628  angle = properties["angle"].toDouble();
3629  }
3630  if ( properties.contains( "width" ) )
3631  {
3632  width = properties["width"].toDouble();
3633  }
3634  QgsRasterFillSymbolLayer* symbolLayer = new QgsRasterFillSymbolLayer( imagePath );
3635  symbolLayer->setCoordinateMode( mode );
3636  symbolLayer->setAlpha( alpha );
3637  symbolLayer->setOffset( offset );
3638  symbolLayer->setAngle( angle );
3639  symbolLayer->setWidth( width );
3640  if ( properties.contains( "offset_unit" ) )
3641  {
3642  symbolLayer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
3643  }
3644  if ( properties.contains( "offset_map_unit_scale" ) )
3645  {
3646  symbolLayer->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["offset_map_unit_scale"] ) );
3647  }
3648  if ( properties.contains( "width_unit" ) )
3649  {
3650  symbolLayer->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["width_unit"] ) );
3651  }
3652  if ( properties.contains( "width_map_unit_scale" ) )
3653  {
3654  symbolLayer->setWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["width_map_unit_scale"] ) );
3655  }
3656 
3657  symbolLayer->restoreDataDefinedProperties( properties );
3658 
3659  return symbolLayer;
3660 }
3661 
3663 {
3664  Q_UNUSED( symbol );
3665  return true;
3666 }
3667 
3669 {
3670  return "RasterFill";
3671 }
3672 
3674 {
3675  QPainter* p = context.renderContext().painter();
3676  if ( !p )
3677  {
3678  return;
3679  }
3680 
3681  QPointF offset;
3682  if ( !mOffset.isNull() )
3683  {
3686  p->translate( offset );
3687  }
3688  if ( mCoordinateMode == Feature )
3689  {
3690  QRectF boundingRect = points.boundingRect();
3691  mBrush.setTransform( mBrush.transform().translate( boundingRect.left() - mBrush.transform().dx(),
3692  boundingRect.top() - mBrush.transform().dy() ) );
3693  }
3694 
3695  QgsImageFillSymbolLayer::renderPolygon( points, rings, context );
3696  if ( !mOffset.isNull() )
3697  {
3698  p->translate( -offset );
3699  }
3700 }
3701 
3703 {
3704  prepareExpressions( context );
3705  applyPattern( mBrush, mImageFilePath, mWidth, mAlpha, context );
3706 }
3707 
3709 {
3710  Q_UNUSED( context );
3711 }
3712 
3714 {
3715  QgsStringMap map;
3716  map["imageFile"] = mImageFilePath;
3717  map["coordinate_mode"] = QString::number( mCoordinateMode );
3718  map["alpha"] = QString::number( mAlpha );
3719  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
3720  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
3721  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
3722  map["angle"] = QString::number( mAngle );
3723  map["width"] = QString::number( mWidth );
3724  map["width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mWidthUnit );
3725  map["width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mWidthMapUnitScale );
3726 
3728  return map;
3729 }
3730 
3732 {
3735  sl->setAlpha( mAlpha );
3736  sl->setOffset( mOffset );
3737  sl->setOffsetUnit( mOffsetUnit );
3739  sl->setAngle( mAngle );
3740  sl->setWidth( mWidth );
3741  sl->setWidthUnit( mWidthUnit );
3744  copyPaintEffect( sl );
3745  return sl;
3746 }
3747 
3749 {
3750  return mOffset.x() > mOffset.y() ? mOffset.x() : mOffset.y();
3751 }
3752 
3754 {
3755  mImageFilePath = imagePath;
3756 }
3757 
3759 {
3760  mCoordinateMode = mode;
3761 }
3762 
3764 {
3765  mAlpha = alpha;
3766 }
3767 
3769 {
3770  if ( !hasDataDefinedProperties() )
3771  return; // shortcut
3772 
3773  bool hasWidthExpression = hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH );
3774  bool hasFileExpression = hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILE );
3775  bool hasAlphaExpression = hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_ALPHA );
3776  bool hasAngleExpression = hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_ANGLE );
3777 
3778  if ( !hasWidthExpression && !hasAngleExpression && !hasAlphaExpression && !hasFileExpression )
3779  {
3780  return; //no data defined settings
3781  }
3782 
3783  bool ok;
3784  if ( hasAngleExpression )
3785  {
3786  context.setOriginalValueVariable( mAngle );
3787  double nextAngle = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_ANGLE, context, QVariant(), &ok ).toDouble();
3788  if ( ok )
3789  mNextAngle = nextAngle;
3790  }
3791 
3792  if ( !hasWidthExpression && !hasAlphaExpression && !hasFileExpression )
3793  {
3794  return; //nothing further to do
3795  }
3796 
3797  double width = mWidth;
3798  if ( hasWidthExpression )
3799  {
3800  context.setOriginalValueVariable( mWidth );
3802  }
3803  double alpha = mAlpha;
3804  if ( hasAlphaExpression )
3805  {
3806  context.setOriginalValueVariable( mAlpha );
3808  }
3809  QString file = mImageFilePath;
3810  if ( hasFileExpression )
3811  {
3814  }
3815  applyPattern( mBrush, file, width, alpha, context );
3816 }
3817 
3818 void QgsRasterFillSymbolLayer::applyPattern( QBrush &brush, const QString &imageFilePath, const double width, const double alpha, const QgsSymbolV2RenderContext &context )
3819 {
3820  QImage image( imageFilePath );
3821  if ( image.isNull() )
3822  {
3823  return;
3824  }
3825  if ( !image.hasAlphaChannel() )
3826  {
3827  image = image.convertToFormat( QImage::Format_ARGB32 );
3828  }
3829 
3830  double pixelWidth;
3831  if ( width > 0 )
3832  {
3834  }
3835  else
3836  {
3837  pixelWidth = image.width();
3838  }
3839 
3840  //reduce alpha of image
3841  if ( alpha < 1.0 )
3842  {
3843  QPainter p;
3844  p.begin( &image );
3845  p.setCompositionMode( QPainter::CompositionMode_DestinationIn );
3846  QColor alphaColor( 0, 0, 0 );
3847  alphaColor.setAlphaF( alpha );
3848  p.fillRect( image.rect(), alphaColor );
3849  p.end();
3850  }
3851 
3852  //resize image if required
3853  if ( !qgsDoubleNear( pixelWidth, image.width() ) )
3854  {
3855  image = image.scaledToWidth( pixelWidth, Qt::SmoothTransformation );
3856  }
3857 
3858  brush.setTextureImage( image );
3859 }
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
static double mapUnitScaleFactor(double scaleDenominator, QgsSymbolV2::OutputUnit symbolUnits, QGis::UnitType mapUnits)
QgsMapUnitScale mSvgOutlineWidthMapUnitScale
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
uchar * scanLine(int i)
static const QString EXPR_DISTANCE_Y
void setBorderWidthMapUnitScale(const QgsMapUnitScale &scale)
QgsMapUnitScale mapUnitScale() const override
QgsSymbolV2 * subSymbol() override
void setForceVectorOutput(bool force)
void setDistanceUnit(QgsSymbolV2::OutputUnit unit)
Sets the unit for the maximum distance to shade inside of the shape from the polygon&#39;s boundary...
static void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
QImage convertToFormat(Format format, QFlags< Qt::ImageConversionFlag > flags) const
#define DEFAULT_SIMPLEFILL_BORDERCOLOR
QString layerType() const override
Returns a string that represents this layer type.
static const QString EXPR_DISPLACEMENT_Y
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
bool ignoreRings() const
Returns whether the shapeburst fill is set to ignore polygon interior rings.
double rendererScale() const
virtual QSet< QString > usedAttributes() const override
Returns the set of attributes referenced by the layer.
void setReferencePoint1(QPointF referencePoint)
Starting point of gradient fill, in the range [0,0] - [1,1].
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:381
QgsSymbolV2::OutputUnit mSvgOutlineWidthUnit
void setStyle(Qt::PenStyle style)
void setReferencePoint2IsCentroid(bool isCentroid)
Sets the end point of the gradient to be the feature centroid.
void startRender(QgsSymbolV2RenderContext &context) override
void setSvgOutlineWidth(double w)
QString & append(QChar ch)
static void multiplyImageOpacity(QImage *image, qreal alpha)
Multiplies opacity of image pixel values with a (global) transparency value.
OutputUnit
The unit of the output.
Definition: qgssymbolv2.h:62
QImage scaledToWidth(int width, Qt::TransformationMode mode) const
QColor dxfColor(QgsSymbolV2RenderContext &context) const override
QgsSymbolV2::OutputUnit mOffsetUnit
static Qt::BrushStyle decodeBrushStyle(const QString &str)
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
FillCoordinateMode mCoordinateMode
static bool lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=nullptr, Qt::PenCapStyle *penCapStyle=nullptr, QVector< qreal > *customDashPattern=nullptr, double *dashOffset=nullptr)
QgsSymbolV2::OutputUnit mLineWidthUnit
QByteArray getImageData(const QString &path) const
Get image data.
virtual QString type() const =0
QSet< QString > usedAttributes() const override
Returns the set of attributes referenced by the layer.
bool end()
bool contains(const Key &key) const
static Q_DECL_DEPRECATED bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &borderColor, double &borderWidth, double &size)
static const QString EXPR_BORDER_COLOR
void fillRect(const QRectF &rectangle, const QBrush &brush)
void setCompositionMode(CompositionMode mode)
QgsRasterFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
virtual QgsLineSymbolV2 * clone() const override
const uchar * constScanLine(int i) const
qreal alphaF() const
void setSvgFillColor(const QColor &c)
void setPatternWidthMapUnitScale(const QgsMapUnitScale &scale)
void setRenderHint(RenderHint hint, bool on)
void startRender(QgsSymbolV2RenderContext &context) override
QDomNode appendChild(const QDomNode &newChild)
QByteArray toHex() const
void setColor(const QColor &c) override
The fill color.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setDistanceYUnit(QgsSymbolV2::OutputUnit unit)
void stopRender(QgsSymbolV2RenderContext &context) override
void append(const T &value)
qreal dx() const
qreal dy() const
QString imageFilePath() const
The path to the raster image used for the fill.
static double rescaleUom(double size, QgsSymbolV2::OutputUnit unit, const QgsStringMap &props)
Rescales the given size based on the uomScale found in the props, if any is found, otherwise returns the value un-modified.
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
static const QString EXPR_USE_WHOLE_SHAPE
double dxfWidth(const QgsDxfExport &e, QgsSymbolV2RenderContext &context) const override
QString name() const
const QPicture & svgAsPicture(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool forceVectorOutput=false)
Get SVG as QPicture&.
static const QString EXPR_REFERENCE2_Y
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
QMap< Key, T > & unite(const QMap< Key, T > &other)
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
double dxfAngle(QgsSymbolV2RenderContext &context) const override
virtual QSet< QString > usedAttributes() const
Returns the set of attributes referenced by the layer.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setMapUnitScale(const QgsMapUnitScale &scale) override
QgsPointPatternFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
GradientCoordinateMode coordinateMode() const
Coordinate mode for gradient.
void setMatrix(const QMatrix &matrix)
GradientType gradientType() const
Type of gradient, eg linear or radial.
bool setSubSymbol(QgsSymbolV2 *symbol) override
set layer&#39;s subsymbol. takes ownership of the passed symbol
void setColorAt(qreal position, const QColor &color)
static QString encodeColor(const QColor &color)
Base class for polygon renderers generating texture images.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QgsMapUnitScale mPatternWidthMapUnitScale
static const QString EXPR_DISPLACEMENT_X
GradientCoordinateMode mCoordinateMode
void stopRender(QgsSymbolV2RenderContext &context) override
void setPointOnSurface(bool pointOnSurface)
static const QString EXPR_WIDTH
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
static void externalGraphicToSld(QDomDocument &doc, QDomElement &element, const QString &path, const QString &mime, const QColor &color, double size=-1)
void scale(qreal sx, qreal sy)
void setIgnoreRings(bool ignoreRings)
Sets whether the shapeburst fill should ignore polygon rings when calculating the buffered shading...
void setRendererScale(double scale)
bool isValid() const
void stopRender(QgsSymbolV2RenderContext &context) override
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the SLD element following the SLD v1.1 specs.
void setTextureImage(const QImage &image)
QPointF offset() const
Returns the offset for the shapeburst fill.
static QString ogrFeatureStyleBrush(const QColor &fillColr)
Create ogr feature style string for brush.
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setDistanceMapUnitScale(const QgsMapUnitScale &scale)
void stopRender(QgsSymbolV2RenderContext &context) override
bool isEmpty() const
QString layerType() const override
Returns a string that represents this layer type.
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.
bool hasAlphaChannel() const
QString layerType() const override
Returns a string that represents this layer type.
QgsMapUnitScale mOutlineWidthMapUnitScale
Qt::BrushStyle dxfBrushStyle() const override
static QString ogrFeatureStylePen(double width, double mmScaleFactor, double mapUnitsScaleFactor, const QColor &c, Qt::PenJoinStyle joinStyle=Qt::MiterJoin, Qt::PenCapStyle capStyle=Qt::FlatCap, double offset=0.0, const QVector< qreal > *dashPattern=nullptr)
Create ogr feature style string for pen.
QgsSymbolV2::OutputUnit outputUnit() const override
static const QString EXPR_BLUR_RADIUS
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
static bool externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)
void setJoinStyle(Qt::PenJoinStyle style)
QgsShapeburstFillSymbolLayerV2(const QColor &color=DEFAULT_SIMPLEFILL_COLOR, const QColor &color2=Qt::white, ShapeburstColorType colorType=SimpleTwoColor, int blurRadius=0, bool useWholeShape=true, double maxDistance=5)
virtual QgsStringMap properties() const =0
SymbolType type() const
Definition: qgssymbolv2.h:104
static const QString EXPR_COORDINATE_MODE
qreal top() const
Line symbol.
Definition: qgssymbolv2.h:79
QgsSymbolV2::OutputUnit mWidthUnit
static QPointF decodePoint(const QString &str)
QgsSymbolV2::OutputUnit mDisplacementXUnit
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void stopRender(QgsSymbolV2RenderContext &context) override
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
static const QString EXPR_COLOR2
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasOutlineParam, QColor &defaultOutlineColor, bool &hasOutlineWidthParam, double &defaultOutlineWidth) const
Tests if an svg file contains parameters for fill, outline color, outline width.
void setDistanceXMapUnitScale(const QgsMapUnitScale &scale)
static const bool selectionIsOpaque
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:375
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
QGis::UnitType mapUnits() const
Retrieve map units.
Definition: qgsdxfexport.h:93
void applyDataDefinedSettings(QgsSymbolV2RenderContext &context) override
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
ShapeburstColorType colorType() const
Returns the color mode used for the shapeburst fill.
bool isNull() const
virtual bool setSubSymbol(QgsSymbolV2 *symbol) override
set layer&#39;s subsymbol. takes ownership of the passed symbol
double mDistance
Distance (in mm or map units) between lines.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setSvgOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
QImage copy(const QRect &rectangle) const
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
double mLineAngle
Vector line angle in degrees (0 = horizontal, counterclockwise)
bool setSubSymbol(QgsSymbolV2 *symbol) override
set layer&#39;s subsymbol. takes ownership of the passed symbol
double estimateMaxBleed() const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
void setMapUnitScale(const QgsMapUnitScale &scale) override
double toDouble(bool *ok) const
QColor color() const override
The fill color.
void setStyle(Qt::BrushStyle style)
QgsVectorColorRampV2 * mGradientRamp
QString layerType() const override
Returns a string that represents this layer type.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QString tr(const char *sourceText, const char *disambiguation, int n)
qreal left() const
void setColorRamp(QgsVectorColorRampV2 *ramp)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:285
virtual QColor color() const override
The fill color.
QgsSymbolV2::OutputUnit svgOutlineWidthUnit() const
static double pixelSizeScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns scale factor painter units -> pixel dimensions.
void setWidth(double width)
virtual Q_DECL_DEPRECATED QVariant evaluateDataDefinedProperty(const QString &property, const QgsFeature *feature, const QVariant &defaultVal=QVariant(), bool *ok=nullptr) const
Evaluates the matching data defined property and returns the calculated value.
Marker symbol.
Definition: qgssymbolv2.h:78
void setMapUnitScale(const QgsMapUnitScale &scale)
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
QgsMapUnitScale mapUnitScale() const override
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const
Writes the SLD element following the SLD v1.1 specs.
QgsSymbolV2::OutputUnit outputUnit() const override
void setSvgOutlineColor(const QColor &c)
double symbologyScaleDenominator() const
Retrieve reference scale for output.
Definition: qgsdxfexport.h:80
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setInterval(double interval)
The interval between individual markers.
static const QString EXPR_JOIN_STYLE
void setDistanceUnit(QgsSymbolV2::OutputUnit unit)
static QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
int width() const
QColor dxfColor(QgsSymbolV2RenderContext &context) const override
static const QString EXPR_FILL_STYLE
static QgsSvgCache * instance()
Definition: qgssvgcache.cpp:97
static const QString EXPR_REFERENCE1_Y
static QString encodePenStyle(Qt::PenStyle style)
static QPointF pointOnLineWithDistance(QPointF startPoint, QPointF directionPoint, double distance)
Returns a point on the line from startPoint to directionPoint that is a certain distance away from th...
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setCapStyle(Qt::PenCapStyle style)
const QImage & svgAsImage(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool &fitsInCache)
Get SVG as QImage.
QString mImageFilePath
Path to the image file.
QgsSymbolV2::OutputUnit mDisplacementYUnit
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
static const QString EXPR_BORDER_STYLE
void setColor(const QColor &color)
static const QString EXPR_REFERENCE2_X
static const QString EXPR_REFERENCE2_ISCENTROID
static QString symbolPathToName(QString path)
Get symbols&#39;s name from its path.
virtual double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
GradientSpread gradientSpread() const
Gradient spread mode.
Mixed units in symbol layers.
Definition: qgssymbolv2.h:66
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
static const QString EXPR_LINEWIDTH
QgsLinePatternFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
QgsSymbolV2::OutputUnit outputUnit() const override
void setImageFilePath(const QString &imagePath)
Sets the path to the raster image used for the fill.
static QgsSymbolLayerV2 * createMarkerLayerFromSld(QDomElement &element)
QTransform & translate(qreal dx, qreal dy)
The output shall be in millimeters.
Definition: qgssymbolv2.h:64
#define DEFAULT_SIMPLEFILL_BORDERSTYLE
void stopRender(QgsSymbolV2RenderContext &context) override
QString number(int n, int base)
A class for filling symbols with a repeated raster image.
void setOffset(QPointF offset)
Sets the offset for the shapeburst fill.
QByteArray mSvgData
SVG data.
qreal x() const
qreal y() const
void append(const T &value)
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
QgsLineSymbolV2 * mOutline
Custom outline.
static const QString EXPR_SPREAD
#define DEFAULT_SIMPLEFILL_STYLE
void startRender(QgsSymbolV2RenderContext &context) override
QPointF p2() const
static bool fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)
void setScaleFactor(double factor)
QgsGradientFillSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
virtual QColor fillColor() const
Get fill color.
void setTransform(const QTransform &matrix)
QgsSymbolV2::OutputUnit patternWidthUnit() const
QTransform & scale(qreal sx, qreal sy)
QString layerType() const override
Returns a string that represents this layer type.
void startRender(QgsRenderContext &context, const QgsFields *fields=nullptr)
static const QString EXPR_LINEANGLE
int toInt(bool *ok) const
void setWidth(const double width)
Sets the width for scaling the image used in the fill.
void startRender(QgsSymbolV2RenderContext &context) override
void applyDataDefinedSettings(QgsSymbolV2RenderContext &context) override
double mOffset
Offset perpendicular to line direction.
void fill(uint pixelValue)
static QString encodePoint(QPointF point)
void setReferencePoint1IsCentroid(bool isCentroid)
Sets the starting point of the gradient to be the feature centroid.
const QgsMapUnitScale & intervalMapUnitScale() 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.
double interval() const
The interval between individual markers.
static const QString EXPR_ALPHA
QColor color() const override
The fill color.
QgsSymbolV2::OutputUnit outputUnit() const override
double dxfWidth(const QgsDxfExport &e, QgsSymbolV2RenderContext &context) const override
QgsVectorColorRampV2 * mTwoColorGradientRamp
void setPen(const QColor &color)
void setLineWidthUnit(QgsSymbolV2::OutputUnit unit)
int width() const
QgsSymbolV2::OutputUnit outputUnit() const override
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:363
void setAttribute(const QString &name, const QString &value)
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the SLD element following the SLD v1.1 specs.
virtual QgsVectorColorRampV2 * clone() const =0
virtual QSet< QString > usedAttributes() const override
Returns the set of attributes referenced by the layer.
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the SLD element following the SLD v1.1 specs.
bool setSubSymbol(QgsSymbolV2 *symbol) override
set layer&#39;s subsymbol. takes ownership of the passed symbol
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
virtual double estimateMaxBleed() const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
void setAngle(qreal angle)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
double estimateMaxBleed() const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
QPointF topLeft() const
void setWidthMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the image&#39;s width.
bool isEmpty() const
QRect rect() const
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
QgsMapUnitScale mapUnitScale() const override
void setAngle(double angle)
virtual double estimateMaxBleed() const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
static QString symbolNameToPath(QString name)
Get symbol&#39;s path from its name.
#define M_PI
void startRender(QgsSymbolV2RenderContext &context) override
QgsSVGFillSymbolLayer(const QString &svgFilePath="", double width=20, double rotation=0.0)
void setDistanceYMapUnitScale(const QgsMapUnitScale &scale)
QColor selectionColor() const
QColor color2() const
Color for endpoint of gradient, only used if the gradient color type is set to SimpleTwoColor.
void setWidthF(qreal width)
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the SLD element following the SLD v1.1 specs.
double alpha() const
The opacity for the raster image used in the fill.
int symbolLayerCount()
Returns total number of symbol layers contained in the symbol.
Definition: qgssymbolv2.h:131
QgsSymbolV2::OutputUnit mOffsetUnit
void setBrush(const QBrush &brush)
void setPainter(QPainter *p)
QgsSymbolV2::OutputUnit outputUnit() const override
static const bool selectFillStyle
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
bool useWholeShape() const
Returns whether the shapeburst fill is set to cover the entire shape.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
const QgsMapUnitScale & svgOutlineWidthMapUnitScale() const
void setDisplacementXUnit(QgsSymbolV2::OutputUnit unit)
void setCoordinateMode(const FillCoordinateMode mode)
Set the coordinate mode for fill.
bool hasDataDefinedProperties() const
Returns whether the symbol utilises any data defined properties.
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
virtual bool setSubSymbol(QgsSymbolV2 *symbol) override
set layer&#39;s subsymbol. takes ownership of the passed symbol
QString layerType() const override
Returns a string that represents this layer type.
QgsShapeburstFillSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
QgsSymbolV2::OutputUnit mOffsetUnit
void setColor(const QColor &color)
virtual Q_DECL_DEPRECATED void prepareExpressions(const QgsFields *fields, double scale=-1.0)
Prepares all data defined property expressions for evaluation.
QgsMapUnitScale mapUnitScale() const
double mapUnitsPerPixel() const
Return current map units per pixel.
virtual QColor color() const
The fill color.
void startRender(QgsSymbolV2RenderContext &context) override
void setBorderWidthUnit(QgsSymbolV2::OutputUnit unit)
double maxDistance() const
Returns the maximum distance from the shape&#39;s boundary which is shaded.
static void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, const QColor &color, double width=-1, const Qt::PenJoinStyle *penJoinStyle=nullptr, const Qt::PenCapStyle *penCapStyle=nullptr, const QVector< qreal > *customDashPattern=nullptr, double dashOffset=0.0)
static const QString EXPR_FILE
void setCoordinateMode(CoordinateMode mode)
void setLineWidthMapUnitScale(const QgsMapUnitScale &scale)
QSet< QString > usedAttributes() const override
Returns the set of attributes referenced by the layer.
int alpha() const
QString layerType() const override
Returns a string that represents this layer type.
void setDisplacementXMapUnitScale(const QgsMapUnitScale &scale)
QgsSymbolV2::OutputUnit mOffsetUnit
void setOffset(QPointF offset)
Sets the offset for the fill.
static Qt::PenStyle decodePenStyle(const QString &str)
void startRender(QgsSymbolV2RenderContext &context) override
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QString mSvgFilePath
Path to the svg file (or empty if constructed directly from data)
virtual QColor color(double value) const =0
QgsSymbolV2::OutputUnit mOffsetUnit
static const QString EXPR_DISTANCE
QgsSymbolV2::OutputUnit mOutlineWidthUnit
QByteArray fromHex(const QByteArray &hexEncoded)
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
double mOutlineWidth
Outline width.
void setDistanceXUnit(QgsSymbolV2::OutputUnit unit)
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
double mLineWidth
Line width (in mm or map units)
QgsVectorColorRampV2 * mGradientRamp
static const QString EXPR_COLOR
bool isNull() const
static const QString EXPR_WIDTH_BORDER
QgsMapUnitScale mapUnitScale() const override
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
static QgsSymbolLayerV2 * createLineLayerFromSld(QDomElement &element)
QgsMapUnitScale mapUnitScale() const override
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
static const QString EXPR_SVG_FILE
static const QString EXPR_ANGLE
void setOffset(QPointF offset)
Offset for gradient fill.
virtual QString layerType() const =0
Returns a string that represents this layer type.
void applyDataDefinedSettings(QgsSymbolV2RenderContext &context) override
QgsExpressionContext & expressionContext()
Gets the expression context.
double estimateMaxBleed() const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
Sets the units used for the offset for the shapeburst fill.
QgsSymbolV2::OutputUnit mDistanceYUnit
static const QString EXPR_DISTANCE_X
bool isNull() const
QgsSymbolV2::OutputUnit intervalUnit() const
QString layerType() const override
Returns a string that represents this layer type.
static const QString EXPR_REFERENCE1_X
double estimateMaxBleed() const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
void setOffset(QPointF offset)
static const QString EXPR_GRADIENT_TYPE
void restore()
QgsRasterFillSymbolLayer(const QString &imageFilePath=QString())
QgsSymbolV2::OutputUnit outputUnit() const
QTransform & rotate(qreal angle, Qt::Axis axis)
void copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
A class for svg fill patterns.
void setMapUnitScale(const QgsMapUnitScale &scale) override
QgsMapUnitScale mapUnitScale() const override
Contains information about the context of a rendering operation.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the fill&#39;s offset.
static const QString EXPR_SVG_FILL_COLOR
QRectF boundingRect() const
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, QFlags< Qt::ImageConversionFlag > flags)
QPainter * painter()
const QgsMapToPixel & mapToPixel() const
qreal width() const
void stopRender(QgsRenderContext &context)
QgsMapUnitScale mBorderWidthMapUnitScale
static QString encodeBrushStyle(Qt::BrushStyle style)
static void fillToSld(QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, const QColor &color=QColor())
QSet< T > & unite(const QSet< T > &other)
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Writes the SLD element following the SLD v1.1 specs.
Struct for storing maximum and minimum scales for measurements in map units.
QgsSymbolV2::OutputUnit mDistanceXUnit
virtual bool hasDataDefinedProperty(const QString &property) const
Checks whether the layer has a matching data defined property and if that property is currently activ...
void setDisplacementYUnit(QgsSymbolV2::OutputUnit unit)
static const QString EXPR_SVG_OUTLINE_COLOR
const QgsMapUnitScale & patternWidthMapUnitScale() const
QgsSymbolV2::OutputUnit outputUnit() const override
void setSvgFilePath(const QString &svgPath)
QString ogrFeatureStyleWidth(double widthScaleFactor) const
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
QColor color() const
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:346
void setX(qreal x)
void setY(qreal y)
QDomElement firstChildElement(const QString &tagName) const
QgsSymbolV2::OutputUnit mBorderWidthUnit
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
QTransform transform() const
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
static const QString EXPR_IGNORE_RINGS
void setColorRamp(QgsVectorColorRampV2 *ramp)
Sets the color ramp used to draw the shapeburst fill.
void setMapToPixel(const QgsMapToPixel &mtp)
static const QString EXPR_COLOR_BORDER
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
QgsSymbolV2::OutputUnit mDistanceUnit
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
QDomComment createComment(const QString &value)
QColor color2() const
Returns the color used for the endpoint of the shapeburst fill.
void renderPoint(QPointF point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
bool toBool() const
void translate(const QPointF &offset)
static const QString EXPR_REFERENCE1_ISCENTROID
void setDisplacementYMapUnitScale(const QgsMapUnitScale &scale)
qreal angle() const
void setAlpha(const double alpha)
Sets the opacity for the raster image used in the fill.
QgsMapUnitScale mapUnitScale() const override
QgsSymbolV2::OutputUnit outputUnit() const override
void startRender(QgsSymbolV2RenderContext &context) override
QgsGradientFillSymbolLayerV2(const QColor &color=DEFAULT_SIMPLEFILL_COLOR, const QColor &color2=Qt::white, GradientColorType gradientColorType=SimpleTwoColor, GradientType gradientType=Linear, GradientCoordinateMode coordinateMode=Feature, GradientSpread gradientSpread=Pad)
QgsSymbolV2 * subSymbol() override
void setAlphaF(qreal alpha)
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
qreal height() const
int height() const
double estimateMaxBleed() const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
QgsCentroidFillSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
double toDouble(bool *ok) const
static QColor decodeColor(const QString &str)
iterator insert(const Key &key, const T &value)
void setMapUnitScale(const QgsMapUnitScale &scale) override
static QPointF polygonCentroid(const QPolygonF &points)
Calculate the centroid point of a QPolygonF.
void setRasterScaleFactor(double factor)
Qt::PenStyle dxfPenStyle() const override
QgsSymbolV2::OutputUnit mDistanceUnit
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
void setColor(const QColor &c) override
The fill color.
void drawPicture(const QPointF &point, const QPicture &picture)
static const QString EXPR_SVG_OUTLINE_WIDTH
double width() const
void restoreDataDefinedProperties(const QgsStringMap &stringMap)
Restores all data defined properties from string map.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
QgsSymbolLayerV2 * symbolLayer(int layer)
Returns a specific symbol layers contained in the symbol.
#define INF
double rasterScaleFactor() const
int height() const
const_iterator constEnd() const
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
QDomElement createElement(const QString &tagName)
const_iterator constBegin() const
QSet< QString > usedAttributes() const
Return a list of attributes required to render this feature.
void setWidthUnit(const QgsSymbolV2::OutputUnit unit)
Sets the units for the image&#39;s width.
void setPatternWidthUnit(QgsSymbolV2::OutputUnit unit)
Draw map such that there are no problems between adjacent tiles.
QgsSymbolV2::OutputUnit mPatternWidthUnit
static QPointF polygonPointOnSurface(const QPolygonF &points)
Calculate a point within of a QPolygonF.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
void _renderPolygon(QPainter *p, const QPolygonF &points, const QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
Default method to render polygon.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
void addStopsToGradient(QGradient *gradient, double alpha=1)
Copy color ramp stops to a QGradient.
static const bool selectFillBorder
QColor dxfBrushColor(QgsSymbolV2RenderContext &context) const override
void setColor(const QColor &color) override
The fill color.
Qt::PenStyle borderStyle() const
int blurRadius() const
Returns the blur radius, which controls the amount of blurring applied to the fill.
double scaleFactor() const
bool begin(QPaintDevice *device)
void setReferencePoint2(QPointF referencePoint)
End point of gradient fill, in the range [0,0] - [1,1].
static const QString EXPR_MAX_DISTANCE
void setColor(const QColor &color)
GradientColorType gradientColorType() const
Gradient color mode, controls how gradient color stops are created.
QgsSymbolV2::SymbolType type() const
#define DEFAULT_SIMPLEFILL_JOINSTYLE
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
QgsSimpleFillSymbolLayerV2 * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
double width() const
Returns the width used for scaling the image used in the fill.
void setSpread(Spread method)
void setMapUnitScale(const QgsMapUnitScale &scale) override
QgsSimpleFillSymbolLayerV2(const QColor &color=DEFAULT_SIMPLEFILL_COLOR, Qt::BrushStyle style=DEFAULT_SIMPLEFILL_STYLE, const QColor &borderColor=DEFAULT_SIMPLEFILL_BORDERCOLOR, Qt::PenStyle borderStyle=DEFAULT_SIMPLEFILL_BORDERSTYLE, double borderWidth=DEFAULT_SIMPLEFILL_BORDERWIDTH, Qt::PenJoinStyle penJoinStyle=DEFAULT_SIMPLEFILL_JOINSTYLE)
static void blurImageInPlace(QImage &image, QRect rect, int radius, bool alphaOnly)
Blurs an image in place, e.g.
void applyDataDefinedSettings(QgsSymbolV2RenderContext &context) override
void setOutputUnit(QgsSymbolV2::OutputUnit u)
QgsSVGFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Qt::PenJoinStyle penJoinStyle() const
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:203
QRectF viewBoxF() const
void setMapUnitScale(const QgsMapUnitScale &scale) override
QgsMapUnitScale mapUnitScale() const override
QColor fillColor() const override
Get fill color.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setOffsetUnit(const QgsSymbolV2::OutputUnit unit)
Sets the units for the fill&#39;s offset.
void stopRender(QgsSymbolV2RenderContext &context) override
void setDistanceMapUnitScale(const QgsMapUnitScale &scale)
Qt::PenStyle dxfPenStyle() const override
#define DEFAULT_SIMPLEFILL_BORDERWIDTH
virtual void applyDataDefinedSettings(QgsSymbolV2RenderContext &context)
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
QRgb rgba() const
virtual QgsMarkerSymbolV2 * clone() const override
static void premultiplyColor(QColor &rgb, int alpha)
Converts a QColor into a premultiplied ARGB QColor value using a specified alpha value.
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
Units for gradient fill offset.
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
bool isValid() const
QRectF mSvgViewBox
SVG view box (to keep the aspect ratio.
QImage * mSvgPattern
SVG pattern image.
void setSvgOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
const T value(const Key &key) const
QPointF offset() const
Returns the offset for the fill.
bool isNull() const
void stopRender(QgsSymbolV2RenderContext &context) override
double mPatternWidth
Width of the pattern (in output units)
static Q_DECL_DEPRECATED void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &borderColor=QColor(), double borderWidth=-1, double size=-1)
#define DEFAULT_SIMPLEFILL_COLOR