QGIS API Documentation  2.14.0-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  }
355 
356  // <se:Displacement>
358 }
359 
360 QString QgsSimpleFillSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
361 {
362  //brush
363  QString symbolStyle;
365  symbolStyle.append( ';' );
366  //pen
367  symbolStyle.append( QgsSymbolLayerV2Utils::ogrFeatureStylePen( mBorderWidth, mmScaleFactor, mapUnitScaleFactor, mBorderColor, mPenJoinStyle ) );
368  return symbolStyle;
369 }
370 
372 {
373  QgsDebugMsg( "Entered." );
374 
376  Qt::BrushStyle fillStyle;
377  Qt::PenStyle borderStyle;
378  double borderWidth;
379 
380  QDomElement fillElem = element.firstChildElement( "Fill" );
381  QgsSymbolLayerV2Utils::fillFromSld( fillElem, fillStyle, color );
382 
383  QDomElement strokeElem = element.firstChildElement( "Stroke" );
384  QgsSymbolLayerV2Utils::lineFromSld( strokeElem, borderStyle, borderColor, borderWidth );
385 
386  QPointF offset;
388 
389  QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, fillStyle, borderColor, borderStyle, borderWidth );
390  sl->setOffset( offset );
391  return sl;
392 }
393 
395 {
396  double penBleed = mBorderStyle == Qt::NoPen ? 0 : ( mBorderWidth / 2.0 );
397  double offsetBleed = mOffset.x() > mOffset.y() ? mOffset.x() : mOffset.y();
398  return penBleed + offsetBleed;
399 }
400 
402 {
403  double width = mBorderWidth;
405  {
408  }
410 }
411 
413 {
415  {
416  bool ok;
419  if ( ok )
420  return QgsSymbolLayerV2Utils::decodeColor( color );
421  }
422  return mBorderColor;
423 }
424 
426 {
427  return mBorderStyle;
428 }
429 
431 {
433  {
434  bool ok;
437  if ( ok )
438  return QgsSymbolLayerV2Utils::decodeColor( color );
439  }
440  return mColor;
441 }
442 
444 {
445  return mBrushStyle;
446 }
447 
448 //QgsGradientFillSymbolLayer
449 
451  GradientColorType colorType, GradientType gradientType,
452  GradientCoordinateMode coordinateMode, GradientSpread spread )
453  : mGradientColorType( colorType )
454  , mGradientRamp( nullptr )
455  , mGradientType( gradientType )
456  , mCoordinateMode( coordinateMode )
457  , mGradientSpread( spread )
458  , mReferencePoint1( QPointF( 0.5, 0 ) )
459  , mReferencePoint1IsCentroid( false )
460  , mReferencePoint2( QPointF( 0.5, 1 ) )
461  , mReferencePoint2IsCentroid( false )
462  , mOffsetUnit( QgsSymbolV2::MM )
463 {
464  mColor = color;
465  mColor2 = color2;
466 }
467 
469 {
470  delete mGradientRamp;
471 }
472 
474 {
475  //default to a two-color, linear gradient with feature mode and pad spreading
480  //default to gradient from the default fill color to white
482  QPointF referencePoint1 = QPointF( 0.5, 0 );
483  bool refPoint1IsCentroid = false;
484  QPointF referencePoint2 = QPointF( 0.5, 1 );
485  bool refPoint2IsCentroid = false;
486  double angle = 0;
487  QPointF offset;
488 
489  //update gradient properties from props
490  if ( props.contains( "type" ) )
491  type = static_cast< GradientType >( props["type"].toInt() );
492  if ( props.contains( "coordinate_mode" ) )
493  coordinateMode = static_cast< GradientCoordinateMode >( props["coordinate_mode"].toInt() );
494  if ( props.contains( "spread" ) )
495  gradientSpread = static_cast< GradientSpread >( props["spread"].toInt() );
496  if ( props.contains( "color_type" ) )
497  colorType = static_cast< GradientColorType >( props["color_type"].toInt() );
498  if ( props.contains( "gradient_color" ) )
499  {
500  //pre 2.5 projects used "gradient_color"
501  color = QgsSymbolLayerV2Utils::decodeColor( props["gradient_color"] );
502  }
503  else if ( props.contains( "color" ) )
504  {
505  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
506  }
507  if ( props.contains( "gradient_color2" ) )
508  {
509  color2 = QgsSymbolLayerV2Utils::decodeColor( props["gradient_color2"] );
510  }
511 
512  if ( props.contains( "reference_point1" ) )
513  referencePoint1 = QgsSymbolLayerV2Utils::decodePoint( props["reference_point1"] );
514  if ( props.contains( "reference_point1_iscentroid" ) )
515  refPoint1IsCentroid = props["reference_point1_iscentroid"].toInt();
516  if ( props.contains( "reference_point2" ) )
517  referencePoint2 = QgsSymbolLayerV2Utils::decodePoint( props["reference_point2"] );
518  if ( props.contains( "reference_point2_iscentroid" ) )
519  refPoint2IsCentroid = props["reference_point2_iscentroid"].toInt();
520  if ( props.contains( "angle" ) )
521  angle = props["angle"].toDouble();
522 
523  if ( props.contains( "offset" ) )
524  offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
525 
526  //attempt to create color ramp from props
528 
529  //create a new gradient fill layer with desired properties
530  QgsGradientFillSymbolLayerV2* sl = new QgsGradientFillSymbolLayerV2( color, color2, colorType, type, coordinateMode, gradientSpread );
531  sl->setOffset( offset );
532  if ( props.contains( "offset_unit" ) )
533  sl->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
534  if ( props.contains( "offset_map_unit_scale" ) )
535  sl->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
536  sl->setReferencePoint1( referencePoint1 );
537  sl->setReferencePoint1IsCentroid( refPoint1IsCentroid );
538  sl->setReferencePoint2( referencePoint2 );
539  sl->setReferencePoint2IsCentroid( refPoint2IsCentroid );
540  sl->setAngle( angle );
541  if ( gradientRamp )
542  sl->setColorRamp( gradientRamp );
543 
544  sl->restoreDataDefinedProperties( props );
545 
546  return sl;
547 }
548 
550 {
551  delete mGradientRamp;
552  mGradientRamp = ramp;
553 }
554 
556 {
557  return "GradientFill";
558 }
559 
560 void QgsGradientFillSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, const QPolygonF& points )
561 {
563  {
564  //shortcut
567  return;
568  }
569 
570  bool ok;
571 
572  //first gradient color
573  QColor color = mColor;
575  {
578  if ( ok )
579  color = QgsSymbolLayerV2Utils::decodeColor( colorString );
580  }
581 
582  //second gradient color
585  {
588  if ( ok )
589  color2 = QgsSymbolLayerV2Utils::decodeColor( colorString );
590  }
591 
592  //gradient rotation angle
593  double angle = mAngle;
595  {
596  context.setOriginalValueVariable( mAngle );
598  }
599 
600  //gradient type
603  {
605  if ( ok )
606  {
607  if ( currentType == QObject::tr( "linear" ) )
608  {
610  }
611  else if ( currentType == QObject::tr( "radial" ) )
612  {
614  }
615  else if ( currentType == QObject::tr( "conical" ) )
616  {
618  }
619  }
620  }
621 
622  //coordinate mode
625  {
627  if ( ok )
628  {
629  if ( currentCoordMode == QObject::tr( "feature" ) )
630  {
631  coordinateMode = QgsGradientFillSymbolLayerV2::Feature;
632  }
633  else if ( currentCoordMode == QObject::tr( "viewport" ) )
634  {
636  }
637  }
638  }
639 
640  //gradient spread
643  {
645  if ( ok )
646  {
647  if ( currentSpread == QObject::tr( "pad" ) )
648  {
650  }
651  else if ( currentSpread == QObject::tr( "repeat" ) )
652  {
654  }
655  else if ( currentSpread == QObject::tr( "reflect" ) )
656  {
658  }
659  }
660  }
661 
662  //reference point 1 x & y
663  double refPoint1X = mReferencePoint1.x();
665  {
666  context.setOriginalValueVariable( refPoint1X );
667  refPoint1X = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE1_X, context, refPoint1X ).toDouble();
668  }
669  double refPoint1Y = mReferencePoint1.y();
671  {
672  context.setOriginalValueVariable( refPoint1Y );
673  refPoint1Y = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE1_Y, context, refPoint1Y ).toDouble();
674  }
675  bool refPoint1IsCentroid = mReferencePoint1IsCentroid;
677  {
678  context.setOriginalValueVariable( refPoint1IsCentroid );
679  refPoint1IsCentroid = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE1_ISCENTROID, context, refPoint1IsCentroid ).toBool();
680  }
681 
682  //reference point 2 x & y
683  double refPoint2X = mReferencePoint2.x();
685  {
686  context.setOriginalValueVariable( refPoint2X );
687  refPoint2X = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE2_X, context, refPoint2X ).toDouble();
688  }
689  double refPoint2Y = mReferencePoint2.y();
691  {
692  context.setOriginalValueVariable( refPoint2Y );
693  refPoint2Y = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE2_Y, context, refPoint2Y ).toDouble();
694  }
695  bool refPoint2IsCentroid = mReferencePoint2IsCentroid;
697  {
698  context.setOriginalValueVariable( refPoint2IsCentroid );
699  refPoint2IsCentroid = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_REFERENCE2_ISCENTROID, context, refPoint2IsCentroid ).toBool();
700  }
701 
702  if ( refPoint1IsCentroid || refPoint2IsCentroid )
703  {
704  //either the gradient is starting or ending at a centroid, so calculate it
705  QPointF centroid = QgsSymbolLayerV2Utils::polygonCentroid( points );
706  //centroid coordinates need to be scaled to a range [0, 1] relative to polygon bounds
707  QRectF bbox = points.boundingRect();
708  double centroidX = ( centroid.x() - bbox.left() ) / bbox.width();
709  double centroidY = ( centroid.y() - bbox.top() ) / bbox.height();
710 
711  if ( refPoint1IsCentroid )
712  {
713  refPoint1X = centroidX;
714  refPoint1Y = centroidY;
715  }
716  if ( refPoint2IsCentroid )
717  {
718  refPoint2X = centroidX;
719  refPoint2Y = centroidY;
720  }
721  }
722 
723  //update gradient with data defined values
724  applyGradient( context, mBrush, color, color2, mGradientColorType, mGradientRamp, gradientType, coordinateMode,
725  spread, QPointF( refPoint1X, refPoint1Y ), QPointF( refPoint2X, refPoint2Y ), angle );
726 }
727 
728 QPointF QgsGradientFillSymbolLayerV2::rotateReferencePoint( QPointF refPoint, double angle )
729 {
730  //rotate a reference point by a specified angle around the point (0.5, 0.5)
731 
732  //create a line from the centrepoint of a rectangle bounded by (0, 0) and (1, 1) to the reference point
733  QLineF refLine = QLineF( QPointF( 0.5, 0.5 ), refPoint );
734  //rotate this line by the current rotation angle
735  refLine.setAngle( refLine.angle() + angle );
736  //get new end point of line
737  QPointF rotatedReferencePoint = refLine.p2();
738  //make sure coords of new end point is within [0, 1]
739  if ( rotatedReferencePoint.x() > 1 )
740  rotatedReferencePoint.setX( 1 );
741  if ( rotatedReferencePoint.x() < 0 )
742  rotatedReferencePoint.setX( 0 );
743  if ( rotatedReferencePoint.y() > 1 )
744  rotatedReferencePoint.setY( 1 );
745  if ( rotatedReferencePoint.y() < 0 )
746  rotatedReferencePoint.setY( 0 );
747 
748  return rotatedReferencePoint;
749 }
750 
751 void QgsGradientFillSymbolLayerV2::applyGradient( const QgsSymbolV2RenderContext &context, QBrush &brush,
756 {
757  //update alpha of gradient colors
759  fillColor.setAlphaF( context.alpha() * fillColor.alphaF() );
760  QColor fillColor2 = color2;
761  fillColor2.setAlphaF( context.alpha() * fillColor2.alphaF() );
762 
763  //rotate reference points
764  QPointF rotatedReferencePoint1 = !qgsDoubleNear( angle, 0.0 ) ? rotateReferencePoint( referencePoint1, angle ) : referencePoint1;
765  QPointF rotatedReferencePoint2 = !qgsDoubleNear( angle, 0.0 ) ? rotateReferencePoint( referencePoint2, angle ) : referencePoint2;
766 
767  //create a QGradient with the desired properties
768  QGradient gradient;
769  switch ( gradientType )
770  {
772  gradient = QLinearGradient( rotatedReferencePoint1, rotatedReferencePoint2 );
773  break;
775  gradient = QRadialGradient( rotatedReferencePoint1, QLineF( rotatedReferencePoint1, rotatedReferencePoint2 ).length() );
776  break;
778  gradient = QConicalGradient( rotatedReferencePoint1, QLineF( rotatedReferencePoint1, rotatedReferencePoint2 ).angle() );
779  break;
780  }
781  switch ( coordinateMode )
782  {
784  gradient.setCoordinateMode( QGradient::ObjectBoundingMode );
785  break;
787  gradient.setCoordinateMode( QGradient::StretchToDeviceMode );
788  break;
789  }
790  switch ( gradientSpread )
791  {
793  gradient.setSpread( QGradient::PadSpread );
794  break;
796  gradient.setSpread( QGradient::ReflectSpread );
797  break;
799  gradient.setSpread( QGradient::RepeatSpread );
800  break;
801  }
802 
803  //add stops to gradient
804  if ( gradientColorType == QgsGradientFillSymbolLayerV2::ColorRamp && gradientRamp && gradientRamp->type() == "gradient" )
805  {
806  //color ramp gradient
807  QgsVectorGradientColorRampV2* gradRamp = static_cast<QgsVectorGradientColorRampV2*>( gradientRamp );
808  gradRamp->addStopsToGradient( &gradient, context.alpha() );
809  }
810  else
811  {
812  //two color gradient
813  gradient.setColorAt( 0.0, fillColor );
814  gradient.setColorAt( 1.0, fillColor2 );
815  }
816 
817  //update QBrush use gradient
818  brush = QBrush( gradient );
819 }
820 
822 {
823  QColor selColor = context.renderContext().selectionColor();
824  if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() );
825  mSelBrush = QBrush( selColor );
826 
827  //update mBrush to use a gradient fill with specified properties
828  prepareExpressions( context );
829 }
830 
832 {
833  Q_UNUSED( context );
834 }
835 
837 {
838  QPainter* p = context.renderContext().painter();
839  if ( !p )
840  {
841  return;
842  }
843 
844  applyDataDefinedSymbology( context, points );
845 
846  p->setBrush( context.selected() ? mSelBrush : mBrush );
847  p->setPen( Qt::NoPen );
848 
849  QPointF offset;
850  if ( !mOffset.isNull() )
851  {
854  p->translate( offset );
855  }
856 
857  _renderPolygon( p, points, rings, context );
858 
859  if ( !mOffset.isNull() )
860  {
861  p->translate( -offset );
862  }
863 }
864 
866 {
867  QgsStringMap map;
868  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
869  map["gradient_color2"] = QgsSymbolLayerV2Utils::encodeColor( mColor2 );
870  map["color_type"] = QString::number( mGradientColorType );
871  map["type"] = QString::number( mGradientType );
872  map["coordinate_mode"] = QString::number( mCoordinateMode );
873  map["spread"] = QString::number( mGradientSpread );
874  map["reference_point1"] = QgsSymbolLayerV2Utils::encodePoint( mReferencePoint1 );
875  map["reference_point1_iscentroid"] = QString::number( mReferencePoint1IsCentroid );
876  map["reference_point2"] = QgsSymbolLayerV2Utils::encodePoint( mReferencePoint2 );
877  map["reference_point2_iscentroid"] = QString::number( mReferencePoint2IsCentroid );
878  map["angle"] = QString::number( mAngle );
879  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
881  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
883  if ( mGradientRamp )
884  {
885  map.unite( mGradientRamp->properties() );
886  }
887  return map;
888 }
889 
891 {
893  if ( mGradientRamp )
894  sl->setColorRamp( mGradientRamp->clone() );
899  sl->setAngle( mAngle );
900  sl->setOffset( mOffset );
901  sl->setOffsetUnit( mOffsetUnit );
904  copyPaintEffect( sl );
905  return sl;
906 }
907 
909 {
910  double offsetBleed = mOffset.x() > mOffset.y() ? mOffset.x() : mOffset.y();
911  return offsetBleed;
912 }
913 
915 {
916  mOffsetUnit = unit;
917 }
918 
920 {
921  return mOffsetUnit;
922 }
923 
925 {
926  mOffsetMapUnitScale = scale;
927 }
928 
930 {
931  return mOffsetMapUnitScale;
932 }
933 
934 //QgsShapeburstFillSymbolLayer
935 
937  int blurRadius, bool useWholeShape, double maxDistance ) :
938 
939  mBlurRadius( blurRadius ),
940  mUseWholeShape( useWholeShape ),
941  mMaxDistance( maxDistance ),
942  mDistanceUnit( QgsSymbolV2::MM ),
943  mColorType( colorType ),
944  mColor2( color2 ),
945  mGradientRamp( nullptr ),
946  mTwoColorGradientRamp( nullptr ),
947  mIgnoreRings( false ),
948  mOffsetUnit( QgsSymbolV2::MM )
949 {
950  mColor = color;
951 }
952 
954 {
955  delete mGradientRamp;
956 }
957 
959 {
960  //default to a two-color gradient
962  QColor color = DEFAULT_SIMPLEFILL_COLOR, color2 = Qt::white;
963  int blurRadius = 0;
964  bool useWholeShape = true;
965  double maxDistance = 5;
966  QPointF offset;
967 
968  //update fill properties from props
969  if ( props.contains( "color_type" ) )
970  {
971  colorType = static_cast< ShapeburstColorType >( props["color_type"].toInt() );
972  }
973  if ( props.contains( "shapeburst_color" ) )
974  {
975  //pre 2.5 projects used "shapeburst_color"
976  color = QgsSymbolLayerV2Utils::decodeColor( props["shapeburst_color"] );
977  }
978  else if ( props.contains( "color" ) )
979  {
980  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
981  }
982 
983  if ( props.contains( "shapeburst_color2" ) )
984  {
985  //pre 2.5 projects used "shapeburst_color2"
986  color2 = QgsSymbolLayerV2Utils::decodeColor( props["shapeburst_color2"] );
987  }
988  else if ( props.contains( "gradient_color2" ) )
989  {
990  color2 = QgsSymbolLayerV2Utils::decodeColor( props["gradient_color2"] );
991  }
992  if ( props.contains( "blur_radius" ) )
993  {
994  blurRadius = props["blur_radius"].toInt();
995  }
996  if ( props.contains( "use_whole_shape" ) )
997  {
998  useWholeShape = props["use_whole_shape"].toInt();
999  }
1000  if ( props.contains( "max_distance" ) )
1001  {
1002  maxDistance = props["max_distance"].toDouble();
1003  }
1004  if ( props.contains( "offset" ) )
1005  {
1006  offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
1007  }
1008 
1009  //attempt to create color ramp from props
1011 
1012  //create a new shapeburst fill layer with desired properties
1013  QgsShapeburstFillSymbolLayerV2* sl = new QgsShapeburstFillSymbolLayerV2( color, color2, colorType, blurRadius, useWholeShape, maxDistance );
1014  sl->setOffset( offset );
1015  if ( props.contains( "offset_unit" ) )
1016  {
1017  sl->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
1018  }
1019  if ( props.contains( "distance_unit" ) )
1020  {
1021  sl->setDistanceUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["distance_unit"] ) );
1022  }
1023  if ( props.contains( "offset_map_unit_scale" ) )
1024  {
1025  sl->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
1026  }
1027  if ( props.contains( "distance_map_unit_scale" ) )
1028  {
1029  sl->setDistanceMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["distance_map_unit_scale"] ) );
1030  }
1031  if ( props.contains( "ignore_rings" ) )
1032  {
1033  sl->setIgnoreRings( props["ignore_rings"].toInt() );
1034  }
1035  if ( gradientRamp )
1036  {
1037  sl->setColorRamp( gradientRamp );
1038  }
1039 
1040  sl->restoreDataDefinedProperties( props );
1041 
1042  return sl;
1043 }
1044 
1046 {
1047  return "ShapeburstFill";
1048 }
1049 
1051 {
1052  delete mGradientRamp;
1053  mGradientRamp = ramp;
1054 }
1055 
1056 void QgsShapeburstFillSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QColor& color, QColor& color2, int& blurRadius, bool& useWholeShape,
1057  double& maxDistance, bool& ignoreRings )
1058 {
1059  bool ok;
1060 
1061  //first gradient color
1062  color = mColor;
1064  {
1067  if ( ok )
1068  color = QgsSymbolLayerV2Utils::decodeColor( colorString );
1069  }
1070 
1071  //second gradient color
1072  color2 = mColor2;
1074  {
1077  if ( ok )
1078  color2 = QgsSymbolLayerV2Utils::decodeColor( colorString );
1079  }
1080 
1081  //blur radius
1084  {
1087  }
1088 
1089  //use whole shape
1092  {
1095  }
1096 
1097  //max distance
1100  {
1103  }
1104 
1105  //ignore rings
1106  ignoreRings = mIgnoreRings;
1108  {
1111  }
1112 
1113 }
1114 
1116 {
1117  //TODO - check this
1118  QColor selColor = context.renderContext().selectionColor();
1119  if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() );
1120  mSelBrush = QBrush( selColor );
1121 
1122  prepareExpressions( context );
1123 }
1124 
1126 {
1127  Q_UNUSED( context );
1128 }
1129 
1131 {
1132  QPainter* p = context.renderContext().painter();
1133  if ( !p )
1134  {
1135  return;
1136  }
1137 
1138  if ( context.selected() )
1139  {
1140  //feature is selected, draw using selection style
1141  p->setBrush( mSelBrush );
1142  QPointF offset;
1143  if ( !mOffset.isNull() )
1144  {
1147  p->translate( offset );
1148  }
1149  _renderPolygon( p, points, rings, context );
1150  if ( !mOffset.isNull() )
1151  {
1152  p->translate( -offset );
1153  }
1154  return;
1155  }
1156 
1157  QColor color1, color2;
1158  int blurRadius;
1159  bool useWholeShape;
1160  double maxDistance;
1161  bool ignoreRings;
1162  //calculate data defined symbology
1163  applyDataDefinedSymbology( context, color1, color2, blurRadius, useWholeShape, maxDistance, ignoreRings );
1164 
1165  //calculate max distance for shapeburst fill to extend from polygon boundary, in pixels
1166  int outputPixelMaxDist = 0;
1167  if ( !useWholeShape && !qgsDoubleNear( maxDistance, 0.0 ) )
1168  {
1169  //convert max distance to pixels
1170  const QgsRenderContext& ctx = context.renderContext();
1171  outputPixelMaxDist = maxDistance * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceUnit, mDistanceMapUnitScale );
1172  }
1173 
1174  //if we are using the two color mode, create a gradient ramp
1176  {
1177  mTwoColorGradientRamp = new QgsVectorGradientColorRampV2( color1, color2 );
1178  }
1179 
1180  //no border for shapeburst fills
1181  p->setPen( QPen( Qt::NoPen ) );
1182 
1183  //calculate margin size in pixels so that QImage of polygon has sufficient space to draw the full blur effect
1184  int sideBuffer = 4 + ( blurRadius + 2 ) * 4;
1185  //create a QImage to draw shapeburst in
1186  double imWidth = points.boundingRect().width() + ( sideBuffer * 2 );
1187  double imHeight = points.boundingRect().height() + ( sideBuffer * 2 );
1188  QImage * fillImage = new QImage( imWidth * context.renderContext().rasterScaleFactor(),
1189  imHeight * context.renderContext().rasterScaleFactor(), QImage::Format_ARGB32_Premultiplied );
1190  //Fill this image with black. Initially the distance transform is drawn in greyscale, where black pixels have zero distance from the
1191  //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
1192  //polygon in white. The distance transform function then fills in the correct distance values for the white pixels.
1193  fillImage->fill( Qt::black );
1194 
1195  //also create an image to store the alpha channel
1196  QImage * alphaImage = new QImage( fillImage->width(), fillImage->height(), QImage::Format_ARGB32_Premultiplied );
1197  //initially fill the alpha channel image with a transparent color
1198  alphaImage->fill( Qt::transparent );
1199 
1200  //now, draw the polygon in the alpha channel image
1201  QPainter imgPainter;
1202  imgPainter.begin( alphaImage );
1203  imgPainter.setRenderHint( QPainter::Antialiasing, true );
1204  imgPainter.setBrush( QBrush( Qt::white ) );
1205  imgPainter.setPen( QPen( Qt::black ) );
1206  imgPainter.translate( -points.boundingRect().left() + sideBuffer, - points.boundingRect().top() + sideBuffer );
1207  imgPainter.scale( context.renderContext().rasterScaleFactor(), context.renderContext().rasterScaleFactor() );
1208  _renderPolygon( &imgPainter, points, rings, context );
1209  imgPainter.end();
1210 
1211  //now that we have a render of the polygon in white, draw this onto the shapeburst fill image too
1212  //(this avoids calling _renderPolygon twice, since that can be slow)
1213  imgPainter.begin( fillImage );
1214  if ( !ignoreRings )
1215  {
1216  imgPainter.drawImage( 0, 0, *alphaImage );
1217  }
1218  else
1219  {
1220  //using ignore rings mode, so the alpha image can't be used
1221  //directly as the alpha channel contains polygon rings and we need
1222  //to draw now without any rings
1223  imgPainter.setBrush( QBrush( Qt::white ) );
1224  imgPainter.setPen( QPen( Qt::black ) );
1225  imgPainter.translate( -points.boundingRect().left() + sideBuffer, - points.boundingRect().top() + sideBuffer );
1226  imgPainter.scale( context.renderContext().rasterScaleFactor(), context.renderContext().rasterScaleFactor() );
1227  _renderPolygon( &imgPainter, points, nullptr, context );
1228  }
1229  imgPainter.end();
1230 
1231  //apply distance transform to image, uses the current color ramp to calculate final pixel colors
1232  double * dtArray = distanceTransform( fillImage );
1233 
1234  //copy distance transform values back to QImage, shading by appropriate color ramp
1236  context.alpha(), useWholeShape, outputPixelMaxDist );
1237 
1238  //clean up some variables
1239  delete [] dtArray;
1241  {
1242  delete mTwoColorGradientRamp;
1243  }
1244 
1245  //apply blur if desired
1246  if ( blurRadius > 0 )
1247  {
1248  QgsSymbolLayerV2Utils::blurImageInPlace( *fillImage, QRect( 0, 0, fillImage->width(), fillImage->height() ), blurRadius, false );
1249  }
1250 
1251  //apply alpha channel to distance transform image, so that areas outside the polygon are transparent
1252  imgPainter.begin( fillImage );
1253  imgPainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
1254  imgPainter.drawImage( 0, 0, *alphaImage );
1255  imgPainter.end();
1256  //we're finished with the alpha channel image now
1257  delete alphaImage;
1258 
1259  //draw shapeburst image in correct place in the destination painter
1260 
1261  p->save();
1262  QPointF offset;
1263  if ( !mOffset.isNull() )
1264  {
1267  p->translate( offset );
1268  }
1269 
1270  p->scale( 1 / context.renderContext().rasterScaleFactor(), 1 / context.renderContext().rasterScaleFactor() );
1271  p->drawImage( points.boundingRect().left() - sideBuffer, points.boundingRect().top() - sideBuffer, *fillImage );
1272 
1273  delete fillImage;
1274 
1275  if ( !mOffset.isNull() )
1276  {
1277  p->translate( -offset );
1278  }
1279  p->restore();
1280 
1281 }
1282 
1283 //fast distance transform code, adapted from http://cs.brown.edu/~pff/dt/
1284 
1285 /* distance transform of a 1d function using squared distance */
1286 void QgsShapeburstFillSymbolLayerV2::distanceTransform1d( double *f, int n, int *v, double *z, double *d )
1287 {
1288  int k = 0;
1289  v[0] = 0;
1290  z[0] = -INF;
1291  z[1] = + INF;
1292  for ( int q = 1; q <= n - 1; q++ )
1293  {
1294  double s = (( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
1295  while ( s <= z[k] )
1296  {
1297  k--;
1298  s = (( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
1299  }
1300  k++;
1301  v[k] = q;
1302  z[k] = s;
1303  z[k+1] = + INF;
1304  }
1305 
1306  k = 0;
1307  for ( int q = 0; q <= n - 1; q++ )
1308  {
1309  while ( z[k+1] < q )
1310  k++;
1311  d[q] = ( q - v[k] ) * ( q - v[k] ) + f[v[k]];
1312  }
1313 }
1314 
1315 /* distance transform of 2d function using squared distance */
1316 void QgsShapeburstFillSymbolLayerV2::distanceTransform2d( double * im, int width, int height )
1317 {
1318  int maxDimension = qMax( width, height );
1319  double *f = new double[ maxDimension ];
1320  int *v = new int[ maxDimension ];
1321  double *z = new double[ maxDimension + 1 ];
1322  double *d = new double[ maxDimension ];
1323 
1324  // transform along columns
1325  for ( int x = 0; x < width; x++ )
1326  {
1327  for ( int y = 0; y < height; y++ )
1328  {
1329  f[y] = im[ x + y * width ];
1330  }
1331  distanceTransform1d( f, height, v, z, d );
1332  for ( int y = 0; y < height; y++ )
1333  {
1334  im[ x + y * width ] = d[y];
1335  }
1336  }
1337 
1338  // transform along rows
1339  for ( int y = 0; y < height; y++ )
1340  {
1341  for ( int x = 0; x < width; x++ )
1342  {
1343  f[x] = im[ x + y*width ];
1344  }
1345  distanceTransform1d( f, width, v, z, d );
1346  for ( int x = 0; x < width; x++ )
1347  {
1348  im[ x + y*width ] = d[x];
1349  }
1350  }
1351 
1352  delete [] d;
1353  delete [] f;
1354  delete [] v;
1355  delete [] z;
1356 }
1357 
1358 /* distance transform of a binary QImage */
1359 double * QgsShapeburstFillSymbolLayerV2::distanceTransform( QImage *im )
1360 {
1361  int width = im->width();
1362  int height = im->height();
1363 
1364  double * dtArray = new double[width * height];
1365 
1366  //load qImage to array
1367  QRgb tmpRgb;
1368  int idx = 0;
1369  for ( int heightIndex = 0; heightIndex < height; ++heightIndex )
1370  {
1371  const QRgb* scanLine = reinterpret_cast< const QRgb* >( im->constScanLine( heightIndex ) );
1372  for ( int widthIndex = 0; widthIndex < width; ++widthIndex )
1373  {
1374  tmpRgb = scanLine[widthIndex];
1375  if ( qRed( tmpRgb ) == 0 )
1376  {
1377  //black pixel, so zero distance
1378  dtArray[ idx ] = 0;
1379  }
1380  else
1381  {
1382  //white pixel, so initially set distance as infinite
1383  dtArray[ idx ] = INF;
1384  }
1385  idx++;
1386  }
1387  }
1388 
1389  //calculate squared distance transform
1390  distanceTransform2d( dtArray, width, height );
1391 
1392  return dtArray;
1393 }
1394 
1395 void QgsShapeburstFillSymbolLayerV2::dtArrayToQImage( double * array, QImage *im, QgsVectorColorRampV2* ramp, double layerAlpha, bool useWholeShape, int maxPixelDistance )
1396 {
1397  int width = im->width();
1398  int height = im->height();
1399 
1400  //find maximum distance value
1401  double maxDistanceValue;
1402 
1403  if ( useWholeShape )
1404  {
1405  //no max distance specified in symbol properties, so calculate from maximum value in distance transform results
1406  double dtMaxValue = array[0];
1407  for ( int i = 1; i < ( width * height ); ++i )
1408  {
1409  if ( array[i] > dtMaxValue )
1410  {
1411  dtMaxValue = array[i];
1412  }
1413  }
1414 
1415  //values in distance transform are squared
1416  maxDistanceValue = sqrt( dtMaxValue );
1417  }
1418  else
1419  {
1420  //use max distance set in symbol properties
1421  maxDistanceValue = maxPixelDistance;
1422  }
1423 
1424  //update the pixels in the provided QImage
1425  int idx = 0;
1426  double squaredVal = 0;
1427  double pixVal = 0;
1428  QColor pixColor;
1429  bool layerHasAlpha = layerAlpha < 1.0;
1430 
1431  for ( int heightIndex = 0; heightIndex < height; ++heightIndex )
1432  {
1433  QRgb* scanLine = reinterpret_cast< QRgb* >( im->scanLine( heightIndex ) );
1434  for ( int widthIndex = 0; widthIndex < width; ++widthIndex )
1435  {
1436  //result of distance transform
1437  squaredVal = array[idx];
1438 
1439  //scale result to fit in the range [0, 1]
1440  if ( maxDistanceValue > 0 )
1441  {
1442  pixVal = squaredVal > 0 ? qMin(( sqrt( squaredVal ) / maxDistanceValue ), 1.0 ) : 0;
1443  }
1444  else
1445  {
1446  pixVal = 1.0;
1447  }
1448 
1449  //convert value to color from ramp
1450  pixColor = ramp->color( pixVal );
1451 
1452  int pixAlpha = pixColor.alpha();
1453  if (( layerHasAlpha ) || ( pixAlpha != 255 ) )
1454  {
1455  //apply layer's transparency to alpha value
1456  double alpha = pixAlpha * layerAlpha;
1457  //premultiply ramp color since we are storing this in a ARGB32_Premultiplied QImage
1458  QgsSymbolLayerV2Utils::premultiplyColor( pixColor, alpha );
1459  }
1460 
1461  scanLine[widthIndex] = pixColor.rgba();
1462  idx++;
1463  }
1464  }
1465 }
1466 
1468 {
1469  QgsStringMap map;
1470  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
1471  map["gradient_color2"] = QgsSymbolLayerV2Utils::encodeColor( mColor2 );
1472  map["color_type"] = QString::number( mColorType );
1473  map["blur_radius"] = QString::number( mBlurRadius );
1474  map["use_whole_shape"] = QString::number( mUseWholeShape );
1475  map["max_distance"] = QString::number( mMaxDistance );
1476  map["distance_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceUnit );
1477  map["distance_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceMapUnitScale );
1478  map["ignore_rings"] = QString::number( mIgnoreRings );
1479  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1480  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1481  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1482 
1484 
1485  if ( mGradientRamp )
1486  {
1487  map.unite( mGradientRamp->properties() );
1488  }
1489 
1490  return map;
1491 }
1492 
1494 {
1496  if ( mGradientRamp )
1497  {
1498  sl->setColorRamp( mGradientRamp->clone() );
1499  }
1503  sl->setOffset( mOffset );
1504  sl->setOffsetUnit( mOffsetUnit );
1507  copyPaintEffect( sl );
1508  return sl;
1509 }
1510 
1512 {
1513  double offsetBleed = qMax( mOffset.x(), mOffset.y() );
1514  return offsetBleed;
1515 }
1516 
1518 {
1519  mDistanceUnit = unit;
1520  mOffsetUnit = unit;
1521 }
1522 
1524 {
1525  if ( mDistanceUnit == mOffsetUnit )
1526  {
1527  return mDistanceUnit;
1528  }
1529  return QgsSymbolV2::Mixed;
1530 }
1531 
1533 {
1534  mDistanceMapUnitScale = scale;
1535  mOffsetMapUnitScale = scale;
1536 }
1537 
1539 {
1541  {
1542  return mDistanceMapUnitScale;
1543  }
1544  return QgsMapUnitScale();
1545 }
1546 
1547 
1548 //QgsImageFillSymbolLayer
1549 
1551  : mNextAngle( 0.0 )
1552  , mOutlineWidth( 0.0 )
1553  , mOutlineWidthUnit( QgsSymbolV2::MM )
1554  , mOutline( nullptr )
1555 {
1556  setSubSymbol( new QgsLineSymbolV2() );
1557 }
1558 
1560 {
1561 }
1562 
1564 {
1565  QPainter* p = context.renderContext().painter();
1566  if ( !p )
1567  {
1568  return;
1569  }
1570 
1571  mNextAngle = mAngle;
1572  applyDataDefinedSettings( context );
1573 
1574  p->setPen( QPen( Qt::NoPen ) );
1575 
1576  QTransform bkTransform = mBrush.transform();
1578  {
1579  //transform brush to upper left corner of geometry bbox
1580  QPointF leftCorner = points.boundingRect().topLeft();
1581  QTransform t = mBrush.transform();
1582  t.translate( leftCorner.x(), leftCorner.y() );
1583  mBrush.setTransform( t );
1584  }
1585 
1586  if ( context.selected() )
1587  {
1588  QColor selColor = context.renderContext().selectionColor();
1589  // Alister - this doesn't seem to work here
1590  //if ( ! selectionIsOpaque )
1591  // selColor.setAlphaF( context.alpha() );
1592  p->setBrush( QBrush( selColor ) );
1593  _renderPolygon( p, points, rings, context );
1594  }
1595 
1596  if ( !qgsDoubleNear( mNextAngle, 0.0 ) )
1597  {
1598  QTransform t = mBrush.transform();
1599  t.rotate( mNextAngle );
1600  mBrush.setTransform( t );
1601  }
1602  p->setBrush( mBrush );
1603  _renderPolygon( p, points, rings, context );
1604  if ( mOutline )
1605  {
1606  mOutline->renderPolyline( points, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
1607  if ( rings )
1608  {
1609  QList<QPolygonF>::const_iterator ringIt = rings->constBegin();
1610  for ( ; ringIt != rings->constEnd(); ++ringIt )
1611  {
1612  mOutline->renderPolyline( *ringIt, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
1613  }
1614  }
1615  }
1616 
1617  mBrush.setTransform( bkTransform );
1618 }
1619 
1621 {
1622  if ( !symbol ) //unset current outline
1623  {
1624  delete mOutline;
1625  mOutline = nullptr;
1626  return true;
1627  }
1628 
1629  if ( symbol->type() != QgsSymbolV2::Line )
1630  {
1631  delete symbol;
1632  return false;
1633  }
1634 
1635  QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
1636  if ( lineSymbol )
1637  {
1638  delete mOutline;
1639  mOutline = lineSymbol;
1640  return true;
1641  }
1642 
1643  delete symbol;
1644  return false;
1645 }
1646 
1648 {
1649  mOutlineWidthUnit = unit;
1650 }
1651 
1653 {
1654  return mOutlineWidthUnit;
1655 }
1656 
1658 {
1659  mOutlineWidthMapUnitScale = scale;
1660 }
1661 
1663 {
1665 }
1666 
1668 {
1669  if ( mOutline && mOutline->symbolLayer( 0 ) )
1670  {
1671  double subLayerBleed = mOutline->symbolLayer( 0 )->estimateMaxBleed();
1672  return subLayerBleed;
1673  }
1674  return 0;
1675 }
1676 
1678 {
1679  double width = mOutlineWidth;
1681  {
1684  }
1686 }
1687 
1689 {
1690  Q_UNUSED( context );
1691  if ( !mOutline )
1692  {
1693  return QColor( Qt::black );
1694  }
1695  return mOutline->color();
1696 }
1697 
1699 {
1700  return Qt::SolidLine;
1701 #if 0
1702  if ( !mOutline )
1703  {
1704  return Qt::SolidLine;
1705  }
1706  else
1707  {
1708  return mOutline->dxfPenStyle();
1709  }
1710 #endif //0
1711 }
1712 
1714 {
1716  if ( mOutline )
1717  attr.unite( mOutline->usedAttributes() );
1718  return attr;
1719 }
1720 
1721 
1722 //QgsSVGFillSymbolLayer
1723 
1725  mPatternWidth( width ),
1726  mPatternWidthUnit( QgsSymbolV2::MM ),
1727  mSvgOutlineWidthUnit( QgsSymbolV2::MM )
1728 {
1729  setSvgFilePath( svgFilePath );
1730  mOutlineWidth = 0.3;
1731  mAngle = angle;
1732  mColor = QColor( 255, 255, 255 );
1733  mSvgOutlineColor = QColor( 0, 0, 0 );
1734  mSvgOutlineWidth = 0.2;
1735  setDefaultSvgParams();
1736  mSvgPattern = nullptr;
1737 }
1738 
1740  mPatternWidth( width ),
1742  mSvgData( svgData ),
1744 {
1745  storeViewBox();
1746  mOutlineWidth = 0.3;
1747  mAngle = angle;
1748  mColor = QColor( 255, 255, 255 );
1749  mSvgOutlineColor = QColor( 0, 0, 0 );
1750  mSvgOutlineWidth = 0.2;
1751  setSubSymbol( new QgsLineSymbolV2() );
1752  setDefaultSvgParams();
1753  mSvgPattern = nullptr;
1754 }
1755 
1757 {
1758  delete mSvgPattern;
1759 }
1760 
1762 {
1764  mPatternWidthUnit = unit;
1765  mSvgOutlineWidthUnit = unit;
1766  mOutlineWidthUnit = unit;
1767 }
1768 
1770 {
1772  if ( mPatternWidthUnit != unit || mSvgOutlineWidthUnit != unit || mOutlineWidthUnit != unit )
1773  {
1774  return QgsSymbolV2::Mixed;
1775  }
1776  return unit;
1777 }
1778 
1780 {
1782  mPatternWidthMapUnitScale = scale;
1784  mOutlineWidthMapUnitScale = scale;
1785 }
1786 
1788 {
1792  {
1794  }
1795  return QgsMapUnitScale();
1796 }
1797 
1799 {
1801  storeViewBox();
1802 
1803  mSvgFilePath = svgPath;
1804  setDefaultSvgParams();
1805 }
1806 
1808 {
1809  QByteArray data;
1810  double width = 20;
1812  double angle = 0.0;
1813 
1814  if ( properties.contains( "width" ) )
1815  {
1816  width = properties["width"].toDouble();
1817  }
1818  if ( properties.contains( "svgFile" ) )
1819  {
1820  QString svgName = properties["svgFile"];
1821  QString savePath = QgsSymbolLayerV2Utils::symbolNameToPath( svgName );
1822  svgFilePath = ( savePath.isEmpty() ? svgName : savePath );
1823  }
1824  if ( properties.contains( "angle" ) )
1825  {
1826  angle = properties["angle"].toDouble();
1827  }
1828 
1829  QgsSVGFillSymbolLayer* symbolLayer = nullptr;
1830  if ( !svgFilePath.isEmpty() )
1831  {
1832  symbolLayer = new QgsSVGFillSymbolLayer( svgFilePath, width, angle );
1833  }
1834  else
1835  {
1836  if ( properties.contains( "data" ) )
1837  {
1838  data = QByteArray::fromHex( properties["data"].toLocal8Bit() );
1839  }
1840  symbolLayer = new QgsSVGFillSymbolLayer( data, width, angle );
1841  }
1842 
1843  //svg parameters
1844  if ( properties.contains( "svgFillColor" ) )
1845  {
1846  //pre 2.5 projects used "svgFillColor"
1847  symbolLayer->setSvgFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["svgFillColor"] ) );
1848  }
1849  else if ( properties.contains( "color" ) )
1850  {
1851  symbolLayer->setSvgFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["color"] ) );
1852  }
1853  if ( properties.contains( "svgOutlineColor" ) )
1854  {
1855  //pre 2.5 projects used "svgOutlineColor"
1856  symbolLayer->setSvgOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["svgOutlineColor"] ) );
1857  }
1858  else if ( properties.contains( "outline_color" ) )
1859  {
1860  symbolLayer->setSvgOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["outline_color"] ) );
1861  }
1862  else if ( properties.contains( "line_color" ) )
1863  {
1864  symbolLayer->setSvgOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["line_color"] ) );
1865  }
1866  if ( properties.contains( "svgOutlineWidth" ) )
1867  {
1868  //pre 2.5 projects used "svgOutlineWidth"
1869  symbolLayer->setSvgOutlineWidth( properties["svgOutlineWidth"].toDouble() );
1870  }
1871  else if ( properties.contains( "outline_width" ) )
1872  {
1873  symbolLayer->setSvgOutlineWidth( properties["outline_width"].toDouble() );
1874  }
1875  else if ( properties.contains( "line_width" ) )
1876  {
1877  symbolLayer->setSvgOutlineWidth( properties["line_width"].toDouble() );
1878  }
1879 
1880  //units
1881  if ( properties.contains( "pattern_width_unit" ) )
1882  {
1883  symbolLayer->setPatternWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["pattern_width_unit"] ) );
1884  }
1885  if ( properties.contains( "pattern_width_map_unit_scale" ) )
1886  {
1887  symbolLayer->setPatternWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["pattern_width_map_unit_scale"] ) );
1888  }
1889  if ( properties.contains( "svg_outline_width_unit" ) )
1890  {
1891  symbolLayer->setSvgOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["svg_outline_width_unit"] ) );
1892  }
1893  if ( properties.contains( "svg_outline_width_map_unit_scale" ) )
1894  {
1895  symbolLayer->setSvgOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["svg_outline_width_map_unit_scale"] ) );
1896  }
1897  if ( properties.contains( "outline_width_unit" ) )
1898  {
1899  symbolLayer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
1900  }
1901  if ( properties.contains( "outline_width_map_unit_scale" ) )
1902  {
1903  symbolLayer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
1904  }
1905 
1906  symbolLayer->restoreDataDefinedProperties( properties );
1907 
1908  return symbolLayer;
1909 }
1910 
1912 {
1913  return "SVGFill";
1914 }
1915 
1916 void QgsSVGFillSymbolLayer::applyPattern( QBrush& brush, const QString& svgFilePath, double patternWidth, QgsSymbolV2::OutputUnit patternWidthUnit,
1917  const QColor& svgFillColor, const QColor& svgOutlineColor, double svgOutlineWidth,
1920 {
1921  if ( mSvgViewBox.isNull() )
1922  {
1923  return;
1924  }
1925 
1926  delete mSvgPattern;
1927  mSvgPattern = nullptr;
1929 
1930  if ( static_cast< int >( size ) < 1.0 || 10000.0 < size )
1931  {
1932  mSvgPattern = new QImage();
1933  brush.setTextureImage( *mSvgPattern );
1934  }
1935  else
1936  {
1937  bool fitsInCache = true;
1939  const QImage& patternImage = QgsSvgCache::instance()->svgAsImage( svgFilePath, size, svgFillColor, svgOutlineColor, outlineWidth,
1940  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
1941  if ( !fitsInCache )
1942  {
1943  const QPicture& patternPict = QgsSvgCache::instance()->svgAsPicture( svgFilePath, size, svgFillColor, svgOutlineColor, outlineWidth,
1944  context.renderContext().scaleFactor(), 1.0 );
1945  double hwRatio = 1.0;
1946  if ( patternPict.width() > 0 )
1947  {
1948  hwRatio = static_cast< double >( patternPict.height() ) / static_cast< double >( patternPict.width() );
1949  }
1950  mSvgPattern = new QImage( static_cast< int >( size ), static_cast< int >( size * hwRatio ), QImage::Format_ARGB32_Premultiplied );
1951  mSvgPattern->fill( 0 ); // transparent background
1952 
1953  QPainter p( mSvgPattern );
1954  p.drawPicture( QPointF( size / 2, size * hwRatio / 2 ), patternPict );
1955  }
1956 
1957  QTransform brushTransform;
1958  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
1959  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1960  {
1961  QImage transparentImage = fitsInCache ? patternImage.copy() : mSvgPattern->copy();
1962  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
1963  brush.setTextureImage( transparentImage );
1964  }
1965  else
1966  {
1967  brush.setTextureImage( fitsInCache ? patternImage : *mSvgPattern );
1968  }
1969  brush.setTransform( brushTransform );
1970  }
1971 }
1972 
1974 {
1975 
1977 
1978  if ( mOutline )
1979  {
1980  mOutline->startRender( context.renderContext(), context.fields() );
1981  }
1982 
1983  prepareExpressions( context );
1984 }
1985 
1987 {
1988  if ( mOutline )
1989  {
1990  mOutline->stopRender( context.renderContext() );
1991  }
1992 }
1993 
1995 {
1996  QgsStringMap map;
1997  if ( !mSvgFilePath.isEmpty() )
1998  {
2000  }
2001  else
2002  {
2003  map.insert( "data", QString( mSvgData.toHex() ) );
2004  }
2005 
2006  map.insert( "width", QString::number( mPatternWidth ) );
2007  map.insert( "angle", QString::number( mAngle ) );
2008 
2009  //svg parameters
2011  map.insert( "outline_color", QgsSymbolLayerV2Utils::encodeColor( mSvgOutlineColor ) );
2012  map.insert( "outline_width", QString::number( mSvgOutlineWidth ) );
2013 
2014  //units
2015  map.insert( "pattern_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mPatternWidthUnit ) );
2016  map.insert( "pattern_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mPatternWidthMapUnitScale ) );
2017  map.insert( "svg_outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mSvgOutlineWidthUnit ) );
2018  map.insert( "svg_outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mSvgOutlineWidthMapUnitScale ) );
2019  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
2020  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
2021 
2023  return map;
2024 }
2025 
2027 {
2028  QgsSVGFillSymbolLayer* clonedLayer = nullptr;
2029  if ( !mSvgFilePath.isEmpty() )
2030  {
2031  clonedLayer = new QgsSVGFillSymbolLayer( mSvgFilePath, mPatternWidth, mAngle );
2032  clonedLayer->setSvgFillColor( mColor );
2033  clonedLayer->setSvgOutlineColor( mSvgOutlineColor );
2034  clonedLayer->setSvgOutlineWidth( mSvgOutlineWidth );
2035  }
2036  else
2037  {
2038  clonedLayer = new QgsSVGFillSymbolLayer( mSvgData, mPatternWidth, mAngle );
2039  }
2040 
2041  clonedLayer->setPatternWidthUnit( mPatternWidthUnit );
2045  clonedLayer->setOutlineWidthUnit( mOutlineWidthUnit );
2047 
2048  if ( mOutline )
2049  {
2050  clonedLayer->setSubSymbol( mOutline->clone() );
2051  }
2052  copyDataDefinedProperties( clonedLayer );
2053  copyPaintEffect( clonedLayer );
2054  return clonedLayer;
2055 }
2056 
2057 void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const
2058 {
2059  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
2060  if ( !props.value( "uom", "" ).isEmpty() )
2061  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
2062  element.appendChild( symbolizerElem );
2063 
2064  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
2065 
2066  QDomElement fillElem = doc.createElement( "se:Fill" );
2067  symbolizerElem.appendChild( fillElem );
2068 
2069  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
2070  fillElem.appendChild( graphicFillElem );
2071 
2072  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2073  graphicFillElem.appendChild( graphicElem );
2074 
2075  if ( !mSvgFilePath.isEmpty() )
2076  {
2077  QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mSvgFilePath, "image/svg+xml", mColor, mPatternWidth );
2078  }
2079  else
2080  {
2081  // TODO: create svg from data
2082  // <se:InlineContent>
2083  symbolizerElem.appendChild( doc.createComment( "SVG from data not implemented yet" ) );
2084  }
2085 
2086  if ( mSvgOutlineColor.isValid() || mSvgOutlineWidth >= 0 )
2087  {
2088  QgsSymbolLayerV2Utils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, mSvgOutlineWidth );
2089  }
2090 
2091  // <Rotation>
2092  QString angleFunc;
2093  bool ok;
2094  double angle = props.value( "angle", "0" ).toDouble( &ok );
2095  if ( !ok )
2096  {
2097  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2098  }
2099  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2100  {
2101  angleFunc = QString::number( angle + mAngle );
2102  }
2103  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2104 
2105  if ( mOutline )
2106  {
2107  // the outline sub symbol should be stored within the Stroke element,
2108  // but it will be stored in a separated LineSymbolizer because it could
2109  // have more than one layer
2110  mOutline->toSld( doc, element, props );
2111  }
2112 }
2113 
2115 {
2116  QgsDebugMsg( "Entered." );
2117 
2118  QString path, mimeType;
2119  QColor fillColor, borderColor;
2120  Qt::PenStyle penStyle;
2121  double size, borderWidth;
2122 
2123  QDomElement fillElem = element.firstChildElement( "Fill" );
2124  if ( fillElem.isNull() )
2125  return nullptr;
2126 
2127  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
2128  if ( graphicFillElem.isNull() )
2129  return nullptr;
2130 
2131  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
2132  if ( graphicElem.isNull() )
2133  return nullptr;
2134 
2135  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
2136  return nullptr;
2137 
2138  if ( mimeType != "image/svg+xml" )
2139  return nullptr;
2140 
2141  QgsSymbolLayerV2Utils::lineFromSld( graphicElem, penStyle, borderColor, borderWidth );
2142 
2143  double angle = 0.0;
2144  QString angleFunc;
2145  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2146  {
2147  bool ok;
2148  double d = angleFunc.toDouble( &ok );
2149  if ( ok )
2150  angle = d;
2151  }
2152 
2153  QgsSVGFillSymbolLayer* sl = new QgsSVGFillSymbolLayer( path, size, angle );
2154  sl->setSvgFillColor( fillColor );
2155  sl->setSvgOutlineColor( borderColor );
2156  sl->setSvgOutlineWidth( borderWidth );
2157 
2158  // try to get the outline
2159  QDomElement strokeElem = element.firstChildElement( "Stroke" );
2160  if ( !strokeElem.isNull() )
2161  {
2163  if ( l )
2164  {
2165  QgsSymbolLayerV2List layers;
2166  layers.append( l );
2167  sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
2168  }
2169  }
2170 
2171  return sl;
2172 }
2173 
2175 {
2179  {
2180  return; //no data defined settings
2181  }
2182 
2183  bool ok;
2184 
2186  {
2187  context.setOriginalValueVariable( mAngle );
2188  double nextAngle = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_ANGLE, context, QVariant(), &ok ).toDouble();
2189  if ( ok )
2190  mNextAngle = nextAngle;
2191  }
2192 
2193  double width = mPatternWidth;
2195  {
2198  }
2199  QString svgFile = mSvgFilePath;
2201  {
2204  }
2205  QColor svgFillColor = mColor;
2207  {
2210  if ( ok )
2211  svgFillColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2212  }
2213  QColor svgOutlineColor = mSvgOutlineColor;
2215  {
2218  if ( ok )
2219  svgOutlineColor = QgsSymbolLayerV2Utils::decodeColor( colorString );
2220  }
2221  double outlineWidth = mSvgOutlineWidth;
2223  {
2226  }
2227  applyPattern( mBrush, svgFile, width, mPatternWidthUnit, svgFillColor, svgOutlineColor, outlineWidth,
2229 
2230 }
2231 
2232 void QgsSVGFillSymbolLayer::storeViewBox()
2233 {
2234  if ( !mSvgData.isEmpty() )
2235  {
2236  QSvgRenderer r( mSvgData );
2237  if ( r.isValid() )
2238  {
2239  mSvgViewBox = r.viewBoxF();
2240  return;
2241  }
2242  }
2243 
2244  mSvgViewBox = QRectF();
2245  return;
2246 }
2247 
2248 void QgsSVGFillSymbolLayer::setDefaultSvgParams()
2249 {
2250  if ( mSvgFilePath.isEmpty() )
2251  {
2252  return;
2253  }
2254 
2255  bool hasFillParam, hasFillOpacityParam, hasOutlineParam, hasOutlineWidthParam, hasOutlineOpacityParam;
2256  bool hasDefaultFillColor, hasDefaultFillOpacity, hasDefaultOutlineColor, hasDefaultOutlineWidth, hasDefaultOutlineOpacity;
2257  QColor defaultFillColor, defaultOutlineColor;
2258  double defaultOutlineWidth, defaultFillOpacity, defaultOutlineOpacity;
2259  QgsSvgCache::instance()->containsParams( mSvgFilePath, hasFillParam, hasDefaultFillColor, defaultFillColor,
2260  hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
2261  hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
2262  hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth,
2263  hasOutlineOpacityParam, hasDefaultOutlineOpacity, defaultOutlineOpacity );
2264 
2265  double newFillOpacity = hasFillOpacityParam ? mColor.alphaF() : 1.0;
2266  double newOutlineOpacity = hasOutlineOpacityParam ? mSvgOutlineColor.alphaF() : 1.0;
2267 
2268  if ( hasDefaultFillColor )
2269  {
2270  mColor = defaultFillColor;
2271  mColor.setAlphaF( newFillOpacity );
2272  }
2273  if ( hasDefaultFillOpacity )
2274  {
2275  mColor.setAlphaF( defaultFillOpacity );
2276  }
2277  if ( hasDefaultOutlineColor )
2278  {
2279  mSvgOutlineColor = defaultOutlineColor;
2280  mSvgOutlineColor.setAlphaF( newOutlineOpacity );
2281  }
2282  if ( hasDefaultOutlineOpacity )
2283  {
2284  mSvgOutlineColor.setAlphaF( defaultOutlineOpacity );
2285  }
2286  if ( hasDefaultOutlineWidth )
2287  {
2288  mSvgOutlineWidth = defaultOutlineWidth;
2289  }
2290 }
2291 
2292 
2295  , mDistance( 5.0 )
2296  , mDistanceUnit( QgsSymbolV2::MM )
2297  , mLineWidth( 0 )
2298  , mLineWidthUnit( QgsSymbolV2::MM )
2299  , mLineAngle( 45.0 )
2300  , mOffset( 0.0 )
2301  , mOffsetUnit( QgsSymbolV2::MM )
2302  , mFillLineSymbol( nullptr )
2303 {
2304  setSubSymbol( new QgsLineSymbolV2() );
2305  QgsImageFillSymbolLayer::setSubSymbol( nullptr ); //no outline
2306 }
2307 
2309 {
2310  mFillLineSymbol->setWidth( w );
2311  mLineWidth = w;
2312 }
2313 
2315 {
2316  mFillLineSymbol->setColor( c );
2317  mColor = c;
2318 }
2319 
2321 {
2322  delete mFillLineSymbol;
2323 }
2324 
2326 {
2327  if ( !symbol )
2328  {
2329  return false;
2330  }
2331 
2332  if ( symbol->type() == QgsSymbolV2::Line )
2333  {
2334  QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
2335  if ( lineSymbol )
2336  {
2337  delete mFillLineSymbol;
2338  mFillLineSymbol = lineSymbol;
2339 
2340  return true;
2341  }
2342  }
2343  delete symbol;
2344  return false;
2345 }
2346 
2348 {
2349  return mFillLineSymbol;
2350 }
2351 
2353 {
2355  if ( mFillLineSymbol )
2356  attr.unite( mFillLineSymbol->usedAttributes() );
2357  return attr;
2358 }
2359 
2361 {
2362  return 0;
2363 }
2364 
2366 {
2368  mDistanceUnit = unit;
2369  mLineWidthUnit = unit;
2370  mOffsetUnit = unit;
2371 }
2372 
2374 {
2376  if ( mDistanceUnit != unit || mLineWidthUnit != unit || mOffsetUnit != unit )
2377  {
2378  return QgsSymbolV2::Mixed;
2379  }
2380  return unit;
2381 }
2382 
2384 {
2386  mDistanceMapUnitScale = scale;
2387  mLineWidthMapUnitScale = scale;
2388  mOffsetMapUnitScale = scale;
2389 }
2390 
2392 {
2396  {
2397  return mDistanceMapUnitScale;
2398  }
2399  return QgsMapUnitScale();
2400 }
2401 
2403 {
2405 
2406  //default values
2407  double lineAngle = 45;
2408  double distance = 5;
2409  double lineWidth = 0.5;
2410  QColor color( Qt::black );
2411  double offset = 0.0;
2412 
2413  if ( properties.contains( "lineangle" ) )
2414  {
2415  //pre 2.5 projects used "lineangle"
2416  lineAngle = properties["lineangle"].toDouble();
2417  }
2418  else if ( properties.contains( "angle" ) )
2419  {
2420  lineAngle = properties["angle"].toDouble();
2421  }
2422  patternLayer->setLineAngle( lineAngle );
2423 
2424  if ( properties.contains( "distance" ) )
2425  {
2426  distance = properties["distance"].toDouble();
2427  }
2428  patternLayer->setDistance( distance );
2429 
2430  if ( properties.contains( "linewidth" ) )
2431  {
2432  //pre 2.5 projects used "linewidth"
2433  lineWidth = properties["linewidth"].toDouble();
2434  }
2435  else if ( properties.contains( "outline_width" ) )
2436  {
2437  lineWidth = properties["outline_width"].toDouble();
2438  }
2439  else if ( properties.contains( "line_width" ) )
2440  {
2441  lineWidth = properties["line_width"].toDouble();
2442  }
2443  patternLayer->setLineWidth( lineWidth );
2444 
2445  if ( properties.contains( "color" ) )
2446  {
2447  color = QgsSymbolLayerV2Utils::decodeColor( properties["color"] );
2448  }
2449  else if ( properties.contains( "outline_color" ) )
2450  {
2451  color = QgsSymbolLayerV2Utils::decodeColor( properties["outline_color"] );
2452  }
2453  else if ( properties.contains( "line_color" ) )
2454  {
2455  color = QgsSymbolLayerV2Utils::decodeColor( properties["line_color"] );
2456  }
2457  patternLayer->setColor( color );
2458 
2459  if ( properties.contains( "offset" ) )
2460  {
2461  offset = properties["offset"].toDouble();
2462  }
2463  patternLayer->setOffset( offset );
2464 
2465 
2466  if ( properties.contains( "distance_unit" ) )
2467  {
2468  patternLayer->setDistanceUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_unit"] ) );
2469  }
2470  if ( properties.contains( "distance_map_unit_scale" ) )
2471  {
2472  patternLayer->setDistanceMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_map_unit_scale"] ) );
2473  }
2474  if ( properties.contains( "line_width_unit" ) )
2475  {
2476  patternLayer->setLineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["line_width_unit"] ) );
2477  }
2478  else if ( properties.contains( "outline_width_unit" ) )
2479  {
2480  patternLayer->setLineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
2481  }
2482  if ( properties.contains( "line_width_map_unit_scale" ) )
2483  {
2484  patternLayer->setLineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["line_width_map_unit_scale"] ) );
2485  }
2486  if ( properties.contains( "offset_unit" ) )
2487  {
2488  patternLayer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
2489  }
2490  if ( properties.contains( "offset_map_unit_scale" ) )
2491  {
2492  patternLayer->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["offset_map_unit_scale"] ) );
2493  }
2494  if ( properties.contains( "outline_width_unit" ) )
2495  {
2496  patternLayer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
2497  }
2498  if ( properties.contains( "outline_width_map_unit_scale" ) )
2499  {
2500  patternLayer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
2501  }
2502 
2503  patternLayer->restoreDataDefinedProperties( properties );
2504 
2505  return patternLayer;
2506 }
2507 
2509 {
2510  return "LinePatternFill";
2511 }
2512 
2513 void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double lineAngle, double distance,
2514  double lineWidth, const QColor& color )
2515 {
2516  Q_UNUSED( lineWidth );
2517  Q_UNUSED( color );
2518 
2519  mBrush.setTextureImage( QImage() ); // set empty in case we have to return
2520 
2521  if ( !mFillLineSymbol )
2522  {
2523  return;
2524  }
2525  // We have to make a copy because marker intervals will have to be adjusted
2526  QgsLineSymbolV2* fillLineSymbol = mFillLineSymbol->clone();
2527  if ( !fillLineSymbol )
2528  {
2529  return;
2530  }
2531 
2532  const QgsRenderContext& ctx = context.renderContext();
2533  //double outlinePixelWidth = lineWidth * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mLineWidthUnit, mLineWidthMapUnitScale );
2536 
2537  // To get all patterns into image, we have to consider symbols size (estimateMaxBleed()).
2538  // For marker lines we have to get markers interval.
2539  double outputPixelBleed = 0;
2540  double outputPixelInterval = 0; // maximum interval
2541  for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2542  {
2543  QgsSymbolLayerV2 *layer = fillLineSymbol->symbolLayer( i );
2544  double layerBleed = layer->estimateMaxBleed();
2545  // TODO: to get real bleed we have to scale it using context and units,
2546  // unfortunately estimateMaxBleed() ignore units completely, e.g.
2547  // QgsMarkerLineSymbolLayerV2::estimateMaxBleed() is mixing marker size and
2548  // offset regardless units. This has to be fixed especially
2549  // in estimateMaxBleed(), context probably has to be used.
2550  // For now, we only support millimeters
2551  double outputPixelLayerBleed = layerBleed * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, QgsSymbolV2::MM );
2552  outputPixelBleed = qMax( outputPixelBleed, outputPixelLayerBleed );
2553 
2554  QgsMarkerLineSymbolLayerV2 *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayerV2 *>( layer );
2555  if ( markerLineLayer )
2556  {
2557  double outputPixelLayerInterval = markerLineLayer->interval() * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, markerLineLayer->intervalUnit(), markerLineLayer->intervalMapUnitScale() );
2558 
2559  // There may be multiple marker lines with different intervals.
2560  // In theory we should find the least common multiple, but that could be too
2561  // big (multiplication of intervals in the worst case).
2562  // Because patterns without small common interval would look strange, we
2563  // believe that the longest interval should usually be sufficient.
2564  outputPixelInterval = qMax( outputPixelInterval, outputPixelLayerInterval );
2565  }
2566  }
2567 
2568  if ( outputPixelInterval > 0 )
2569  {
2570  // We have to adjust marker intervals to integer pixel size to get
2571  // repeatable pattern.
2572  double intervalScale = qRound( outputPixelInterval ) / outputPixelInterval;
2573  outputPixelInterval = qRound( outputPixelInterval );
2574 
2575  for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2576  {
2577  QgsSymbolLayerV2 *layer = fillLineSymbol->symbolLayer( i );
2578 
2579  QgsMarkerLineSymbolLayerV2 *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayerV2 *>( layer );
2580  if ( markerLineLayer )
2581  {
2582  markerLineLayer->setInterval( intervalScale * markerLineLayer->interval() );
2583  }
2584  }
2585  }
2586 
2587  //create image
2588  int height, width;
2589  if ( qgsDoubleNear( lineAngle, 0 ) || qgsDoubleNear( lineAngle, 360 ) || qgsDoubleNear( lineAngle, 180 ) )
2590  {
2591  height = outputPixelDist;
2592  width = outputPixelInterval > 0 ? outputPixelInterval : height;
2593  }
2594  else if ( qgsDoubleNear( lineAngle, 90 ) || qgsDoubleNear( lineAngle, 270 ) )
2595  {
2596  width = outputPixelDist;
2597  height = outputPixelInterval > 0 ? outputPixelInterval : width;
2598  }
2599  else
2600  {
2601  height = outputPixelDist / cos( lineAngle * M_PI / 180 ); //keep perpendicular distance between lines constant
2602  width = outputPixelDist / sin( lineAngle * M_PI / 180 );
2603 
2604  // recalculate real angle and distance after rounding to pixels
2605  lineAngle = 180 * atan2( static_cast< double >( height ), static_cast< double >( width ) ) / M_PI;
2606  if ( lineAngle < 0 )
2607  {
2608  lineAngle += 360.;
2609  }
2610 
2611  height = qAbs( height );
2612  width = qAbs( width );
2613 
2614  outputPixelDist = height * cos( lineAngle * M_PI / 180 );
2615 
2616  // Round offset to correspond to one pixel height, otherwise lines may
2617  // be shifted on tile border if offset falls close to pixel center
2618  int offsetHeight = qRound( qAbs( outputPixelOffset / cos( lineAngle * M_PI / 180 ) ) );
2619  outputPixelOffset = offsetHeight * cos( lineAngle * M_PI / 180 );
2620  }
2621 
2622  //depending on the angle, we might need to render into a larger image and use a subset of it
2623  double dx = 0;
2624  double dy = 0;
2625 
2626  // Add buffer based on bleed but keep precisely the height/width ratio (angle)
2627  // thus we add integer multiplications of width and height covering the bleed
2628  int bufferMulti = qMax( qCeil( outputPixelBleed / width ), qCeil( outputPixelBleed / width ) );
2629 
2630  // Always buffer at least once so that center of line marker in upper right corner
2631  // does not fall outside due to representation error
2632  bufferMulti = qMax( bufferMulti, 1 );
2633 
2634  int xBuffer = width * bufferMulti;
2635  int yBuffer = height * bufferMulti;
2636  int innerWidth = width;
2637  int innerHeight = height;
2638  width += 2 * xBuffer;
2639  height += 2 * yBuffer;
2640 
2641  if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
2642  {
2643  return;
2644  }
2645 
2646  QImage patternImage( width, height, QImage::Format_ARGB32 );
2647  patternImage.fill( 0 );
2648 
2649  QPointF p1, p2, p3, p4, p5, p6;
2650  if ( qgsDoubleNear( lineAngle, 0.0 ) || qgsDoubleNear( lineAngle, 360.0 ) || qgsDoubleNear( lineAngle, 180.0 ) )
2651  {
2652  p1 = QPointF( 0, yBuffer );
2653  p2 = QPointF( width, yBuffer );
2654  p3 = QPointF( 0, yBuffer + innerHeight );
2655  p4 = QPointF( width, yBuffer + innerHeight );
2656  }
2657  else if ( qgsDoubleNear( lineAngle, 90.0 ) || qgsDoubleNear( lineAngle, 270.0 ) )
2658  {
2659  p1 = QPointF( xBuffer, height );
2660  p2 = QPointF( xBuffer, 0 );
2661  p3 = QPointF( xBuffer + innerWidth, height );
2662  p4 = QPointF( xBuffer + innerWidth, 0 );
2663  }
2664  else if ( lineAngle > 0 && lineAngle < 90 )
2665  {
2666  dx = outputPixelDist * cos(( 90 - lineAngle ) * M_PI / 180.0 );
2667  dy = outputPixelDist * sin(( 90 - lineAngle ) * M_PI / 180.0 );
2668  p1 = QPointF( 0, height );
2669  p2 = QPointF( width, 0 );
2670  p3 = QPointF( -dx, height - dy );
2671  p4 = QPointF( width - dx, -dy );
2672  p5 = QPointF( dx, height + dy );
2673  p6 = QPointF( width + dx, dy );
2674  }
2675  else if ( lineAngle > 180 && lineAngle < 270 )
2676  {
2677  dx = outputPixelDist * cos(( 90 - lineAngle ) * M_PI / 180.0 );
2678  dy = outputPixelDist * sin(( 90 - lineAngle ) * M_PI / 180.0 );
2679  p1 = QPointF( width, 0 );
2680  p2 = QPointF( 0, height );
2681  p3 = QPointF( width - dx, -dy );
2682  p4 = QPointF( -dx, height - dy );
2683  p5 = QPointF( width + dx, dy );
2684  p6 = QPointF( dx, height + dy );
2685  }
2686  else if ( lineAngle > 90 && lineAngle < 180 )
2687  {
2688  dy = outputPixelDist * cos(( 180 - lineAngle ) * M_PI / 180 );
2689  dx = outputPixelDist * sin(( 180 - lineAngle ) * M_PI / 180 );
2690  p1 = QPointF( 0, 0 );
2691  p2 = QPointF( width, height );
2692  p5 = QPointF( dx, -dy );
2693  p6 = QPointF( width + dx, height - dy );
2694  p3 = QPointF( -dx, dy );
2695  p4 = QPointF( width - dx, height + dy );
2696  }
2697  else if ( lineAngle > 270 && lineAngle < 360 )
2698  {
2699  dy = outputPixelDist * cos(( 180 - lineAngle ) * M_PI / 180 );
2700  dx = outputPixelDist * sin(( 180 - lineAngle ) * M_PI / 180 );
2701  p1 = QPointF( width, height );
2702  p2 = QPointF( 0, 0 );
2703  p5 = QPointF( width + dx, height - dy );
2704  p6 = QPointF( dx, -dy );
2705  p3 = QPointF( width - dx, height + dy );
2706  p4 = QPointF( -dx, dy );
2707  }
2708 
2709  if ( !qgsDoubleNear( mOffset, 0.0 ) ) //shift everything
2710  {
2711  QPointF tempPt;
2712  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelDist + outputPixelOffset );
2713  p3 = QPointF( tempPt.x(), tempPt.y() );
2714  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelDist + outputPixelOffset );
2715  p4 = QPointF( tempPt.x(), tempPt.y() );
2716  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p5, outputPixelDist - outputPixelOffset );
2717  p5 = QPointF( tempPt.x(), tempPt.y() );
2718  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p6, outputPixelDist - outputPixelOffset );
2719  p6 = QPointF( tempPt.x(), tempPt.y() );
2720 
2721  //update p1, p2 last
2722  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelOffset );
2723  p1 = QPointF( tempPt.x(), tempPt.y() );
2724  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelOffset );
2725  p2 = QPointF( tempPt.x(), tempPt.y() );
2726  }
2727 
2728  QPainter p( &patternImage );
2729 
2730 #if 0
2731  // DEBUG: Draw rectangle
2732  p.setRenderHint( QPainter::Antialiasing, false ); // get true rect
2733  QPen pen( QColor( Qt::black ) );
2734  pen.setWidthF( 0.1 );
2735  pen.setCapStyle( Qt::FlatCap );
2736  p.setPen( pen );
2737 
2738  // To see this rectangle, comment buffer cut below.
2739  // Subtract 1 because not antialiased are rendered to the right/down by 1 pixel
2740  QPolygon polygon = QPolygon() << QPoint( 0, 0 ) << QPoint( width - 1, 0 ) << QPoint( width - 1, height - 1 ) << QPoint( 0, height - 1 ) << QPoint( 0, 0 );
2741  p.drawPolygon( polygon );
2742 
2743  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 );
2744  p.drawPolygon( polygon );
2745 #endif
2746 
2747  // Use antialiasing because without antialiasing lines are rendered to the
2748  // right and below the mathematically defined points (not symmetrical)
2749  // and such tiles become useless for are filling
2750  p.setRenderHint( QPainter::Antialiasing, true );
2751 
2752  // line rendering needs context for drawing on patternImage
2753  QgsRenderContext lineRenderContext;
2754  lineRenderContext.setPainter( &p );
2755  lineRenderContext.setRasterScaleFactor( 1.0 );
2756  lineRenderContext.setScaleFactor( context.renderContext().scaleFactor() * context.renderContext().rasterScaleFactor() );
2758  lineRenderContext.setMapToPixel( mtp );
2759  lineRenderContext.setForceVectorOutput( false );
2760  lineRenderContext.setExpressionContext( context.renderContext().expressionContext() );
2761 
2762  fillLineSymbol->startRender( lineRenderContext, context.fields() );
2763 
2764  QVector<QPolygonF> polygons;
2765  polygons.append( QPolygonF() << p1 << p2 );
2766  polygons.append( QPolygonF() << p3 << p4 );
2767  if ( !qgsDoubleNear( lineAngle, 0 ) && !qgsDoubleNear( lineAngle, 360 ) && !qgsDoubleNear( lineAngle, 90 ) && !qgsDoubleNear( lineAngle, 180 ) && !qgsDoubleNear( lineAngle, 270 ) )
2768  {
2769  polygons.append( QPolygonF() << p5 << p6 );
2770  }
2771 
2772  Q_FOREACH ( const QPolygonF& polygon, polygons )
2773  {
2774  fillLineSymbol->renderPolyline( polygon, context.feature(), lineRenderContext, -1, context.selected() );
2775  }
2776 
2777  fillLineSymbol->stopRender( lineRenderContext );
2778  p.end();
2779 
2780  // Cut off the buffer
2781  patternImage = patternImage.copy( xBuffer, yBuffer, patternImage.width() - 2 * xBuffer, patternImage.height() - 2 * yBuffer );
2782 
2783  //set image to mBrush
2784  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
2785  {
2786  QImage transparentImage = patternImage.copy();
2787  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
2788  brush.setTextureImage( transparentImage );
2789  }
2790  else
2791  {
2792  brush.setTextureImage( patternImage );
2793  }
2794 
2795  QTransform brushTransform;
2796  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
2797  brush.setTransform( brushTransform );
2798 
2799  delete fillLineSymbol;
2800 }
2801 
2803 {
2804  applyPattern( context, mBrush, mLineAngle, mDistance, mLineWidth, mColor );
2805 
2806  if ( mFillLineSymbol )
2807  {
2808  mFillLineSymbol->startRender( context.renderContext(), context.fields() );
2809  }
2810 
2811  prepareExpressions( context );
2812 }
2813 
2815 {
2816 }
2817 
2819 {
2820  QgsStringMap map;
2821  map.insert( "angle", QString::number( mLineAngle ) );
2822  map.insert( "distance", QString::number( mDistance ) );
2823  map.insert( "line_width", QString::number( mLineWidth ) );
2825  map.insert( "offset", QString::number( mOffset ) );
2827  map.insert( "line_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mLineWidthUnit ) );
2829  map.insert( "distance_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceMapUnitScale ) );
2830  map.insert( "line_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mLineWidthMapUnitScale ) );
2831  map.insert( "offset_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale ) );
2832  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
2833  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
2835  return map;
2836 }
2837 
2839 {
2841  if ( mFillLineSymbol )
2842  {
2843  clonedLayer->setSubSymbol( mFillLineSymbol->clone() );
2844  }
2845  copyPaintEffect( clonedLayer );
2846  return clonedLayer;
2847 }
2848 
2850 {
2851  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
2852  if ( !props.value( "uom", "" ).isEmpty() )
2853  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
2854  element.appendChild( symbolizerElem );
2855 
2856  // <Geometry>
2857  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
2858 
2859  QDomElement fillElem = doc.createElement( "se:Fill" );
2860  symbolizerElem.appendChild( fillElem );
2861 
2862  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
2863  fillElem.appendChild( graphicFillElem );
2864 
2865  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2866  graphicFillElem.appendChild( graphicElem );
2867 
2868  //line properties must be inside the graphic definition
2869  QColor lineColor = mFillLineSymbol ? mFillLineSymbol->color() : QColor();
2870  double lineWidth = mFillLineSymbol ? mFillLineSymbol->width() : 0.0;
2871  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), lineColor, Qt::SolidLine, lineWidth, mDistance );
2872 
2873  // <Rotation>
2874  QString angleFunc;
2875  bool ok;
2876  double angle = props.value( "angle", "0" ).toDouble( &ok );
2877  if ( !ok )
2878  {
2879  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mLineAngle );
2880  }
2881  else if ( !qgsDoubleNear( angle + mLineAngle, 0.0 ) )
2882  {
2883  angleFunc = QString::number( angle + mLineAngle );
2884  }
2885  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2886 
2887  // <se:Displacement>
2888  QPointF lineOffset( sin( mLineAngle ) * mOffset, cos( mLineAngle ) * mOffset );
2889  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, lineOffset );
2890 }
2891 
2893 {
2894  QString featureStyle;
2895  featureStyle.append( "Brush(" );
2896  featureStyle.append( QString( "fc:%1" ).arg( mColor.name() ) );
2897  featureStyle.append( QString( ",bc:%1" ).arg( "#00000000" ) ); //transparent background
2898  featureStyle.append( ",id:\"ogr-brush-2\"" );
2899  featureStyle.append( QString( ",a:%1" ).arg( mLineAngle ) );
2900  featureStyle.append( QString( ",s:%1" ).arg( mLineWidth * widthScaleFactor ) );
2901  featureStyle.append( ",dx:0mm" );
2902  featureStyle.append( QString( ",dy:%1mm" ).arg( mDistance * widthScaleFactor ) );
2903  featureStyle.append( ')' );
2904  return featureStyle;
2905 }
2906 
2908 {
2911  && ( !mFillLineSymbol || !mFillLineSymbol->hasDataDefinedProperties() ) )
2912  {
2913  return; //no data defined settings
2914  }
2915 
2916  bool ok;
2917  double lineAngle = mLineAngle;
2919  {
2922  }
2923  double distance = mDistance;
2925  {
2928  }
2929  double lineWidth = mLineWidth;
2931  {
2934  }
2935  QColor color = mColor;
2937  {
2940  if ( ok )
2941  color = QgsSymbolLayerV2Utils::decodeColor( colorString );
2942  }
2943  applyPattern( context, mBrush, lineAngle, distance, lineWidth, color );
2944 }
2945 
2947 {
2948  QgsDebugMsg( "Entered." );
2949 
2950  QString name;
2951  QColor fillColor, lineColor;
2952  double size, lineWidth;
2953  Qt::PenStyle lineStyle;
2954 
2955  QDomElement fillElem = element.firstChildElement( "Fill" );
2956  if ( fillElem.isNull() )
2957  return nullptr;
2958 
2959  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
2960  if ( graphicFillElem.isNull() )
2961  return nullptr;
2962 
2963  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
2964  if ( graphicElem.isNull() )
2965  return nullptr;
2966 
2967  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, lineColor, lineStyle, lineWidth, size ) )
2968  return nullptr;
2969 
2970  if ( name != "horline" )
2971  return nullptr;
2972 
2973  double angle = 0.0;
2974  QString angleFunc;
2975  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2976  {
2977  bool ok;
2978  double d = angleFunc.toDouble( &ok );
2979  if ( ok )
2980  angle = d;
2981  }
2982 
2983  double offset = 0.0;
2984  QPointF vectOffset;
2985  if ( QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, vectOffset ) )
2986  {
2987  offset = sqrt( pow( vectOffset.x(), 2 ) + pow( vectOffset.y(), 2 ) );
2988  }
2989 
2991  sl->setColor( lineColor );
2992  sl->setLineWidth( lineWidth );
2993  sl->setLineAngle( angle );
2994  sl->setOffset( offset );
2995  sl->setDistance( size );
2996 
2997  // try to get the outline
2998  QDomElement strokeElem = element.firstChildElement( "Stroke" );
2999  if ( !strokeElem.isNull() )
3000  {
3002  if ( l )
3003  {
3004  QgsSymbolLayerV2List layers;
3005  layers.append( l );
3006  sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
3007  }
3008  }
3009 
3010  return sl;
3011 }
3012 
3013 
3015 
3017  mDistanceXUnit( QgsSymbolV2::MM ), mDistanceY( 15 ), mDistanceYUnit( QgsSymbolV2::MM ), mDisplacementX( 0 ), mDisplacementXUnit( QgsSymbolV2::MM ),
3018  mDisplacementY( 0 ), mDisplacementYUnit( QgsSymbolV2::MM )
3019 {
3020  mDistanceX = 15;
3021  mDistanceY = 15;
3022  mDisplacementX = 0;
3023  mDisplacementY = 0;
3025  QgsImageFillSymbolLayer::setSubSymbol( nullptr ); //no outline
3026 }
3027 
3029 {
3030  delete mMarkerSymbol;
3031 }
3032 
3034 {
3036  mDistanceXUnit = unit;
3037  mDistanceYUnit = unit;
3038  mDisplacementXUnit = unit;
3039  mDisplacementYUnit = unit;
3040 }
3041 
3043 {
3045  if ( mDistanceXUnit != unit || mDistanceYUnit != unit || mDisplacementXUnit != unit || mDisplacementYUnit != unit )
3046  {
3047  return QgsSymbolV2::Mixed;
3048  }
3049  return unit;
3050 }
3051 
3053 {
3055  mDistanceXMapUnitScale = scale;
3056  mDistanceYMapUnitScale = scale;
3059 }
3060 
3062 {
3067  {
3068  return mDistanceXMapUnitScale;
3069  }
3070  return QgsMapUnitScale();
3071 }
3072 
3074 {
3076  if ( properties.contains( "distance_x" ) )
3077  {
3078  layer->setDistanceX( properties["distance_x"].toDouble() );
3079  }
3080  if ( properties.contains( "distance_y" ) )
3081  {
3082  layer->setDistanceY( properties["distance_y"].toDouble() );
3083  }
3084  if ( properties.contains( "displacement_x" ) )
3085  {
3086  layer->setDisplacementX( properties["displacement_x"].toDouble() );
3087  }
3088  if ( properties.contains( "displacement_y" ) )
3089  {
3090  layer->setDisplacementY( properties["displacement_y"].toDouble() );
3091  }
3092 
3093  if ( properties.contains( "distance_x_unit" ) )
3094  {
3095  layer->setDistanceXUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_x_unit"] ) );
3096  }
3097  if ( properties.contains( "distance_x_map_unit_scale" ) )
3098  {
3099  layer->setDistanceXMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_x_map_unit_scale"] ) );
3100  }
3101  if ( properties.contains( "distance_y_unit" ) )
3102  {
3103  layer->setDistanceYUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_y_unit"] ) );
3104  }
3105  if ( properties.contains( "distance_y_map_unit_scale" ) )
3106  {
3107  layer->setDistanceYMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_y_map_unit_scale"] ) );
3108  }
3109  if ( properties.contains( "displacement_x_unit" ) )
3110  {
3111  layer->setDisplacementXUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["displacement_x_unit"] ) );
3112  }
3113  if ( properties.contains( "displacement_x_map_unit_scale" ) )
3114  {
3115  layer->setDisplacementXMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["displacement_x_map_unit_scale"] ) );
3116  }
3117  if ( properties.contains( "displacement_y_unit" ) )
3118  {
3119  layer->setDisplacementYUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["displacement_y_unit"] ) );
3120  }
3121  if ( properties.contains( "displacement_y_map_unit_scale" ) )
3122  {
3123  layer->setDisplacementYMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["displacement_y_map_unit_scale"] ) );
3124  }
3125  if ( properties.contains( "outline_width_unit" ) )
3126  {
3127  layer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
3128  }
3129  if ( properties.contains( "outline_width_map_unit_scale" ) )
3130  {
3131  layer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
3132  }
3133 
3134  layer->restoreDataDefinedProperties( properties );
3135 
3136  return layer;
3137 }
3138 
3140 {
3141  return "PointPatternFill";
3142 }
3143 
3144 void QgsPointPatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double distanceX, double distanceY,
3145  double displacementX, double displacementY )
3146 {
3147  //render 3 rows and columns in one go to easily incorporate displacement
3148  const QgsRenderContext& ctx = context.renderContext();
3151 
3152  if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
3153  {
3154  QImage img;
3155  brush.setTextureImage( img );
3156  return;
3157  }
3158 
3159  QImage patternImage( width, height, QImage::Format_ARGB32 );
3160  patternImage.fill( 0 );
3161 
3162  if ( mMarkerSymbol )
3163  {
3164  QPainter p( &patternImage );
3165 
3166  //marker rendering needs context for drawing on patternImage
3167  QgsRenderContext pointRenderContext;
3168  pointRenderContext.setRendererScale( context.renderContext().rendererScale() );
3169  pointRenderContext.setPainter( &p );
3170  pointRenderContext.setRasterScaleFactor( 1.0 );
3171  pointRenderContext.setScaleFactor( context.renderContext().scaleFactor() * context.renderContext().rasterScaleFactor() );
3173  pointRenderContext.setMapToPixel( mtp );
3174  pointRenderContext.setForceVectorOutput( false );
3175  pointRenderContext.setExpressionContext( context.renderContext().expressionContext() );
3176 
3177  mMarkerSymbol->startRender( pointRenderContext, context.fields() );
3178 
3179  //render corner points
3180  mMarkerSymbol->renderPoint( QPointF( 0, 0 ), context.feature(), pointRenderContext );
3181  mMarkerSymbol->renderPoint( QPointF( width, 0 ), context.feature(), pointRenderContext );
3182  mMarkerSymbol->renderPoint( QPointF( 0, height ), context.feature(), pointRenderContext );
3183  mMarkerSymbol->renderPoint( QPointF( width, height ), context.feature(), pointRenderContext );
3184 
3185  //render displaced points
3187  double displacementPixelY = displacementY * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDisplacementYUnit, mDisplacementYMapUnitScale );
3188  mMarkerSymbol->renderPoint( QPointF( width / 2.0, -displacementPixelY ), context.feature(), pointRenderContext );
3189  mMarkerSymbol->renderPoint( QPointF( displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
3190  mMarkerSymbol->renderPoint( QPointF( width / 2.0 + displacementPixelX, height / 2.0 - displacementPixelY ), context.feature(), pointRenderContext );
3191  mMarkerSymbol->renderPoint( QPointF( width + displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
3192  mMarkerSymbol->renderPoint( QPointF( width / 2.0, height - displacementPixelY ), context.feature(), pointRenderContext );
3193 
3194  mMarkerSymbol->stopRender( pointRenderContext );
3195  }
3196 
3197  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
3198  {
3199  QImage transparentImage = patternImage.copy();
3200  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
3201  brush.setTextureImage( transparentImage );
3202  }
3203  else
3204  {
3205  brush.setTextureImage( patternImage );
3206  }
3207  QTransform brushTransform;
3208  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
3209  brush.setTransform( brushTransform );
3210 }
3211 
3213 {
3214  applyPattern( context, mBrush, mDistanceX, mDistanceY, mDisplacementX, mDisplacementY );
3215 
3216  if ( mOutline )
3217  {
3218  mOutline->startRender( context.renderContext(), context.fields() );
3219  }
3220  prepareExpressions( context );
3221 }
3222 
3224 {
3225  if ( mOutline )
3226  {
3227  mOutline->stopRender( context.renderContext() );
3228  }
3229 }
3230 
3232 {
3233  QgsStringMap map;
3234  map.insert( "distance_x", QString::number( mDistanceX ) );
3235  map.insert( "distance_y", QString::number( mDistanceY ) );
3236  map.insert( "displacement_x", QString::number( mDisplacementX ) );
3237  map.insert( "displacement_y", QString::number( mDisplacementY ) );
3238  map.insert( "distance_x_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceXUnit ) );
3239  map.insert( "distance_y_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceYUnit ) );
3240  map.insert( "displacement_x_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementXUnit ) );
3241  map.insert( "displacement_y_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementYUnit ) );
3242  map.insert( "distance_x_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceXMapUnitScale ) );
3243  map.insert( "distance_y_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceYMapUnitScale ) );
3244  map.insert( "displacement_x_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDisplacementXMapUnitScale ) );
3245  map.insert( "displacement_y_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDisplacementYMapUnitScale ) );
3246  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
3247  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
3249  return map;
3250 }
3251 
3253 {
3255  if ( mMarkerSymbol )
3256  {
3257  clonedLayer->setSubSymbol( mMarkerSymbol->clone() );
3258  }
3259  copyPaintEffect( clonedLayer );
3260  return clonedLayer;
3261 }
3262 
3264 {
3265  for ( int i = 0; i < mMarkerSymbol->symbolLayerCount(); i++ )
3266  {
3267  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
3268  if ( !props.value( "uom", "" ).isEmpty() )
3269  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
3270  element.appendChild( symbolizerElem );
3271 
3272  // <Geometry>
3273  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
3274 
3275  QDomElement fillElem = doc.createElement( "se:Fill" );
3276  symbolizerElem.appendChild( fillElem );
3277 
3278  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
3279  fillElem.appendChild( graphicFillElem );
3280 
3281  // store distanceX, distanceY, displacementX, displacementY in a <VendorOption>
3283  QDomElement distanceElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "distance", dist );
3284  symbolizerElem.appendChild( distanceElem );
3285 
3287  QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
3288  if ( !markerLayer )
3289  {
3290  QString errorMsg = QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() );
3291  graphicFillElem.appendChild( doc.createComment( errorMsg ) );
3292  }
3293  else
3294  {
3295  markerLayer->writeSldMarker( doc, graphicFillElem, props );
3296  }
3297  }
3298 }
3299 
3301 {
3302  Q_UNUSED( element );
3303  return nullptr;
3304 }
3305 
3307 {
3308  if ( !symbol )
3309  {
3310  return false;
3311  }
3312 
3313  if ( symbol->type() == QgsSymbolV2::Marker )
3314  {
3315  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( symbol );
3316  delete mMarkerSymbol;
3317  mMarkerSymbol = markerSymbol;
3318  }
3319  return true;
3320 }
3321 
3323 {
3327  {
3328  return;
3329  }
3330 
3331  double distanceX = mDistanceX;
3333  {
3336  }
3337  double distanceY = mDistanceY;
3339  {
3342  }
3343  double displacementX = mDisplacementX;
3345  {
3348  }
3349  double displacementY = mDisplacementY;
3351  {
3354  }
3355  applyPattern( context, mBrush, distanceX, distanceY, displacementX, displacementY );
3356 }
3357 
3359 {
3360  return 0;
3361 }
3362 
3364 {
3366 
3367  if ( mMarkerSymbol )
3368  attributes.unite( mMarkerSymbol->usedAttributes() );
3369 
3370  return attributes;
3371 }
3372 
3374 
3375 
3376 QgsCentroidFillSymbolLayerV2::QgsCentroidFillSymbolLayerV2(): mMarker( nullptr ), mPointOnSurface( false )
3377 {
3379 }
3380 
3382 {
3383  delete mMarker;
3384 }
3385 
3387 {
3389 
3390  if ( properties.contains( "point_on_surface" ) )
3391  sl->setPointOnSurface( properties["point_on_surface"].toInt() != 0 );
3392 
3393  return sl;
3394 }
3395 
3397 {
3398  return "CentroidFill";
3399 }
3400 
3402 {
3403  mMarker->setColor( color );
3404  mColor = color;
3405 }
3406 
3408 {
3409  mMarker->setAlpha( context.alpha() );
3410  mMarker->startRender( context.renderContext(), context.fields() );
3411 }
3412 
3414 {
3415  mMarker->stopRender( context.renderContext() );
3416 }
3417 
3419 {
3420  Q_UNUSED( rings );
3421 
3423  mMarker->renderPoint( centroid, context.feature(), context.renderContext(), -1, context.selected() );
3424 }
3425 
3427 {
3428  QgsStringMap map;
3429  map["point_on_surface"] = QString::number( mPointOnSurface );
3430  return map;
3431 }
3432 
3434 {
3436  x->mAngle = mAngle;
3437  x->mColor = mColor;
3438  x->setSubSymbol( mMarker->clone() );
3440  copyPaintEffect( x );
3441  return x;
3442 }
3443 
3445 {
3446  // SLD 1.0 specs says: "if a line, polygon, or raster geometry is
3447  // used with PointSymbolizer, then the semantic is to use the centroid
3448  // of the geometry, or any similar representative point.
3449  mMarker->toSld( doc, element, props );
3450 }
3451 
3453 {
3454  QgsDebugMsg( "Entered." );
3455 
3457  if ( !l )
3458  return nullptr;
3459 
3460  QgsSymbolLayerV2List layers;
3461  layers.append( l );
3462  QgsMarkerSymbolV2 *marker = new QgsMarkerSymbolV2( layers );
3463 
3465  sl->setSubSymbol( marker );
3466  return sl;
3467 }
3468 
3469 
3471 {
3472  return mMarker;
3473 }
3474 
3476 {
3477  if ( !symbol || symbol->type() != QgsSymbolV2::Marker )
3478  {
3479  delete symbol;
3480  return false;
3481  }
3482 
3483  delete mMarker;
3484  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
3485  mColor = mMarker->color();
3486  return true;
3487 }
3488 
3490 {
3492 
3493  if ( mMarker )
3494  attributes.unite( mMarker->usedAttributes() );
3495 
3496  return attributes;
3497 }
3498 
3500 {
3501  if ( mMarker )
3502  {
3503  mMarker->setOutputUnit( unit );
3504  }
3505 }
3506 
3508 {
3509  if ( mMarker )
3510  {
3511  return mMarker->outputUnit();
3512  }
3513  return QgsSymbolV2::Mixed; //mOutputUnit;
3514 }
3515 
3517 {
3518  if ( mMarker )
3519  {
3520  mMarker->setMapUnitScale( scale );
3521  }
3522 }
3523 
3525 {
3526  if ( mMarker )
3527  {
3528  return mMarker->mapUnitScale();
3529  }
3530  return QgsMapUnitScale();
3531 }
3532 
3533 
3534 
3535 
3538  , mImageFilePath( imageFilePath )
3539  , mCoordinateMode( QgsRasterFillSymbolLayer::Feature )
3540  , mAlpha( 1.0 )
3541  , mOffsetUnit( QgsSymbolV2::MM )
3542  , mWidth( 0.0 )
3543  , mWidthUnit( QgsSymbolV2::Pixel )
3544 {
3545  QgsImageFillSymbolLayer::setSubSymbol( nullptr ); //disable sub symbol
3546 }
3547 
3549 {
3550 
3551 }
3552 
3554 {
3556  double alpha = 1.0;
3557  QPointF offset;
3558  double angle = 0.0;
3559  double width = 0.0;
3560 
3561  QString imagePath;
3562  if ( properties.contains( "imageFile" ) )
3563  {
3564  imagePath = properties["imageFile"];
3565  }
3566  if ( properties.contains( "coordinate_mode" ) )
3567  {
3568  mode = static_cast< FillCoordinateMode >( properties["coordinate_mode"].toInt() );
3569  }
3570  if ( properties.contains( "alpha" ) )
3571  {
3572  alpha = properties["alpha"].toDouble();
3573  }
3574  if ( properties.contains( "offset" ) )
3575  {
3576  offset = QgsSymbolLayerV2Utils::decodePoint( properties["offset"] );
3577  }
3578  if ( properties.contains( "angle" ) )
3579  {
3580  angle = properties["angle"].toDouble();
3581  }
3582  if ( properties.contains( "width" ) )
3583  {
3584  width = properties["width"].toDouble();
3585  }
3586  QgsRasterFillSymbolLayer* symbolLayer = new QgsRasterFillSymbolLayer( imagePath );
3587  symbolLayer->setCoordinateMode( mode );
3588  symbolLayer->setAlpha( alpha );
3589  symbolLayer->setOffset( offset );
3590  symbolLayer->setAngle( angle );
3591  symbolLayer->setWidth( width );
3592  if ( properties.contains( "offset_unit" ) )
3593  {
3594  symbolLayer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
3595  }
3596  if ( properties.contains( "offset_map_unit_scale" ) )
3597  {
3598  symbolLayer->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["offset_map_unit_scale"] ) );
3599  }
3600  if ( properties.contains( "width_unit" ) )
3601  {
3602  symbolLayer->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["width_unit"] ) );
3603  }
3604  if ( properties.contains( "width_map_unit_scale" ) )
3605  {
3606  symbolLayer->setWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["width_map_unit_scale"] ) );
3607  }
3608 
3609  symbolLayer->restoreDataDefinedProperties( properties );
3610 
3611  return symbolLayer;
3612 }
3613 
3615 {
3616  Q_UNUSED( symbol );
3617  return true;
3618 }
3619 
3621 {
3622  return "RasterFill";
3623 }
3624 
3626 {
3627  QPainter* p = context.renderContext().painter();
3628  if ( !p )
3629  {
3630  return;
3631  }
3632 
3633  QPointF offset;
3634  if ( !mOffset.isNull() )
3635  {
3638  p->translate( offset );
3639  }
3640  if ( mCoordinateMode == Feature )
3641  {
3642  QRectF boundingRect = points.boundingRect();
3643  mBrush.setTransform( mBrush.transform().translate( boundingRect.left() - mBrush.transform().dx(),
3644  boundingRect.top() - mBrush.transform().dy() ) );
3645  }
3646 
3647  QgsImageFillSymbolLayer::renderPolygon( points, rings, context );
3648  if ( !mOffset.isNull() )
3649  {
3650  p->translate( -offset );
3651  }
3652 }
3653 
3655 {
3656  prepareExpressions( context );
3657  applyPattern( mBrush, mImageFilePath, mWidth, mAlpha, context );
3658 }
3659 
3661 {
3662  Q_UNUSED( context );
3663 }
3664 
3666 {
3667  QgsStringMap map;
3668  map["imageFile"] = mImageFilePath;
3669  map["coordinate_mode"] = QString::number( mCoordinateMode );
3670  map["alpha"] = QString::number( mAlpha );
3671  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
3672  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
3673  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
3674  map["angle"] = QString::number( mAngle );
3675  map["width"] = QString::number( mWidth );
3676  map["width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mWidthUnit );
3677  map["width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mWidthMapUnitScale );
3678 
3680  return map;
3681 }
3682 
3684 {
3687  sl->setAlpha( mAlpha );
3688  sl->setOffset( mOffset );
3689  sl->setOffsetUnit( mOffsetUnit );
3691  sl->setAngle( mAngle );
3692  sl->setWidth( mWidth );
3693  sl->setWidthUnit( mWidthUnit );
3696  copyPaintEffect( sl );
3697  return sl;
3698 }
3699 
3701 {
3702  return mOffset.x() > mOffset.y() ? mOffset.x() : mOffset.y();
3703 }
3704 
3706 {
3707  mImageFilePath = imagePath;
3708 }
3709 
3711 {
3712  mCoordinateMode = mode;
3713 }
3714 
3716 {
3717  mAlpha = alpha;
3718 }
3719 
3721 {
3722  if ( !hasDataDefinedProperties() )
3723  return; // shortcut
3724 
3725  bool hasWidthExpression = hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH );
3726  bool hasFileExpression = hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_FILE );
3727  bool hasAlphaExpression = hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_ALPHA );
3728  bool hasAngleExpression = hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_ANGLE );
3729 
3730  if ( !hasWidthExpression && !hasAngleExpression && !hasAlphaExpression && !hasFileExpression )
3731  {
3732  return; //no data defined settings
3733  }
3734 
3735  bool ok;
3736  if ( hasAngleExpression )
3737  {
3738  context.setOriginalValueVariable( mAngle );
3739  double nextAngle = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_ANGLE, context, QVariant(), &ok ).toDouble();
3740  if ( ok )
3741  mNextAngle = nextAngle;
3742  }
3743 
3744  if ( !hasWidthExpression && !hasAlphaExpression && !hasFileExpression )
3745  {
3746  return; //nothing further to do
3747  }
3748 
3749  double width = mWidth;
3750  if ( hasWidthExpression )
3751  {
3752  context.setOriginalValueVariable( mWidth );
3754  }
3755  double alpha = mAlpha;
3756  if ( hasAlphaExpression )
3757  {
3758  context.setOriginalValueVariable( mAlpha );
3760  }
3761  QString file = mImageFilePath;
3762  if ( hasFileExpression )
3763  {
3766  }
3767  applyPattern( mBrush, file, width, alpha, context );
3768 }
3769 
3770 void QgsRasterFillSymbolLayer::applyPattern( QBrush &brush, const QString &imageFilePath, const double width, const double alpha, const QgsSymbolV2RenderContext &context )
3771 {
3772  QImage image( imageFilePath );
3773  if ( image.isNull() )
3774  {
3775  return;
3776  }
3777  if ( !image.hasAlphaChannel() )
3778  {
3779  image = image.convertToFormat( QImage::Format_ARGB32 );
3780  }
3781 
3782  double pixelWidth;
3783  if ( width > 0 )
3784  {
3786  }
3787  else
3788  {
3789  pixelWidth = image.width();
3790  }
3791 
3792  //reduce alpha of image
3793  if ( alpha < 1.0 )
3794  {
3795  QPainter p;
3796  p.begin( &image );
3797  p.setCompositionMode( QPainter::CompositionMode_DestinationIn );
3798  QColor alphaColor( 0, 0, 0 );
3799  alphaColor.setAlphaF( alpha );
3800  p.fillRect( image.rect(), alphaColor );
3801  p.end();
3802  }
3803 
3804  //resize image if required
3805  if ( !qgsDoubleNear( pixelWidth, image.width() ) )
3806  {
3807  image = image.scaledToWidth( pixelWidth, Qt::SmoothTransformation );
3808  }
3809 
3810  brush.setTextureImage( image );
3811 }
virtual QSet< QString > usedAttributes() const
Returns the set of attributes referenced by the layer.
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
bool ignoreRings() const
Returns whether the shapeburst fill is set to ignore polygon interior rings.
void setForceVectorOutput(bool force)
QgsSymbolV2::OutputUnit intervalUnit() const
QgsSymbolV2::OutputUnit patternWidthUnit() const
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
const QgsMapUnitScale & patternWidthMapUnitScale() 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
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].
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
QString ogrFeatureStyleWidth(double widthScaleFactor) const
virtual 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
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
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setDistanceYUnit(QgsSymbolV2::OutputUnit unit)
QString svgFilePath() const
void stopRender(QgsSymbolV2RenderContext &context) override
void append(const T &value)
qreal dx() const
qreal dy() const
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
SymbolType type() const
Definition: qgssymbolv2.h:104
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
static const QString EXPR_USE_WHOLE_SHAPE
virtual 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)
QColor selectionColor() const
QMap< Key, T > & unite(const QMap< Key, T > &other)
QSet< QString > usedAttributes() const
Return a list of attributes required to render this feature.
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
#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.
void setMatrix(const QMatrix &matrix)
bool setSubSymbol(QgsSymbolV2 *symbol) override
set layer&#39;s subsymbol. takes ownership of the passed symbol
double svgOutlineWidth() const
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
double rendererScale() const
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)
QgsSymbolV2::OutputUnit svgOutlineWidthUnit() const
void scale(qreal sx, qreal sy)
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const
QGis::UnitType mapUnits() const
Retrieve map units.
Definition: qgsdxfexport.h:86
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
void setTextureImage(const QImage &image)
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.
const QgsMapUnitScale & intervalMapUnitScale() const
void save()
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
bool hasAlphaChannel() const
QgsMapUnitScale mapUnitScale() 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
static const QString EXPR_COORDINATE_MODE
GradientCoordinateMode coordinateMode() const
Coordinate mode for gradient.
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 copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
void setDistanceXMapUnitScale(const QgsMapUnitScale &scale)
static const bool selectionIsOpaque
int blurRadius() const
Returns the blur radius, which controls the amount of blurring applied to the fill.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
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 applyDataDefinedSettings(QgsSymbolV2RenderContext &context) override
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
double scaleFactor() const
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.
virtual QColor fillColor() const
Get 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
static double pixelSizeScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns scale factor painter units -> pixel dimensions.
void setWidth(double width)
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
virtual double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
QgsSymbolV2::OutputUnit outputUnit() const override
void setSvgOutlineColor(const QColor &c)
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)
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.
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
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:362
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.
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.
Qt::PenStyle borderStyle() const
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
double width() const
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.
void setTransform(const QTransform &matrix)
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:374
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.
QByteArray getImageData(const QString &path) const
Get image data.
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.
static const QString EXPR_ALPHA
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)
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
int width() const
QgsSymbolV2::OutputUnit outputUnit() const override
void setAttribute(const QString &name, const QString &value)
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
virtual QgsVectorColorRampV2 * clone() const =0
virtual QSet< QString > usedAttributes() const override
Returns the set of attributes referenced by the layer.
bool useWholeShape() const
Returns whether the shapeburst fill is set to cover the entire shape.
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
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
QPointF offset() const
Returns the offset for the shapeburst fill.
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
QString imageFilePath() const
The path to the raster image used for the fill.
QgsSVGFillSymbolLayer(const QString &svgFilePath="", double width=20, double rotation=0.0)
void setDistanceYMapUnitScale(const QgsMapUnitScale &scale)
void setWidthF(qreal width)
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
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)
double rasterScaleFactor() const
ShapeburstColorType colorType() const
Returns the color mode used for the shapeburst fill.
QgsSymbolV2::OutputUnit outputUnit() const override
static const bool selectFillStyle
double interval() const
The interval between individual markers.
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context) override
double mapUnitsPerPixel() const
Return current map units per pixel.
virtual QColor color() const
The fill color.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
GradientColorType gradientColorType() const
Gradient color mode, controls how gradient color stops are created.
void setDisplacementXUnit(QgsSymbolV2::OutputUnit unit)
void setCoordinateMode(const FillCoordinateMode mode)
Set the coordinate mode for fill.
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.
void startRender(QgsSymbolV2RenderContext &context) override
void setBorderWidthUnit(QgsSymbolV2::OutputUnit unit)
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)
virtual bool hasDataDefinedProperties() const
Checks whether the layer has any associated data defined properties.
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)
QgsSymbolV2::SymbolType type() const
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...
double mOutlineWidth
Outline width.
void setDistanceXUnit(QgsSymbolV2::OutputUnit unit)
double mLineWidth
Line width (in mm or map units)
QgsVectorColorRampV2 * mGradientRamp
QColor svgOutlineColor() const
static const QString EXPR_COLOR
bool isNull() const
static const QString EXPR_WIDTH_BORDER
QgsMapUnitScale mapUnitScale() const override
GradientSpread gradientSpread() const
Gradient spread mode.
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
QColor color2() const
Returns the color used for the endpoint of the shapeburst fill.
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 symbologyScaleDenominator() const
Retrieve reference scale for output.
Definition: qgsdxfexport.h:73
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
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())
QTransform & rotate(qreal angle, Qt::Axis axis)
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
QColor color2() const
Color for endpoint of gradient, only used if the gradient color type is set to SimpleTwoColor.
QRectF boundingRect() const
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, QFlags< Qt::ImageConversionFlag > flags)
QPainter * painter()
qreal width() const
void stopRender(QgsRenderContext &context)
QgsMapUnitScale mBorderWidthMapUnitScale
QPointF offset() const
Returns the offset for the fill.
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)
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Struct for storing maximum and minimum scales for measurements in map units.
QgsSymbolV2::OutputUnit mDistanceXUnit
void setDisplacementYUnit(QgsSymbolV2::OutputUnit unit)
static const QString EXPR_SVG_OUTLINE_COLOR
QgsSymbolV2::OutputUnit outputUnit() const override
void setSvgFilePath(const QString &svgPath)
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:345
void setX(qreal x)
void setY(qreal y)
QDomElement firstChildElement(const QString &tagName) const
QgsSymbolV2::OutputUnit mBorderWidthUnit
Qt::PenJoinStyle penJoinStyle() const
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)
QgsSymbolV2::OutputUnit outputUnit() const
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)
void renderPoint(QPointF point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
bool toBool() const
void translate(const QPointF &offset)
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
static const QString EXPR_REFERENCE1_ISCENTROID
void setDisplacementYMapUnitScale(const QgsMapUnitScale &scale)
const QgsMapToPixel & mapToPixel() const
qreal angle() const
void setAlpha(const double alpha)
Sets the opacity for the raster image used in the fill.
QgsMapUnitScale mapUnitScale() const override
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:380
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
GradientType gradientType() const
Type of gradient, eg linear or radial.
bool selected() const
Definition: qgssymbolv2.h:366
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
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
int height() const
const_iterator constEnd() const
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
QDomElement createElement(const QString &tagName)
const_iterator constBegin() const
void setWidthUnit(const QgsSymbolV2::OutputUnit unit)
Sets the units for the image&#39;s width.
void setPatternWidthUnit(QgsSymbolV2::OutputUnit unit)
double width() const
Returns the width used for scaling the image used in the fill.
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.
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)
const QgsMapUnitScale & svgOutlineWidthMapUnitScale() 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.
void setSpread(Spread method)
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
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
double angle() const
void setOutputUnit(QgsSymbolV2::OutputUnit u)
QgsSVGFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:202
QRectF viewBoxF() const
bool hasDataDefinedProperties() const
Returns whether the symbol utilises any data defined properties.
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)
virtual Qt::PenStyle dxfPenStyle() const override
#define DEFAULT_SIMPLEFILL_BORDERWIDTH
virtual void applyDataDefinedSettings(QgsSymbolV2RenderContext &context)
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
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.
double maxDistance() const
Returns the maximum distance from the shape&#39;s boundary which is shaded.
void setSvgOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
const T value(const Key &key) const
bool isNull() const
void stopRender(QgsSymbolV2RenderContext &context) override
QColor color() const
double alpha() const
The opacity for the raster image used in the fill.
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)
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.
#define DEFAULT_SIMPLEFILL_COLOR