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