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