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