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