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