QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgsfillsymbollayerv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfillsymbollayerv2.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsfillsymbollayerv2.h"
17 #include "qgslinesymbollayerv2.h"
18 #include "qgsmarkersymbollayerv2.h"
19 #include "qgssymbollayerv2utils.h"
20 #include "qgsdxfexport.h"
21 #include "qgsexpression.h"
22 #include "qgsrendercontext.h"
23 #include "qgsproject.h"
24 #include "qgssvgcache.h"
25 #include "qgslogger.h"
26 #include "qgsvectorcolorrampv2.h"
27 
28 #include <QPainter>
29 #include <QFile>
30 #include <QSvgRenderer>
31 #include <QDomDocument>
32 #include <QDomElement>
33 
34 QgsSimpleFillSymbolLayerV2::QgsSimpleFillSymbolLayerV2( QColor color, Qt::BrushStyle style, QColor borderColor, Qt::PenStyle borderStyle, double borderWidth,
35  Qt::PenJoinStyle penJoinStyle )
36  : mBrushStyle( style )
37  , mBorderColor( borderColor )
38  , mBorderStyle( borderStyle )
39  , mBorderWidth( borderWidth )
40  , mBorderWidthUnit( QgsSymbolV2::MM )
41  , mPenJoinStyle( penJoinStyle )
42  , mOffsetUnit( QgsSymbolV2::MM )
43 {
44  mColor = color;
45 }
46 
48 {
49  mBorderWidthUnit = unit;
50  mOffsetUnit = unit;
51 }
52 
54 {
56  if ( mOffsetUnit != unit )
57  {
58  return QgsSymbolV2::Mixed;
59  }
60  return unit;
61 }
62 
64 {
66  mOffsetMapUnitScale = scale;
67 }
68 
70 {
72  {
74  }
75  return QgsMapUnitScale();
76 }
77 
78 void QgsSimpleFillSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QBrush& brush, QPen& pen, QPen& selPen )
79 {
80  if ( mDataDefinedProperties.isEmpty() )
81  return; // shortcut
82 
83  QgsExpression* colorExpression = expression( "color" );
84  if ( colorExpression )
85  {
86  brush.setColor( QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() ) );
87  }
88  QgsExpression* 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
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,
762  const GradientCoordinateMode &coordinateMode, const GradientSpread &gradientSpread,
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" );
1091  blurRadius = mBlurRadius;
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" );
1097  useWholeShape = mUseWholeShape;
1098  if ( useWholeShapeExpression )
1099  useWholeShape = useWholeShapeExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toBool();
1100 
1101  //max distance
1102  QgsExpression* maxDistanceExpression = expression( "max_distance" );
1103  maxDistance = mMaxDistance;
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  pixVal = squaredVal > 0 ? qMin(( sqrt( squaredVal ) / maxDistanceValue ), 1.0 ) : 0;
1441 
1442  //convert value to color from ramp
1443  pixColor = ramp->color( pixVal );
1444 
1445  int pixAlpha = pixColor.alpha();
1446  if (( layerHasAlpha ) || ( pixAlpha != 255 ) )
1447  {
1448  //apply layer's transparency to alpha value
1449  double alpha = pixAlpha * layerAlpha;
1450  //premultiply ramp color since we are storing this in a ARGB32_Premultiplied QImage
1451  QgsSymbolLayerV2Utils::premultiplyColor( pixColor, alpha );
1452  }
1453 
1454  scanLine[widthIndex] = pixColor.rgba();
1455  idx++;
1456  }
1457  }
1458 }
1459 
1461 {
1462  QgsStringMap map;
1463  map["color"] = QgsSymbolLayerV2Utils::encodeColor( mColor );
1464  map["gradient_color2"] = QgsSymbolLayerV2Utils::encodeColor( mColor2 );
1465  map["color_type"] = QString::number( mColorType );
1466  map["blur_radius"] = QString::number( mBlurRadius );
1467  map["use_whole_shape"] = QString::number( mUseWholeShape );
1468  map["max_distance"] = QString::number( mMaxDistance );
1469  map["distance_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceUnit );
1470  map["distance_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceMapUnitScale );
1471  map["ignore_rings"] = QString::number( mIgnoreRings );
1472  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
1473  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
1474  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
1475 
1477 
1478  if ( mGradientRamp )
1479  {
1480  map.unite( mGradientRamp->properties() );
1481  }
1482 
1483  return map;
1484 }
1485 
1487 {
1489  if ( mGradientRamp )
1490  {
1491  sl->setColorRamp( mGradientRamp->clone() );
1492  }
1496  sl->setOffset( mOffset );
1497  sl->setOffsetUnit( mOffsetUnit );
1500  return sl;
1501 }
1502 
1504 {
1505  double offsetBleed = qMax( mOffset.x(), mOffset.y() );
1506  return offsetBleed;
1507 }
1508 
1510 {
1511  mDistanceUnit = unit;
1512  mOffsetUnit = unit;
1513 }
1514 
1516 {
1517  if ( mDistanceUnit == mOffsetUnit )
1518  {
1519  return mDistanceUnit;
1520  }
1521  return QgsSymbolV2::Mixed;
1522 }
1523 
1525 {
1526  mDistanceMapUnitScale = scale;
1527  mOffsetMapUnitScale = scale;
1528 }
1529 
1531 {
1533  {
1534  return mDistanceMapUnitScale;
1535  }
1536  return QgsMapUnitScale();
1537 }
1538 
1539 
1540 //QgsImageFillSymbolLayer
1541 
1542 QgsImageFillSymbolLayer::QgsImageFillSymbolLayer(): mOutlineWidth( 0.0 ), mOutlineWidthUnit( QgsSymbolV2::MM ), mOutline( 0 )
1543 {
1544  setSubSymbol( new QgsLineSymbolV2() );
1545 }
1546 
1548 {
1549 }
1550 
1551 void QgsImageFillSymbolLayer::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
1552 {
1553  QPainter* p = context.renderContext().painter();
1554  if ( !p )
1555  {
1556  return;
1557  }
1558 
1559  mNextAngle = mAngle;
1560  applyDataDefinedSettings( context );
1561 
1562  p->setPen( QPen( Qt::NoPen ) );
1563  if ( context.selected() )
1564  {
1565  QColor selColor = context.renderContext().selectionColor();
1566  // Alister - this doesn't seem to work here
1567  //if ( ! selectionIsOpaque )
1568  // selColor.setAlphaF( context.alpha() );
1569  p->setBrush( QBrush( selColor ) );
1570  _renderPolygon( p, points, rings, context );
1571  }
1572 
1573  if ( qgsDoubleNear( mNextAngle, 0.0 ) )
1574  {
1575  p->setBrush( mBrush );
1576  }
1577  else
1578  {
1579  QTransform t = mBrush.transform();
1580  t.rotate( mNextAngle );
1581  QBrush rotatedBrush = mBrush;
1582  rotatedBrush.setTransform( t );
1583  p->setBrush( rotatedBrush );
1584  }
1585  _renderPolygon( p, points, rings, context );
1586  if ( mOutline )
1587  {
1588  mOutline->renderPolyline( points, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
1589  if ( rings )
1590  {
1591  QList<QPolygonF>::const_iterator ringIt = rings->constBegin();
1592  for ( ; ringIt != rings->constEnd(); ++ringIt )
1593  {
1594  mOutline->renderPolyline( *ringIt, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() );
1595  }
1596  }
1597  }
1598 }
1599 
1601 {
1602  if ( !symbol ) //unset current outline
1603  {
1604  delete mOutline;
1605  mOutline = 0;
1606  return true;
1607  }
1608 
1609  if ( symbol->type() != QgsSymbolV2::Line )
1610  {
1611  delete symbol;
1612  return false;
1613  }
1614 
1615  QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
1616  if ( lineSymbol )
1617  {
1618  delete mOutline;
1619  mOutline = lineSymbol;
1620  return true;
1621  }
1622 
1623  delete symbol;
1624  return false;
1625 }
1626 
1628 {
1629  mOutlineWidthUnit = unit;
1630 }
1631 
1633 {
1634  return mOutlineWidthUnit;
1635 }
1636 
1638 {
1639  mOutlineWidthMapUnitScale = scale;
1640 }
1641 
1643 {
1645 }
1646 
1648 {
1649  if ( mOutline && mOutline->symbolLayer( 0 ) )
1650  {
1651  double subLayerBleed = mOutline->symbolLayer( 0 )->estimateMaxBleed();
1652  return subLayerBleed;
1653  }
1654  return 0;
1655 }
1656 
1658 {
1659  double width = mOutlineWidth;
1660  QgsExpression* widthExpression = expression( "width" );
1661  if ( widthExpression )
1662  {
1663  width = widthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
1664  }
1666 }
1667 
1669 {
1670  Q_UNUSED( context );
1671  if ( !mOutline )
1672  {
1673  return QColor( Qt::black );
1674  }
1675  return mOutline->color();
1676 }
1677 
1679 {
1680  return Qt::SolidLine;
1681 #if 0
1682  if ( !mOutline )
1683  {
1684  return Qt::SolidLine;
1685  }
1686  else
1687  {
1688  return mOutline->dxfPenStyle();
1689  }
1690 #endif //0
1691 }
1692 
1693 
1694 //QgsSVGFillSymbolLayer
1695 
1696 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QString& svgFilePath, double width, double angle ): QgsImageFillSymbolLayer(),
1697  mPatternWidth( width ),
1698  mPatternWidthUnit( QgsSymbolV2::MM ),
1699  mSvgOutlineWidthUnit( QgsSymbolV2::MM )
1700 {
1701  setSvgFilePath( svgFilePath );
1702  mOutlineWidth = 0.3;
1703  mAngle = angle;
1704  setDefaultSvgParams();
1705  mSvgPattern = 0;
1706 }
1707 
1708 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QByteArray& svgData, double width, double angle ): QgsImageFillSymbolLayer(),
1709  mPatternWidth( width ),
1710  mPatternWidthUnit( QgsSymbolV2::MM ),
1711  mSvgData( svgData ),
1712  mSvgOutlineWidthUnit( QgsSymbolV2::MM )
1713 {
1714  storeViewBox();
1715  mOutlineWidth = 0.3;
1716  mAngle = angle;
1717  setSubSymbol( new QgsLineSymbolV2() );
1718  setDefaultSvgParams();
1719  mSvgPattern = 0;
1720 }
1721 
1723 {
1724  delete mSvgPattern;
1725 }
1726 
1728 {
1730  mPatternWidthUnit = unit;
1731  mSvgOutlineWidthUnit = unit;
1732  mOutlineWidthUnit = unit;
1733 }
1734 
1736 {
1738  if ( mPatternWidthUnit != unit || mSvgOutlineWidthUnit != unit || mOutlineWidthUnit != unit )
1739  {
1740  return QgsSymbolV2::Mixed;
1741  }
1742  return unit;
1743 }
1744 
1746 {
1748  mPatternWidthMapUnitScale = scale;
1750  mOutlineWidthMapUnitScale = scale;
1751 }
1752 
1754 {
1758  {
1760  }
1761  return QgsMapUnitScale();
1762 }
1763 
1764 void QgsSVGFillSymbolLayer::setSvgFilePath( const QString& svgPath )
1765 {
1767  storeViewBox();
1768 
1769  mSvgFilePath = svgPath;
1770  setDefaultSvgParams();
1771 }
1772 
1774 {
1775  QByteArray data;
1776  double width = 20;
1777  QString svgFilePath;
1778  double angle = 0.0;
1779 
1780  if ( properties.contains( "width" ) )
1781  {
1782  width = properties["width"].toDouble();
1783  }
1784  if ( properties.contains( "svgFile" ) )
1785  {
1786  QString svgName = properties["svgFile"];
1787  QString savePath = QgsSymbolLayerV2Utils::symbolNameToPath( svgName );
1788  svgFilePath = ( savePath.isEmpty() ? svgName : savePath );
1789  }
1790  if ( properties.contains( "angle" ) )
1791  {
1792  angle = properties["angle"].toDouble();
1793  }
1794 
1795  QgsSVGFillSymbolLayer* symbolLayer = 0;
1796  if ( !svgFilePath.isEmpty() )
1797  {
1798  symbolLayer = new QgsSVGFillSymbolLayer( svgFilePath, width, angle );
1799  }
1800  else
1801  {
1802  if ( properties.contains( "data" ) )
1803  {
1804  data = QByteArray::fromHex( properties["data"].toLocal8Bit() );
1805  }
1806  symbolLayer = new QgsSVGFillSymbolLayer( data, width, angle );
1807  }
1808 
1809  //svg parameters
1810  if ( properties.contains( "svgFillColor" ) )
1811  {
1812  //pre 2.5 projects used "svgFillColor"
1813  symbolLayer->setSvgFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["svgFillColor"] ) );
1814  }
1815  else if ( properties.contains( "color" ) )
1816  {
1817  symbolLayer->setSvgFillColor( QgsSymbolLayerV2Utils::decodeColor( properties["color"] ) );
1818  }
1819  if ( properties.contains( "svgOutlineColor" ) )
1820  {
1821  //pre 2.5 projects used "svgOutlineColor"
1822  symbolLayer->setSvgOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["svgOutlineColor"] ) );
1823  }
1824  else if ( properties.contains( "outline_color" ) )
1825  {
1826  symbolLayer->setSvgOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["outline_color"] ) );
1827  }
1828  else if ( properties.contains( "line_color" ) )
1829  {
1830  symbolLayer->setSvgOutlineColor( QgsSymbolLayerV2Utils::decodeColor( properties["line_color"] ) );
1831  }
1832  if ( properties.contains( "svgOutlineWidth" ) )
1833  {
1834  //pre 2.5 projects used "svgOutlineWidth"
1835  symbolLayer->setSvgOutlineWidth( properties["svgOutlineWidth"].toDouble() );
1836  }
1837  else if ( properties.contains( "outline_width" ) )
1838  {
1839  symbolLayer->setSvgOutlineWidth( properties["outline_width"].toDouble() );
1840  }
1841  else if ( properties.contains( "line_width" ) )
1842  {
1843  symbolLayer->setSvgOutlineWidth( properties["line_width"].toDouble() );
1844  }
1845 
1846  //units
1847  if ( properties.contains( "pattern_width_unit" ) )
1848  {
1849  symbolLayer->setPatternWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["pattern_width_unit"] ) );
1850  }
1851  if ( properties.contains( "pattern_width_map_unit_scale" ) )
1852  {
1853  symbolLayer->setPatternWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["pattern_width_map_unit_scale"] ) );
1854  }
1855  if ( properties.contains( "svg_outline_width_unit" ) )
1856  {
1857  symbolLayer->setSvgOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["svg_outline_width_unit"] ) );
1858  }
1859  if ( properties.contains( "svg_outline_width_map_unit_scale" ) )
1860  {
1861  symbolLayer->setSvgOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["svg_outline_width_map_unit_scale"] ) );
1862  }
1863  if ( properties.contains( "outline_width_unit" ) )
1864  {
1865  symbolLayer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
1866  }
1867  if ( properties.contains( "outline_width_map_unit_scale" ) )
1868  {
1869  symbolLayer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
1870  }
1871 
1872  if ( properties.contains( "width_expression" ) )
1873  symbolLayer->setDataDefinedProperty( "width", properties["width_expression"] );
1874  if ( properties.contains( "svgFile_expression" ) )
1875  symbolLayer->setDataDefinedProperty( "svgFile", properties["svgFile_expression"] );
1876  if ( properties.contains( "angle_expression" ) )
1877  symbolLayer->setDataDefinedProperty( "angle", properties["angle_expression"] );
1878  if ( properties.contains( "svgFillColor_expression" ) )
1879  symbolLayer->setDataDefinedProperty( "svgFillColor", properties["svgFillColor_expression"] );
1880  if ( properties.contains( "svgOutlineColor_expression" ) )
1881  symbolLayer->setDataDefinedProperty( "svgOutlineColor", properties["svgOutlineColor_expression"] );
1882  if ( properties.contains( "svgOutlineWidth_expression" ) )
1883  symbolLayer->setDataDefinedProperty( "svgOutlineWidth", properties["svgOutlineWidth_expression"] );
1884 
1885  return symbolLayer;
1886 }
1887 
1889 {
1890  return "SVGFill";
1891 }
1892 
1893 void QgsSVGFillSymbolLayer::applyPattern( QBrush& brush, const QString& svgFilePath, double patternWidth, QgsSymbolV2::OutputUnit patternWidthUnit,
1894  const QColor& svgFillColor, const QColor& svgOutlineColor, double svgOutlineWidth,
1895  QgsSymbolV2::OutputUnit svgOutlineWidthUnit, const QgsSymbolV2RenderContext& context,
1896  const QgsMapUnitScale& patternWidthMapUnitScale, const QgsMapUnitScale& svgOutlineWidthMapUnitScale )
1897 {
1898  if ( mSvgViewBox.isNull() )
1899  {
1900  return;
1901  }
1902 
1903  delete mSvgPattern;
1904  mSvgPattern = 0;
1906 
1907  if (( int )size < 1.0 || 10000.0 < size )
1908  {
1909  mSvgPattern = new QImage();
1910  brush.setTextureImage( *mSvgPattern );
1911  }
1912  else
1913  {
1914  bool fitsInCache = true;
1916  const QImage& patternImage = QgsSvgCache::instance()->svgAsImage( svgFilePath, size, svgFillColor, svgOutlineColor, outlineWidth,
1917  context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
1918  if ( !fitsInCache )
1919  {
1920  const QPicture& patternPict = QgsSvgCache::instance()->svgAsPicture( svgFilePath, size, svgFillColor, svgOutlineColor, outlineWidth,
1921  context.renderContext().scaleFactor(), 1.0 );
1922  double hwRatio = 1.0;
1923  if ( patternPict.width() > 0 )
1924  {
1925  hwRatio = ( double )patternPict.height() / ( double )patternPict.width();
1926  }
1927  mSvgPattern = new QImage(( int )size, ( int )( size * hwRatio ), QImage::Format_ARGB32_Premultiplied );
1928  mSvgPattern->fill( 0 ); // transparent background
1929 
1930  QPainter p( mSvgPattern );
1931  p.drawPicture( QPointF( size / 2, size * hwRatio / 2 ), patternPict );
1932  }
1933 
1934  QTransform brushTransform;
1935  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
1936  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
1937  {
1938  QImage transparentImage = fitsInCache ? patternImage.copy() : mSvgPattern->copy();
1939  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
1940  brush.setTextureImage( transparentImage );
1941  }
1942  else
1943  {
1944  brush.setTextureImage( fitsInCache ? patternImage : *mSvgPattern );
1945  }
1946  brush.setTransform( brushTransform );
1947  }
1948 }
1949 
1951 {
1952 
1954 
1955  if ( mOutline )
1956  {
1957  mOutline->startRender( context.renderContext(), context.fields() );
1958  }
1959 
1960  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
1961 }
1962 
1964 {
1965  if ( mOutline )
1966  {
1967  mOutline->stopRender( context.renderContext() );
1968  }
1969 }
1970 
1972 {
1973  QgsStringMap map;
1974  if ( !mSvgFilePath.isEmpty() )
1975  {
1976  map.insert( "svgFile", QgsSymbolLayerV2Utils::symbolPathToName( mSvgFilePath ) );
1977  }
1978  else
1979  {
1980  map.insert( "data", QString( mSvgData.toHex() ) );
1981  }
1982 
1983  map.insert( "width", QString::number( mPatternWidth ) );
1984  map.insert( "angle", QString::number( mAngle ) );
1985 
1986  //svg parameters
1987  map.insert( "color", QgsSymbolLayerV2Utils::encodeColor( mSvgFillColor ) );
1988  map.insert( "outline_color", QgsSymbolLayerV2Utils::encodeColor( mSvgOutlineColor ) );
1989  map.insert( "outline_width", QString::number( mSvgOutlineWidth ) );
1990 
1991  //units
1992  map.insert( "pattern_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mPatternWidthUnit ) );
1993  map.insert( "pattern_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mPatternWidthMapUnitScale ) );
1994  map.insert( "svg_outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mSvgOutlineWidthUnit ) );
1995  map.insert( "svg_outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mSvgOutlineWidthMapUnitScale ) );
1996  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
1997  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
1998 
2000  return map;
2001 }
2002 
2004 {
2005  QgsSVGFillSymbolLayer* clonedLayer = 0;
2006  if ( !mSvgFilePath.isEmpty() )
2007  {
2008  clonedLayer = new QgsSVGFillSymbolLayer( mSvgFilePath, mPatternWidth, mAngle );
2009  clonedLayer->setSvgFillColor( mSvgFillColor );
2010  clonedLayer->setSvgOutlineColor( mSvgOutlineColor );
2011  clonedLayer->setSvgOutlineWidth( mSvgOutlineWidth );
2012  }
2013  else
2014  {
2015  clonedLayer = new QgsSVGFillSymbolLayer( mSvgData, mPatternWidth, mAngle );
2016  }
2017 
2018  clonedLayer->setPatternWidthUnit( mPatternWidthUnit );
2022  clonedLayer->setOutlineWidthUnit( mOutlineWidthUnit );
2024 
2025  if ( mOutline )
2026  {
2027  clonedLayer->setSubSymbol( mOutline->clone() );
2028  }
2029  copyDataDefinedProperties( clonedLayer );
2030  return clonedLayer;
2031 }
2032 
2033 void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
2034 {
2035  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
2036  if ( !props.value( "uom", "" ).isEmpty() )
2037  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
2038  element.appendChild( symbolizerElem );
2039 
2040  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
2041 
2042  QDomElement fillElem = doc.createElement( "se:Fill" );
2043  symbolizerElem.appendChild( fillElem );
2044 
2045  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
2046  fillElem.appendChild( graphicFillElem );
2047 
2048  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2049  graphicFillElem.appendChild( graphicElem );
2050 
2051  if ( !mSvgFilePath.isEmpty() )
2052  {
2054  }
2055  else
2056  {
2057  // TODO: create svg from data
2058  // <se:InlineContent>
2059  symbolizerElem.appendChild( doc.createComment( "SVG from data not implemented yet" ) );
2060  }
2061 
2062  if ( mSvgOutlineColor.isValid() || mSvgOutlineWidth >= 0 )
2063  {
2064  QgsSymbolLayerV2Utils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, mSvgOutlineWidth );
2065  }
2066 
2067  // <Rotation>
2068  QString angleFunc;
2069  bool ok;
2070  double angle = props.value( "angle", "0" ).toDouble( &ok );
2071  if ( !ok )
2072  {
2073  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
2074  }
2075  else if ( angle + mAngle != 0 )
2076  {
2077  angleFunc = QString::number( angle + mAngle );
2078  }
2079  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2080 
2081  if ( mOutline )
2082  {
2083  // the outline sub symbol should be stored within the Stroke element,
2084  // but it will be stored in a separated LineSymbolizer because it could
2085  // have more than one layer
2086  mOutline->toSld( doc, element, props );
2087  }
2088 }
2089 
2091 {
2092  QgsDebugMsg( "Entered." );
2093 
2094  QString path, mimeType;
2095  QColor fillColor, borderColor;
2096  Qt::PenStyle penStyle;
2097  double size, borderWidth;
2098 
2099  QDomElement fillElem = element.firstChildElement( "Fill" );
2100  if ( fillElem.isNull() )
2101  return NULL;
2102 
2103  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
2104  if ( graphicFillElem.isNull() )
2105  return NULL;
2106 
2107  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
2108  if ( graphicElem.isNull() )
2109  return NULL;
2110 
2111  if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
2112  return NULL;
2113 
2114  if ( mimeType != "image/svg+xml" )
2115  return NULL;
2116 
2117  QgsSymbolLayerV2Utils::lineFromSld( graphicElem, penStyle, borderColor, borderWidth );
2118 
2119  double angle = 0.0;
2120  QString angleFunc;
2121  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2122  {
2123  bool ok;
2124  double d = angleFunc.toDouble( &ok );
2125  if ( ok )
2126  angle = d;
2127  }
2128 
2129  QgsSVGFillSymbolLayer* sl = new QgsSVGFillSymbolLayer( path, size, angle );
2130  sl->setSvgFillColor( fillColor );
2131  sl->setSvgOutlineColor( borderColor );
2132  sl->setSvgOutlineWidth( borderWidth );
2133 
2134  // try to get the outline
2135  QDomElement strokeElem = element.firstChildElement( "Stroke" );
2136  if ( !strokeElem.isNull() )
2137  {
2139  if ( l )
2140  {
2141  QgsSymbolLayerV2List layers;
2142  layers.append( l );
2143  sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
2144  }
2145  }
2146 
2147  return sl;
2148 }
2149 
2151 {
2152  QgsExpression* widthExpression = expression( "width" );
2153  QgsExpression* svgFileExpression = expression( "svgFile" );
2154  QgsExpression* fillColorExpression = expression( "svgFillColor" );
2155  QgsExpression* outlineColorExpression = expression( "svgOutlineColor" );
2156  QgsExpression* outlineWidthExpression = expression( "svgOutlineWidth" );
2157  QgsExpression* angleExpression = expression( "angle" );
2158  if ( !widthExpression && !svgFileExpression && !fillColorExpression && !outlineColorExpression && !outlineWidthExpression && !angleExpression )
2159  {
2160  return; //no data defined settings
2161  }
2162 
2163  if ( angleExpression )
2164  {
2165  mNextAngle = angleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2166  }
2167 
2168  double width = mPatternWidth;
2169  if ( widthExpression )
2170  {
2171  width = widthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2172  }
2173  QString svgFile = mSvgFilePath;
2174  if ( svgFileExpression )
2175  {
2176  svgFile = svgFileExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
2177  }
2178  QColor svgFillColor = mSvgFillColor;
2179  if ( fillColorExpression )
2180  {
2181  svgFillColor = QgsSymbolLayerV2Utils::decodeColor( fillColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
2182  }
2183  QColor svgOutlineColor = mSvgOutlineColor;
2184  if ( outlineColorExpression )
2185  {
2186  svgOutlineColor = QgsSymbolLayerV2Utils::decodeColor( outlineColorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
2187  }
2188  double outlineWidth = mSvgOutlineWidth;
2189  if ( outlineWidthExpression )
2190  {
2191  outlineWidth = outlineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2192  }
2193  applyPattern( mBrush, svgFile, width, mPatternWidthUnit, svgFillColor, svgOutlineColor, outlineWidth,
2195 
2196 }
2197 
2198 void QgsSVGFillSymbolLayer::storeViewBox()
2199 {
2200  if ( !mSvgData.isEmpty() )
2201  {
2202  QSvgRenderer r( mSvgData );
2203  if ( r.isValid() )
2204  {
2205  mSvgViewBox = r.viewBoxF();
2206  return;
2207  }
2208  }
2209 
2210  mSvgViewBox = QRectF();
2211  return;
2212 }
2213 
2214 void QgsSVGFillSymbolLayer::setDefaultSvgParams()
2215 {
2216  //default values
2217  mSvgFillColor = QColor( 0, 0, 0 );
2218  mSvgOutlineColor = QColor( 0, 0, 0 );
2219  mSvgOutlineWidth = 0.3;
2220 
2221  if ( mSvgFilePath.isEmpty() )
2222  {
2223  return;
2224  }
2225 
2226  bool hasFillParam, hasOutlineParam, hasOutlineWidthParam;
2227  QColor defaultFillColor, defaultOutlineColor;
2228  double defaultOutlineWidth;
2229  QgsSvgCache::instance()->containsParams( mSvgFilePath, hasFillParam, defaultFillColor, hasOutlineParam, defaultOutlineColor, hasOutlineWidthParam,
2230  defaultOutlineWidth );
2231 
2232  if ( hasFillParam )
2233  {
2234  mSvgFillColor = defaultFillColor;
2235  }
2236  if ( hasOutlineParam )
2237  {
2238  mSvgOutlineColor = defaultOutlineColor;
2239  }
2240  if ( hasOutlineWidthParam )
2241  {
2242  mSvgOutlineWidth = defaultOutlineWidth;
2243  }
2244 }
2245 
2246 
2248  mOffsetUnit( QgsSymbolV2::MM ), mFillLineSymbol( 0 )
2249 {
2250  setSubSymbol( new QgsLineSymbolV2() );
2251  QgsImageFillSymbolLayer::setSubSymbol( 0 ); //no outline
2252 }
2253 
2255 {
2256  mFillLineSymbol->setWidth( w );
2257  mLineWidth = w;
2258 }
2259 
2261 {
2262  mFillLineSymbol->setColor( c );
2263  mColor = c;
2264 }
2265 
2267 {
2268  delete mFillLineSymbol;
2269 }
2270 
2272 {
2273  if ( !symbol )
2274  {
2275  return false;
2276  }
2277 
2278  if ( symbol->type() == QgsSymbolV2::Line )
2279  {
2280  QgsLineSymbolV2* lineSymbol = dynamic_cast<QgsLineSymbolV2*>( symbol );
2281  if ( lineSymbol )
2282  {
2283  delete mFillLineSymbol;
2284  mFillLineSymbol = lineSymbol;
2285 
2286  return true;
2287  }
2288  }
2289  delete symbol;
2290  return false;
2291 }
2292 
2294 {
2295  return mFillLineSymbol;
2296 }
2297 
2299 {
2300  return 0;
2301 }
2302 
2304 {
2306  mDistanceUnit = unit;
2307  mLineWidthUnit = unit;
2308  mOffsetUnit = unit;
2309 }
2310 
2312 {
2314  if ( mDistanceUnit != unit || mLineWidthUnit != unit || mOffsetUnit != unit )
2315  {
2316  return QgsSymbolV2::Mixed;
2317  }
2318  return unit;
2319 }
2320 
2322 {
2324  mDistanceMapUnitScale = scale;
2325  mLineWidthMapUnitScale = scale;
2326  mOffsetMapUnitScale = scale;
2327 }
2328 
2330 {
2334  {
2335  return mDistanceMapUnitScale;
2336  }
2337  return QgsMapUnitScale();
2338 }
2339 
2341 {
2343 
2344  //default values
2345  double lineAngle = 45;
2346  double distance = 5;
2347  double lineWidth = 0.5;
2348  QColor color( Qt::black );
2349  double offset = 0.0;
2350 
2351  if ( properties.contains( "lineangle" ) )
2352  {
2353  //pre 2.5 projects used "lineangle"
2354  lineAngle = properties["lineangle"].toDouble();
2355  }
2356  else if ( properties.contains( "angle" ) )
2357  {
2358  lineAngle = properties["angle"].toDouble();
2359  }
2360  patternLayer->setLineAngle( lineAngle );
2361 
2362  if ( properties.contains( "distance" ) )
2363  {
2364  distance = properties["distance"].toDouble();
2365  }
2366  patternLayer->setDistance( distance );
2367 
2368  if ( properties.contains( "linewidth" ) )
2369  {
2370  //pre 2.5 projects used "linewidth"
2371  lineWidth = properties["linewidth"].toDouble();
2372  }
2373  else if ( properties.contains( "outline_width" ) )
2374  {
2375  lineWidth = properties["outline_width"].toDouble();
2376  }
2377  else if ( properties.contains( "line_width" ) )
2378  {
2379  lineWidth = properties["line_width"].toDouble();
2380  }
2381  patternLayer->setLineWidth( lineWidth );
2382 
2383  if ( properties.contains( "color" ) )
2384  {
2385  color = QgsSymbolLayerV2Utils::decodeColor( properties["color"] );
2386  }
2387  else if ( properties.contains( "outline_color" ) )
2388  {
2389  color = QgsSymbolLayerV2Utils::decodeColor( properties["outline_color"] );
2390  }
2391  else if ( properties.contains( "line_color" ) )
2392  {
2393  color = QgsSymbolLayerV2Utils::decodeColor( properties["line_color"] );
2394  }
2395  patternLayer->setColor( color );
2396 
2397  if ( properties.contains( "offset" ) )
2398  {
2399  offset = properties["offset"].toDouble();
2400  }
2401  patternLayer->setOffset( offset );
2402 
2403 
2404  if ( properties.contains( "distance_unit" ) )
2405  {
2406  patternLayer->setDistanceUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_unit"] ) );
2407  }
2408  if ( properties.contains( "distance_map_unit_scale" ) )
2409  {
2410  patternLayer->setDistanceMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_map_unit_scale"] ) );
2411  }
2412  if ( properties.contains( "line_width_unit" ) )
2413  {
2414  patternLayer->setLineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["line_width_unit"] ) );
2415  }
2416  else if ( properties.contains( "outline_width_unit" ) )
2417  {
2418  patternLayer->setLineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
2419  }
2420  if ( properties.contains( "line_width_map_unit_scale" ) )
2421  {
2422  patternLayer->setLineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["line_width_map_unit_scale"] ) );
2423  }
2424  if ( properties.contains( "offset_unit" ) )
2425  {
2426  patternLayer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
2427  }
2428  if ( properties.contains( "offset_map_unit_scale" ) )
2429  {
2430  patternLayer->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["offset_map_unit_scale"] ) );
2431  }
2432  if ( properties.contains( "outline_width_unit" ) )
2433  {
2434  patternLayer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
2435  }
2436  if ( properties.contains( "outline_width_map_unit_scale" ) )
2437  {
2438  patternLayer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
2439  }
2440 
2441 
2442  //data defined properties
2443  if ( properties.contains( "lineangle_expression" ) )
2444  {
2445  patternLayer->setDataDefinedProperty( "lineangle", properties["lineangle_expression"] );
2446  }
2447  if ( properties.contains( "distance_expression" ) )
2448  {
2449  patternLayer->setDataDefinedProperty( "distance", properties["distance_expression"] );
2450  }
2451  if ( properties.contains( "linewidth_expression" ) )
2452  {
2453  patternLayer->setDataDefinedProperty( "linewidth", properties["linewidth_expression"] );
2454  }
2455  if ( properties.contains( "color_expression" ) )
2456  {
2457  patternLayer->setDataDefinedProperty( "color", properties["color_expression"] );
2458  }
2459  return patternLayer;
2460 }
2461 
2463 {
2464  return "LinePatternFill";
2465 }
2466 
2467 void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double lineAngle, double distance,
2468  double lineWidth, const QColor& color )
2469 {
2470  Q_UNUSED( lineWidth );
2471  Q_UNUSED( color );
2472 
2473  mBrush.setTextureImage( QImage() ); // set empty in case we have to return
2474 
2475  if ( !mFillLineSymbol )
2476  {
2477  return;
2478  }
2479  // We have to make a copy because marker intervals will have to be adjusted
2480  QgsLineSymbolV2* fillLineSymbol = dynamic_cast<QgsLineSymbolV2*>( mFillLineSymbol->clone() );
2481  if ( !fillLineSymbol )
2482  {
2483  return;
2484  }
2485 
2486  const QgsRenderContext& ctx = context.renderContext();
2487  //double outlinePixelWidth = lineWidth * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mLineWidthUnit, mLineWidthMapUnitScale );
2488  double outputPixelDist = distance * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceUnit, mDistanceMapUnitScale );
2490 
2491  // To get all patterns into image, we have to consider symbols size (estimateMaxBleed()).
2492  // For marker lines we have to get markers interval.
2493  double outputPixelBleed = 0;
2494  double outputPixelInterval = 0; // maximum interval
2495  for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2496  {
2497  QgsSymbolLayerV2 *layer = fillLineSymbol->symbolLayer( i );
2498  double layerBleed = layer->estimateMaxBleed();
2499  // TODO: to get real bleed we have to scale it using context and units,
2500  // unfortunately estimateMaxBleed() ignore units completely, e.g.
2501  // QgsMarkerLineSymbolLayerV2::estimateMaxBleed() is mixing marker size and
2502  // offset regardless units. This has to be fixed especially
2503  // in estimateMaxBleed(), context probably has to be used.
2504  // For now, we only support millimeters
2505  double outputPixelLayerBleed = layerBleed * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, QgsSymbolV2::MM );
2506  outputPixelBleed = qMax( outputPixelBleed, outputPixelLayerBleed );
2507 
2508  QgsMarkerLineSymbolLayerV2 *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayerV2 *>( layer );
2509  if ( markerLineLayer )
2510  {
2511  double outputPixelLayerInterval = markerLineLayer->interval() * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, markerLineLayer->intervalUnit(), markerLineLayer->intervalMapUnitScale() );
2512 
2513  // There may be multiple marker lines with different intervals.
2514  // In theory we should find the least common multiple, but that could be too
2515  // big (multiplication of intervals in the worst case).
2516  // Because patterns without small common interval would look strange, we
2517  // believe that the longest interval should usually be sufficient.
2518  outputPixelInterval = qMax( outputPixelInterval, outputPixelLayerInterval );
2519  }
2520  }
2521 
2522  if ( outputPixelInterval > 0 )
2523  {
2524  // We have to adjust marker intervals to integer pixel size to get
2525  // repeatable pattern.
2526  double intervalScale = qRound( outputPixelInterval ) / outputPixelInterval;
2527  outputPixelInterval = qRound( outputPixelInterval );
2528 
2529  for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2530  {
2531  QgsSymbolLayerV2 *layer = fillLineSymbol->symbolLayer( i );
2532 
2533  QgsMarkerLineSymbolLayerV2 *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayerV2 *>( layer );
2534  if ( markerLineLayer )
2535  {
2536  markerLineLayer->setInterval( intervalScale * markerLineLayer->interval() );
2537  }
2538  }
2539  }
2540 
2541  //create image
2542  int height, width;
2543  if ( qgsDoubleNear( lineAngle, 0 ) || qgsDoubleNear( lineAngle, 360 ) || qgsDoubleNear( lineAngle, 180 ) )
2544  {
2545  height = outputPixelDist;
2546  width = outputPixelInterval > 0 ? outputPixelInterval : height;
2547  }
2548  else if ( qgsDoubleNear( lineAngle, 90 ) || qgsDoubleNear( lineAngle, 270 ) )
2549  {
2550  width = outputPixelDist;
2551  height = outputPixelInterval > 0 ? outputPixelInterval : width;
2552  }
2553  else
2554  {
2555  height = outputPixelDist / cos( lineAngle * M_PI / 180 ); //keep perpendicular distance between lines constant
2556  width = outputPixelDist / sin( lineAngle * M_PI / 180 );
2557 
2558  // recalculate real angle and distance after rounding to pixels
2559  lineAngle = 180 * atan2(( double ) height, ( double ) width ) / M_PI;
2560  if ( lineAngle < 0 )
2561  {
2562  lineAngle += 360.;
2563  }
2564 
2565  height = qAbs( height );
2566  width = qAbs( width );
2567 
2568  outputPixelDist = height * cos( lineAngle * M_PI / 180 );
2569 
2570  // Round offset to correspond to one pixel height, otherwise lines may
2571  // be shifted on tile border if offset falls close to pixel center
2572  int offsetHeight = qRound( qAbs( outputPixelOffset / cos( lineAngle * M_PI / 180 ) ) );
2573  outputPixelOffset = offsetHeight * cos( lineAngle * M_PI / 180 );
2574  }
2575 
2576  //depending on the angle, we might need to render into a larger image and use a subset of it
2577  double dx = 0;
2578  double dy = 0;
2579 
2580  // Add buffer based on bleed but keep precisely the height/width ratio (angle)
2581  // thus we add integer multiplications of width and height covering the bleed
2582  int bufferMulti = qMax( qCeil( outputPixelBleed / width ), qCeil( outputPixelBleed / width ) );
2583 
2584  // Always buffer at least once so that center of line marker in upper right corner
2585  // does not fall outside due to representation error
2586  bufferMulti = qMax( bufferMulti, 1 );
2587 
2588  int xBuffer = width * bufferMulti;
2589  int yBuffer = height * bufferMulti;
2590  int innerWidth = width;
2591  int innerHeight = height;
2592  width += 2 * xBuffer;
2593  height += 2 * yBuffer;
2594 
2595  if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
2596  {
2597  return;
2598  }
2599 
2600  QImage patternImage( width, height, QImage::Format_ARGB32 );
2601  patternImage.fill( 0 );
2602 
2603  QPointF p1, p2, p3, p4, p5, p6;
2604  if ( qgsDoubleNear( lineAngle, 0.0 ) || qgsDoubleNear( lineAngle, 360.0 ) || qgsDoubleNear( lineAngle, 180.0 ) )
2605  {
2606  p1 = QPointF( 0, yBuffer );
2607  p2 = QPointF( width, yBuffer );
2608  p3 = QPointF( 0, yBuffer + innerHeight );
2609  p4 = QPointF( width, yBuffer + innerHeight );
2610  }
2611  else if ( qgsDoubleNear( lineAngle, 90.0 ) || qgsDoubleNear( lineAngle, 270.0 ) )
2612  {
2613  p1 = QPointF( xBuffer, height );
2614  p2 = QPointF( xBuffer, 0 );
2615  p3 = QPointF( xBuffer + innerWidth, height );
2616  p4 = QPointF( xBuffer + innerWidth, 0 );
2617  }
2618  else if ( lineAngle > 0 && lineAngle < 90 )
2619  {
2620  dx = outputPixelDist * cos(( 90 - lineAngle ) * M_PI / 180.0 );
2621  dy = outputPixelDist * sin(( 90 - lineAngle ) * M_PI / 180.0 );
2622  p1 = QPointF( 0, height );
2623  p2 = QPointF( width, 0 );
2624  p3 = QPointF( -dx, height - dy );
2625  p4 = QPointF( width - dx, -dy );
2626  p5 = QPointF( dx, height + dy );
2627  p6 = QPointF( width + dx, dy );
2628  }
2629  else if ( lineAngle > 180 && lineAngle < 270 )
2630  {
2631  dx = outputPixelDist * cos(( 90 - lineAngle ) * M_PI / 180.0 );
2632  dy = outputPixelDist * sin(( 90 - lineAngle ) * M_PI / 180.0 );
2633  p1 = QPointF( width, 0 );
2634  p2 = QPointF( 0, height );
2635  p3 = QPointF( width - dx, -dy );
2636  p4 = QPointF( -dx, height - dy );
2637  p5 = QPointF( width + dx, dy );
2638  p6 = QPointF( dx, height + dy );
2639  }
2640  else if ( lineAngle > 90 && lineAngle < 180 )
2641  {
2642  dy = outputPixelDist * cos(( 180 - lineAngle ) * M_PI / 180 );
2643  dx = outputPixelDist * sin(( 180 - lineAngle ) * M_PI / 180 );
2644  p1 = QPointF( 0, 0 );
2645  p2 = QPointF( width, height );
2646  p5 = QPointF( dx, -dy );
2647  p6 = QPointF( width + dx, height - dy );
2648  p3 = QPointF( -dx, dy );
2649  p4 = QPointF( width - dx, height + dy );
2650  }
2651  else if ( lineAngle > 270 && lineAngle < 360 )
2652  {
2653  dy = outputPixelDist * cos(( 180 - lineAngle ) * M_PI / 180 );
2654  dx = outputPixelDist * sin(( 180 - lineAngle ) * M_PI / 180 );
2655  p1 = QPointF( width, height );
2656  p2 = QPointF( 0, 0 );
2657  p5 = QPointF( width + dx, height - dy );
2658  p6 = QPointF( dx, -dy );
2659  p3 = QPointF( width - dx, height + dy );
2660  p4 = QPointF( -dx, dy );
2661  }
2662 
2663  if ( !qgsDoubleNear( mOffset, 0.0 ) ) //shift everything
2664  {
2665  QPointF tempPt;
2666  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelDist + outputPixelOffset );
2667  p3 = QPointF( tempPt.x(), tempPt.y() );
2668  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelDist + outputPixelOffset );
2669  p4 = QPointF( tempPt.x(), tempPt.y() );
2670  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p5, outputPixelDist - outputPixelOffset );
2671  p5 = QPointF( tempPt.x(), tempPt.y() );
2672  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p6, outputPixelDist - outputPixelOffset );
2673  p6 = QPointF( tempPt.x(), tempPt.y() );
2674 
2675  //update p1, p2 last
2676  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelOffset );
2677  p1 = QPointF( tempPt.x(), tempPt.y() );
2678  tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelOffset );
2679  p2 = QPointF( tempPt.x(), tempPt.y() );;
2680  }
2681 
2682  QPainter p( &patternImage );
2683 
2684 #if 0
2685  // DEBUG: Draw rectangle
2686  p.setRenderHint( QPainter::Antialiasing, false ); // get true rect
2687  QPen pen( QColor( Qt::black ) );
2688  pen.setWidthF( 0.1 );
2689  pen.setCapStyle( Qt::FlatCap );
2690  p.setPen( pen );
2691 
2692  // To see this rectangle, comment buffer cut below.
2693  // Subtract 1 because not antialiased are rendered to the right/down by 1 pixel
2694  QPolygon polygon = QPolygon() << QPoint( 0, 0 ) << QPoint( width - 1, 0 ) << QPoint( width - 1, height - 1 ) << QPoint( 0, height - 1 ) << QPoint( 0, 0 );
2695  p.drawPolygon( polygon );
2696 
2697  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 );
2698  p.drawPolygon( polygon );
2699 #endif
2700 
2701  // Use antialiasing because without antialiasing lines are rendered to the
2702  // right and below the mathematically defined points (not symetrical)
2703  // and such tiles become useless for are filling
2704  p.setRenderHint( QPainter::Antialiasing, true );
2705 
2706  // line rendering needs context for drawing on patternImage
2707  QgsRenderContext lineRenderContext;
2708  lineRenderContext.setPainter( &p );
2709  lineRenderContext.setRasterScaleFactor( 1.0 );
2710  lineRenderContext.setScaleFactor( context.renderContext().scaleFactor() * context.renderContext().rasterScaleFactor() );
2712  lineRenderContext.setMapToPixel( mtp );
2713  lineRenderContext.setForceVectorOutput( false );
2714 
2715  fillLineSymbol->startRender( lineRenderContext, context.fields() );
2716 
2717  QVector<QPolygonF> polygons;
2718  polygons.append( QPolygonF() << p1 << p2 );
2719  polygons.append( QPolygonF() << p3 << p4 );
2720  if ( !qgsDoubleNear( lineAngle, 0 ) && !qgsDoubleNear( lineAngle, 360 ) && !qgsDoubleNear( lineAngle, 90 ) && !qgsDoubleNear( lineAngle, 180 ) && !qgsDoubleNear( lineAngle, 270 ) )
2721  {
2722  polygons.append( QPolygonF() << p5 << p6 );
2723  }
2724 
2725  foreach ( QPolygonF polygon, polygons )
2726  {
2727  fillLineSymbol->renderPolyline( polygon, context.feature(), lineRenderContext, -1, context.selected() );
2728  }
2729 
2730  fillLineSymbol->stopRender( lineRenderContext );
2731  p.end();
2732 
2733  // Cut off the buffer
2734  patternImage = patternImage.copy( xBuffer, yBuffer, patternImage.width() - 2 * xBuffer, patternImage.height() - 2 * yBuffer );
2735 
2736  //set image to mBrush
2737  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
2738  {
2739  QImage transparentImage = patternImage.copy();
2740  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
2741  brush.setTextureImage( transparentImage );
2742  }
2743  else
2744  {
2745  brush.setTextureImage( patternImage );
2746  }
2747 
2748  QTransform brushTransform;
2749  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
2750  brush.setTransform( brushTransform );
2751 
2752  delete fillLineSymbol;
2753 }
2754 
2756 {
2757  applyPattern( context, mBrush, mLineAngle, mDistance, mLineWidth, mColor );
2758 
2759  if ( mFillLineSymbol )
2760  {
2761  mFillLineSymbol->startRender( context.renderContext(), context.fields() );
2762  }
2763 
2764  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
2765 }
2766 
2768 {
2769 }
2770 
2772 {
2773  QgsStringMap map;
2774  map.insert( "angle", QString::number( mLineAngle ) );
2775  map.insert( "distance", QString::number( mDistance ) );
2776  map.insert( "line_width", QString::number( mLineWidth ) );
2777  map.insert( "color", QgsSymbolLayerV2Utils::encodeColor( mColor ) );
2778  map.insert( "offset", QString::number( mOffset ) );
2779  map.insert( "distance_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceUnit ) );
2780  map.insert( "line_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mLineWidthUnit ) );
2781  map.insert( "offset_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit ) );
2782  map.insert( "distance_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceMapUnitScale ) );
2783  map.insert( "line_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mLineWidthMapUnitScale ) );
2784  map.insert( "offset_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale ) );
2785  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
2786  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
2788  return map;
2789 }
2790 
2792 {
2794  if ( mFillLineSymbol )
2795  {
2796  clonedLayer->setSubSymbol( mFillLineSymbol->clone() );
2797  }
2798  return clonedLayer;
2799 }
2800 
2801 void QgsLinePatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
2802 {
2803  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
2804  if ( !props.value( "uom", "" ).isEmpty() )
2805  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
2806  element.appendChild( symbolizerElem );
2807 
2808  // <Geometry>
2809  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
2810 
2811  QDomElement fillElem = doc.createElement( "se:Fill" );
2812  symbolizerElem.appendChild( fillElem );
2813 
2814  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
2815  fillElem.appendChild( graphicFillElem );
2816 
2817  QDomElement graphicElem = doc.createElement( "se:Graphic" );
2818  graphicFillElem.appendChild( graphicElem );
2819 
2820  //line properties must be inside the graphic definition
2821  QColor lineColor = mFillLineSymbol ? mFillLineSymbol->color() : QColor();
2822  double lineWidth = mFillLineSymbol ? mFillLineSymbol->width() : 0.0;
2823  QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), lineColor, Qt::SolidLine, lineWidth, mDistance );
2824 
2825  // <Rotation>
2826  QString angleFunc;
2827  bool ok;
2828  double angle = props.value( "angle", "0" ).toDouble( &ok );
2829  if ( !ok )
2830  {
2831  angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mLineAngle );
2832  }
2833  else if ( angle + mLineAngle != 0 )
2834  {
2835  angleFunc = QString::number( angle + mLineAngle );
2836  }
2837  QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
2838 
2839  // <se:Displacement>
2840  QPointF lineOffset( sin( mLineAngle ) * mOffset, cos( mLineAngle ) * mOffset );
2841  QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, lineOffset );
2842 }
2843 
2845 {
2846  QString featureStyle;
2847  featureStyle.append( "Brush(" );
2848  featureStyle.append( QString( "fc:%1" ).arg( mColor.name() ) );
2849  featureStyle.append( QString( ",bc:%1" ).arg( "#00000000" ) ); //transparent background
2850  featureStyle.append( ",id:\"ogr-brush-2\"" );
2851  featureStyle.append( QString( ",a:%1" ).arg( mLineAngle ) );
2852  featureStyle.append( QString( ",s:%1" ).arg( mLineWidth * widthScaleFactor ) );
2853  featureStyle.append( ",dx:0mm" );
2854  featureStyle.append( QString( ",dy:%1mm" ).arg( mDistance * widthScaleFactor ) );
2855  featureStyle.append( ")" );
2856  return featureStyle;
2857 }
2858 
2860 {
2861  QgsExpression* lineAngleExpression = expression( "lineangle" );
2862  QgsExpression* distanceExpression = expression( "distance" );
2863  QgsExpression* lineWidthExpression = expression( "linewidth" );
2864  QgsExpression* colorExpression = expression( "color" );
2865  if ( !lineAngleExpression && !distanceExpression && !lineWidthExpression && !colorExpression )
2866  {
2867  return; //no data defined settings
2868  }
2869 
2870  double lineAngle = mLineAngle;
2871  if ( lineAngleExpression )
2872  {
2873  lineAngle = lineAngleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2874  }
2875  double distance = mDistance;
2876  if ( distanceExpression )
2877  {
2878  distance = distanceExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2879  }
2880  double lineWidth = mLineWidth;
2881  if ( lineWidthExpression )
2882  {
2883  lineWidth = lineWidthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
2884  }
2885  QColor color = mColor;
2886  if ( colorExpression )
2887  {
2888  color = QgsSymbolLayerV2Utils::decodeColor( colorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
2889  }
2890  applyPattern( context, mBrush, lineAngle, distance, lineWidth, color );
2891 }
2892 
2894 {
2895  QgsDebugMsg( "Entered." );
2896 
2897  QString name;
2898  QColor fillColor, lineColor;
2899  double size, lineWidth;
2900  Qt::PenStyle lineStyle;
2901 
2902  QDomElement fillElem = element.firstChildElement( "Fill" );
2903  if ( fillElem.isNull() )
2904  return NULL;
2905 
2906  QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
2907  if ( graphicFillElem.isNull() )
2908  return NULL;
2909 
2910  QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
2911  if ( graphicElem.isNull() )
2912  return NULL;
2913 
2914  if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, lineColor, lineStyle, lineWidth, size ) )
2915  return NULL;
2916 
2917  if ( name != "horline" )
2918  return NULL;
2919 
2920  double angle = 0.0;
2921  QString angleFunc;
2922  if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
2923  {
2924  bool ok;
2925  double d = angleFunc.toDouble( &ok );
2926  if ( ok )
2927  angle = d;
2928  }
2929 
2930  double offset = 0.0;
2931  QPointF vectOffset;
2932  if ( QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, vectOffset ) )
2933  {
2934  offset = sqrt( pow( vectOffset.x(), 2 ) + pow( vectOffset.y(), 2 ) );
2935  }
2936 
2938  sl->setColor( lineColor );
2939  sl->setLineWidth( lineWidth );
2940  sl->setLineAngle( angle );
2941  sl->setOffset( offset );
2942  sl->setDistance( size );
2943 
2944  // try to get the outline
2945  QDomElement strokeElem = element.firstChildElement( "Stroke" );
2946  if ( !strokeElem.isNull() )
2947  {
2949  if ( l )
2950  {
2951  QgsSymbolLayerV2List layers;
2952  layers.append( l );
2953  sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
2954  }
2955  }
2956 
2957  return sl;
2958 }
2959 
2960 
2962 
2964  mDistanceXUnit( QgsSymbolV2::MM ), mDistanceY( 15 ), mDistanceYUnit( QgsSymbolV2::MM ), mDisplacementX( 0 ), mDisplacementXUnit( QgsSymbolV2::MM ),
2965  mDisplacementY( 0 ), mDisplacementYUnit( QgsSymbolV2::MM )
2966 {
2967  mDistanceX = 15;
2968  mDistanceY = 15;
2969  mDisplacementX = 0;
2970  mDisplacementY = 0;
2972  QgsImageFillSymbolLayer::setSubSymbol( 0 ); //no outline
2973 }
2974 
2976 {
2977 }
2978 
2980 {
2982  mDistanceXUnit = unit;
2983  mDistanceYUnit = unit;
2984  mDisplacementXUnit = unit;
2985  mDisplacementYUnit = unit;
2986 }
2987 
2989 {
2991  if ( mDistanceXUnit != unit || mDistanceYUnit != unit || mDisplacementXUnit != unit || mDisplacementYUnit != unit )
2992  {
2993  return QgsSymbolV2::Mixed;
2994  }
2995  return unit;
2996 }
2997 
2999 {
3001  mDistanceXMapUnitScale = scale;
3002  mDistanceYMapUnitScale = scale;
3005 }
3006 
3008 {
3013  {
3014  return mDistanceXMapUnitScale;
3015  }
3016  return QgsMapUnitScale();
3017 }
3018 
3020 {
3022  if ( properties.contains( "distance_x" ) )
3023  {
3024  layer->setDistanceX( properties["distance_x"].toDouble() );
3025  }
3026  if ( properties.contains( "distance_y" ) )
3027  {
3028  layer->setDistanceY( properties["distance_y"].toDouble() );
3029  }
3030  if ( properties.contains( "displacement_x" ) )
3031  {
3032  layer->setDisplacementX( properties["displacement_x"].toDouble() );
3033  }
3034  if ( properties.contains( "displacement_y" ) )
3035  {
3036  layer->setDisplacementY( properties["displacement_y"].toDouble() );
3037  }
3038 
3039  if ( properties.contains( "distance_x_unit" ) )
3040  {
3041  layer->setDistanceXUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_x_unit"] ) );
3042  }
3043  if ( properties.contains( "distance_x_map_unit_scale" ) )
3044  {
3045  layer->setDistanceXMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_x_map_unit_scale"] ) );
3046  }
3047  if ( properties.contains( "distance_y_unit" ) )
3048  {
3049  layer->setDistanceYUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["distance_y_unit"] ) );
3050  }
3051  if ( properties.contains( "distance_y_map_unit_scale" ) )
3052  {
3053  layer->setDistanceYMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["distance_y_map_unit_scale"] ) );
3054  }
3055  if ( properties.contains( "displacement_x_unit" ) )
3056  {
3057  layer->setDisplacementXUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["displacement_x_unit"] ) );
3058  }
3059  if ( properties.contains( "displacement_x_map_unit_scale" ) )
3060  {
3061  layer->setDisplacementXMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["displacement_x_map_unit_scale"] ) );
3062  }
3063  if ( properties.contains( "displacement_y_unit" ) )
3064  {
3065  layer->setDisplacementYUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["displacement_y_unit"] ) );
3066  }
3067  if ( properties.contains( "displacement_y_map_unit_scale" ) )
3068  {
3069  layer->setDisplacementYMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["displacement_y_map_unit_scale"] ) );
3070  }
3071  if ( properties.contains( "outline_width_unit" ) )
3072  {
3073  layer->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["outline_width_unit"] ) );
3074  }
3075  if ( properties.contains( "outline_width_map_unit_scale" ) )
3076  {
3077  layer->setOutlineWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["outline_width_map_unit_scale"] ) );
3078  }
3079 
3080  //data defined properties
3081  if ( properties.contains( "distance_x_expression" ) )
3082  {
3083  layer->setDataDefinedProperty( "distance_x", properties["distance_x_expression"] );
3084  }
3085  if ( properties.contains( "distance_y_expression" ) )
3086  {
3087  layer->setDataDefinedProperty( "distance_y", properties["distance_y_expression"] );
3088  }
3089  if ( properties.contains( "displacement_x_expression" ) )
3090  {
3091  layer->setDataDefinedProperty( "displacement_x", properties["displacement_x_expression"] );
3092  }
3093  if ( properties.contains( "displacement_y_expression" ) )
3094  {
3095  layer->setDataDefinedProperty( "displacement_y", properties["displacement_y_expression"] );
3096  }
3097  return layer;
3098 }
3099 
3101 {
3102  return "PointPatternFill";
3103 }
3104 
3105 void QgsPointPatternFillSymbolLayer::applyPattern( const QgsSymbolV2RenderContext& context, QBrush& brush, double distanceX, double distanceY,
3106  double displacementX, double displacementY )
3107 {
3108  //render 3 rows and columns in one go to easily incorporate displacement
3109  const QgsRenderContext& ctx = context.renderContext();
3110  double width = distanceX * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDistanceXUnit, mDistanceXMapUnitScale ) * 2.0;
3112 
3113  if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
3114  {
3115  QImage img;
3116  brush.setTextureImage( img );
3117  return;
3118  }
3119 
3120  QImage patternImage( width, height, QImage::Format_ARGB32 );
3121  patternImage.fill( 0 );
3122 
3123  if ( mMarkerSymbol )
3124  {
3125  QPainter p( &patternImage );
3126 
3127  //marker rendering needs context for drawing on patternImage
3128  QgsRenderContext pointRenderContext;
3129  pointRenderContext.setRendererScale( context.renderContext().rendererScale() );
3130  pointRenderContext.setPainter( &p );
3131  pointRenderContext.setRasterScaleFactor( 1.0 );
3132  pointRenderContext.setScaleFactor( context.renderContext().scaleFactor() * context.renderContext().rasterScaleFactor() );
3134  pointRenderContext.setMapToPixel( mtp );
3135  pointRenderContext.setForceVectorOutput( false );
3136 
3137  mMarkerSymbol->startRender( pointRenderContext, context.fields() );
3138 
3139  //render corner points
3140  mMarkerSymbol->renderPoint( QPointF( 0, 0 ), context.feature(), pointRenderContext );
3141  mMarkerSymbol->renderPoint( QPointF( width, 0 ), context.feature(), pointRenderContext );
3142  mMarkerSymbol->renderPoint( QPointF( 0, height ), context.feature(), pointRenderContext );
3143  mMarkerSymbol->renderPoint( QPointF( width, height ), context.feature(), pointRenderContext );
3144 
3145  //render displaced points
3146  double displacementPixelX = displacementX * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDisplacementXUnit, mDisplacementXMapUnitScale );
3147  double displacementPixelY = displacementY * QgsSymbolLayerV2Utils::pixelSizeScaleFactor( ctx, mDisplacementYUnit, mDisplacementYMapUnitScale );
3148  mMarkerSymbol->renderPoint( QPointF( width / 2.0, -displacementPixelY ), context.feature(), pointRenderContext );
3149  mMarkerSymbol->renderPoint( QPointF( displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
3150  mMarkerSymbol->renderPoint( QPointF( width / 2.0 + displacementPixelX, height / 2.0 - displacementPixelY ), context.feature(), pointRenderContext );
3151  mMarkerSymbol->renderPoint( QPointF( width + displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext );
3152  mMarkerSymbol->renderPoint( QPointF( width / 2.0, height - displacementPixelY ), context.feature(), pointRenderContext );
3153 
3154  mMarkerSymbol->stopRender( pointRenderContext );
3155  }
3156 
3157  if ( !qgsDoubleNear( context.alpha(), 1.0 ) )
3158  {
3159  QImage transparentImage = patternImage.copy();
3160  QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() );
3161  brush.setTextureImage( transparentImage );
3162  }
3163  else
3164  {
3165  brush.setTextureImage( patternImage );
3166  }
3167  QTransform brushTransform;
3168  brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() );
3169  brush.setTransform( brushTransform );
3170 }
3171 
3173 {
3174  applyPattern( context, mBrush, mDistanceX, mDistanceY, mDisplacementX, mDisplacementY );
3175 
3176  if ( mOutline )
3177  {
3178  mOutline->startRender( context.renderContext(), context.fields() );
3179  }
3180  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
3181 }
3182 
3184 {
3185  if ( mOutline )
3186  {
3187  mOutline->stopRender( context.renderContext() );
3188  }
3189 }
3190 
3192 {
3193  QgsStringMap map;
3194  map.insert( "distance_x", QString::number( mDistanceX ) );
3195  map.insert( "distance_y", QString::number( mDistanceY ) );
3196  map.insert( "displacement_x", QString::number( mDisplacementX ) );
3197  map.insert( "displacement_y", QString::number( mDisplacementY ) );
3198  map.insert( "distance_x_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceXUnit ) );
3199  map.insert( "distance_y_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDistanceYUnit ) );
3200  map.insert( "displacement_x_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementXUnit ) );
3201  map.insert( "displacement_y_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mDisplacementYUnit ) );
3202  map.insert( "distance_x_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceXMapUnitScale ) );
3203  map.insert( "distance_y_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDistanceYMapUnitScale ) );
3204  map.insert( "displacement_x_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDisplacementXMapUnitScale ) );
3205  map.insert( "displacement_y_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mDisplacementYMapUnitScale ) );
3206  map.insert( "outline_width_unit", QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit ) );
3207  map.insert( "outline_width_map_unit_scale", QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale ) );
3209  return map;
3210 }
3211 
3213 {
3215  if ( mMarkerSymbol )
3216  {
3217  clonedLayer->setSubSymbol( mMarkerSymbol->clone() );
3218  }
3219  return clonedLayer;
3220 }
3221 
3222 void QgsPointPatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
3223 {
3224  for ( int i = 0; i < mMarkerSymbol->symbolLayerCount(); i++ )
3225  {
3226  QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
3227  if ( !props.value( "uom", "" ).isEmpty() )
3228  symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
3229  element.appendChild( symbolizerElem );
3230 
3231  // <Geometry>
3232  QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );
3233 
3234  QDomElement fillElem = doc.createElement( "se:Fill" );
3235  symbolizerElem.appendChild( fillElem );
3236 
3237  QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
3238  fillElem.appendChild( graphicFillElem );
3239 
3240  // store distanceX, distanceY, displacementX, displacementY in a <VendorOption>
3241  QString dist = QgsSymbolLayerV2Utils::encodePoint( QPointF( mDistanceX, mDistanceY ) );
3242  QDomElement distanceElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "distance", dist );
3243  symbolizerElem.appendChild( distanceElem );
3244 
3246  QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
3247  if ( !markerLayer )
3248  {
3249  QString errorMsg = QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() );
3250  graphicFillElem.appendChild( doc.createComment( errorMsg ) );
3251  }
3252  else
3253  {
3254  markerLayer->writeSldMarker( doc, graphicFillElem, props );
3255  }
3256  }
3257 }
3258 
3260 {
3261  Q_UNUSED( element );
3262  return NULL;
3263 }
3264 
3266 {
3267  if ( !symbol )
3268  {
3269  return false;
3270  }
3271 
3272  if ( symbol->type() == QgsSymbolV2::Marker )
3273  {
3274  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( symbol );
3275  delete mMarkerSymbol;
3276  mMarkerSymbol = markerSymbol;
3277  }
3278  return true;
3279 }
3280 
3282 {
3283  QgsExpression* distanceXExpression = expression( "distance_x" );
3284  QgsExpression* distanceYExpression = expression( "distance_y" );
3285  QgsExpression* displacementXExpression = expression( "displacement_x" );
3286  QgsExpression* displacementYExpression = expression( "displacement_y" );
3287 
3288 #if 0
3289  // TODO: enable but check also if mMarkerSymbol has data defined properties
3290  if ( !distanceXExpression && !distanceYExpression && !displacementXExpression && !displacementYExpression )
3291  {
3292  return;
3293  }
3294 #endif
3295 
3296  double distanceX = mDistanceX;
3297  if ( distanceXExpression )
3298  {
3299  distanceX = distanceXExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
3300  }
3301  double distanceY = mDistanceY;
3302  if ( distanceYExpression )
3303  {
3304  distanceY = distanceYExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
3305  }
3306  double displacementX = mDisplacementX;
3307  if ( displacementXExpression )
3308  {
3309  displacementX = displacementXExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
3310  }
3311  double displacementY = mDisplacementY;
3312  if ( displacementYExpression )
3313  {
3314  displacementY = displacementYExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
3315  }
3316  applyPattern( context, mBrush, distanceX, distanceY, displacementX, displacementY );
3317 }
3318 
3320 {
3321  return 0;
3322 }
3323 
3325 {
3326  QSet<QString> attributes = QgsSymbolLayerV2::usedAttributes();
3327 
3328  if ( mMarkerSymbol )
3329  attributes.unite( mMarkerSymbol->usedAttributes() );
3330 
3331  return attributes;
3332 }
3333 
3335 
3336 
3337 QgsCentroidFillSymbolLayerV2::QgsCentroidFillSymbolLayerV2(): mMarker( NULL ), mPointOnSurface( false )
3338 {
3340 }
3341 
3343 {
3344  delete mMarker;
3345 }
3346 
3348 {
3350 
3351  if ( properties.contains( "point_on_surface" ) )
3352  sl->setPointOnSurface( properties["point_on_surface"].toInt() != 0 );
3353 
3354  return sl;
3355 }
3356 
3358 {
3359  return "CentroidFill";
3360 }
3361 
3362 void QgsCentroidFillSymbolLayerV2::setColor( const QColor& color )
3363 {
3364  mMarker->setColor( color );
3365  mColor = color;
3366 }
3367 
3369 {
3370  mMarker->setAlpha( context.alpha() );
3371  mMarker->startRender( context.renderContext(), context.fields() );
3372 }
3373 
3375 {
3376  mMarker->stopRender( context.renderContext() );
3377 }
3378 
3379 void QgsCentroidFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context )
3380 {
3381  Q_UNUSED( rings );
3382 
3384  mMarker->renderPoint( centroid, context.feature(), context.renderContext(), -1, context.selected() );
3385 }
3386 
3388 {
3389  QgsStringMap map;
3390  map["point_on_surface"] = QString::number( mPointOnSurface );
3391  return map;
3392 }
3393 
3395 {
3397  x->mAngle = mAngle;
3398  x->mColor = mColor;
3399  x->setSubSymbol( mMarker->clone() );
3401  return x;
3402 }
3403 
3404 void QgsCentroidFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
3405 {
3406  // SLD 1.0 specs says: "if a line, polygon, or raster geometry is
3407  // used with PointSymbolizer, then the semantic is to use the centroid
3408  // of the geometry, or any similar representative point.
3409  mMarker->toSld( doc, element, props );
3410 }
3411 
3413 {
3414  QgsDebugMsg( "Entered." );
3415 
3417  if ( !l )
3418  return NULL;
3419 
3420  QgsSymbolLayerV2List layers;
3421  layers.append( l );
3422  QgsMarkerSymbolV2 *marker = new QgsMarkerSymbolV2( layers );
3423 
3425  sl->setSubSymbol( marker );
3426  return sl;
3427 }
3428 
3429 
3431 {
3432  return mMarker;
3433 }
3434 
3436 {
3437  if ( symbol == NULL || symbol->type() != QgsSymbolV2::Marker )
3438  {
3439  delete symbol;
3440  return false;
3441  }
3442 
3443  delete mMarker;
3444  mMarker = static_cast<QgsMarkerSymbolV2*>( symbol );
3445  mColor = mMarker->color();
3446  return true;
3447 }
3448 
3450 {
3451  QSet<QString> attributes;
3452 
3453  attributes.unite( QgsSymbolLayerV2::usedAttributes() );
3454 
3455  if ( mMarker )
3456  attributes.unite( mMarker->usedAttributes() );
3457 
3458  return attributes;
3459 }
3460 
3462 {
3463  if ( mMarker )
3464  {
3465  mMarker->setOutputUnit( unit );
3466  }
3467 }
3468 
3470 {
3471  if ( mMarker )
3472  {
3473  return mMarker->outputUnit();
3474  }
3475  return QgsSymbolV2::Mixed; //mOutputUnit;
3476 }
3477 
3479 {
3480  if ( mMarker )
3481  {
3482  mMarker->setMapUnitScale( scale );
3483  }
3484 }
3485 
3487 {
3488  if ( mMarker )
3489  {
3490  return mMarker->mapUnitScale();
3491  }
3492  return QgsMapUnitScale();
3493 }
3494 
3495 
3496 
3497 
3500  , mImageFilePath( imageFilePath )
3501  , mCoordinateMode( QgsRasterFillSymbolLayer::Feature )
3502  , mAlpha( 1.0 )
3503  , mOffsetUnit( QgsSymbolV2::MM )
3504  , mWidth( 0.0 )
3505  , mWidthUnit( QgsSymbolV2::Pixel )
3506 {
3507  QgsImageFillSymbolLayer::setSubSymbol( 0 ); //disable sub symbol
3508 }
3509 
3511 {
3512 
3513 }
3514 
3516 {
3518  double alpha = 1.0;
3519  QPointF offset;
3520  double angle = 0.0;
3521  double width = 0.0;
3522 
3523  QString imagePath;
3524  if ( properties.contains( "imageFile" ) )
3525  {
3526  imagePath = properties["imageFile"];
3527  }
3528  if ( properties.contains( "coordinate_mode" ) )
3529  {
3530  mode = ( FillCoordinateMode )properties["coordinate_mode"].toInt();
3531  }
3532  if ( properties.contains( "alpha" ) )
3533  {
3534  alpha = properties["alpha"].toDouble();
3535  }
3536  if ( properties.contains( "offset" ) )
3537  {
3538  offset = QgsSymbolLayerV2Utils::decodePoint( properties["offset"] );
3539  }
3540  if ( properties.contains( "angle" ) )
3541  {
3542  angle = properties["angle"].toDouble();
3543  }
3544  if ( properties.contains( "width" ) )
3545  {
3546  width = properties["width"].toDouble();
3547  }
3548  QgsRasterFillSymbolLayer* symbolLayer = new QgsRasterFillSymbolLayer( imagePath );
3549  symbolLayer->setCoordinateMode( mode );
3550  symbolLayer->setAlpha( alpha );
3551  symbolLayer->setOffset( offset );
3552  symbolLayer->setAngle( angle );
3553  symbolLayer->setWidth( width );
3554  if ( properties.contains( "offset_unit" ) )
3555  {
3556  symbolLayer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
3557  }
3558  if ( properties.contains( "offset_map_unit_scale" ) )
3559  {
3560  symbolLayer->setOffsetMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["offset_map_unit_scale"] ) );
3561  }
3562  if ( properties.contains( "width_unit" ) )
3563  {
3564  symbolLayer->setWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["width_unit"] ) );
3565  }
3566  if ( properties.contains( "width_map_unit_scale" ) )
3567  {
3568  symbolLayer->setWidthMapUnitScale( QgsSymbolLayerV2Utils::decodeMapUnitScale( properties["width_map_unit_scale"] ) );
3569  }
3570 
3571  //data defined
3572  if ( properties.contains( "file_expression" ) )
3573  {
3574  symbolLayer->setDataDefinedProperty( "file", properties["file_expression"] );
3575  }
3576  if ( properties.contains( "alpha_expression" ) )
3577  {
3578  symbolLayer->setDataDefinedProperty( "alpha", properties["alpha_expression"] );
3579  }
3580  if ( properties.contains( "angle_expression" ) )
3581  {
3582  symbolLayer->setDataDefinedProperty( "angle", properties["angle_expression"] );
3583  }
3584  if ( properties.contains( "width_expression" ) )
3585  {
3586  symbolLayer->setDataDefinedProperty( "width", properties["width_expression"] );
3587  }
3588  return symbolLayer;
3589 }
3590 
3592 {
3593  Q_UNUSED( symbol );
3594  return true;
3595 }
3596 
3598 {
3599  return "RasterFill";
3600 }
3601 
3602 void QgsRasterFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolV2RenderContext &context )
3603 {
3604  QPainter* p = context.renderContext().painter();
3605  if ( !p )
3606  {
3607  return;
3608  }
3609 
3610  QPointF offset;
3611  if ( !mOffset.isNull() )
3612  {
3615  p->translate( offset );
3616  }
3617  if ( mCoordinateMode == Feature )
3618  {
3619  QRectF boundingRect = points.boundingRect();
3620  mBrush.setTransform( mBrush.transform().translate( boundingRect.left() - mBrush.transform().dx(),
3621  boundingRect.top() - mBrush.transform().dy() ) );
3622  }
3623 
3624  QgsImageFillSymbolLayer::renderPolygon( points, rings, context );
3625  if ( !mOffset.isNull() )
3626  {
3627  p->translate( -offset );
3628  }
3629 }
3630 
3632 {
3633  prepareExpressions( context.fields(), context.renderContext().rendererScale() );
3634  applyPattern( mBrush, mImageFilePath, mWidth, mAlpha, context );
3635 }
3636 
3638 {
3639  Q_UNUSED( context );
3640 }
3641 
3643 {
3644  QgsStringMap map;
3645  map["imageFile"] = mImageFilePath;
3646  map["coordinate_mode"] = QString::number( mCoordinateMode );
3647  map["alpha"] = QString::number( mAlpha );
3648  map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
3649  map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
3650  map["offset_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOffsetMapUnitScale );
3651  map["angle"] = QString::number( mAngle );
3652  map["width"] = QString::number( mWidth );
3653  map["width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mWidthUnit );
3654  map["width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mWidthMapUnitScale );
3655 
3657  return map;
3658 }
3659 
3661 {
3664  sl->setAlpha( mAlpha );
3665  sl->setOffset( mOffset );
3666  sl->setOffsetUnit( mOffsetUnit );
3668  sl->setAngle( mAngle );
3669  sl->setWidth( mWidth );
3670  sl->setWidthUnit( mWidthUnit );
3673  return sl;
3674 }
3675 
3677 {
3678  return mOffset.x() > mOffset.y() ? mOffset.x() : mOffset.y();
3679 }
3680 
3681 void QgsRasterFillSymbolLayer::setImageFilePath( const QString &imagePath )
3682 {
3683  mImageFilePath = imagePath;
3684 }
3685 
3687 {
3688  mCoordinateMode = mode;
3689 }
3690 
3691 void QgsRasterFillSymbolLayer::setAlpha( const double alpha )
3692 {
3693  mAlpha = alpha;
3694 }
3695 
3697 {
3698  if ( mDataDefinedProperties.isEmpty() )
3699  return; // shortcut
3700 
3701  QgsExpression* widthExpression = expression( "width" );
3702  QgsExpression* fileExpression = expression( "file" );
3703  QgsExpression* alphaExpression = expression( "alpha" );
3704  QgsExpression* angleExpression = expression( "angle" );
3705 
3706  if ( !widthExpression && !angleExpression && !alphaExpression && !fileExpression )
3707  {
3708  return; //no data defined settings
3709  }
3710 
3711  if ( angleExpression )
3712  {
3713  mNextAngle = angleExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
3714  }
3715 
3716  if ( !widthExpression && !alphaExpression && !fileExpression )
3717  {
3718  return; //nothing further to do
3719  }
3720 
3721  double width = mWidth;
3722  if ( widthExpression )
3723  {
3724  width = widthExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
3725  }
3726  double alpha = mAlpha;
3727  if ( alphaExpression )
3728  {
3729  alpha = alphaExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toDouble();
3730  }
3731  QString file = mImageFilePath;
3732  if ( fileExpression )
3733  {
3734  file = fileExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
3735  }
3736  applyPattern( mBrush, file, width, alpha, context );
3737 }
3738 
3739 void QgsRasterFillSymbolLayer::applyPattern( QBrush &brush, const QString &imageFilePath, const double width, const double alpha, const QgsSymbolV2RenderContext &context )
3740 {
3741  QImage image( imageFilePath );
3742  if ( image.isNull() )
3743  {
3744  return;
3745  }
3746  if ( !image.hasAlphaChannel() )
3747  {
3748  image = image.convertToFormat( QImage::Format_ARGB32 );
3749  }
3750 
3751  double pixelWidth;
3752  if ( width > 0 )
3753  {
3755  }
3756  else
3757  {
3758  pixelWidth = image.width();
3759  }
3760 
3761  //reduce alpha of image
3762  if ( alpha < 1.0 )
3763  {
3764  QPainter p;
3765  p.begin( &image );
3766  p.setCompositionMode( QPainter::CompositionMode_DestinationIn );
3767  QColor alphaColor( 0, 0, 0 );
3768  alphaColor.setAlphaF( alpha );
3769  p.fillRect( image.rect(), alphaColor );
3770  p.end();
3771  }
3772 
3773  //resize image if required
3774  if ( !qgsDoubleNear( pixelWidth, image.width() ) )
3775  {
3776  image = image.scaledToWidth( pixelWidth, Qt::SmoothTransformation );
3777  }
3778 
3779  brush.setTextureImage( image );
3780 }
virtual QSet< QString > usedAttributes() const
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's boundary...
const QgsMapUnitScale & patternWidthMapUnitScale() const
#define DEFAULT_SIMPLEFILL_BORDERCOLOR
QString layerType() const override
double outlineWidth
Definition: qgssvgcache.cpp:78
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
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:416
void setColorRamp(QgsVectorColorRampV2 *ramp)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:325
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:84
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'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'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's path from its name.
#define M_PI
void startRender(QgsSymbolV2RenderContext &context) override
QgsSVGFillSymbolLayer(const QString &svgFilePath="", double width=20, double rotation=0.0)
virtual QgsSymbolV2 * clone() const override
void setDistanceYMapUnitScale(const QgsMapUnitScale &scale)
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())
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)
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.
double rasterScaleFactor
Definition: qgssvgcache.cpp:80
void setDistanceXUnit(QgsSymbolV2::OutputUnit unit)
double mLineWidth
Line width (in mm or map units)
QgsVectorColorRampV2 * mGradientRamp
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...
QString file
Definition: qgssvgcache.cpp:76
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)
double widthScaleFactor
Definition: qgssvgcache.cpp:79
static void createGeometryElement(QDomDocument &doc, QDomElement &element, QString geomFunc)
QgsMapUnitScale mapUnitScale() const override
Contains information about the context of a rendering operation.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the fill's offset.
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.
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
#define INF
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.
static QgsSymbolLayerV2 * createFromSld(QDomElement &element)
void setWidthUnit(const QgsSymbolV2::OutputUnit unit)
Sets the units for the image's width.
void setPatternWidthUnit(QgsSymbolV2::OutputUnit unit)
static bool lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=0, Qt::PenCapStyle *penCapStyle=0, QVector< qreal > *customDashPattern=0, double *dashOffset=0)
QgsSymbolV2::OutputUnit mPatternWidthUnit
static QPointF polygonPointOnSurface(const QPolygonF &points)
Calculate a point within of a QPolygonF.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
void _renderPolygon(QPainter *p, const QPolygonF &points, const QList< QPolygonF > *rings, QgsSymbolV2RenderContext &context)
Default method to render polygon.
void setOutputUnit(QgsSymbolV2::OutputUnit unit) override
void addStopsToGradient(QGradient *gradient, double alpha=1)
copy color ramp stops to a QGradient
static const bool selectFillBorder
void setColor(const QColor &color) override
static QPointF pointOnLineWithDistance(const QPointF &startPoint, const QPointF &directionPoint, double distance)
Returns a point on the line from startPoint to directionPoint that is a certain distance away from th...
double size
Definition: qgssvgcache.cpp:77
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'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'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