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