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