QGIS API Documentation  2.4.0-Chugiak
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsfillsymbollayerv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfillsymbollayerv2.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsfillsymbollayerv2.h"
17 #include "qgslinesymbollayerv2.h"
18 #include "qgsmarkersymbollayerv2.h"
19 #include "qgssymbollayerv2utils.h"
20 #include "qgsdxfexport.h"
21 #include "qgsexpression.h"
22 #include "qgsrendercontext.h"
23 #include "qgsproject.h"
24 #include "qgssvgcache.h"
25 #include "qgslogger.h"
26 #include "qgsvectorcolorrampv2.h"
27 
28 #include <QPainter>
29 #include <QFile>
30 #include <QSvgRenderer>
31 #include <QDomDocument>
32 #include <QDomElement>
33 
34 QgsSimpleFillSymbolLayerV2::QgsSimpleFillSymbolLayerV2( QColor color, Qt::BrushStyle style, QColor borderColor, Qt::PenStyle borderStyle, double borderWidth,
35  Qt::PenJoinStyle penJoinStyle ) :
36  mBrushStyle( style ),
37  mBorderColor( borderColor ),
38  mBorderStyle( borderStyle ),
39  mBorderWidth( borderWidth ),
40  mBorderWidthUnit( QgsSymbolV2::MM ),
41  mPenJoinStyle( penJoinStyle ),
42  mOffsetUnit( QgsSymbolV2::MM )
43 {
44  mColor = color;
45 }
46 
48 {
49  mBorderWidthUnit = unit;
50  mOffsetUnit = unit;
51 }
52 
54 {
56  if ( mOffsetUnit != unit )
57  {
58  return QgsSymbolV2::Mixed;
59  }
60  return unit;
61 }
62 
64 {
66  mOffsetMapUnitScale = scale;
67 }
68 
70 {
72  {
74  }
75  return QgsMapUnitScale();
76 }
77 
78 void QgsSimpleFillSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QBrush& brush, QPen& pen, QPen& selPen )
79 {
80  QgsExpression* colorExpression = expression( "color" );
81  if ( colorExpression )
82  {
83  brush.setColor( QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
84  }
85  QgsExpression* colorBorderExpression = expression( "color_border" );
86  if ( colorBorderExpression )
87  {
88  pen.setColor( QgsSymbolLayerV2Utils::decodeColor( colorBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
89  }
90  QgsExpression* widthBorderExpression = expression( "width_border" );
91  if ( widthBorderExpression )
92  {
93  double width = widthBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
95  pen.setWidthF( width );
96  selPen.setWidthF( width );
97  }
98 }
99 
100 
102 {
104  Qt::BrushStyle style = DEFAULT_SIMPLEFILL_STYLE;
108  Qt::PenJoinStyle penJoinStyle = DEFAULT_SIMPLEFILL_JOINSTYLE;
109  QPointF offset;
110 
111  if ( props.contains( "color" ) )
112  color = QgsSymbolLayerV2Utils::decodeColor( props["color"] );
113  if ( props.contains( "style" ) )
114  style = QgsSymbolLayerV2Utils::decodeBrushStyle( props["style"] );
115  if ( props.contains( "color_border" ) )
116  borderColor = QgsSymbolLayerV2Utils::decodeColor( props["color_border"] );
117  if ( props.contains( "style_border" ) )
118  borderStyle = QgsSymbolLayerV2Utils::decodePenStyle( props["style_border"] );
119  if ( props.contains( "width_border" ) )
120  borderWidth = props["width_border"].toDouble();
121  if ( props.contains( "offset" ) )
122  offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
123  if ( props.contains( "joinstyle" ) )
124  penJoinStyle = QgsSymbolLayerV2Utils::decodePenJoinStyle( props["joinstyle"] );
125 
126  QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, style, borderColor, borderStyle, borderWidth, penJoinStyle );
127  sl->setOffset( offset );
128  if ( props.contains( "border_width_unit" ) )
129  sl->setBorderWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["border_width_unit"] ) );
130  if ( props.contains( "offset_unit" ) )
131  sl->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
132 
133  if ( props.contains( "border_width_map_unit_scale" ) )
134  sl->setBorderWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["border_width_map_unit_scale"] ) );
135  if ( props.contains( "offset_map_unit_scale" ) )
136  sl->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
137 
138  if ( props.contains( "color_expression" ) )
139  {
140  sl->setDataDefinedProperty( "color", props["color_expression"] );
141  }
142  if ( props.contains( "color_border_expression" ) )
143  {
144  sl->setDataDefinedProperty( "color_border", props["color_border_expression"] );
145  }
146  if ( props.contains( "width_border_expression" ) )
147  {
148  sl->setDataDefinedProperty( "width_border", props["width_border_expression"] );
149  }
150  return sl;
151 }
152 
153 
155 {
156  return "SimpleFill";
157 }
158 
160 {
161  QColor fillColor = mColor;
162  fillColor.setAlphaF( context.alpha() * mColor.alphaF() );
163  mBrush = QBrush( fillColor, mBrushStyle );
164 
165  // scale brush content for printout
167  if ( rasterScaleFactor != 1.0 )
168  {
169  mBrush.setMatrix( QMatrix().scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor ) );
170  }
171 
172  QColor selColor = context.renderContext().selectionColor();
173  QColor selPenColor = selColor == mColor ? selColor : mBorderColor;
174  if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() );
175  mSelBrush = QBrush( selColor );
176  // N.B. unless a "selection line color" is implemented in addition to the "selection color" option
177  // this would mean symbols with "no fill" look the same whether or not they are selected
178  if ( selectFillStyle )
179  mSelBrush.setStyle( mBrushStyle );
180 
181  QColor borderColor = mBorderColor;
182  borderColor.setAlphaF( context.alpha() * mBorderColor.alphaF() );
183  mPen = QPen( borderColor );
184  mSelPen = QPen( selPenColor );
185  mPen.setStyle( mBorderStyle );
187  mPen.setJoinStyle( mPenJoinStyle );
188  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
189 }
190 
192 {
193  Q_UNUSED( context );
194 }
195 
196 void QgsSimpleFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
197 {
198  QPainter* p = context.renderContext().painter();
199  if ( !p )
200  {
201  return;
202  }
203 
205 
206  p->setBrush( context.selected() ? mSelBrush : mBrush );
207  p->setPen( context.selected() ? mSelPen : mPen );
208 
209  QPointF offset;
210  if ( !mOffset.isNull() )
211  {
214  p->translate( offset );
215  }
216 
217  _renderPolygon( p, points, rings, context );
218 
219  if ( !mOffset.isNull() )
220  {
221  p->translate( -offset );
222  }
223 }
224 
226 {
227  QgsStringMap map;
228  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
230  map["color_border"] = QgsSymbolLayerV2Utils::encodeColor( mBorderColor );
231  map["style_border"] = QgsSymbolLayerV2Utils::encodePenStyle( mBorderStyle );
232  map["width_border"] = QString::number( mBorderWidth );
233  map["border_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mBorderWidthUnit );
234  map["border_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mBorderWidthMapUnitScale );
236  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
238  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
240  return map;
241 }
242 
244 {
246  sl->setOffset( mOffset );
247  sl->setOffsetUnit( mOffsetUnit );
252  return sl;
253 }
254 
255 void QgsSimpleFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
256 {
257  if ( mBrushStyle == Qt::NoBrush && mBorderStyle == Qt::NoPen )
258  return;
259 
260  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
261  if ( !props.value( "uom", "" ).isEmpty() )
262  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
263  element.appendChild( symbolizerElem );
264 
265  // <Geometry>
266  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
267 
268  if ( mBrushStyle != Qt::NoBrush )
269  {
270  // <Fill>
271  QDomElement fillElem = doc.createElement( "se:Fill" );
272  symbolizerElem.appendChild( fillElem );
274  }
275 
276  if ( mBorderStyle != Qt::NoPen )
277  {
278  // <Stroke>
279  QDomElement strokeElem = doc.createElement( "se:Stroke" );
280  symbolizerElem.appendChild( strokeElem );
282  }
283 
284  // <se:Displacement>
286 }
287 
288 QString QgsSimpleFillSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
289 {
290  //brush
291  QString symbolStyle;
292  symbolStyle.append( QgsSymbolLayerV2Utils::ogrFeatureStyleBrush( mColor ) );
293  symbolStyle.append( ";" );
294  //pen
295  symbolStyle.append( QgsSymbolLayerV2Utils::ogrFeatureStylePen( mBorderWidth, mmScaleFactor, mapUnitScaleFactor, mBorderColor, mPenJoinStyle ) );
296  return symbolStyle;
297 }
298 
300 {
301  QgsDebugMsg( "Entered." );
302 
303  QColor color, borderColor;
304  Qt::BrushStyle fillStyle;
305  Qt::PenStyle borderStyle;
306  double borderWidth;
307 
308  QDomElement fillElem = element.firstChildElement( "Fill" );
309  QgsSymbolLayerV2Utils::fillFromSld( fillElem, fillStyle, color );
310 
311  QDomElement strokeElem = element.firstChildElement( "Stroke" );
312  QgsSymbolLayerV2Utils::lineFromSld( strokeElem, borderStyle, borderColor, borderWidth );
313 
314  QPointF offset;
316 
317  QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, fillStyle, borderColor, borderStyle, borderWidth );
318  sl->setOffset( offset );
319  return sl;
320 }
321 
323 {
324  double penBleed = mBorderStyle == Qt::NoPen ? 0 : ( mBorderWidth / 2.0 );
325  double offsetBleed = mOffset.x() > mOffset.y() ? mOffset.x() : mOffset.y();
326  return penBleed + offsetBleed;
327 }
328 
329 double QgsSimpleFillSymbolLayerV2::dxfWidth( const QgsDxfExport& e, const QgsSymbolV2RenderContext& context ) const
330 {
331  double width = mBorderWidth;
332  QgsExpression* widthBorderExpression = expression( "width_border" );
333  if ( widthBorderExpression )
334  {
335  width = widthBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
336  }
337  return width * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), mBorderWidthUnit, e.mapUnits() );
338 }
339 
341 {
342  QgsExpression* colorBorderExpression = expression( "color_border" );
343  if ( colorBorderExpression )
344  {
345  return QgsSymbolLayerV2Utils::decodeColor( colorBorderExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
346  }
347  return mBorderColor;
348 }
349 
351 {
352  return mBorderStyle;
353 }
354 
355 //QgsGradientFillSymbolLayer
356 
358  GradientColorType colorType, GradientType gradientType,
359  GradientCoordinateMode coordinateMode, GradientSpread spread )
360  : mGradientColorType( colorType ),
361  mGradientRamp( NULL ),
362  mGradientType( gradientType ),
363  mCoordinateMode( coordinateMode ),
364  mGradientSpread( spread ),
365  mReferencePoint1( QPointF( 0.5, 0 ) ),
366  mReferencePoint1IsCentroid( false ),
367  mReferencePoint2( QPointF( 0.5, 1 ) ),
368  mReferencePoint2IsCentroid( false ),
369  mAngle( 0 ),
370  mOffsetUnit( QgsSymbolV2::MM )
371 {
372  mColor = color;
373  mColor2 = color2;
374 }
375 
377 {
378  delete mGradientRamp;
379 }
380 
382 {
383  //default to a two-color, linear gradient with feature mode and pad spreading
388  //default to gradient from the default fill color to white
389  QColor color = DEFAULT_SIMPLEFILL_COLOR, color2 = Qt::white;
390  QPointF referencePoint1 = QPointF( 0.5, 0 );
391  bool refPoint1IsCentroid = false;
392  QPointF referencePoint2 = QPointF( 0.5, 1 );
393  bool refPoint2IsCentroid = false;
394  double angle = 0;
395  QPointF offset;
396 
397  //update gradient properties from props
398  if ( props.contains( "type" ) )
399  type = ( GradientType )props["type"].toInt();
400  if ( props.contains( "coordinate_mode" ) )
401  coordinateMode = ( GradientCoordinateMode )props["coordinate_mode"].toInt();
402  if ( props.contains( "spread" ) )
403  gradientSpread = ( GradientSpread )props["spread"].toInt();
404  if ( props.contains( "color_type" ) )
405  colorType = ( GradientColorType )props["color_type"].toInt();
406  if ( props.contains( "gradient_color" ) )
407  color = QgsSymbolLayerV2Utils::decodeColor( props["gradient_color"] );
408  if ( props.contains( "gradient_color2" ) )
409  color2 = QgsSymbolLayerV2Utils::decodeColor( props["gradient_color2"] );
410  if ( props.contains( "reference_point1" ) )
411  referencePoint1 = QgsSymbolLayerV2Utils::decodePoint( props["reference_point1"] );
412  if ( props.contains( "reference_point1_iscentroid" ) )
413  refPoint1IsCentroid = props["reference_point1_iscentroid"].toInt();
414  if ( props.contains( "reference_point2" ) )
415  referencePoint2 = QgsSymbolLayerV2Utils::decodePoint( props["reference_point2"] );
416  if ( props.contains( "reference_point2_iscentroid" ) )
417  refPoint2IsCentroid = props["reference_point2_iscentroid"].toInt();
418  if ( props.contains( "angle" ) )
419  angle = props["angle"].toDouble();
420  if ( props.contains( "offset" ) )
421  offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
422 
423  //attempt to create color ramp from props
425 
426  //create a new gradient fill layer with desired properties
427  QgsGradientFillSymbolLayerV2* sl = new QgsGradientFillSymbolLayerV2( color, color2, colorType, type, coordinateMode, gradientSpread );
428  sl->setOffset( offset );
429  if ( props.contains( "offset_unit" ) )
430  sl->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
431  if ( props.contains( "offset_map_unit_scale" ) )
432  sl->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
433  sl->setReferencePoint1( referencePoint1 );
434  sl->setReferencePoint1IsCentroid( refPoint1IsCentroid );
435  sl->setReferencePoint2( referencePoint2 );
436  sl->setReferencePoint2IsCentroid( refPoint2IsCentroid );
437  sl->setAngle( angle );
438  if ( gradientRamp )
439  sl->setColorRamp( gradientRamp );
440 
441  //data defined symbology expressions
442  if ( props.contains( "color_expression" ) )
443  sl->setDataDefinedProperty( "color", props["color_expression"] );
444  if ( props.contains( "color2_expression" ) )
445  sl->setDataDefinedProperty( "color2", props["color2_expression"] );
446  if ( props.contains( "angle_expression" ) )
447  sl->setDataDefinedProperty( "angle", props["angle_expression"] );
448  if ( props.contains( "gradient_type_expression" ) )
449  sl->setDataDefinedProperty( "gradient_type", props["gradient_type_expression"] );
450  if ( props.contains( "coordinate_mode_expression" ) )
451  sl->setDataDefinedProperty( "coordinate_mode", props["coordinate_mode_expression"] );
452  if ( props.contains( "spread_expression" ) )
453  sl->setDataDefinedProperty( "spread", props["spread_expression"] );
454  if ( props.contains( "reference1_x_expression" ) )
455  sl->setDataDefinedProperty( "reference1_x", props["reference1_x_expression"] );
456  if ( props.contains( "reference1_y_expression" ) )
457  sl->setDataDefinedProperty( "reference1_y", props["reference1_y_expression"] );
458  if ( props.contains( "reference1_iscentroid_expression" ) )
459  sl->setDataDefinedProperty( "reference1_iscentroid", props["reference1_iscentroid_expression"] );
460  if ( props.contains( "reference2_x_expression" ) )
461  sl->setDataDefinedProperty( "reference2_x", props["reference2_x_expression"] );
462  if ( props.contains( "reference2_y_expression" ) )
463  sl->setDataDefinedProperty( "reference2_y", props["reference2_y_expression"] );
464  if ( props.contains( "reference2_iscentroid_expression" ) )
465  sl->setDataDefinedProperty( "reference2_iscentroid", props["reference2_iscentroid_expression"] );
466 
467  return sl;
468 }
469 
471 {
472  delete mGradientRamp;
473  mGradientRamp = ramp;
474 }
475 
477 {
478  return "GradientFill";
479 }
480 
482 {
483  //first gradient color
484  QgsExpression* colorExpression = expression( "color" );
485  QColor color = mColor;
486  if ( colorExpression )
487  color = QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
488 
489  //second gradient color
490  QgsExpression* colorExpression2 = expression( "color2" );
491  QColor color2 = mColor2;
492  if ( colorExpression2 )
493  color2 = QgsSymbolLayerV2Utils::decodeColor( colorExpression2->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
494 
495  //gradient rotation angle
496  QgsExpression* angleExpression = expression( "angle" );
497  double angle = mAngle;
498  if ( angleExpression )
499  angle = angleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
500 
501  //gradient type
502  QgsExpression* typeExpression = expression( "gradient_type" );
504  if ( typeExpression )
505  {
506  QString currentType = typeExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
507  if ( currentType == QObject::tr( "linear" ) )
508  {
510  }
511  else if ( currentType == QObject::tr( "radial" ) )
512  {
514  }
515  else if ( currentType == QObject::tr( "conical" ) )
516  {
518  }
519  else
520  {
521  //default to linear
523  }
524  }
525 
526  //coordinate mode
527  QgsExpression* coordModeExpression = expression( "coordinate_mode" );
529  if ( coordModeExpression )
530  {
531  QString currentCoordMode = coordModeExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
532  if ( currentCoordMode == QObject::tr( "feature" ) )
533  {
534  coordinateMode = QgsGradientFillSymbolLayerV2::Feature;
535  }
536  else if ( currentCoordMode == QObject::tr( "viewport" ) )
537  {
539  }
540  else
541  {
542  //default to feature mode
543  coordinateMode = QgsGradientFillSymbolLayerV2::Feature;
544  }
545  }
546 
547  //gradient spread
548  QgsExpression* spreadExpression = expression( "spread" );
550  if ( spreadExpression )
551  {
552  QString currentSpread = spreadExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
553  if ( currentSpread == QObject::tr( "pad" ) )
554  {
556  }
557  else if ( currentSpread == QObject::tr( "repeat" ) )
558  {
560  }
561  else if ( currentSpread == QObject::tr( "reflect" ) )
562  {
564  }
565  else
566  {
567  //default to pad spread
569  }
570  }
571 
572  //reference point 1 x & y
573  QgsExpression* ref1XExpression = expression( "reference1_x" );
574  double refPoint1X = mReferencePoint1.x();
575  if ( ref1XExpression )
576  refPoint1X = ref1XExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
577  QgsExpression* ref1YExpression = expression( "reference1_y" );
578  double refPoint1Y = mReferencePoint1.y();
579  if ( ref1YExpression )
580  refPoint1Y = ref1YExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
581  QgsExpression* ref1IsCentroidExpression = expression( "reference1_iscentroid" );
582  bool refPoint1IsCentroid = mReferencePoint1IsCentroid;
583  if ( ref1IsCentroidExpression )
584  refPoint1IsCentroid = ref1IsCentroidExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toBool();
585 
586  //reference point 2 x & y
587  QgsExpression* ref2XExpression = expression( "reference2_x" );
588  double refPoint2X = mReferencePoint2.x();
589  if ( ref2XExpression )
590  refPoint2X = ref2XExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
591  QgsExpression* ref2YExpression = expression( "reference2_y" );
592  double refPoint2Y = mReferencePoint2.y();
593  if ( ref2YExpression )
594  refPoint2Y = ref2YExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
595  QgsExpression* ref2IsCentroidExpression = expression( "reference2_iscentroid" );
596  bool refPoint2IsCentroid = mReferencePoint2IsCentroid;
597  if ( ref2IsCentroidExpression )
598  refPoint2IsCentroid = ref2IsCentroidExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toBool();
599 
600  if ( refPoint1IsCentroid || refPoint2IsCentroid )
601  {
602  //either the gradient is starting or ending at a centroid, so calculate it
603  QPointF centroid = QgsSymbolLayerV2Utils::polygonCentroid( points );
604  //centroid coordinates need to be scaled to a range [0, 1] relative to polygon bounds
605  QRectF bbox = points.boundingRect();
606  double centroidX = ( centroid.x() - bbox.left() ) / bbox.width();
607  double centroidY = ( centroid.y() - bbox.top() ) / bbox.height();
608 
609  if ( refPoint1IsCentroid )
610  {
611  refPoint1X = centroidX;
612  refPoint1Y = centroidY;
613  }
614  if ( refPoint2IsCentroid )
615  {
616  refPoint2X = centroidX;
617  refPoint2Y = centroidY;
618  }
619  }
620 
621  //update gradient with data defined values
622  applyGradient( context, mBrush, color, color2, mGradientColorType, mGradientRamp, gradientType, coordinateMode,
623  spread, QPointF( refPoint1X, refPoint1Y ), QPointF( refPoint2X, refPoint2Y ), angle );
624 }
625 
626 QPointF QgsGradientFillSymbolLayerV2::rotateReferencePoint( const QPointF & refPoint, double angle )
627 {
628  //rotate a reference point by a specified angle around the point (0.5, 0.5)
629 
630  //create a line from the centrepoint of a rectangle bounded by (0, 0) and (1, 1) to the reference point
631  QLineF refLine = QLineF( QPointF( 0.5, 0.5 ), refPoint );
632  //rotate this line by the current rotation angle
633  refLine.setAngle( refLine.angle() + angle );
634  //get new end point of line
635  QPointF rotatedReferencePoint = refLine.p2();
636  //make sure coords of new end point is within [0, 1]
637  if ( rotatedReferencePoint.x() > 1 )
638  rotatedReferencePoint.setX( 1 );
639  if ( rotatedReferencePoint.x() < 0 )
640  rotatedReferencePoint.setX( 0 );
641  if ( rotatedReferencePoint.y() > 1 )
642  rotatedReferencePoint.setY( 1 );
643  if ( rotatedReferencePoint.y() < 0 )
644  rotatedReferencePoint.setY( 0 );
645 
646  return rotatedReferencePoint;
647 }
648 
650  const QColor &color, const QColor &color2, const GradientColorType &gradientColorType,
651  QgsVectorColorRampV2 *gradientRamp, const GradientType &gradientType,
652  const GradientCoordinateMode &coordinateMode, const GradientSpread &gradientSpread,
653  const QPointF &referencePoint1, const QPointF &referencePoint2, const double angle )
654 {
655  //update alpha of gradient colors
656  QColor fillColor = color;
657  fillColor.setAlphaF( context.alpha() * fillColor.alphaF() );
658  QColor fillColor2 = color2;
659  fillColor2.setAlphaF( context.alpha() * fillColor2.alphaF() );
660 
661  //rotate reference points
662  QPointF rotatedReferencePoint1 = angle != 0 ? rotateReferencePoint( referencePoint1, angle ) : referencePoint1;
663  QPointF rotatedReferencePoint2 = angle != 0 ? rotateReferencePoint( referencePoint2, angle ) : referencePoint2;
664 
665  //create a QGradient with the desired properties
666  QGradient gradient;
667  switch ( gradientType )
668  {
670  gradient = QLinearGradient( rotatedReferencePoint1, rotatedReferencePoint2 );
671  break;
673  gradient = QRadialGradient( rotatedReferencePoint1, QLineF( rotatedReferencePoint1, rotatedReferencePoint2 ).length() );
674  break;
676  gradient = QConicalGradient( rotatedReferencePoint1, QLineF( rotatedReferencePoint1, rotatedReferencePoint2 ).angle() );
677  break;
678  }
679  switch ( coordinateMode )
680  {
682  gradient.setCoordinateMode( QGradient::ObjectBoundingMode );
683  break;
685  gradient.setCoordinateMode( QGradient::StretchToDeviceMode );
686  break;
687  }
688  switch ( gradientSpread )
689  {
691  gradient.setSpread( QGradient::PadSpread );
692  break;
694  gradient.setSpread( QGradient::ReflectSpread );
695  break;
697  gradient.setSpread( QGradient::RepeatSpread );
698  break;
699  }
700 
701  //add stops to gradient
702  if ( gradientColorType == QgsGradientFillSymbolLayerV2::ColorRamp && gradientRamp && gradientRamp->type() == "gradient" )
703  {
704  //color ramp gradient
705  QgsVectorGradientColorRampV2* gradRamp = static_cast<QgsVectorGradientColorRampV2*>( gradientRamp );
706  gradRamp->addStopsToGradient( &gradient, context.alpha() );
707  }
708  else
709  {
710  //two color gradient
711  gradient.setColorAt( 0.0, fillColor );
712  gradient.setColorAt( 1.0, fillColor2 );
713  }
714 
715  //update QBrush use gradient
716  brush = QBrush( gradient );
717 }
718 
720 {
721  QColor selColor = context.renderContext().selectionColor();
722  if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() );
723  mSelBrush = QBrush( selColor );
724 
725  //update mBrush to use a gradient fill with specified properties
726  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
727 }
728 
730 {
731  Q_UNUSED( context );
732 }
733 
734 void QgsGradientFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
735 {
736  QPainter* p = context.renderContext().painter();
737  if ( !p )
738  {
739  return;
740  }
741 
742  QPen mSelPen;
743  applyDataDefinedSymbology( context, points );
744 
745  p->setBrush( context.selected() ? mSelBrush : mBrush );
746  p->setPen( QPen( Qt::NoPen ) );
747 
748  QPointF offset;
749  if ( !mOffset.isNull() )
750  {
753  p->translate( offset );
754  }
755 
756  _renderPolygon( p, points, rings, context );
757 
758  if ( !mOffset.isNull() )
759  {
760  p->translate( -offset );
761  }
762 }
763 
765 {
766  QgsStringMap map;
767  map["gradient_color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
768  map["gradient_color2"] = QgsSymbolLayerV2Utils::encodeColor( mColor2 );
769  map["color_type"] = QString::number( mGradientColorType );
770  map["type"] = QString::number( mGradientType );
771  map["coordinate_mode"] = QString::number( mCoordinateMode );
772  map["spread"] = QString::number( mGradientSpread );
773  map["reference_point1"] = QgsSymbolLayerV2Utils::encodePoint( mReferencePoint1 );
774  map["reference_point1_iscentroid"] = QString::number( mReferencePoint1IsCentroid );
775  map["reference_point2"] = QgsSymbolLayerV2Utils::encodePoint( mReferencePoint2 );
776  map["reference_point2_iscentroid"] = QString::number( mReferencePoint2IsCentroid );
777  map["angle"] = QString::number( mAngle );
778  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
780  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
782  if ( mGradientRamp )
783  {
784  map.unite( mGradientRamp->properties() );
785  }
786  return map;
787 }
788 
790 {
792  if ( mGradientRamp )
793  sl->setColorRamp( mGradientRamp->clone() );
798  sl->setAngle( mAngle );
799  sl->setOffset( mOffset );
800  sl->setOffsetUnit( mOffsetUnit );
803  return sl;
804 }
805 
807 {
808  double offsetBleed = mOffset.x() > mOffset.y() ? mOffset.x() : mOffset.y();
809  return offsetBleed;
810 }
811 
813 {
814  mOffsetUnit = unit;
815 }
816 
818 {
819  return mOffsetUnit;
820 }
821 
823 {
824  mOffsetMapUnitScale = scale;
825 }
826 
828 {
829  return mOffsetMapUnitScale;
830 }
831 
832 //QgsShapeburstFillSymbolLayer
833 
835  int blurRadius, bool useWholeShape, double maxDistance ) :
836 
837  mBlurRadius( blurRadius ),
838  mUseWholeShape( useWholeShape ),
839  mMaxDistance( maxDistance ),
840  mDistanceUnit( QgsSymbolV2::MM ),
841  mColorType( colorType ),
842  mColor2( color2 ),
843  mGradientRamp( NULL ),
844  mTwoColorGradientRamp( 0 ),
845  mIgnoreRings( false ),
846  mOffsetUnit( QgsSymbolV2::MM )
847 {
848  mColor = color;
849 }
850 
852 {
853  delete mGradientRamp;
854 }
855 
857 {
858  //default to a two-color gradient
860  QColor color = DEFAULT_SIMPLEFILL_COLOR, color2 = Qt::white;
861  int blurRadius = 0;
862  bool useWholeShape = true;
863  double maxDistance = 5;
864  QPointF offset;
865 
866  //update fill properties from props
867  if ( props.contains( "color_type" ) )
868  {
869  colorType = ( ShapeburstColorType )props["color_type"].toInt();
870  }
871  if ( props.contains( "shapeburst_color" ) )
872  {
873  color = QgsSymbolLayerV2Utils::decodeColor( props["shapeburst_color"] );
874  }
875  if ( props.contains( "shapeburst_color2" ) )
876  {
877  color2 = QgsSymbolLayerV2Utils::decodeColor( props["shapeburst_color2"] );
878  }
879  if ( props.contains( "blur_radius" ) )
880  {
881  blurRadius = props["blur_radius"].toInt();
882  }
883  if ( props.contains( "use_whole_shape" ) )
884  {
885  useWholeShape = props["use_whole_shape"].toInt();
886  }
887  if ( props.contains( "max_distance" ) )
888  {
889  maxDistance = props["max_distance"].toDouble();
890  }
891  if ( props.contains( "offset" ) )
892  {
893  offset = QgsSymbolLayerV2Utils::decodePoint( props["offset"] );
894  }
895 
896  //attempt to create color ramp from props
898 
899  //create a new shapeburst fill layer with desired properties
900  QgsShapeburstFillSymbolLayerV2* sl = new QgsShapeburstFillSymbolLayerV2( color, color2, colorType, blurRadius, useWholeShape, maxDistance );
901  sl->setOffset( offset );
902  if ( props.contains( "offset_unit" ) )
903  {
904  sl->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit"] ) );
905  }
906  if ( props.contains( "distance_unit" ) )
907  {
908  sl->setDistanceUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["distance_unit"] ) );
909  }
910  if ( props.contains( "offset_map_unit_scale" ) )
911  {
912  sl->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["offset_map_unit_scale"] ) );
913  }
914  if ( props.contains( "distance_map_unit_scale" ) )
915  {
916  sl->setDistanceMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( props["distance_map_unit_scale"] ) );
917  }
918  if ( props.contains( "ignore_rings" ) )
919  {
920  sl->setIgnoreRings( props["ignore_rings"].toInt() );
921  }
922  if ( gradientRamp )
923  {
924  sl->setColorRamp( gradientRamp );
925  }
926 
927  if ( props.contains( "color_expression" ) )
928  sl->setDataDefinedProperty( "color", props["color_expression"] );
929  if ( props.contains( "color2_expression" ) )
930  sl->setDataDefinedProperty( "color2", props["color2_expression"] );
931  if ( props.contains( "blur_radius_expression" ) )
932  sl->setDataDefinedProperty( "blur_radius", props["blur_radius_expression"] );
933  if ( props.contains( "use_whole_shape_expression" ) )
934  sl->setDataDefinedProperty( "use_whole_shape", props["use_whole_shape_expression"] );
935  if ( props.contains( "max_distance_expression" ) )
936  sl->setDataDefinedProperty( "max_distance", props["max_distance_expression"] );
937  if ( props.contains( "ignore_rings_expression" ) )
938  sl->setDataDefinedProperty( "ignore_rings", props["ignore_rings_expression"] );
939 
940  return sl;
941 }
942 
944 {
945  return "ShapeburstFill";
946 }
947 
949 {
950  delete mGradientRamp;
951  mGradientRamp = ramp;
952 }
953 
954 void QgsShapeburstFillSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QColor& color, QColor& color2, int& blurRadius, bool& useWholeShape,
955  double& maxDistance, bool& ignoreRings )
956 {
957  //first gradient color
958  QgsExpression* colorExpression = expression( "color" );
959  color = mColor;
960  if ( colorExpression )
961  color = QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
962 
963  //second gradient color
964  QgsExpression* colorExpression2 = expression( "color2" );
965  color2 = mColor2;
966  if ( colorExpression2 )
967  color2 = QgsSymbolLayerV2Utils::decodeColor( colorExpression2->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
968 
969  //blur radius
970  QgsExpression* blurRadiusExpression = expression( "blur_radius" );
971  blurRadius = mBlurRadius;
972  if ( blurRadiusExpression )
973  blurRadius = blurRadiusExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toInt();
974 
975  //use whole shape
976  QgsExpression* useWholeShapeExpression = expression( "use_whole_shape" );
977  useWholeShape = mUseWholeShape;
978  if ( useWholeShapeExpression )
979  useWholeShape = useWholeShapeExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toBool();
980 
981  //max distance
982  QgsExpression* maxDistanceExpression = expression( "max_distance" );
983  maxDistance = mMaxDistance;
984  if ( maxDistanceExpression )
985  maxDistance = maxDistanceExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
986 
987  //ignore rings
988  QgsExpression* ignoreRingsExpression = expression( "ignore_rings" );
989  ignoreRings = mIgnoreRings;
990  if ( ignoreRingsExpression )
991  ignoreRings = ignoreRingsExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toBool();
992 
993 }
994 
996 {
997  //TODO - check this
998  QColor selColor = context.renderContext().selectionColor();
999  if ( ! selectionIsOpaque ) selColor.setAlphaF( context.alpha() );
1000  mSelBrush = QBrush( selColor );
1001 
1002  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
1003 }
1004 
1006 {
1007  Q_UNUSED( context );
1008 }
1009 
1010 void QgsShapeburstFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
1011 {
1012  QPainter* p = context.renderContext().painter();
1013  if ( !p )
1014  {
1015  return;
1016  }
1017 
1018  if ( context.selected() )
1019  {
1020  //feature is selected, draw using selection style
1021  p->setBrush( mSelBrush );
1022  QPointF offset;
1023  if ( !mOffset.isNull() )
1024  {
1027  p->translate( offset );
1028  }
1029  _renderPolygon( p, points, rings, context );
1030  if ( !mOffset.isNull() )
1031  {
1032  p->translate( -offset );
1033  }
1034  return;
1035  }
1036 
1037  QColor color1, color2;
1038  int blurRadius;
1039  bool useWholeShape;
1040  double maxDistance;
1041  bool ignoreRings;
1042  //calculate data defined symbology
1043  applyDataDefinedSymbology( context, color1, color2, blurRadius, useWholeShape, maxDistance, ignoreRings );
1044 
1045  //calculate max distance for shapeburst fill to extend from polygon boundary, in pixels
1046  int outputPixelMaxDist = 0;
1047  if ( !useWholeShape && maxDistance != 0 )
1048  {
1049  //convert max distance to pixels
1050  const QgsRenderContext& ctx = context.renderContext();
1051  outputPixelMaxDist = maxDistance * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceUnit, mDistanceMapUnitScale );
1052  }
1053 
1054  //if we are using the two color mode, create a gradient ramp
1056  {
1057  mTwoColorGradientRamp = new QgsVectorGradientColorRampV2( color1, color2 );
1058  }
1059 
1060  //no border for shapeburst fills
1061  p->setPen( QPen( Qt::NoPen ) );
1062 
1063  //calculate margin size in pixels so that QImage of polygon has sufficient space to draw the full blur effect
1064  int sideBuffer = 4 + ( blurRadius + 2 ) * 4 ;
1065  //create a QImage to draw shapeburst in
1066  double imWidth = points.boundingRect().width() + ( sideBuffer * 2 );
1067  double imHeight = points.boundingRect().height() + ( sideBuffer * 2 );
1068  QImage * fillImage = new QImage( imWidth * context.renderContext().rasterScaleFactor(),
1069  imHeight * context.renderContext().rasterScaleFactor(), QImage::Format_ARGB32_Premultiplied );
1070  //Fill this image with black. Initially the distance transform is drawn in greyscale, where black pixels have zero distance from the
1071  //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
1072  //polygon in white. The distance transform function then fills in the correct distance values for the white pixels.
1073  fillImage->fill( Qt::black );
1074 
1075  //also create an image to store the alpha channel
1076  QImage * alphaImage = new QImage( fillImage->width(), fillImage->height(), QImage::Format_ARGB32_Premultiplied );
1077  //initially fill the alpha channel image with a transparent color
1078  alphaImage->fill( Qt::transparent );
1079 
1080  //now, draw the polygon in the alpha channel image
1081  QPainter imgPainter;
1082  imgPainter.begin( alphaImage );
1083  imgPainter.setRenderHint( QPainter::Antialiasing, true );
1084  imgPainter.setBrush( QBrush( Qt::white ) );
1085  imgPainter.setPen( QPen( Qt::black ) );
1086  imgPainter.translate( -points.boundingRect().left() + sideBuffer, - points.boundingRect().top() + sideBuffer );
1087  imgPainter.scale( context.renderContext().rasterScaleFactor(), context.renderContext().rasterScaleFactor() );
1088  _renderPolygon( &imgPainter, points, rings, context );
1089  imgPainter.end();
1090 
1091  //now that we have a render of the polygon in white, draw this onto the shapeburst fill image too
1092  //(this avoids calling _renderPolygon twice, since that can be slow)
1093  imgPainter.begin( fillImage );
1094  if ( !ignoreRings )
1095  {
1096  imgPainter.drawImage( 0, 0, *alphaImage );
1097  }
1098  else
1099  {
1100  //using ignore rings mode, so the alpha image can't be used
1101  //directly as the alpha channel contains polygon rings and we need
1102  //to draw now without any rings
1103  imgPainter.setBrush( QBrush( Qt::white ) );
1104  imgPainter.setPen( QPen( Qt::black ) );
1105  imgPainter.translate( -points.boundingRect().left() + sideBuffer, - points.boundingRect().top() + sideBuffer );
1106  imgPainter.scale( context.renderContext().rasterScaleFactor(), context.renderContext().rasterScaleFactor() );
1107  _renderPolygon( &imgPainter, points, NULL, context );
1108  }
1109  imgPainter.end();
1110 
1111  //apply distance transform to image, uses the current color ramp to calculate final pixel colors
1112  double * dtArray = distanceTransform( fillImage );
1113 
1114  //copy distance transform values back to QImage, shading by appropriate color ramp
1116  context.alpha(), useWholeShape, outputPixelMaxDist );
1117 
1118  //clean up some variables
1119  delete [] dtArray;
1121  {
1122  delete mTwoColorGradientRamp;
1123  }
1124 
1125  //apply blur if desired
1126  if ( blurRadius > 0 )
1127  {
1128  QgsSymbolLayerV2Utils::blurImageInPlace( *fillImage, QRect( 0, 0, fillImage->width(), fillImage->height() ), blurRadius, false );
1129  }
1130 
1131  //apply alpha channel to distance transform image, so that areas outside the polygon are transparent
1132  imgPainter.begin( fillImage );
1133  imgPainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
1134  imgPainter.drawImage( 0, 0, *alphaImage );
1135  imgPainter.end();
1136  //we're finished with the alpha channel image now
1137  delete alphaImage;
1138 
1139  //draw shapeburst image in correct place in the destination painter
1140 
1141  p->save();
1142  QPointF offset;
1143  if ( !mOffset.isNull() )
1144  {
1147  p->translate( offset );
1148  }
1149 
1150  p->scale( 1 / context.renderContext().rasterScaleFactor(), 1 / context.renderContext().rasterScaleFactor() );
1151  p->drawImage( points.boundingRect().left() - sideBuffer, points.boundingRect().top() - sideBuffer, *fillImage );
1152 
1153  delete fillImage;
1154 
1155  if ( !mOffset.isNull() )
1156  {
1157  p->translate( -offset );
1158  }
1159  p->restore();
1160 
1161 }
1162 
1163 //fast distance transform code, adapted from http://cs.brown.edu/~pff/dt/
1164 
1165 /* distance transform of a 1d function using squared distance */
1166 void QgsShapeburstFillSymbolLayerV2::distanceTransform1d( double *f, int n, int *v, double *z, double *d )
1167 {
1168  int k = 0;
1169  v[0] = 0;
1170  z[0] = -INF;
1171  z[1] = + INF;
1172  for ( int q = 1; q <= n - 1; q++ )
1173  {
1174  double s = (( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
1175  while ( s <= z[k] )
1176  {
1177  k--;
1178  s = (( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
1179  }
1180  k++;
1181  v[k] = q;
1182  z[k] = s;
1183  z[k+1] = + INF;
1184  }
1185 
1186  k = 0;
1187  for ( int q = 0; q <= n - 1; q++ )
1188  {
1189  while ( z[k+1] < q )
1190  k++;
1191  d[q] = ( q - v[k] ) * ( q - v[k] ) + f[v[k]];
1192  }
1193 }
1194 
1195 /* distance transform of 2d function using squared distance */
1196 void QgsShapeburstFillSymbolLayerV2::distanceTransform2d( double * im, int width, int height )
1197 {
1198  double *f = new double[ qMax( width,height )];
1199  int *v = new int[ qMax( width,height )];
1200  double *z = new double[ qMax( width,height ) + 1 ];
1201  double *d = new double[ qMax( width,height )];
1202 
1203  // transform along columns
1204  for ( int x = 0; x < width; x++ )
1205  {
1206  for ( int y = 0; y < height; y++ )
1207  {
1208  f[y] = im[ x + y * width ];
1209  }
1210  distanceTransform1d( f, height, v, z, d );
1211  for ( int y = 0; y < height; y++ )
1212  {
1213  im[ x + y * width ] = d[y];
1214  }
1215  }
1216 
1217  // transform along rows
1218  for ( int y = 0; y < height; y++ )
1219  {
1220  for ( int x = 0; x < width; x++ )
1221  {
1222  f[x] = im[ x + y*width ];
1223  }
1224  distanceTransform1d( f, width, v, z, d );
1225  for ( int x = 0; x < width; x++ )
1226  {
1227  im[ x + y*width ] = d[x];
1228  }
1229  }
1230 
1231  delete [] d;
1232  delete [] f;
1233  delete [] v;
1234  delete [] z;
1235 }
1236 
1237 /* distance transform of a binary QImage */
1239 {
1240  int width = im->width();
1241  int height = im->height();
1242 
1243  double * dtArray = new double[width * height];
1244 
1245  //load qImage to array
1246  QRgb tmpRgb;
1247  int idx = 0;
1248  for ( int heightIndex = 0; heightIndex < height; ++heightIndex )
1249  {
1250  QRgb* scanLine = ( QRgb* )im->constScanLine( heightIndex );
1251  for ( int widthIndex = 0; widthIndex < width; ++widthIndex )
1252  {
1253  tmpRgb = scanLine[widthIndex];
1254  if ( qRed( tmpRgb ) == 0 )
1255  {
1256  //black pixel, so zero distance
1257  dtArray[ idx ] = 0;
1258  }
1259  else
1260  {
1261  //white pixel, so initially set distance as infinite
1262  dtArray[ idx ] = INF;
1263  }
1264  idx++;
1265  }
1266  }
1267 
1268  //calculate squared distance transform
1269  distanceTransform2d( dtArray, width, height );
1270 
1271  return dtArray;
1272 }
1273 
1274 void QgsShapeburstFillSymbolLayerV2::dtArrayToQImage( double * array, QImage *im, QgsVectorColorRampV2* ramp, double layerAlpha, bool useWholeShape, int maxPixelDistance )
1275 {
1276  //find maximum distance value
1277  double maxDistanceValue;
1278 
1279  if ( useWholeShape )
1280  {
1281  //no max distance specified in symbol properties, so calculate from maximum value in distance transform results
1282  double dtMaxValue = array[0];
1283  for ( int i = 1; i < ( im->width() * im->height() ); ++i )
1284  {
1285  dtMaxValue = qMax( dtMaxValue, array[i] );
1286  }
1287 
1288  //values in distance transform are squared
1289  maxDistanceValue = sqrt( dtMaxValue );
1290  }
1291  else
1292  {
1293  //use max distance set in symbol properties
1294  maxDistanceValue = maxPixelDistance;
1295  }
1296 
1297  //update the pixels in the provided QImage
1298  int idx = 0;
1299  double squaredVal = 0;
1300  double pixVal = 0;
1301  QColor pixColor;
1302 
1303  for ( int heightIndex = 0; heightIndex < im->height(); ++heightIndex )
1304  {
1305  QRgb* scanLine = ( QRgb* )im->scanLine( heightIndex );
1306  for ( int widthIndex = 0; widthIndex < im->width(); ++widthIndex )
1307  {
1308  //result of distance transform
1309  squaredVal = array[idx];
1310 
1311  //scale result to fit in the range [0, 1]
1312  pixVal = squaredVal > 0 ? qMin(( sqrt( squaredVal ) / maxDistanceValue ), 1.0 ) : 0;
1313 
1314  //convert value to color from ramp
1315  pixColor = ramp->color( pixVal );
1316 
1317  //apply layer's transparency to alpha value
1318  double alpha = pixColor.alpha() * layerAlpha;
1319 
1320  //premultiply ramp color since we are storing this in a ARGB32_Premultiplied QImage
1321  QgsSymbolLayerV2Utils::premultiplyColor( pixColor, alpha );
1322  scanLine[widthIndex] = pixColor.rgba();
1323  idx++;
1324  }
1325  }
1326 }
1327 
1329 {
1330  QgsStringMap map;
1331  map["shapeburst_color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
1332  map["shapeburst_color2"] = QgsSymbolLayerV2Utils::encodeColor( mColor2 );
1333  map["color_type"] = QString::number( mColorType );
1334  map["blur_radius"] = QString::number( mBlurRadius );
1335  map["use_whole_shape"] = QString::number( mUseWholeShape );
1336  map["max_distance"] = QString::number( mMaxDistance );
1337  map["distance_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceUnit );
1338  map["distance_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceMapUnitScale );
1339  map["ignore_rings"] = QString::number( mIgnoreRings );
1340  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1341  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1342  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1343 
1345 
1346  if ( mGradientRamp )
1347  {
1348  map.unite( mGradientRamp->properties() );
1349  }
1350 
1351  return map;
1352 }
1353 
1355 {
1357  if ( mGradientRamp )
1358  {
1359  sl->setColorRamp( mGradientRamp->clone() );
1360  }
1364  sl->setOffset( mOffset );
1365  sl->setOffsetUnit( mOffsetUnit );
1368  return sl;
1369 }
1370 
1372 {
1373  double offsetBleed = qMax( mOffset.x(), mOffset.y() );
1374  return offsetBleed;
1375 }
1376 
1378 {
1379  mDistanceUnit = unit;
1380  mOffsetUnit = unit;
1381 }
1382 
1384 {
1385  if ( mDistanceUnit == mOffsetUnit )
1386  {
1387  return mDistanceUnit;
1388  }
1389  return QgsSymbolV2::Mixed;
1390 }
1391 
1393 {
1394  mDistanceMapUnitScale = scale;
1395  mOffsetMapUnitScale = scale;
1396 }
1397 
1399 {
1401  {
1402  return mDistanceMapUnitScale;
1403  }
1404  return QgsMapUnitScale();
1405 }
1406 
1407 
1408 //QgsImageFillSymbolLayer
1409 
1410 QgsImageFillSymbolLayer::QgsImageFillSymbolLayer(): mOutlineWidth( 0.0 ), mOutlineWidthUnit( QgsSymbolV2::MM ), mOutline( 0 )
1411 {
1412  setSubSymbol( new QgsLineSymbolV2() );
1413 }
1414 
1416 {
1417 }
1418 
1419 void QgsImageFillSymbolLayer::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
1420 {
1421  QPainter* p = context.renderContext().painter();
1422  if ( !p )
1423  {
1424  return;
1425  }
1426 
1427  mNextAngle = mAngle;
1428  applyDataDefinedSettings( context );
1429 
1430  p->setPen( QPen( Qt::NoPen ) );
1431  if ( context.selected() )
1432  {
1433  QColor selColor = context.renderContext().selectionColor();
1434  // Alister - this doesn't seem to work here
1435  //if ( ! selectionIsOpaque )
1436  // selColor.setAlphaF( context.alpha() );
1437  p->setBrush( QBrush( selColor ) );
1438  _renderPolygon( p, points, rings, context );
1439  }
1440 
1441  if ( qgsDoubleNear( mNextAngle, 0.0 ) )
1442  {
1443  p->setBrush( mBrush );
1444  }
1445  else
1446  {
1447  QTransform t = mBrush.transform();
1448  t.rotate( mNextAngle );
1449  QBrush rotatedBrush = mBrush;
1450  rotatedBrush.setTransform( t );
1451  p->setBrush( rotatedBrush );
1452  }
1453  _renderPolygon( p, points, rings, context );
1454  if ( mOutline )
1455  {
1456  mOutline->renderPolyline( points, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
1457  if ( rings )
1458  {
1459  QList<QPolygonF>::const_iterator ringIt = rings->constBegin();
1460  for ( ; ringIt != rings->constEnd(); ++ringIt )
1461  {
1462  mOutline->renderPolyline( *ringIt, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
1463  }
1464  }
1465  }
1466 }
1467 
1469 {
1470  if ( !symbol ) //unset current outline
1471  {
1472  delete mOutline;
1473  mOutline = 0;
1474  return true;
1475  }
1476 
1477  if ( symbol->type() != QgsSymbolV2::Line )
1478  {
1479  delete symbol;
1480  return false;
1481  }
1482 
1483  QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
1484  if ( lineSymbol )
1485  {
1486  delete mOutline;
1487  mOutline = lineSymbol;
1488  return true;
1489  }
1490 
1491  delete symbol;
1492  return false;
1493 }
1494 
1496 {
1497  mOutlineWidthUnit = unit;
1498 }
1499 
1501 {
1502  return mOutlineWidthUnit;
1503 }
1504 
1506 {
1507  mOutlineWidthMapUnitScale = scale;
1508 }
1509 
1511 {
1513 }
1514 
1516 {
1517  if ( mOutline && mOutline->symbolLayer( 0 ) )
1518  {
1519  double subLayerBleed = mOutline->symbolLayer( 0 )->estimateMaxBleed();
1520  return subLayerBleed;
1521  }
1522  return 0;
1523 }
1524 
1525 double QgsImageFillSymbolLayer::dxfWidth( const QgsDxfExport& e, const QgsSymbolV2RenderContext& context ) const
1526 {
1527  double width = mOutlineWidth;
1528  QgsExpression* widthExpression = expression( "width" );
1529  if ( widthExpression )
1530  {
1531  width = widthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
1532  }
1533  return width * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), mOutlineWidthUnit, e.mapUnits() );
1534 }
1535 
1537 {
1538  Q_UNUSED( context );
1539  if ( !mOutline )
1540  {
1541  return QColor( Qt::black );
1542  }
1543  return mOutline->color();
1544 }
1545 
1547 {
1548  return Qt::SolidLine;
1549 #if 0
1550  if ( !mOutline )
1551  {
1552  return Qt::SolidLine;
1553  }
1554  else
1555  {
1556  return mOutline->dxfPenStyle();
1557  }
1558 #endif //0
1559 }
1560 
1561 
1562 //QgsSVGFillSymbolLayer
1563 
1564 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QString& svgFilePath, double width, double angle ): QgsImageFillSymbolLayer(),
1565  mPatternWidth( width ),
1566  mPatternWidthUnit( QgsSymbolV2::MM ),
1567  mSvgOutlineWidthUnit( QgsSymbolV2::MM )
1568 {
1569  setSvgFilePath( svgFilePath );
1570  mOutlineWidth = 0.3;
1571  mAngle = angle;
1573  mSvgPattern = 0;
1574 }
1575 
1576 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QByteArray& svgData, double width, double angle ): QgsImageFillSymbolLayer(),
1577  mPatternWidth( width ),
1578  mPatternWidthUnit( QgsSymbolV2::MM ),
1579  mSvgData( svgData ),
1580  mSvgOutlineWidthUnit( QgsSymbolV2::MM )
1581 {
1582  storeViewBox();
1583  mOutlineWidth = 0.3;
1584  mAngle = angle;
1585  setSubSymbol( new QgsLineSymbolV2() );
1587  mSvgPattern = 0;
1588 }
1589 
1591 {
1592  delete mSvgPattern;
1593 }
1594 
1596 {
1598  mPatternWidthUnit = unit;
1599  mSvgOutlineWidthUnit = unit;
1600  mOutlineWidthUnit = unit;
1601 }
1602 
1604 {
1606  if ( mPatternWidthUnit != unit || mSvgOutlineWidthUnit != unit || mOutlineWidthUnit != unit )
1607  {
1608  return QgsSymbolV2::Mixed;
1609  }
1610  return unit;
1611 }
1612 
1614 {
1616  mPatternWidthMapUnitScale = scale;
1618  mOutlineWidthMapUnitScale = scale;
1619 }
1620 
1622 {
1626  {
1628  }
1629  return QgsMapUnitScale();
1630 }
1631 
1632 void QgsSVGFillSymbolLayer::setSvgFilePath( const QString& svgPath )
1633 {
1635  storeViewBox();
1636 
1637  mSvgFilePath = svgPath;
1639 }
1640 
1642 {
1643  QByteArray data;
1644  double width = 20;
1645  QString svgFilePath;
1646  double angle = 0.0;
1647 
1648  if ( properties.contains( "width" ) )
1649  {
1650  width = properties["width"].toDouble();
1651  }
1652  if ( properties.contains( "svgFile" ) )
1653  {
1654  QString svgName = properties["svgFile"];
1655  QString savePath = QgsSymbolLayerV2Utils::symbolNameToPath( svgName );
1656  svgFilePath = ( savePath.isEmpty() ? svgName : savePath );
1657  }
1658  if ( properties.contains( "angle" ) )
1659  {
1660  angle = properties["angle"].toDouble();
1661  }
1662 
1663  QgsSVGFillSymbolLayer* symbolLayer = 0;
1664  if ( !svgFilePath.isEmpty() )
1665  {
1666  symbolLayer = new QgsSVGFillSymbolLayer( svgFilePath, width, angle );
1667  }
1668  else
1669  {
1670  if ( properties.contains( "data" ) )
1671  {
1672  data = QByteArray::fromHex( properties["data"].toLocal8Bit() );
1673  }
1674  symbolLayer = new QgsSVGFillSymbolLayer( data, width, angle );
1675  }
1676 
1677  //svg parameters
1678  if ( properties.contains( "svgFillColor" ) )
1679  {
1680  symbolLayer->setSvgFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["svgFillColor"] ) );
1681  }
1682  if ( properties.contains( "svgOutlineColor" ) )
1683  {
1684  symbolLayer->setSvgOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["svgOutlineColor"] ) );
1685  }
1686  if ( properties.contains( "svgOutlineWidth" ) )
1687  {
1688  symbolLayer->setSvgOutlineWidth( properties["svgOutlineWidth"].toDouble() );
1689  }
1690 
1691  //units
1692  if ( properties.contains( "pattern_width_unit" ) )
1693  {
1694  symbolLayer->setPatternWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["pattern_width_unit"] ) );
1695  }
1696  if ( properties.contains( "pattern_width_map_unit_scale" ) )
1697  {
1698  symbolLayer->setPatternWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["pattern_width_map_unit_scale"] ) );
1699  }
1700  if ( properties.contains( "svg_outline_width_unit" ) )
1701  {
1702  symbolLayer->setSvgOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["svg_outline_width_unit"] ) );
1703  }
1704  if ( properties.contains( "svg_outline_width_map_unit_scale" ) )
1705  {
1706  symbolLayer->setSvgOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["svg_outline_width_map_unit_scale"] ) );
1707  }
1708  if ( properties.contains( "outline_width_unit" ) )
1709  {
1710  symbolLayer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
1711  }
1712  if ( properties.contains( "outline_width_map_unit_scale" ) )
1713  {
1714  symbolLayer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
1715  }
1716 
1717  if ( properties.contains( "width_expression" ) )
1718  symbolLayer->setDataDefinedProperty( "width", properties["width_expression"] );
1719  if ( properties.contains( "svgFile_expression" ) )
1720  symbolLayer->setDataDefinedProperty( "svgFile", properties["svgFile_expression"] );
1721  if ( properties.contains( "angle_expression" ) )
1722  symbolLayer->setDataDefinedProperty( "angle", properties["angle_expression"] );
1723  if ( properties.contains( "svgFillColor_expression" ) )
1724  symbolLayer->setDataDefinedProperty( "svgFillColor", properties["svgFillColor_expression"] );
1725  if ( properties.contains( "svgOutlineColor_expression" ) )
1726  symbolLayer->setDataDefinedProperty( "svgOutlineColor", properties["svgOutlineColor_expression"] );
1727  if ( properties.contains( "svgOutlineWidth_expression" ) )
1728  symbolLayer->setDataDefinedProperty( "svgOutlineWidth", properties["svgOutlineWidth_expression"] );
1729 
1730  return symbolLayer;
1731 }
1732 
1734 {
1735  return "SVGFill";
1736 }
1737 
1738 void QgsSVGFillSymbolLayer::applyPattern( QBrush& brush, const QString& svgFilePath, double patternWidth, QgsSymbolV2::OutputUnit patternWidthUnit,
1739  const QColor& svgFillColor, const QColor& svgOutlineColor, double svgOutlineWidth,
1740  QgsSymbolV2::OutputUnit svgOutlineWidthUnit, const QgsSymbolV2RenderContext& context,
1741  const QgsMapUnitScale& patternWidthMapUnitScale, const QgsMapUnitScale& svgOutlineWidthMapUnitScale )
1742 {
1743  if ( mSvgViewBox.isNull() )
1744  {
1745  return;
1746  }
1747 
1748  delete mSvgPattern;
1749  mSvgPattern = 0;
1751 
1752  if (( int )size < 1.0 || 10000.0 < size )
1753  {
1754  mSvgPattern = new QImage();
1755  brush.setTextureImage( *mSvgPattern );
1756  }
1757  else
1758  {
1759  bool fitsInCache = true;
1761  const QImage& patternImage = QgsSvgCache::instance()->svgAsImage( svgFilePath, size, svgFillColor, svgOutlineColor, outlineWidth,
1762  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
1763  if ( !fitsInCache )
1764  {
1765  const QPicture& patternPict = QgsSvgCache::instance()->svgAsPicture( svgFilePath, size, svgFillColor, svgOutlineColor, outlineWidth,
1766  context.renderContext().scaleFactor(), 1.0 );
1767  double hwRatio = 1.0;
1768  if ( patternPict.width() > 0 )
1769  {
1770  hwRatio = ( double )patternPict.height() / ( double )patternPict.width();
1771  }
1772  mSvgPattern = new QImage(( int )size, ( int )( size * hwRatio ), QImage::Format_ARGB32_Premultiplied );
1773  mSvgPattern->fill( 0 ); // transparent background
1774 
1775  QPainter p( mSvgPattern );
1776  p.drawPicture( QPointF( size / 2, size * hwRatio / 2 ), patternPict );
1777  }
1778 
1779  QTransform brushTransform;
1780  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
1781  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1782  {
1783  QImage transparentImage = fitsInCache ? patternImage.copy() : mSvgPattern->copy();
1784  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
1785  brush.setTextureImage( transparentImage );
1786  }
1787  else
1788  {
1789  brush.setTextureImage( fitsInCache ? patternImage : *mSvgPattern );
1790  }
1791  brush.setTransform( brushTransform );
1792  }
1793 }
1794 
1796 {
1797 
1799 
1800  if ( mOutline )
1801  {
1802  mOutline->startRender( context.renderContext(), context.fields() );
1803  }
1804 
1805  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
1806 }
1807 
1809 {
1810  if ( mOutline )
1811  {
1812  mOutline->stopRender( context.renderContext() );
1813  }
1814 }
1815 
1817 {
1818  QgsStringMap map;
1819  if ( !mSvgFilePath.isEmpty() )
1820  {
1821  map.insert( "svgFile", QgsSymbolLayerV2Utils::symbolPathToName( mSvgFilePath ) );
1822  }
1823  else
1824  {
1825  map.insert( "data", QString( mSvgData.toHex() ) );
1826  }
1827 
1828  map.insert( "width", QString::number( mPatternWidth ) );
1829  map.insert( "angle", QString::number( mAngle ) );
1830 
1831  //svg parameters
1832  map.insert( "svgFillColor", QgsSymbolLayerV2Utils::encodeColor( mSvgFillColor ) );
1833  map.insert( "svgOutlineColor", QgsSymbolLayerV2Utils::encodeColor( mSvgOutlineColor ) );
1834  map.insert( "svgOutlineWidth", QString::number( mSvgOutlineWidth ) );
1835 
1836  //units
1837  map.insert( "pattern_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mPatternWidthUnit ) );
1838  map.insert( "pattern_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mPatternWidthMapUnitScale ) );
1839  map.insert( "svg_outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mSvgOutlineWidthUnit ) );
1840  map.insert( "svg_outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mSvgOutlineWidthMapUnitScale ) );
1841  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
1842  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
1843 
1845  return map;
1846 }
1847 
1849 {
1850  QgsSVGFillSymbolLayer* clonedLayer = 0;
1851  if ( !mSvgFilePath.isEmpty() )
1852  {
1853  clonedLayer = new QgsSVGFillSymbolLayer( mSvgFilePath, mPatternWidth, mAngle );
1854  clonedLayer->setSvgFillColor( mSvgFillColor );
1855  clonedLayer->setSvgOutlineColor( mSvgOutlineColor );
1856  clonedLayer->setSvgOutlineWidth( mSvgOutlineWidth );
1857  }
1858  else
1859  {
1860  clonedLayer = new QgsSVGFillSymbolLayer( mSvgData, mPatternWidth, mAngle );
1861  }
1862 
1863  clonedLayer->setPatternWidthUnit( mPatternWidthUnit );
1867  clonedLayer->setOutlineWidthUnit( mOutlineWidthUnit );
1869 
1870  if ( mOutline )
1871  {
1872  clonedLayer->setSubSymbol( mOutline->clone() );
1873  }
1874  copyDataDefinedProperties( clonedLayer );
1875  return clonedLayer;
1876 }
1877 
1878 void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
1879 {
1880  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
1881  if ( !props.value( "uom", "" ).isEmpty() )
1882  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
1883  element.appendChild( symbolizerElem );
1884 
1885  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
1886 
1887  QDomElement fillElem = doc.createElement( "se:Fill" );
1888  symbolizerElem.appendChild( fillElem );
1889 
1890  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
1891  fillElem.appendChild( graphicFillElem );
1892 
1893  QDomElement graphicElem = doc.createElement( "se:Graphic" );
1894  graphicFillElem.appendChild( graphicElem );
1895 
1896  if ( !mSvgFilePath.isEmpty() )
1897  {
1899  }
1900  else
1901  {
1902  // TODO: create svg from data
1903  // <se:InlineContent>
1904  symbolizerElem.appendChild( doc.createComment( "SVG from data not implemented yet" ) );
1905  }
1906 
1907  if ( mSvgOutlineColor.isValid() || mSvgOutlineWidth >= 0 )
1908  {
1909  QgsSymbolLayerV2Utils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, mSvgOutlineWidth );
1910  }
1911 
1912  // <Rotation>
1913  QString angleFunc;
1914  bool ok;
1915  double angle = props.value( "angle", "0" ).toDouble( &ok );
1916  if ( !ok )
1917  {
1918  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
1919  }
1920  else if ( angle + mAngle != 0 )
1921  {
1922  angleFunc = QString::number( angle + mAngle );
1923  }
1924  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
1925 
1926  if ( mOutline )
1927  {
1928  // the outline sub symbol should be stored within the Stroke element,
1929  // but it will be stored in a separated LineSymbolizer because it could
1930  // have more than one layer
1931  mOutline->toSld( doc, element, props );
1932  }
1933 }
1934 
1936 {
1937  QgsDebugMsg( "Entered." );
1938 
1939  QString path, mimeType;
1940  QColor fillColor, borderColor;
1941  Qt::PenStyle penStyle;
1942  double size, borderWidth;
1943 
1944  QDomElement fillElem = element.firstChildElement( "Fill" );
1945  if ( fillElem.isNull() )
1946  return NULL;
1947 
1948  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
1949  if ( graphicFillElem.isNull() )
1950  return NULL;
1951 
1952  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
1953  if ( graphicElem.isNull() )
1954  return NULL;
1955 
1956  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
1957  return NULL;
1958 
1959  if ( mimeType != "image/svg+xml" )
1960  return NULL;
1961 
1962  QgsSymbolLayerV2Utils::lineFromSld( graphicElem, penStyle, borderColor, borderWidth );
1963 
1964  double angle = 0.0;
1965  QString angleFunc;
1966  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
1967  {
1968  bool ok;
1969  double d = angleFunc.toDouble( &ok );
1970  if ( ok )
1971  angle = d;
1972  }
1973 
1974  QgsSVGFillSymbolLayer* sl = new QgsSVGFillSymbolLayer( path, size, angle );
1975  sl->setSvgFillColor( fillColor );
1976  sl->setSvgOutlineColor( borderColor );
1977  sl->setSvgOutlineWidth( borderWidth );
1978 
1979  // try to get the outline
1980  QDomElement strokeElem = element.firstChildElement( "Stroke" );
1981  if ( !strokeElem.isNull() )
1982  {
1984  if ( l )
1985  {
1986  QgsSymbolLayerV2List layers;
1987  layers.append( l );
1988  sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
1989  }
1990  }
1991 
1992  return sl;
1993 }
1994 
1996 {
1997  QgsExpression* widthExpression = expression( "width" );
1998  QgsExpression* svgFileExpression = expression( "svgFile" );
1999  QgsExpression* fillColorExpression = expression( "svgFillColor" );
2000  QgsExpression* outlineColorExpression = expression( "svgOutlineColor" );
2001  QgsExpression* outlineWidthExpression = expression( "svgOutlineWidth" );
2002  QgsExpression* angleExpression = expression( "angle" );
2003  if ( !widthExpression && !svgFileExpression && !fillColorExpression && !outlineColorExpression && !outlineWidthExpression && !angleExpression )
2004  {
2005  return; //no data defined settings
2006  }
2007 
2008  if ( angleExpression )
2009  {
2010  mNextAngle = angleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2011  }
2012 
2013  double width = mPatternWidth;
2014  if ( widthExpression )
2015  {
2016  width = widthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2017  }
2018  QString svgFile = mSvgFilePath;
2019  if ( svgFileExpression )
2020  {
2021  svgFile = svgFileExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
2022  }
2023  QColor svgFillColor = mSvgFillColor;
2024  if ( fillColorExpression )
2025  {
2026  svgFillColor = QgsSymbolLayerV2Utils::decodeColor( fillColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
2027  }
2029  if ( outlineColorExpression )
2030  {
2031  svgOutlineColor = QgsSymbolLayerV2Utils::decodeColor( outlineColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
2032  }
2033  double outlineWidth = mSvgOutlineWidth;
2034  if ( outlineWidthExpression )
2035  {
2036  outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2037  }
2038  applyPattern( mBrush, svgFile, width, mPatternWidthUnit, svgFillColor, svgOutlineColor, outlineWidth,
2040 
2041 }
2042 
2044 {
2045  if ( !mSvgData.isEmpty() )
2046  {
2047  QSvgRenderer r( mSvgData );
2048  if ( r.isValid() )
2049  {
2050  mSvgViewBox = r.viewBoxF();
2051  return;
2052  }
2053  }
2054 
2055  mSvgViewBox = QRectF();
2056  return;
2057 }
2058 
2060 {
2061  //default values
2062  mSvgFillColor = QColor( 0, 0, 0 );
2063  mSvgOutlineColor = QColor( 0, 0, 0 );
2064  mSvgOutlineWidth = 0.3;
2065 
2066  if ( mSvgFilePath.isEmpty() )
2067  {
2068  return;
2069  }
2070 
2071  bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
2072  QColor defaultFillColor, defaultOutlineColor;
2073  double defaultOutlineWidth;
2074  QgsSvgCache::instance()->containsParams( mSvgFilePath, hasFillParam, defaultFillColor, hasOutlineParam, defaultOutlineColor, hasOutlineWidthParam,
2075  defaultOutlineWidth );
2076 
2077  if ( hasFillParam )
2078  {
2079  mSvgFillColor = defaultFillColor;
2080  }
2081  if ( hasOutlineParam )
2082  {
2083  mSvgOutlineColor = defaultOutlineColor;
2084  }
2085  if ( hasOutlineWidthParam )
2086  {
2087  mSvgOutlineWidth = defaultOutlineWidth;
2088  }
2089 }
2090 
2091 
2093  mOffsetUnit( QgsSymbolV2::MM ), mFillLineSymbol( 0 )
2094 {
2095  setSubSymbol( new QgsLineSymbolV2() );
2096  QgsImageFillSymbolLayer::setSubSymbol( 0 ); //no outline
2097 }
2098 
2100 {
2101  mFillLineSymbol->setWidth( w );
2102  mLineWidth = w;
2103 }
2104 
2106 {
2107  mFillLineSymbol->setColor( c );
2108  mColor = c;
2109 }
2110 
2112 {
2113  delete mFillLineSymbol;
2114 }
2115 
2117 {
2118  if ( !symbol )
2119  {
2120  return false;
2121  }
2122 
2123  if ( symbol->type() == QgsSymbolV2::Line )
2124  {
2125  QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
2126  if ( lineSymbol )
2127  {
2128  delete mFillLineSymbol;
2129  mFillLineSymbol = lineSymbol;
2130 
2131  return true;
2132  }
2133  }
2134  delete symbol;
2135  return false;
2136 }
2137 
2139 {
2140  return mFillLineSymbol;
2141 }
2142 
2144 {
2145  return 0;
2146 }
2147 
2149 {
2151  mDistanceUnit = unit;
2152  mLineWidthUnit = unit;
2153  mOffsetUnit = unit;
2154 }
2155 
2157 {
2159  if ( mDistanceUnit != unit || mLineWidthUnit != unit || mOffsetUnit != unit )
2160  {
2161  return QgsSymbolV2::Mixed;
2162  }
2163  return unit;
2164 }
2165 
2167 {
2169  mDistanceMapUnitScale = scale;
2170  mLineWidthMapUnitScale = scale;
2171  mOffsetMapUnitScale = scale;
2172 }
2173 
2175 {
2179  {
2180  return mDistanceMapUnitScale;
2181  }
2182  return QgsMapUnitScale();
2183 }
2184 
2186 {
2188 
2189  //default values
2190  double lineAngle = 45;
2191  double distance = 5;
2192  double lineWidth = 0.5;
2193  QColor color( Qt::black );
2194  double offset = 0.0;
2195 
2196  if ( properties.contains( "lineangle" ) )
2197  {
2198  lineAngle = properties["lineangle"].toDouble();
2199  }
2200  patternLayer->setLineAngle( lineAngle );
2201 
2202  if ( properties.contains( "distance" ) )
2203  {
2204  distance = properties["distance"].toDouble();
2205  }
2206  patternLayer->setDistance( distance );
2207 
2208  if ( properties.contains( "linewidth" ) )
2209  {
2210  lineWidth = properties["linewidth"].toDouble();
2211  }
2212  patternLayer->setLineWidth( lineWidth );
2213 
2214  if ( properties.contains( "color" ) )
2215  {
2216  color = QgsSymbolLayerV2Utils::decodeColor( properties["color"] );
2217  }
2218  patternLayer->setColor( color );
2219 
2220  if ( properties.contains( "offset" ) )
2221  {
2222  offset = properties["offset"].toDouble();
2223  }
2224  patternLayer->setOffset( offset );
2225 
2226 
2227  if ( properties.contains( "distance_unit" ) )
2228  {
2229  patternLayer->setDistanceUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_unit"] ) );
2230  }
2231  if ( properties.contains( "distance_map_unit_scale" ) )
2232  {
2233  patternLayer->setDistanceMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_map_unit_scale"] ) );
2234  }
2235  if ( properties.contains( "line_width_unit" ) )
2236  {
2237  patternLayer->setLineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["line_width_unit"] ) );
2238  }
2239  if ( properties.contains( "line_width_map_unit_scale" ) )
2240  {
2241  patternLayer->setLineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["line_width_map_unit_scale"] ) );
2242  }
2243  if ( properties.contains( "offset_unit" ) )
2244  {
2245  patternLayer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
2246  }
2247  if ( properties.contains( "offset_map_unit_scale" ) )
2248  {
2249  patternLayer->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["offset_map_unit_scale"] ) );
2250  }
2251  if ( properties.contains( "outline_width_unit" ) )
2252  {
2253  patternLayer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
2254  }
2255  if ( properties.contains( "outline_width_map_unit_scale" ) )
2256  {
2257  patternLayer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
2258  }
2259 
2260 
2261  //data defined properties
2262  if ( properties.contains( "lineangle_expression" ) )
2263  {
2264  patternLayer->setDataDefinedProperty( "lineangle", properties["lineangle_expression"] );
2265  }
2266  if ( properties.contains( "distance_expression" ) )
2267  {
2268  patternLayer->setDataDefinedProperty( "distance", properties["distance_expression"] );
2269  }
2270  if ( properties.contains( "linewidth_expression" ) )
2271  {
2272  patternLayer->setDataDefinedProperty( "linewidth", properties["linewidth_expression"] );
2273  }
2274  if ( properties.contains( "color_expression" ) )
2275  {
2276  patternLayer->setDataDefinedProperty( "color", properties["color_expression"] );
2277  }
2278  return patternLayer;
2279 }
2280 
2282 {
2283  return "LinePatternFill";
2284 }
2285 
2286 void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double lineAngle, double distance,
2287  double lineWidth, const QColor& color )
2288 {
2289  Q_UNUSED( lineWidth );
2290  Q_UNUSED( color );
2291 
2292  mBrush.setTextureImage( QImage() ); // set empty in case we have to return
2293 
2294  if ( !mFillLineSymbol )
2295  {
2296  return;
2297  }
2298  // We have to make a copy because marker intervals will have to be adjusted
2299  QgsLineSymbolV2* fillLineSymbol = dynamic_cast<QgsLineSymbolV2*>( mFillLineSymbol->clone() );
2300  if ( !fillLineSymbol )
2301  {
2302  return;
2303  }
2304 
2305  const QgsRenderContext& ctx = context.renderContext();
2306  //double outlinePixelWidth = lineWidth * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mLineWidthUnit, mLineWidthMapUnitScale );
2307  double outputPixelDist = distance * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceUnit, mDistanceMapUnitScale );
2309 
2310  // To get all patterns into image, we have to consider symbols size (estimateMaxBleed()).
2311  // For marker lines we have to get markers interval.
2312  double outputPixelBleed = 0;
2313  double outputPixelInterval = 0; // maximum interval
2314  for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2315  {
2316  QgsSymbolLayerV2 *layer = fillLineSymbol->symbolLayer( i );
2317  double layerBleed = layer->estimateMaxBleed();
2318  // TODO: to get real bleed we have to scale it using context and units,
2319  // unfortunately estimateMaxBleed() ignore units completely, e.g.
2320  // QgsMarkerLineSymbolLayerV2::estimateMaxBleed() is mixing marker size and
2321  // offset regardless units. This has to be fixed especially
2322  // in estimateMaxBleed(), context probably has to be used.
2323  // For now, we only support millimeters
2324  double outputPixelLayerBleed = layerBleed * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, QgsSymbolV2::MM );
2325  outputPixelBleed = qMax( outputPixelBleed, outputPixelLayerBleed );
2326 
2327  QgsMarkerLineSymbolLayerV2 *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayerV2 *>( layer );
2328  if ( markerLineLayer )
2329  {
2330  double outputPixelLayerInterval = markerLineLayer->interval() * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, markerLineLayer->intervalUnit(), markerLineLayer->intervalMapUnitScale() );
2331 
2332  // There may be multiple marker lines with different intervals.
2333  // In theory we should find the least common multiple, but that could be too
2334  // big (multiplication of intervals in the worst case).
2335  // Because patterns without small common interval would look strange, we
2336  // believe that the longest interval should usually be sufficient.
2337  outputPixelInterval = qMax( outputPixelInterval, outputPixelLayerInterval );
2338  }
2339  }
2340 
2341  if ( outputPixelInterval > 0 )
2342  {
2343  // We have to adjust marker intervals to integer pixel size to get
2344  // repeatable pattern.
2345  double intervalScale = qRound( outputPixelInterval ) / outputPixelInterval;
2346  outputPixelInterval = qRound( outputPixelInterval );
2347 
2348  for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2349  {
2350  QgsSymbolLayerV2 *layer = fillLineSymbol->symbolLayer( i );
2351 
2352  QgsMarkerLineSymbolLayerV2 *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayerV2 *>( layer );
2353  if ( markerLineLayer )
2354  {
2355  markerLineLayer->setInterval( intervalScale * markerLineLayer->interval() );
2356  }
2357  }
2358  }
2359 
2360  //create image
2361  int height, width;
2362  if ( qgsDoubleNear( lineAngle, 0 ) || qgsDoubleNear( lineAngle, 360 ) || qgsDoubleNear( lineAngle, 180 ) )
2363  {
2364  height = outputPixelDist;
2365  width = outputPixelInterval > 0 ? outputPixelInterval : height;
2366  }
2367  else if ( qgsDoubleNear( lineAngle, 90 ) || qgsDoubleNear( lineAngle, 270 ) )
2368  {
2369  width = outputPixelDist;
2370  height = outputPixelInterval > 0 ? outputPixelInterval : width;
2371  }
2372  else
2373  {
2374  height = outputPixelDist / cos( lineAngle * M_PI / 180 ); //keep perpendicular distance between lines constant
2375  width = outputPixelDist / sin( lineAngle * M_PI / 180 );
2376 
2377  // recalculate real angle and distance after rounding to pixels
2378  lineAngle = 180 * atan2(( double ) height, ( double ) width ) / M_PI;
2379  if ( lineAngle < 0 )
2380  {
2381  lineAngle += 360.;
2382  }
2383 
2384  height = qAbs( height );
2385  width = qAbs( width );
2386 
2387  outputPixelDist = height * cos( lineAngle * M_PI / 180 );
2388 
2389  // Round offset to correspond to one pixel height, otherwise lines may
2390  // be shifted on tile border if offset falls close to pixel center
2391  int offsetHeight = qRound( qAbs( outputPixelOffset / cos( lineAngle * M_PI / 180 ) ) );
2392  outputPixelOffset = offsetHeight * cos( lineAngle * M_PI / 180 );
2393  }
2394 
2395  //depending on the angle, we might need to render into a larger image and use a subset of it
2396  double dx = 0;
2397  double dy = 0;
2398 
2399  // Add buffer based on bleed but keep precisely the height/width ratio (angle)
2400  // thus we add integer multiplications of width and height covering the bleed
2401  int bufferMulti = qMax( qCeil( outputPixelBleed / width ), qCeil( outputPixelBleed / width ) );
2402 
2403  // Always buffer at least once so that center of line marker in upper right corner
2404  // does not fall outside due to representation error
2405  bufferMulti = qMax( bufferMulti, 1 );
2406 
2407  int xBuffer = width * bufferMulti;
2408  int yBuffer = height * bufferMulti;
2409  int innerWidth = width;
2410  int innerHeight = height;
2411  width += 2 * xBuffer;
2412  height += 2 * yBuffer;
2413 
2414  if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
2415  {
2416  return;
2417  }
2418 
2419  QImage patternImage( width, height, QImage::Format_ARGB32 );
2420  patternImage.fill( 0 );
2421 
2422  QPointF p1, p2, p3, p4, p5, p6;
2423  if ( qgsDoubleNear( lineAngle, 0.0 ) || qgsDoubleNear( lineAngle, 360.0 ) || qgsDoubleNear( lineAngle, 180.0 ) )
2424  {
2425  p1 = QPointF( 0, yBuffer );
2426  p2 = QPointF( width, yBuffer );
2427  p3 = QPointF( 0, yBuffer + innerHeight );
2428  p4 = QPointF( width, yBuffer + innerHeight );
2429  }
2430  else if ( qgsDoubleNear( lineAngle, 90.0 ) || qgsDoubleNear( lineAngle, 270.0 ) )
2431  {
2432  p1 = QPointF( xBuffer, height );
2433  p2 = QPointF( xBuffer, 0 );
2434  p3 = QPointF( xBuffer + innerWidth, height );
2435  p4 = QPointF( xBuffer + innerWidth, 0 );
2436  }
2437  else if ( lineAngle > 0 && lineAngle < 90 )
2438  {
2439  dx = outputPixelDist * cos(( 90 - lineAngle ) * M_PI / 180.0 );
2440  dy = outputPixelDist * sin(( 90 - lineAngle ) * M_PI / 180.0 );
2441  p1 = QPointF( 0, height );
2442  p2 = QPointF( width, 0 );
2443  p3 = QPointF( -dx, height - dy );
2444  p4 = QPointF( width - dx, -dy );
2445  p5 = QPointF( dx, height + dy );
2446  p6 = QPointF( width + dx, dy );
2447  }
2448  else if ( lineAngle > 180 && lineAngle < 270 )
2449  {
2450  dx = outputPixelDist * cos(( 90 - lineAngle ) * M_PI / 180.0 );
2451  dy = outputPixelDist * sin(( 90 - lineAngle ) * M_PI / 180.0 );
2452  p1 = QPointF( width, 0 );
2453  p2 = QPointF( 0, height );
2454  p3 = QPointF( width - dx, -dy );
2455  p4 = QPointF( -dx, height - dy );
2456  p5 = QPointF( width + dx, dy );
2457  p6 = QPointF( dx, height + dy );
2458  }
2459  else if ( lineAngle > 90 && lineAngle < 180 )
2460  {
2461  dy = outputPixelDist * cos(( 180 - lineAngle ) * M_PI / 180 );
2462  dx = outputPixelDist * sin(( 180 - lineAngle ) * M_PI / 180 );
2463  p1 = QPointF( 0, 0 );
2464  p2 = QPointF( width, height );
2465  p5 = QPointF( dx, -dy );
2466  p6 = QPointF( width + dx, height - dy );
2467  p3 = QPointF( -dx, dy );
2468  p4 = QPointF( width - dx, height + dy );
2469  }
2470  else if ( lineAngle > 270 && lineAngle < 360 )
2471  {
2472  dy = outputPixelDist * cos(( 180 - lineAngle ) * M_PI / 180 );
2473  dx = outputPixelDist * sin(( 180 - lineAngle ) * M_PI / 180 );
2474  p1 = QPointF( width, height );
2475  p2 = QPointF( 0, 0 );
2476  p5 = QPointF( width + dx, height - dy );
2477  p6 = QPointF( dx, -dy );
2478  p3 = QPointF( width - dx, height + dy );
2479  p4 = QPointF( -dx, dy );
2480  }
2481 
2482  if ( !qgsDoubleNear( mOffset, 0.0 ) ) //shift everything
2483  {
2484  QPointF tempPt;
2485  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelDist + outputPixelOffset );
2486  p3 = QPointF( tempPt.x(), tempPt.y() );
2487  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelDist + outputPixelOffset );
2488  p4 = QPointF( tempPt.x(), tempPt.y() );
2489  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p5, outputPixelDist - outputPixelOffset );
2490  p5 = QPointF( tempPt.x(), tempPt.y() );
2491  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p6, outputPixelDist - outputPixelOffset );
2492  p6 = QPointF( tempPt.x(), tempPt.y() );
2493 
2494  //update p1, p2 last
2495  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelOffset );
2496  p1 = QPointF( tempPt.x(), tempPt.y() );
2497  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelOffset );
2498  p2 = QPointF( tempPt.x(), tempPt.y() );;
2499  }
2500 
2501  QPainter p( &patternImage );
2502 
2503 #if 0
2504  // DEBUG: Draw rectangle
2505  p.setRenderHint( QPainter::Antialiasing, false ); // get true rect
2506  QPen pen( QColor( Qt::black ) );
2507  pen.setWidthF( 0.1 );
2508  pen.setCapStyle( Qt::FlatCap );
2509  p.setPen( pen );
2510 
2511  // To see this rectangle, comment buffer cut below.
2512  // Subtract 1 because not antialiased are rendered to the right/down by 1 pixel
2513  QPolygon polygon = QPolygon() << QPoint( 0, 0 ) << QPoint( width - 1, 0 ) << QPoint( width - 1, height - 1 ) << QPoint( 0, height - 1 ) << QPoint( 0, 0 ) ;
2514  p.drawPolygon( polygon );
2515 
2516  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 ) ;
2517  p.drawPolygon( polygon );
2518 #endif
2519 
2520  // Use antialiasing because without antialiasing lines are rendered to the
2521  // right and below the mathematically defined points (not symetrical)
2522  // and such tiles become useless for are filling
2523  p.setRenderHint( QPainter::Antialiasing, true );
2524 
2525  // line rendering needs context for drawing on patternImage
2526  QgsRenderContext lineRenderContext;
2527  lineRenderContext.setPainter( &p );
2528  lineRenderContext.setRasterScaleFactor( 1.0 );
2529  lineRenderContext.setScaleFactor( context.renderContext().scaleFactor() * context.renderContext().rasterScaleFactor() );
2531  lineRenderContext.setMapToPixel( mtp );
2532  lineRenderContext.setForceVectorOutput( false );
2533 
2534  fillLineSymbol->startRender( lineRenderContext, context.fields() );
2535 
2536  QVector<QPolygonF> polygons;
2537  polygons.append( QPolygonF() << p1 << p2 );
2538  polygons.append( QPolygonF() << p3 << p4 );
2539  if ( !qgsDoubleNear( lineAngle, 0 ) && !qgsDoubleNear( lineAngle, 360 ) && !qgsDoubleNear( lineAngle, 90 ) && !qgsDoubleNear( lineAngle, 180 ) && !qgsDoubleNear( lineAngle, 270 ) )
2540  {
2541  polygons.append( QPolygonF() << p5 << p6 );
2542  }
2543 
2544  foreach ( QPolygonF polygon, polygons )
2545  {
2546  fillLineSymbol->renderPolyline( polygon, context.feature(), lineRenderContext, -1, context.selected() );
2547  }
2548 
2549  fillLineSymbol->stopRender( lineRenderContext );
2550  p.end();
2551 
2552  // Cut off the buffer
2553  patternImage = patternImage.copy( xBuffer, yBuffer, patternImage.width() - 2 * xBuffer, patternImage.height() - 2 * yBuffer );
2554 
2555  //set image to mBrush
2556  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
2557  {
2558  QImage transparentImage = patternImage.copy();
2559  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
2560  brush.setTextureImage( transparentImage );
2561  }
2562  else
2563  {
2564  brush.setTextureImage( patternImage );
2565  }
2566 
2567  QTransform brushTransform;
2568  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
2569  brush.setTransform( brushTransform );
2570 
2571  delete fillLineSymbol;
2572 }
2573 
2575 {
2577 
2578  if ( mFillLineSymbol )
2579  {
2580  mFillLineSymbol->startRender( context.renderContext(), context.fields() );
2581  }
2582 
2583  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
2584 }
2585 
2587 {
2588 }
2589 
2591 {
2592  QgsStringMap map;
2593  map.insert( "lineangle", QString::number( mLineAngle ) );
2594  map.insert( "distance", QString::number( mDistance ) );
2595  map.insert( "linewidth", QString::number( mLineWidth ) );
2596  map.insert( "color", QgsSymbolLayerV2Utils::encodeColor( mColor ) );
2597  map.insert( "offset", QString::number( mOffset ) );
2598  map.insert( "distance_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceUnit ) );
2599  map.insert( "line_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mLineWidthUnit ) );
2600  map.insert( "offset_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit ) );
2601  map.insert( "distance_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceMapUnitScale ) );
2602  map.insert( "line_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mLineWidthMapUnitScale ) );
2603  map.insert( "offset_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale ) );
2604  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
2605  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
2607  return map;
2608 }
2609 
2611 {
2613  if ( mFillLineSymbol )
2614  {
2615  clonedLayer->setSubSymbol( mFillLineSymbol->clone() );
2616  }
2617  return clonedLayer;
2618 }
2619 
2620 void QgsLinePatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
2621 {
2622  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
2623  if ( !props.value( "uom", "" ).isEmpty() )
2624  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
2625  element.appendChild( symbolizerElem );
2626 
2627  // <Geometry>
2628  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
2629 
2630  QDomElement fillElem = doc.createElement( "se:Fill" );
2631  symbolizerElem.appendChild( fillElem );
2632 
2633  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
2634  fillElem.appendChild( graphicFillElem );
2635 
2636  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2637  graphicFillElem.appendChild( graphicElem );
2638 
2639  //line properties must be inside the graphic definition
2640  QColor lineColor = mFillLineSymbol ? mFillLineSymbol->color() : QColor();
2641  double lineWidth = mFillLineSymbol ? mFillLineSymbol->width() : 0.0;
2642  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), lineColor, Qt::SolidLine, lineWidth, mDistance );
2643 
2644  // <Rotation>
2645  QString angleFunc;
2646  bool ok;
2647  double angle = props.value( "angle", "0" ).toDouble( &ok );
2648  if ( !ok )
2649  {
2650  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mLineAngle );
2651  }
2652  else if ( angle + mLineAngle != 0 )
2653  {
2654  angleFunc = QString::number( angle + mLineAngle );
2655  }
2656  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2657 
2658  // <se:Displacement>
2659  QPointF lineOffset( sin( mLineAngle ) * mOffset, cos( mLineAngle ) * mOffset );
2660  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, lineOffset );
2661 }
2662 
2664 {
2665  QString featureStyle;
2666  featureStyle.append( "Brush(" );
2667  featureStyle.append( QString( "fc:%1" ).arg( mColor.name() ) );
2668  featureStyle.append( QString( ",bc:%1" ).arg( "#00000000" ) ); //transparent background
2669  featureStyle.append( ",id:\"ogr-brush-2\"" );
2670  featureStyle.append( QString( ",a:%1" ).arg( mLineAngle ) );
2671  featureStyle.append( QString( ",s:%1" ).arg( mLineWidth * widthScaleFactor ) );
2672  featureStyle.append( ",dx:0mm" );
2673  featureStyle.append( QString( ",dy:%1mm" ).arg( mDistance * widthScaleFactor ) );
2674  featureStyle.append( ")" );
2675  return featureStyle;
2676 }
2677 
2679 {
2680  QgsExpression* lineAngleExpression = expression( "lineangle" );
2681  QgsExpression* distanceExpression = expression( "distance" );
2682  QgsExpression* lineWidthExpression = expression( "linewidth" );
2683  QgsExpression* colorExpression = expression( "color" );
2684  if ( !lineAngleExpression && !distanceExpression && !lineWidthExpression && !colorExpression )
2685  {
2686  return; //no data defined settings
2687  }
2688 
2689  double lineAngle = mLineAngle;
2690  if ( lineAngleExpression )
2691  {
2692  lineAngle = lineAngleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2693  }
2694  double distance = mDistance;
2695  if ( distanceExpression )
2696  {
2697  distance = distanceExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2698  }
2699  double lineWidth = mLineWidth;
2700  if ( lineWidthExpression )
2701  {
2702  lineWidth = lineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2703  }
2704  QColor color = mColor;
2705  if ( colorExpression )
2706  {
2707  color = QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
2708  }
2709  applyPattern( context, mBrush, lineAngle, distance, lineWidth, color );
2710 }
2711 
2713 {
2714  QgsDebugMsg( "Entered." );
2715 
2716  QString name;
2717  QColor fillColor, lineColor;
2718  double size, lineWidth;
2719  Qt::PenStyle lineStyle;
2720 
2721  QDomElement fillElem = element.firstChildElement( "Fill" );
2722  if ( fillElem.isNull() )
2723  return NULL;
2724 
2725  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
2726  if ( graphicFillElem.isNull() )
2727  return NULL;
2728 
2729  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
2730  if ( graphicElem.isNull() )
2731  return NULL;
2732 
2733  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, lineColor, lineStyle, lineWidth, size ) )
2734  return NULL;
2735 
2736  if ( name != "horline" )
2737  return NULL;
2738 
2739  double angle = 0.0;
2740  QString angleFunc;
2741  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2742  {
2743  bool ok;
2744  double d = angleFunc.toDouble( &ok );
2745  if ( ok )
2746  angle = d;
2747  }
2748 
2749  double offset = 0.0;
2750  QPointF vectOffset;
2751  if ( QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, vectOffset ) )
2752  {
2753  offset = sqrt( pow( vectOffset.x(), 2 ) + pow( vectOffset.y(), 2 ) );
2754  }
2755 
2757  sl->setColor( lineColor );
2758  sl->setLineWidth( lineWidth );
2759  sl->setLineAngle( angle );
2760  sl->setOffset( offset );
2761  sl->setDistance( size );
2762 
2763  // try to get the outline
2764  QDomElement strokeElem = element.firstChildElement( "Stroke" );
2765  if ( !strokeElem.isNull() )
2766  {
2768  if ( l )
2769  {
2770  QgsSymbolLayerV2List layers;
2771  layers.append( l );
2772  sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
2773  }
2774  }
2775 
2776  return sl;
2777 }
2778 
2779 
2781 
2783  mDistanceXUnit( QgsSymbolV2::MM ), mDistanceY( 15 ), mDistanceYUnit( QgsSymbolV2::MM ), mDisplacementX( 0 ), mDisplacementXUnit( QgsSymbolV2::MM ),
2784  mDisplacementY( 0 ), mDisplacementYUnit( QgsSymbolV2::MM )
2785 {
2786  mDistanceX = 15;
2787  mDistanceY = 15;
2788  mDisplacementX = 0;
2789  mDisplacementY = 0;
2791  QgsImageFillSymbolLayer::setSubSymbol( 0 ); //no outline
2792 }
2793 
2795 {
2796 }
2797 
2799 {
2801  mDistanceXUnit = unit;
2802  mDistanceYUnit = unit;
2803  mDisplacementXUnit = unit;
2804  mDisplacementYUnit = unit;
2805 }
2806 
2808 {
2810  if ( mDistanceXUnit != unit || mDistanceYUnit != unit || mDisplacementXUnit != unit || mDisplacementYUnit != unit )
2811  {
2812  return QgsSymbolV2::Mixed;
2813  }
2814  return unit;
2815 }
2816 
2818 {
2820  mDistanceXMapUnitScale = scale;
2821  mDistanceYMapUnitScale = scale;
2824 }
2825 
2827 {
2832  {
2833  return mDistanceXMapUnitScale;
2834  }
2835  return QgsMapUnitScale();
2836 }
2837 
2839 {
2841  if ( properties.contains( "distance_x" ) )
2842  {
2843  layer->setDistanceX( properties["distance_x"].toDouble() );
2844  }
2845  if ( properties.contains( "distance_y" ) )
2846  {
2847  layer->setDistanceY( properties["distance_y"].toDouble() );
2848  }
2849  if ( properties.contains( "displacement_x" ) )
2850  {
2851  layer->setDisplacementX( properties["displacement_x"].toDouble() );
2852  }
2853  if ( properties.contains( "displacement_y" ) )
2854  {
2855  layer->setDisplacementY( properties["displacement_y"].toDouble() );
2856  }
2857 
2858  if ( properties.contains( "distance_x_unit" ) )
2859  {
2860  layer->setDistanceXUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_x_unit"] ) );
2861  }
2862  if ( properties.contains( "distance_x_map_unit_scale" ) )
2863  {
2864  layer->setDistanceXMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_x_map_unit_scale"] ) );
2865  }
2866  if ( properties.contains( "distance_y_unit" ) )
2867  {
2868  layer->setDistanceYUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_y_unit"] ) );
2869  }
2870  if ( properties.contains( "distance_y_map_unit_scale" ) )
2871  {
2872  layer->setDistanceYMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_y_map_unit_scale"] ) );
2873  }
2874  if ( properties.contains( "displacement_x_unit" ) )
2875  {
2876  layer->setDisplacementXUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["displacement_x_unit"] ) );
2877  }
2878  if ( properties.contains( "displacement_x_map_unit_scale" ) )
2879  {
2880  layer->setDisplacementXMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["displacement_x_map_unit_scale"] ) );
2881  }
2882  if ( properties.contains( "displacement_y_unit" ) )
2883  {
2884  layer->setDisplacementYUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["displacement_y_unit"] ) );
2885  }
2886  if ( properties.contains( "displacement_y_map_unit_scale" ) )
2887  {
2888  layer->setDisplacementYMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["displacement_y_map_unit_scale"] ) );
2889  }
2890  if ( properties.contains( "outline_width_unit" ) )
2891  {
2892  layer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
2893  }
2894  if ( properties.contains( "outline_width_map_unit_scale" ) )
2895  {
2896  layer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
2897  }
2898 
2899  //data defined properties
2900  if ( properties.contains( "distance_x_expression" ) )
2901  {
2902  layer->setDataDefinedProperty( "distance_x", properties["distance_x_expression"] );
2903  }
2904  if ( properties.contains( "distance_y_expression" ) )
2905  {
2906  layer->setDataDefinedProperty( "distance_y", properties["distance_y_expression"] );
2907  }
2908  if ( properties.contains( "displacement_x_expression" ) )
2909  {
2910  layer->setDataDefinedProperty( "displacement_x", properties["displacement_x_expression"] );
2911  }
2912  if ( properties.contains( "displacement_y_expression" ) )
2913  {
2914  layer->setDataDefinedProperty( "displacement_y", properties["displacement_y_expression"] );
2915  }
2916  return layer;
2917 }
2918 
2920 {
2921  return "PointPatternFill";
2922 }
2923 
2924 void QgsPointPatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double distanceX, double distanceY,
2925  double displacementX, double displacementY )
2926 {
2927  //render 3 rows and columns in one go to easily incorporate displacement
2928  const QgsRenderContext& ctx = context.renderContext();
2929  double width = distanceX * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceXUnit, mDistanceXMapUnitScale ) * 2.0;
2931 
2932  if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
2933  {
2934  QImage img;
2935  brush.setTextureImage( img );
2936  return;
2937  }
2938 
2939  QImage patternImage( width, height, QImage::Format_ARGB32 );
2940  patternImage.fill( 0 );
2941 
2942  if ( mMarkerSymbol )
2943  {
2944  QPainter p( &patternImage );
2945 
2946  //marker rendering needs context for drawing on patternImage
2947  QgsRenderContext pointRenderContext;
2948  pointRenderContext.setRendererScale( context.renderContext().rendererScale() );
2949  pointRenderContext.setPainter( &p );
2950  pointRenderContext.setRasterScaleFactor( 1.0 );
2951  pointRenderContext.setScaleFactor( context.renderContext().scaleFactor() * context.renderContext().rasterScaleFactor() );
2953  pointRenderContext.setMapToPixel( mtp );
2954  pointRenderContext.setForceVectorOutput( false );
2955 
2956  mMarkerSymbol->startRender( pointRenderContext, context.fields() );
2957 
2958  //render corner points
2959  mMarkerSymbol->renderPoint( QPointF( 0, 0 ), context.feature(), pointRenderContext );
2960  mMarkerSymbol->renderPoint( QPointF( width, 0 ), context.feature(), pointRenderContext );
2961  mMarkerSymbol->renderPoint( QPointF( 0, height ), context.feature(), pointRenderContext );
2962  mMarkerSymbol->renderPoint( QPointF( width, height ), context.feature(), pointRenderContext );
2963 
2964  //render displaced points
2965  double displacementPixelX = displacementX * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDisplacementXUnit, mDisplacementXMapUnitScale );
2966  double displacementPixelY = displacementY * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDisplacementYUnit, mDisplacementYMapUnitScale );
2967  mMarkerSymbol->renderPoint( QPointF( width / 2.0, -displacementPixelY ), context.feature(), pointRenderContext );
2968  mMarkerSymbol->renderPoint( QPointF( displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
2969  mMarkerSymbol->renderPoint( QPointF( width / 2.0 + displacementPixelX, height / 2.0 - displacementPixelY ), context.feature(), pointRenderContext );
2970  mMarkerSymbol->renderPoint( QPointF( width + displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
2971  mMarkerSymbol->renderPoint( QPointF( width / 2.0, height - displacementPixelY ), context.feature(), pointRenderContext );
2972 
2973  mMarkerSymbol->stopRender( pointRenderContext );
2974  }
2975 
2976  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
2977  {
2978  QImage transparentImage = patternImage.copy();
2979  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
2980  brush.setTextureImage( transparentImage );
2981  }
2982  else
2983  {
2984  brush.setTextureImage( patternImage );
2985  }
2986  QTransform brushTransform;
2987  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
2988  brush.setTransform( brushTransform );
2989 }
2990 
2992 {
2994 
2995  if ( mOutline )
2996  {
2997  mOutline->startRender( context.renderContext(), context.fields() );
2998  }
2999  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
3000 }
3001 
3003 {
3004  if ( mOutline )
3005  {
3006  mOutline->stopRender( context.renderContext() );
3007  }
3008 }
3009 
3011 {
3012  QgsStringMap map;
3013  map.insert( "distance_x", QString::number( mDistanceX ) );
3014  map.insert( "distance_y", QString::number( mDistanceY ) );
3015  map.insert( "displacement_x", QString::number( mDisplacementX ) );
3016  map.insert( "displacement_y", QString::number( mDisplacementY ) );
3017  map.insert( "distance_x_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceXUnit ) );
3018  map.insert( "distance_y_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceYUnit ) );
3019  map.insert( "displacement_x_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementXUnit ) );
3020  map.insert( "displacement_y_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementYUnit ) );
3021  map.insert( "distance_x_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceXMapUnitScale ) );
3022  map.insert( "distance_y_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceYMapUnitScale ) );
3023  map.insert( "displacement_x_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDisplacementXMapUnitScale ) );
3024  map.insert( "displacement_y_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDisplacementYMapUnitScale ) );
3025  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
3026  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
3028  return map;
3029 }
3030 
3032 {
3034  if ( mMarkerSymbol )
3035  {
3036  clonedLayer->setSubSymbol( mMarkerSymbol->clone() );
3037  }
3038  return clonedLayer;
3039 }
3040 
3041 void QgsPointPatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
3042 {
3043  for ( int i = 0; i < mMarkerSymbol->symbolLayerCount(); i++ )
3044  {
3045  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
3046  if ( !props.value( "uom", "" ).isEmpty() )
3047  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
3048  element.appendChild( symbolizerElem );
3049 
3050  // <Geometry>
3051  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
3052 
3053  QDomElement fillElem = doc.createElement( "se:Fill" );
3054  symbolizerElem.appendChild( fillElem );
3055 
3056  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
3057  fillElem.appendChild( graphicFillElem );
3058 
3059  // store distanceX, distanceY, displacementX, displacementY in a <VendorOption>
3060  QString dist = QgsSymbolLayerV2Utils::encodePoint( QPointF( mDistanceX, mDistanceY ) );
3061  QDomElement distanceElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "distance", dist );
3062  symbolizerElem.appendChild( distanceElem );
3063 
3065  QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
3066  if ( !markerLayer )
3067  {
3068  QString errorMsg = QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() );
3069  graphicFillElem.appendChild( doc.createComment( errorMsg ) );
3070  }
3071  else
3072  {
3073  markerLayer->writeSldMarker( doc, graphicFillElem, props );
3074  }
3075  }
3076 }
3077 
3079 {
3080  Q_UNUSED( element );
3081  return NULL;
3082 }
3083 
3085 {
3086  if ( !symbol )
3087  {
3088  return false;
3089  }
3090 
3091  if ( symbol->type() == QgsSymbolV2::Marker )
3092  {
3093  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( symbol );
3094  delete mMarkerSymbol;
3095  mMarkerSymbol = markerSymbol;
3096  }
3097  return true;
3098 }
3099 
3101 {
3102  QgsExpression* distanceXExpression = expression( "distance_x" );
3103  QgsExpression* distanceYExpression = expression( "distance_y" );
3104  QgsExpression* displacementXExpression = expression( "displacement_x" );
3105  QgsExpression* displacementYExpression = expression( "displacement_y" );
3106 
3107 #if 0
3108  // TODO: enable but check also if mMarkerSymbol has data defined properties
3109  if ( !distanceXExpression && !distanceYExpression && !displacementXExpression && !displacementYExpression )
3110  {
3111  return;
3112  }
3113 #endif
3114 
3115  double distanceX = mDistanceX;
3116  if ( distanceXExpression )
3117  {
3118  distanceX = distanceXExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
3119  }
3120  double distanceY = mDistanceY;
3121  if ( distanceYExpression )
3122  {
3123  distanceY = distanceYExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
3124  }
3125  double displacementX = mDisplacementX;
3126  if ( displacementXExpression )
3127  {
3128  displacementX = displacementXExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
3129  }
3130  double displacementY = mDisplacementY;
3131  if ( displacementYExpression )
3132  {
3133  displacementY = displacementYExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
3134  }
3135  applyPattern( context, mBrush, distanceX, distanceY, displacementX, displacementY );
3136 }
3137 
3139 {
3140  return 0;
3141 }
3142 
3144 {
3145  QSet<QString> attributes = QgsSymbolLayerV2::usedAttributes();
3146 
3147  if ( mMarkerSymbol )
3148  attributes.unite( mMarkerSymbol->usedAttributes() );
3149 
3150  return attributes;
3151 }
3152 
3154 
3155 
3156 QgsCentroidFillSymbolLayerV2::QgsCentroidFillSymbolLayerV2(): mMarker( NULL ), mPointOnSurface( false )
3157 {
3159 }
3160 
3162 {
3163  delete mMarker;
3164 }
3165 
3167 {
3169 
3170  if ( properties.contains( "point_on_surface" ) )
3171  sl->setPointOnSurface( properties["point_on_surface"].toInt() != 0 );
3172 
3173  return sl;
3174 }
3175 
3177 {
3178  return "CentroidFill";
3179 }
3180 
3181 void QgsCentroidFillSymbolLayerV2::setColor( const QColor& color )
3182 {
3183  mMarker->setColor( color );
3184  mColor = color;
3185 }
3186 
3188 {
3189  mMarker->setAlpha( context.alpha() );
3190  mMarker->startRender( context.renderContext(), context.fields() );
3191 }
3192 
3194 {
3195  mMarker->stopRender( context.renderContext() );
3196 }
3197 
3198 void QgsCentroidFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
3199 {
3200  Q_UNUSED( rings );
3201 
3203  mMarker->renderPoint( centroid, context.feature(), context.renderContext(), -1, context.selected() );
3204 }
3205 
3207 {
3208  QgsStringMap map;
3209  map["point_on_surface"] = QString::number( mPointOnSurface );
3210  return map;
3211 }
3212 
3214 {
3216  x->mAngle = mAngle;
3217  x->mColor = mColor;
3218  x->setSubSymbol( mMarker->clone() );
3220  return x;
3221 }
3222 
3223 void QgsCentroidFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
3224 {
3225  // SLD 1.0 specs says: "if a line, polygon, or raster geometry is
3226  // used with PointSymbolizer, then the semantic is to use the centroid
3227  // of the geometry, or any similar representative point.
3228  mMarker->toSld( doc, element, props );
3229 }
3230 
3232 {
3233  QgsDebugMsg( "Entered." );
3234 
3236  if ( !l )
3237  return NULL;
3238 
3239  QgsSymbolLayerV2List layers;
3240  layers.append( l );
3241  QgsMarkerSymbolV2 *marker = new QgsMarkerSymbolV2( layers );
3242 
3244  sl->setSubSymbol( marker );
3245  return sl;
3246 }
3247 
3248 
3250 {
3251  return mMarker;
3252 }
3253 
3255 {
3256  if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
3257  {
3258  delete symbol;
3259  return false;
3260  }
3261 
3262  delete mMarker;
3263  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
3264  mColor = mMarker->color();
3265  return true;
3266 }
3267 
3269 {
3270  QSet<QString> attributes;
3271 
3272  attributes.unite( QgsSymbolLayerV2::usedAttributes() );
3273 
3274  if ( mMarker )
3275  attributes.unite( mMarker->usedAttributes() );
3276 
3277  return attributes;
3278 }
3279 
3281 {
3282  if ( mMarker )
3283  {
3284  mMarker->setOutputUnit( unit );
3285  }
3286 }
3287 
3289 {
3290  if ( mMarker )
3291  {
3292  return mMarker->outputUnit();
3293  }
3294  return QgsSymbolV2::Mixed; //mOutputUnit;
3295 }
3296 
3298 {
3299  if ( mMarker )
3300  {
3301  mMarker->setMapUnitScale( scale );
3302  }
3303 }
3304 
3306 {
3307  if ( mMarker )
3308  {
3309  return mMarker->mapUnitScale();
3310  }
3311  return QgsMapUnitScale();
3312 }
3313 
3314 
virtual QSet< QString > usedAttributes() const
QgsMapUnitScale mSvgOutlineWidthMapUnitScale
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
void setBorderWidthMapUnitScale(const QgsMapUnitScale &scale)
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:89
static Qt::BrushStyle decodeBrushStyle(QString str)
void setForceVectorOutput(bool force)
Added in QGIS v1.5.
QgsSymbolV2::OutputUnit intervalUnit() const
QgsSymbolV2::OutputUnit patternWidthUnit() const
void setDistanceUnit(QgsSymbolV2::OutputUnit unit)
Sets the unit for the maximum distance to shade inside of the shape from the polygon's boundary...
const QgsMapUnitScale & patternWidthMapUnitScale() const
#define DEFAULT_SIMPLEFILL_BORDERCOLOR
double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
double outlineWidth
Definition: qgssvgcache.cpp:78
double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
void setReferencePoint1(QPointF referencePoint)
Starting point of gradient fill, in the range [0,0] - [1,1].
QgsSymbolV2::OutputUnit mSvgOutlineWidthUnit
void setReferencePoint2IsCentroid(bool isCentroid)
Sets the end point of the gradient to be the feature centroid.
void setSvgOutlineWidth(double w)
static void multiplyImageOpacity(QImage *image, qreal alpha)
Multiplies opacity of image pixel values with a (global) transparency value.
QgsStringMap properties() const
void stopRender(QgsSymbolV2RenderContext &context)
void startRender(QgsSymbolV2RenderContext &context)
void setAngle(double angle)
Rotation angle for gradient fill.
QString ogrFeatureStyleWidth(double widthScaleFactor) const
void applyDataDefinedSettings(const QgsSymbolV2RenderContext &context)
double ignoreRings() const
Returns whether the shapeburst fill is set to ignore polygon interior rings.
void setMapUnitScale(const QgsMapUnitScale &scale)
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
QgsSymbolV2::OutputUnit mLineWidthUnit
virtual QString type() const =0
static Q_DECL_DEPRECATED bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &borderColor, double &borderWidth, double &size)
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
virtual Qt::PenStyle dxfPenStyle() const
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
void setSvgFillColor(const QColor &c)
void setPatternWidthMapUnitScale(const QgsMapUnitScale &scale)
QgsSymbolV2::OutputUnit outputUnit() const
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setDistanceYUnit(QgsSymbolV2::OutputUnit unit)
QString svgFilePath() const
virtual void applyDataDefinedSettings(const QgsSymbolV2RenderContext &context)
SymbolType type() const
Definition: qgssymbolv2.h:79
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
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&.
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
QColor selectionColor() const
Added in QGIS v2.0.
QSet< QString > usedAttributes() const
void setOutlineWidthMapUnitScale(const QgsMapUnitScale &scale)
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
virtual QSet< QString > usedAttributes() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
double dxfWidth(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const
bool setSubSymbol(QgsSymbolV2 *symbol)
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
Base class for polygon renderers generating texture images.
QgsMapUnitScale mPatternWidthMapUnitScale
GradientCoordinateMode mCoordinateMode
static void createRotationElement(QDomDocument &doc, QDomElement &element, QString rotationFunc)
double rendererScale() const
void setPointOnSurface(bool pointOnSurface)
QgsSymbolV2::OutputUnit outputUnit() const
QgsSymbolV2::OutputUnit svgOutlineWidthUnit() const
double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
void setRendererScale(double scale)
void setMapUnitScale(const QgsMapUnitScale &scale)
static QString ogrFeatureStyleBrush(const QColor &fillColr)
Create ogr feature style string for brush.
void applyDataDefinedSymbology(QgsSymbolV2RenderContext &context, QColor &color, QColor &color2, int &blurRadius, bool &useWholeShape, double &maxDistance, bool &ignoreRings)
void setDistanceMapUnitScale(const QgsMapUnitScale &scale)
static void fillToSld(QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, QColor color=QColor())
QgsSymbolLayerV2 * clone() const
QgsSymbolV2::OutputUnit outputUnit() const
const QgsMapUnitScale & intervalMapUnitScale() const
void distanceTransform1d(double *f, int n, int *v, double *z, double *d)
QgsMapUnitScale mapUnitScale() const
Definition: qgssymbolv2.cpp:84
QgsMapUnitScale mOutlineWidthMapUnitScale
static QPointF decodePoint(QString str)
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
static bool externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)
QgsSymbolV2::OutputUnit outputUnit() const
virtual QgsStringMap properties() const =0
static QDomElement createVendorOptionElement(QDomDocument &doc, QString name, QString value)
GradientCoordinateMode coordinateMode() const
Coordinate mode for gradient.
static QColor decodeColor(QString str)
QgsSymbolV2::OutputUnit mDisplacementXUnit
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
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.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
double useWholeShape() const
Returns whether the shapeburst fill is set to cover the entire shape.
double scaleFactor() const
void stopRender(QgsSymbolV2RenderContext &context)
virtual QColor dxfColor(const QgsSymbolV2RenderContext &context) const
QgsMapUnitScale mapUnitScale() const
double mDistance
Distance (in mm or map units) between lines.
QColor fillColor() const
Get fill color.
QgsSymbolLayerV2 * clone() const
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setSvgOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
double mLineAngle
Vector line angle in degrees (0 = horizontal, counterclockwise)
virtual QColor fillColor() const
Get fill color.
void applyDataDefinedSymbology(QgsSymbolV2RenderContext &context, const QPolygonF &points)
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
QgsVectorColorRampV2 * mGradientRamp
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
void startRender(QgsSymbolV2RenderContext &context)
QgsSymbolLayerV2 * clone() const
void setColorRamp(QgsVectorColorRampV2 *ramp)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:324
QgsSymbolV2::OutputUnit outputUnit() const
static double pixelSizeScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns scale factor painter units -> pixel dimensions.
void setWidth(double width)
void setMapUnitScale(const QgsMapUnitScale &scale)
virtual double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
void setSvgOutlineColor(const QColor &c)
static QString encodeColor(QColor color)
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
void setInterval(double interval)
void applyPattern(const QgsSymbolV2RenderContext &context, QBrush &brush, double lineAngle, double distance, double lineWidth, const QColor &color)
Applies the svg pattern to the brush.
QgsSymbolV2::OutputUnit outputUnit() const
void setDistanceUnit(QgsSymbolV2::OutputUnit unit)
virtual QgsExpression * expression(const QString &property) const
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasOutlineParam, QColor &defaultOutlineColor, bool &hasOutlineWidthParam, double &defaultOutlineWidth) const
Tests if an svg file contains parameters for fill, outline color, outline width.
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:179
static QgsSvgCache * instance()
Definition: qgssvgcache.cpp:84
static QString encodePenStyle(Qt::PenStyle style)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
bool setSubSymbol(QgsSymbolV2 *symbol)
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.
QgsSymbolV2::OutputUnit mDisplacementYUnit
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:33
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
void setColor(const QColor &color)
static QString symbolPathToName(QString path)
Get symbols's name from its path.
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
void setMapUnitScale(const QgsMapUnitScale &scale)
static QgsSymbolLayerV2 * createMarkerLayerFromSld(QDomElement &element)
#define DEFAULT_SIMPLEFILL_BORDERSTYLE
double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
void setOffset(QPointF offset)
Sets the offset for the shapeburst fill.
QByteArray mSvgData
SVG data.
Qt::PenStyle borderStyle() const
void setOutlineWidthUnit(QgsSymbolV2::OutputUnit unit)
QgsLineSymbolV2 * mOutline
Custom outline.
#define DEFAULT_SIMPLEFILL_STYLE
static QString ogrFeatureStylePen(double width, double mmScaleFactor, double mapUnitsScaleFactor, const QColor &c, Qt::PenJoinStyle joinStyle=Qt::MiterJoin, Qt::PenCapStyle capStyle=Qt::FlatCap, double offset=0.0, const QVector< qreal > *dashPattern=0)
Create ogr feature style string for pen.
static bool fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)
void setScaleFactor(double factor)
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
const QgsFeature * feature() const
Current feature being rendered - may be null.
Definition: qgssymbolv2.h:193
QgsSymbolLayerV2 * clone() const
double mOffset
Offset perpendicular to line direction.
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.
QColor dxfColor(const QgsSymbolV2RenderContext &context) const
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
static Qt::PenStyle decodePenStyle(QString str)
QgsVectorColorRampV2 * mTwoColorGradientRamp
void setLineWidthUnit(QgsSymbolV2::OutputUnit unit)
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
virtual QgsVectorColorRampV2 * clone() const =0
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void applyPattern(QBrush &brush, const QString &svgFilePath, double patternWidth, QgsSymbolV2::OutputUnit patternWidthUnit, const QColor &svgFillColor, const QColor &svgOutlineColor, double svgOutlineWidth, QgsSymbolV2::OutputUnit svgOutlineWidthUnit, const QgsSymbolV2RenderContext &context, const QgsMapUnitScale &patternWidthMapUnitScale, const QgsMapUnitScale &svgOutlineWidthMapUnitScale)
Applies the svg pattern to the brush.
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
virtual QSet< QString > usedAttributes() 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
void applyGradient(const QgsSymbolV2RenderContext &context, QBrush &brush, const QColor &color, const QColor &color2, const GradientColorType &gradientColorType, QgsVectorColorRampV2 *gradientRamp, const GradientType &gradientType, const GradientCoordinateMode &coordinateMode, const GradientSpread &gradientSpread, const QPointF &referencePoint1, const QPointF &referencePoint2, const double angle)
Applies the gradient to a brush.
void setMapUnitScale(const QgsMapUnitScale &scale)
void dtArrayToQImage(double *array, QImage *im, QgsVectorColorRampV2 *ramp, double layerAlpha=1, bool useWholeShape=true, int maxPixelDistance=0)
static QString symbolNameToPath(QString name)
Get symbol's path from its name.
QgsMapUnitScale mapUnitScale() const
#define M_PI
void setMapUnitScale(const QgsMapUnitScale &scale)
QgsSVGFillSymbolLayer(const QString &svgFilePath="", double width=20, double rotation=0.0)
void setDistanceYMapUnitScale(const QgsMapUnitScale &scale)
void stopRender(QgsSymbolV2RenderContext &context)
int symbolLayerCount()
Definition: qgssymbolv2.h:85
QgsSymbolV2::OutputUnit mOffsetUnit
void setPainter(QPainter *p)
double rasterScaleFactor() const
ShapeburstColorType colorType() const
Returns the color mode used for the shapeburst fill.
static const bool selectFillStyle
double mapUnitsPerPixel() const
Return current map units per pixel.
virtual QColor color() const
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setMapUnitScale(const QgsMapUnitScale &scale)
QgsMapUnitScale mapUnitScale() const
void setDisplacementXUnit(QgsSymbolV2::OutputUnit unit)
QgsSymbolV2::OutputUnit mOffsetUnit
void renderPoint(const QPointF &point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
virtual void prepareExpressions(const QgsFields *fields, double scale=-1.0)
QgsSymbolLayerV2 * clone() const
void setMapUnitScale(const QgsMapUnitScale &scale)
void setBorderWidthUnit(QgsSymbolV2::OutputUnit unit)
void startRender(QgsSymbolV2RenderContext &context)
void setLineWidthMapUnitScale(const QgsMapUnitScale &scale)
void setDisplacementXMapUnitScale(const QgsMapUnitScale &scale)
QgsSymbolV2::OutputUnit mOffsetUnit
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
QgsSymbolV2::OutputUnit mOutlineWidthUnit
double mOutlineWidth
Outline width.
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
double rasterScaleFactor
Definition: qgssvgcache.cpp:80
void setDistanceXUnit(QgsSymbolV2::OutputUnit unit)
double mLineWidth
Line width (in mm or map units)
QgsVectorColorRampV2 * mGradientRamp
QColor svgOutlineColor() const
void startRender(QgsSymbolV2RenderContext &context)
GradientSpread gradientSpread() const
Gradient spread mode.
static QgsSymbolLayerV2 * createLineLayerFromSld(QDomElement &element)
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
QColor color2() const
Returns the color used for the endpoint of the shapeburst fill.
virtual bool setSubSymbol(QgsSymbolV2 *symbol)
void setOffset(QPointF offset)
Offset for gradient fill.
virtual QString layerType() const =0
void stopRender(QgsSymbolV2RenderContext &context)
double estimateMaxBleed() const
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
virtual QgsSymbolV2 * clone() const
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
void setOffset(QPointF offset)
void applyPattern(const QgsSymbolV2RenderContext &context, QBrush &brush, double distanceX, double distanceY, double displacementX, double displacementY)
A class for svg fill patterns.
void stopRender(QgsSymbolV2RenderContext &context)
bool setSubSymbol(QgsSymbolV2 *symbol)
static void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, QColor color, double width=-1, const Qt::PenJoinStyle *penJoinStyle=0, const Qt::PenCapStyle *penCapStyle=0, const QVector< qreal > *customDashPattern=0, double dashOffset=0.0)
double widthScaleFactor
Definition: qgssvgcache.cpp:79
static void createGeometryElement(QDomDocument &doc, QDomElement &element, QString geomFunc)
Contains information about the context of a rendering operation.
QColor color2() const
Color for endpoint of gradient, only used if the gradient color type is set to SimpleTwoColor.
QPointF rotateReferencePoint(const QPointF &refPoint, double angle)
rotates a reference point by a specified angle around the point (0.5, 0.5)
QPainter * painter()
void stopRender(QgsRenderContext &context)
void setColor(const QColor &color)
void storeViewBox()
Helper function that gets the view box from the byte array.
QgsMapUnitScale mBorderWidthMapUnitScale
static QString encodeBrushStyle(Qt::BrushStyle style)
QgsMapUnitScale mapUnitScale() const
static double lineWidthScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns the line width scale factor depending on the unit and the paint device.
void startRender(QgsSymbolV2RenderContext &context)
QgsSymbolV2::OutputUnit mDistanceXUnit
QgsMapUnitScale mapUnitScale() const
QgsStringMap properties() const
QgsGradientFillSymbolLayerV2(QColor color=DEFAULT_SIMPLEFILL_COLOR, QColor color2=Qt::white, GradientColorType gradientColorType=SimpleTwoColor, GradientType gradientType=Linear, GradientCoordinateMode coordinateMode=Feature, GradientSpread gradientSpread=Pad)
void setDisplacementYUnit(QgsSymbolV2::OutputUnit unit)
virtual QgsSymbolV2 * clone() const
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
QList< QgsSymbolLayerV2 * > QgsSymbolLayerV2List
Definition: qgssymbolv2.h:39
void setSvgFilePath(const QString &svgPath)
QgsRenderContext & renderContext()
Definition: qgssymbolv2.h:168
QgsSymbolV2::OutputUnit mBorderWidthUnit
Qt::PenJoinStyle penJoinStyle() const
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void applyDataDefinedSettings(const QgsSymbolV2RenderContext &context)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setColorRamp(QgsVectorColorRampV2 *ramp)
Sets the color ramp used to draw the shapeburst fill.
void setMapToPixel(const QgsMapToPixel &mtp)
QgsSymbolV2::OutputUnit outputUnit() const
Definition: qgssymbolv2.cpp:63
static void externalGraphicToSld(QDomDocument &doc, QDomElement &element, QString path, QString mime, QColor color, double size=-1)
QgsSymbolV2::OutputUnit mDistanceUnit
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
#define INF
QgsMapUnitScale mapUnitScale() const
void setDisplacementYMapUnitScale(const QgsMapUnitScale &scale)
static Q_DECL_DEPRECATED void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, QString name, QColor color, QColor borderColor=QColor(), double borderWidth=-1, double size=-1)
const QgsMapToPixel & mapToPixel() const
void startRender(QgsSymbolV2RenderContext &context)
void distanceTransform2d(double *im, int width, int height)
const QgsFields * fields() const
Fields of the layer.
Definition: qgssymbolv2.h:199
QgsSimpleFillSymbolLayerV2(QColor color=DEFAULT_SIMPLEFILL_COLOR, Qt::BrushStyle style=DEFAULT_SIMPLEFILL_STYLE, QColor borderColor=DEFAULT_SIMPLEFILL_BORDERCOLOR, Qt::PenStyle borderStyle=DEFAULT_SIMPLEFILL_BORDERSTYLE, double borderWidth=DEFAULT_SIMPLEFILL_BORDERWIDTH, Qt::PenJoinStyle penJoinStyle=DEFAULT_SIMPLEFILL_JOINSTYLE)
static Qt::PenJoinStyle decodePenJoinStyle(QString str)
QgsMapUnitScale mapUnitScale() const
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
GradientType gradientType() const
Type of gradient, eg linear or radial.
bool selected() const
Definition: qgssymbolv2.h:183
QgsShapeburstFillSymbolLayerV2(QColor color=DEFAULT_SIMPLEFILL_COLOR, QColor color2=Qt::white, ShapeburstColorType colorType=SimpleTwoColor, int blurRadius=0, bool useWholeShape=true, double maxDistance=5)
static QPointF polygonCentroid(const QPolygonF &points)
Calculate the centroid point of a QPolygonF.
void stopRender(QgsSymbolV2RenderContext &context)
void setRasterScaleFactor(double factor)
QgsSymbolV2::OutputUnit mDistanceUnit
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
QgsLineSymbolV2 * mFillLineSymbol
Fill line.
virtual double estimateMaxBleed() const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape...
void applyDataDefinedSettings(const QgsSymbolV2RenderContext &context)
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
QgsSymbolLayerV2 * symbolLayer(int layer)
void setMapUnitScale(const QgsMapUnitScale &scale)
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
virtual double dxfWidth(const QgsDxfExport &e, const QgsSymbolV2RenderContext &context) const
void setPatternWidthUnit(QgsSymbolV2::OutputUnit unit)
void stopRender(QgsSymbolV2RenderContext &context)
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.
QgsSymbolLayerV2 * clone() const
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
void _renderPolygon(QPainter *p, const QPolygonF &points, const QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
Default method to render polygon.
void addStopsToGradient(QGradient *gradient, double alpha=1)
copy color ramp stops to a QGradient
static const bool selectFillBorder
QgsSymbolV2::OutputUnit outputUnit() const
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...
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
double size
Definition: qgssvgcache.cpp:77
void setReferencePoint2(QPointF referencePoint)
End point of gradient fill, in the range [0,0] - [1,1].
QgsSymbolV2::OutputUnit outputUnit() const
QgsSymbolLayerV2 * clone() const
const QgsMapUnitScale & svgOutlineWidthMapUnitScale() const
#define DEFAULT_SIMPLEFILL_JOINSTYLE
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves data defined properties to string map.
double angle() const
void setOutputUnit(QgsSymbolV2::OutputUnit u)
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:127
static void blurImageInPlace(QImage &image, const QRect &rect, int radius, bool alphaOnly)
Blurs an image in place, e.g.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
void setOutputUnit(QgsSymbolV2::OutputUnit unit)
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
static QgsSymbolV2::OutputUnit decodeOutputUnit(QString str)
void setDistanceMapUnitScale(const QgsMapUnitScale &scale)
#define DEFAULT_SIMPLEFILL_BORDERWIDTH
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies data defined properties of this layer to another symbol layer.
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.
Qt::PenStyle dxfPenStyle() const
QRectF mSvgViewBox
SVG view box (to keep the aspect ratio.
void setIgnoreRings(double ignoreRings)
Sets whether the shapeburst fill should ignore polygon rings when calculating the buffered shading...
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)
QColor color() const
double mPatternWidth
Width of the pattern (in output units)
virtual void setDataDefinedProperty(const QString &property, const QString &expressionString)
#define tr(sourceText)
void applyDataDefinedSymbology(QgsSymbolV2RenderContext &context, QBrush &brush, QPen &pen, QPen &selPen)
#define DEFAULT_SIMPLEFILL_COLOR
void startRender(QgsSymbolV2RenderContext &context)
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const