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