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