QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsfillsymbollayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfillsymbollayer.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 "qgsfillsymbollayer.h"
17 #include "qgslinesymbollayer.h"
18 #include "qgsmarkersymbollayer.h"
19 #include "qgssymbollayerutils.h"
20 #include "qgsdxfexport.h"
21 #include "qgsexpression.h"
22 #include "qgsgeometry.h"
23 #include "qgsgeometrycollection.h"
24 #include "qgsimagecache.h"
25 #include "qgsrendercontext.h"
26 #include "qgsproject.h"
27 #include "qgssvgcache.h"
28 #include "qgslogger.h"
29 #include "qgscolorramp.h"
30 #include "qgscolorrampimpl.h"
31 #include "qgsunittypes.h"
32 #include "qgsmessagelog.h"
33 #include "qgsapplication.h"
34 #include "qgsimageoperation.h"
35 #include "qgspolygon.h"
36 #include "qgslinestring.h"
38 #include "qgssymbol.h"
39 #include "qgsmarkersymbol.h"
40 #include "qgslinesymbol.h"
41 #include "qgsfeedback.h"
42 #include "qgsgeometryengine.h"
43 
44 #include <QPainter>
45 #include <QFile>
46 #include <QSvgRenderer>
47 #include <QDomDocument>
48 #include <QDomElement>
49 #include <random>
50 
51 #ifndef QT_NO_PRINTER
52 #include <QPrinter>
53 #endif
54 
55 QgsSimpleFillSymbolLayer::QgsSimpleFillSymbolLayer( const QColor &color, Qt::BrushStyle style, const QColor &strokeColor, Qt::PenStyle strokeStyle, double strokeWidth,
56  Qt::PenJoinStyle penJoinStyle )
57  : mBrushStyle( style )
58  , mStrokeColor( strokeColor )
59  , mStrokeStyle( strokeStyle )
60  , mStrokeWidth( strokeWidth )
61  , mPenJoinStyle( penJoinStyle )
62 {
63  mColor = color;
64 }
65 
67 
69 {
70  mStrokeWidthUnit = unit;
71  mOffsetUnit = unit;
72 }
73 
75 {
77  if ( mOffsetUnit != unit )
78  {
80  }
81  return unit;
82 }
83 
85 {
88 }
89 
91 {
93  mOffsetMapUnitScale = scale;
94 }
95 
97 {
99  {
101  }
102  return QgsMapUnitScale();
103 }
104 
105 void QgsSimpleFillSymbolLayer::applyDataDefinedSymbology( QgsSymbolRenderContext &context, QBrush &brush, QPen &pen, QPen &selPen )
106 {
107  if ( !dataDefinedProperties().hasActiveProperties() )
108  return; // shortcut
109 
110  bool ok;
111 
113  {
116  fillColor.setAlphaF( context.opacity() * fillColor.alphaF() );
117  brush.setColor( fillColor );
118  }
120  {
123  if ( !exprVal.isNull() )
124  brush.setStyle( QgsSymbolLayerUtils::decodeBrushStyle( exprVal.toString() ) );
125  }
127  {
130  penColor.setAlphaF( context.opacity() * penColor.alphaF() );
131  pen.setColor( penColor );
132  }
134  {
137  if ( !exprVal.isNull() )
138  {
139  double width = exprVal.toDouble( &ok );
140  if ( ok )
141  {
143  pen.setWidthF( width );
144  selPen.setWidthF( width );
145  }
146  }
147  }
149  {
152  if ( ok )
153  {
154  pen.setStyle( QgsSymbolLayerUtils::decodePenStyle( style ) );
155  selPen.setStyle( QgsSymbolLayerUtils::decodePenStyle( style ) );
156  }
157  }
159  {
162  if ( ok )
163  {
164  pen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( style ) );
165  selPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( style ) );
166  }
167  }
168 }
169 
170 
172 {
174  Qt::BrushStyle style = DEFAULT_SIMPLEFILL_STYLE;
178  Qt::PenJoinStyle penJoinStyle = DEFAULT_SIMPLEFILL_JOINSTYLE;
179  QPointF offset;
180 
181  if ( props.contains( QStringLiteral( "color" ) ) )
182  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color" )].toString() );
183  if ( props.contains( QStringLiteral( "style" ) ) )
184  style = QgsSymbolLayerUtils::decodeBrushStyle( props[QStringLiteral( "style" )].toString() );
185  if ( props.contains( QStringLiteral( "color_border" ) ) )
186  {
187  //pre 2.5 projects used "color_border"
188  strokeColor = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color_border" )].toString() );
189  }
190  else if ( props.contains( QStringLiteral( "outline_color" ) ) )
191  {
192  strokeColor = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "outline_color" )].toString() );
193  }
194  else if ( props.contains( QStringLiteral( "line_color" ) ) )
195  {
196  strokeColor = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "line_color" )].toString() );
197  }
198 
199  if ( props.contains( QStringLiteral( "style_border" ) ) )
200  {
201  //pre 2.5 projects used "style_border"
202  strokeStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "style_border" )].toString() );
203  }
204  else if ( props.contains( QStringLiteral( "outline_style" ) ) )
205  {
206  strokeStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "outline_style" )].toString() );
207  }
208  else if ( props.contains( QStringLiteral( "line_style" ) ) )
209  {
210  strokeStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "line_style" )].toString() );
211  }
212  if ( props.contains( QStringLiteral( "width_border" ) ) )
213  {
214  //pre 2.5 projects used "width_border"
215  strokeWidth = props[QStringLiteral( "width_border" )].toDouble();
216  }
217  else if ( props.contains( QStringLiteral( "outline_width" ) ) )
218  {
219  strokeWidth = props[QStringLiteral( "outline_width" )].toDouble();
220  }
221  else if ( props.contains( QStringLiteral( "line_width" ) ) )
222  {
223  strokeWidth = props[QStringLiteral( "line_width" )].toDouble();
224  }
225  if ( props.contains( QStringLiteral( "offset" ) ) )
226  offset = QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "offset" )].toString() );
227  if ( props.contains( QStringLiteral( "joinstyle" ) ) )
228  penJoinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( props[QStringLiteral( "joinstyle" )].toString() );
229 
230  std::unique_ptr< QgsSimpleFillSymbolLayer > sl = std::make_unique< QgsSimpleFillSymbolLayer >( color, style, strokeColor, strokeStyle, strokeWidth, penJoinStyle );
231  sl->setOffset( offset );
232  if ( props.contains( QStringLiteral( "border_width_unit" ) ) )
233  {
234  sl->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "border_width_unit" )].toString() ) );
235  }
236  else if ( props.contains( QStringLiteral( "outline_width_unit" ) ) )
237  {
238  sl->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "outline_width_unit" )].toString() ) );
239  }
240  else if ( props.contains( QStringLiteral( "line_width_unit" ) ) )
241  {
242  sl->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "line_width_unit" )].toString() ) );
243  }
244  if ( props.contains( QStringLiteral( "offset_unit" ) ) )
245  sl->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )].toString() ) );
246 
247  if ( props.contains( QStringLiteral( "border_width_map_unit_scale" ) ) )
248  sl->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "border_width_map_unit_scale" )].toString() ) );
249  if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
250  sl->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
251 
252  sl->restoreOldDataDefinedProperties( props );
253 
254  return sl.release();
255 }
256 
257 
259 {
260  return QStringLiteral( "SimpleFill" );
261 }
262 
264 {
265  QColor fillColor = mColor;
266  fillColor.setAlphaF( context.opacity() * mColor.alphaF() );
267  mBrush = QBrush( fillColor, mBrushStyle );
268 
269  QColor selColor = context.renderContext().selectionColor();
270  QColor selPenColor = selColor == mColor ? selColor : mStrokeColor;
271  if ( ! SELECTION_IS_OPAQUE )
272  selColor.setAlphaF( context.opacity() );
273  mSelBrush = QBrush( selColor );
274  // N.B. unless a "selection line color" is implemented in addition to the "selection color" option
275  // this would mean symbols with "no fill" look the same whether or not they are selected
276  if ( SELECT_FILL_STYLE )
277  mSelBrush.setStyle( mBrushStyle );
278 
279  QColor strokeColor = mStrokeColor;
280  strokeColor.setAlphaF( context.opacity() * mStrokeColor.alphaF() );
281  mPen = QPen( strokeColor );
282  mSelPen = QPen( selPenColor );
283  mPen.setStyle( mStrokeStyle );
285  mPen.setJoinStyle( mPenJoinStyle );
286 }
287 
289 {
290  Q_UNUSED( context )
291 }
292 
293 void QgsSimpleFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
294 {
295  QPainter *p = context.renderContext().painter();
296  if ( !p )
297  {
298  return;
299  }
300 
301  QColor fillColor = mColor;
302  fillColor.setAlphaF( context.opacity() * mColor.alphaF() );
303  mBrush.setColor( fillColor );
304  QColor strokeColor = mStrokeColor;
305  strokeColor.setAlphaF( context.opacity() * mStrokeColor.alphaF() );
306  mPen.setColor( strokeColor );
307 
308  applyDataDefinedSymbology( context, mBrush, mPen, mSelPen );
309 
310  QPointF offset = mOffset;
311 
313  {
315  const QVariant val = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), QString() );
316  bool ok = false;
317  const QPointF res = QgsSymbolLayerUtils::toPoint( val, &ok );
318  if ( ok )
319  offset = res;
320  }
321 
322  if ( !offset.isNull() )
323  {
326  p->translate( offset );
327  }
328 
329 #ifndef QT_NO_PRINTER
330  if ( mBrush.style() == Qt::SolidPattern || mBrush.style() == Qt::NoBrush || !dynamic_cast<QPrinter *>( p->device() ) )
331 #endif
332  {
333  p->setPen( context.selected() ? mSelPen : mPen );
334  p->setBrush( context.selected() ? mSelBrush : mBrush );
335  _renderPolygon( p, points, rings, context );
336  }
337 #ifndef QT_NO_PRINTER
338  else
339  {
340  // workaround upstream issue https://github.com/qgis/QGIS/issues/36580
341  // when a non-solid brush is set with opacity, the opacity incorrectly applies to the pen
342  // when exporting to PDF/print devices
343  p->setBrush( context.selected() ? mSelBrush : mBrush );
344  p->setPen( Qt::NoPen );
345  _renderPolygon( p, points, rings, context );
346 
347  p->setPen( context.selected() ? mSelPen : mPen );
348  p->setBrush( Qt::NoBrush );
349  _renderPolygon( p, points, rings, context );
350  }
351 #endif
352 
353  if ( !offset.isNull() )
354  {
355  p->translate( -offset );
356  }
357 }
358 
360 {
361  QVariantMap map;
362  map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
363  map[QStringLiteral( "style" )] = QgsSymbolLayerUtils::encodeBrushStyle( mBrushStyle );
364  map[QStringLiteral( "outline_color" )] = QgsSymbolLayerUtils::encodeColor( mStrokeColor );
365  map[QStringLiteral( "outline_style" )] = QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle );
366  map[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
367  map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
368  map[QStringLiteral( "border_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
369  map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
370  map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
371  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
372  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
373  return map;
374 }
375 
377 {
378  std::unique_ptr< QgsSimpleFillSymbolLayer > sl = std::make_unique< QgsSimpleFillSymbolLayer >( mColor, mBrushStyle, mStrokeColor, mStrokeStyle, mStrokeWidth, mPenJoinStyle );
379  sl->setOffset( mOffset );
380  sl->setOffsetUnit( mOffsetUnit );
381  sl->setOffsetMapUnitScale( mOffsetMapUnitScale );
382  sl->setStrokeWidthUnit( mStrokeWidthUnit );
383  sl->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
384  copyDataDefinedProperties( sl.get() );
385  copyPaintEffect( sl.get() );
386  return sl.release();
387 }
388 
389 void QgsSimpleFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
390 {
391  if ( mBrushStyle == Qt::NoBrush && mStrokeStyle == Qt::NoPen )
392  return;
393 
394  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PolygonSymbolizer" ) );
395  if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
396  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
397  element.appendChild( symbolizerElem );
398 
399  // <Geometry>
400  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
401 
402  if ( mBrushStyle != Qt::NoBrush )
403  {
404  // <Fill>
405  QDomElement fillElem = doc.createElement( QStringLiteral( "se:Fill" ) );
406  symbolizerElem.appendChild( fillElem );
408  }
409 
410  if ( mStrokeStyle != Qt::NoPen )
411  {
412  // <Stroke>
413  QDomElement strokeElem = doc.createElement( QStringLiteral( "se:Stroke" ) );
414  symbolizerElem.appendChild( strokeElem );
417  }
418 
419  // <se:Displacement>
422 }
423 
424 QString QgsSimpleFillSymbolLayer::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
425 {
426  //brush
427  QString symbolStyle;
428  symbolStyle.append( QgsSymbolLayerUtils::ogrFeatureStyleBrush( mColor ) );
429  symbolStyle.append( ';' );
430  //pen
431  symbolStyle.append( QgsSymbolLayerUtils::ogrFeatureStylePen( mStrokeWidth, mmScaleFactor, mapUnitScaleFactor, mStrokeColor, mPenJoinStyle ) );
432  return symbolStyle;
433 }
434 
436 {
437  QColor color, strokeColor;
438  Qt::BrushStyle fillStyle;
439  Qt::PenStyle strokeStyle;
440  double strokeWidth;
441 
442  QDomElement fillElem = element.firstChildElement( QStringLiteral( "Fill" ) );
443  QgsSymbolLayerUtils::fillFromSld( fillElem, fillStyle, color );
444 
445  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
447 
448  QPointF offset;
450 
451  double scaleFactor = 1.0;
452  const QString uom = element.attribute( QStringLiteral( "uom" ) );
453  QgsUnitTypes::RenderUnit sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( uom, &scaleFactor );
454  offset.setX( offset.x() * scaleFactor );
455  offset.setY( offset.y() * scaleFactor );
456  strokeWidth = strokeWidth * scaleFactor;
457 
458  std::unique_ptr< QgsSimpleFillSymbolLayer > sl = std::make_unique< QgsSimpleFillSymbolLayer >( color, fillStyle, strokeColor, strokeStyle, strokeWidth );
459  sl->setOutputUnit( sldUnitSize );
460  sl->setOffset( offset );
461  return sl.release();
462 }
463 
465 {
466  double penBleed = context.convertToPainterUnits( mStrokeStyle == Qt::NoPen ? 0 : ( mStrokeWidth / 2.0 ), mStrokeWidthUnit, mStrokeWidthMapUnitScale );
467  double offsetBleed = context.convertToPainterUnits( std::max( std::fabs( mOffset.x() ), std::fabs( mOffset.y() ) ), mOffsetUnit, mOffsetMapUnitScale );
468  return penBleed + offsetBleed;
469 }
470 
472 {
473  double width = mStrokeWidth;
475  {
478  }
480 }
481 
483 {
484  QColor c = mStrokeColor;
486  {
489  }
490  return c;
491 }
492 
494 {
495  double angle = mAngle;
497  {
498  context.setOriginalValueVariable( mAngle );
500  }
501  return angle;
502 }
503 
505 {
506  return mStrokeStyle;
507 }
508 
510 {
511  QColor c = mColor;
513  {
515  }
516  return c;
517 }
518 
520 {
521  return mBrushStyle;
522 }
523 
524 //QgsGradientFillSymbolLayer
525 
526 QgsGradientFillSymbolLayer::QgsGradientFillSymbolLayer( const QColor &color, const QColor &color2,
527  Qgis::GradientColorSource colorType, Qgis::GradientType gradientType,
529  : mGradientColorType( colorType )
530  , mGradientType( gradientType )
531  , mCoordinateMode( coordinateMode )
532  , mGradientSpread( spread )
533  , mReferencePoint1( QPointF( 0.5, 0 ) )
534  , mReferencePoint2( QPointF( 0.5, 1 ) )
535 {
536  mColor = color;
537  mColor2 = color2;
538 }
539 
541 {
542  delete mGradientRamp;
543 }
544 
546 {
547  //default to a two-color, linear gradient with feature mode and pad spreading
552  //default to gradient from the default fill color to white
553  QColor color = DEFAULT_SIMPLEFILL_COLOR, color2 = Qt::white;
554  QPointF referencePoint1 = QPointF( 0.5, 0 );
555  bool refPoint1IsCentroid = false;
556  QPointF referencePoint2 = QPointF( 0.5, 1 );
557  bool refPoint2IsCentroid = false;
558  double angle = 0;
559  QPointF offset;
560 
561  //update gradient properties from props
562  if ( props.contains( QStringLiteral( "type" ) ) )
563  type = static_cast< Qgis::GradientType >( props[QStringLiteral( "type" )].toInt() );
564  if ( props.contains( QStringLiteral( "coordinate_mode" ) ) )
565  coordinateMode = static_cast< Qgis::SymbolCoordinateReference >( props[QStringLiteral( "coordinate_mode" )].toInt() );
566  if ( props.contains( QStringLiteral( "spread" ) ) )
567  gradientSpread = static_cast< Qgis::GradientSpread >( props[QStringLiteral( "spread" )].toInt() );
568  if ( props.contains( QStringLiteral( "color_type" ) ) )
569  colorType = static_cast< Qgis::GradientColorSource >( props[QStringLiteral( "color_type" )].toInt() );
570  if ( props.contains( QStringLiteral( "gradient_color" ) ) )
571  {
572  //pre 2.5 projects used "gradient_color"
573  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "gradient_color" )].toString() );
574  }
575  else if ( props.contains( QStringLiteral( "color" ) ) )
576  {
577  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color" )].toString() );
578  }
579  if ( props.contains( QStringLiteral( "gradient_color2" ) ) )
580  {
581  color2 = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "gradient_color2" )].toString() );
582  }
583 
584  if ( props.contains( QStringLiteral( "reference_point1" ) ) )
585  referencePoint1 = QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "reference_point1" )].toString() );
586  if ( props.contains( QStringLiteral( "reference_point1_iscentroid" ) ) )
587  refPoint1IsCentroid = props[QStringLiteral( "reference_point1_iscentroid" )].toInt();
588  if ( props.contains( QStringLiteral( "reference_point2" ) ) )
589  referencePoint2 = QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "reference_point2" )].toString() );
590  if ( props.contains( QStringLiteral( "reference_point2_iscentroid" ) ) )
591  refPoint2IsCentroid = props[QStringLiteral( "reference_point2_iscentroid" )].toInt();
592  if ( props.contains( QStringLiteral( "angle" ) ) )
593  angle = props[QStringLiteral( "angle" )].toDouble();
594 
595  if ( props.contains( QStringLiteral( "offset" ) ) )
596  offset = QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "offset" )].toString() );
597 
598  //attempt to create color ramp from props
599  QgsColorRamp *gradientRamp = nullptr;
600  if ( props.contains( QStringLiteral( "rampType" ) ) && props[QStringLiteral( "rampType" )] == QgsCptCityColorRamp::typeString() )
601  {
602  gradientRamp = QgsCptCityColorRamp::create( props );
603  }
604  else
605  {
606  gradientRamp = QgsGradientColorRamp::create( props );
607  }
608 
609  //create a new gradient fill layer with desired properties
610  std::unique_ptr< QgsGradientFillSymbolLayer > sl = std::make_unique< QgsGradientFillSymbolLayer >( color, color2, colorType, type, coordinateMode, gradientSpread );
611  sl->setOffset( offset );
612  if ( props.contains( QStringLiteral( "offset_unit" ) ) )
613  sl->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )].toString() ) );
614  if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
615  sl->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
616  sl->setReferencePoint1( referencePoint1 );
617  sl->setReferencePoint1IsCentroid( refPoint1IsCentroid );
618  sl->setReferencePoint2( referencePoint2 );
619  sl->setReferencePoint2IsCentroid( refPoint2IsCentroid );
620  sl->setAngle( angle );
621  if ( gradientRamp )
622  sl->setColorRamp( gradientRamp );
623 
624  sl->restoreOldDataDefinedProperties( props );
625 
626  return sl.release();
627 }
628 
630 {
631  delete mGradientRamp;
632  mGradientRamp = ramp;
633 }
634 
636 {
637  return QStringLiteral( "GradientFill" );
638 }
639 
640 void QgsGradientFillSymbolLayer::applyDataDefinedSymbology( QgsSymbolRenderContext &context, const QPolygonF &points )
641 {
642  if ( !dataDefinedProperties().hasActiveProperties() && !mReferencePoint1IsCentroid && !mReferencePoint2IsCentroid )
643  {
644  //shortcut
647  return;
648  }
649 
650  bool ok;
651 
652  //first gradient color
653  QColor color = mColor;
655  {
658  color.setAlphaF( context.opacity() * color.alphaF() );
659  }
660 
661  //second gradient color
662  QColor color2 = mColor2;
664  {
667  color2.setAlphaF( context.opacity() * color2.alphaF() );
668  }
669 
670  //gradient rotation angle
671  double angle = mAngle;
673  {
674  context.setOriginalValueVariable( mAngle );
676  }
677 
678  //gradient type
681  {
683  if ( ok )
684  {
685  if ( currentType == QObject::tr( "linear" ) )
686  {
688  }
689  else if ( currentType == QObject::tr( "radial" ) )
690  {
692  }
693  else if ( currentType == QObject::tr( "conical" ) )
694  {
696  }
697  }
698  }
699 
700  //coordinate mode
703  {
704  QString currentCoordMode = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyCoordinateMode, context.renderContext().expressionContext(), QString(), &ok );
705  if ( ok )
706  {
707  if ( currentCoordMode == QObject::tr( "feature" ) )
708  {
710  }
711  else if ( currentCoordMode == QObject::tr( "viewport" ) )
712  {
714  }
715  }
716  }
717 
718  //gradient spread
721  {
723  if ( ok )
724  {
725  if ( currentSpread == QObject::tr( "pad" ) )
726  {
727  spread = Qgis::GradientSpread::Pad;
728  }
729  else if ( currentSpread == QObject::tr( "repeat" ) )
730  {
732  }
733  else if ( currentSpread == QObject::tr( "reflect" ) )
734  {
736  }
737  }
738  }
739 
740  //reference point 1 x & y
741  double refPoint1X = mReferencePoint1.x();
743  {
744  context.setOriginalValueVariable( refPoint1X );
746  }
747  double refPoint1Y = mReferencePoint1.y();
749  {
750  context.setOriginalValueVariable( refPoint1Y );
752  }
753  bool refPoint1IsCentroid = mReferencePoint1IsCentroid;
755  {
756  context.setOriginalValueVariable( refPoint1IsCentroid );
758  }
759 
760  //reference point 2 x & y
761  double refPoint2X = mReferencePoint2.x();
763  {
764  context.setOriginalValueVariable( refPoint2X );
766  }
767  double refPoint2Y = mReferencePoint2.y();
769  {
770  context.setOriginalValueVariable( refPoint2Y );
772  }
773  bool refPoint2IsCentroid = mReferencePoint2IsCentroid;
775  {
776  context.setOriginalValueVariable( refPoint2IsCentroid );
778  }
779 
780  if ( refPoint1IsCentroid || refPoint2IsCentroid )
781  {
782  //either the gradient is starting or ending at a centroid, so calculate it
784  //centroid coordinates need to be scaled to a range [0, 1] relative to polygon bounds
785  QRectF bbox = points.boundingRect();
786  double centroidX = ( centroid.x() - bbox.left() ) / bbox.width();
787  double centroidY = ( centroid.y() - bbox.top() ) / bbox.height();
788 
789  if ( refPoint1IsCentroid )
790  {
791  refPoint1X = centroidX;
792  refPoint1Y = centroidY;
793  }
794  if ( refPoint2IsCentroid )
795  {
796  refPoint2X = centroidX;
797  refPoint2Y = centroidY;
798  }
799  }
800 
801  //update gradient with data defined values
803  spread, QPointF( refPoint1X, refPoint1Y ), QPointF( refPoint2X, refPoint2Y ), angle );
804 }
805 
806 QPointF QgsGradientFillSymbolLayer::rotateReferencePoint( QPointF refPoint, double angle )
807 {
808  //rotate a reference point by a specified angle around the point (0.5, 0.5)
809 
810  //create a line from the centrepoint of a rectangle bounded by (0, 0) and (1, 1) to the reference point
811  QLineF refLine = QLineF( QPointF( 0.5, 0.5 ), refPoint );
812  //rotate this line by the current rotation angle
813  refLine.setAngle( refLine.angle() + angle );
814  //get new end point of line
815  QPointF rotatedReferencePoint = refLine.p2();
816  //make sure coords of new end point is within [0, 1]
817  if ( rotatedReferencePoint.x() > 1 )
818  rotatedReferencePoint.setX( 1 );
819  if ( rotatedReferencePoint.x() < 0 )
820  rotatedReferencePoint.setX( 0 );
821  if ( rotatedReferencePoint.y() > 1 )
822  rotatedReferencePoint.setY( 1 );
823  if ( rotatedReferencePoint.y() < 0 )
824  rotatedReferencePoint.setY( 0 );
825 
826  return rotatedReferencePoint;
827 }
828 
829 void QgsGradientFillSymbolLayer::applyGradient( const QgsSymbolRenderContext &context, QBrush &brush,
830  const QColor &color, const QColor &color2, Qgis::GradientColorSource gradientColorType,
831  QgsColorRamp *gradientRamp, Qgis::GradientType gradientType,
832  Qgis::SymbolCoordinateReference coordinateMode, Qgis::GradientSpread gradientSpread,
833  QPointF referencePoint1, QPointF referencePoint2, const double angle )
834 {
835  //update alpha of gradient colors
836  QColor fillColor = color;
837  fillColor.setAlphaF( context.opacity() * fillColor.alphaF() );
838  QColor fillColor2 = color2;
839  fillColor2.setAlphaF( context.opacity() * fillColor2.alphaF() );
840 
841  //rotate reference points
842  QPointF rotatedReferencePoint1 = !qgsDoubleNear( angle, 0.0 ) ? rotateReferencePoint( referencePoint1, angle ) : referencePoint1;
843  QPointF rotatedReferencePoint2 = !qgsDoubleNear( angle, 0.0 ) ? rotateReferencePoint( referencePoint2, angle ) : referencePoint2;
844 
845  //create a QGradient with the desired properties
846  QGradient gradient;
847  switch ( gradientType )
848  {
850  gradient = QLinearGradient( rotatedReferencePoint1, rotatedReferencePoint2 );
851  break;
853  gradient = QRadialGradient( rotatedReferencePoint1, QLineF( rotatedReferencePoint1, rotatedReferencePoint2 ).length() );
854  break;
856  gradient = QConicalGradient( rotatedReferencePoint1, QLineF( rotatedReferencePoint1, rotatedReferencePoint2 ).angle() );
857  break;
858  }
859  switch ( coordinateMode )
860  {
862  gradient.setCoordinateMode( QGradient::ObjectBoundingMode );
863  break;
865  gradient.setCoordinateMode( QGradient::StretchToDeviceMode );
866  break;
867  }
868  switch ( gradientSpread )
869  {
871  gradient.setSpread( QGradient::PadSpread );
872  break;
874  gradient.setSpread( QGradient::ReflectSpread );
875  break;
877  gradient.setSpread( QGradient::RepeatSpread );
878  break;
879  }
880 
881  //add stops to gradient
883  ( gradientRamp->type() == QgsGradientColorRamp::typeString() || gradientRamp->type() == QgsCptCityColorRamp::typeString() ) )
884  {
885  //color ramp gradient
886  QgsGradientColorRamp *gradRamp = static_cast<QgsGradientColorRamp *>( gradientRamp );
887  gradRamp->addStopsToGradient( &gradient, context.opacity() );
888  }
889  else
890  {
891  //two color gradient
892  gradient.setColorAt( 0.0, fillColor );
893  gradient.setColorAt( 1.0, fillColor2 );
894  }
895 
896  //update QBrush use gradient
897  brush = QBrush( gradient );
898 }
899 
901 {
902  QColor selColor = context.renderContext().selectionColor();
903  if ( ! SELECTION_IS_OPAQUE )
904  selColor.setAlphaF( context.opacity() );
905  mSelBrush = QBrush( selColor );
906 }
907 
909 {
910  Q_UNUSED( context )
911 }
912 
913 void QgsGradientFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
914 {
915  QPainter *p = context.renderContext().painter();
916  if ( !p )
917  {
918  return;
919  }
920 
921  applyDataDefinedSymbology( context, points );
922 
923  p->setBrush( context.selected() ? mSelBrush : mBrush );
924  p->setPen( Qt::NoPen );
925 
926  QPointF offset = mOffset;
928  {
930  const QVariant val = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), QString() );
931  bool ok = false;
932  const QPointF res = QgsSymbolLayerUtils::toPoint( val, &ok );
933  if ( ok )
934  offset = res;
935  }
936 
937  if ( !offset.isNull() )
938  {
941  p->translate( offset );
942  }
943 
944  _renderPolygon( p, points, rings, context );
945 
946  if ( !offset.isNull() )
947  {
948  p->translate( -offset );
949  }
950 }
951 
953 {
954  QVariantMap map;
955  map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
956  map[QStringLiteral( "gradient_color2" )] = QgsSymbolLayerUtils::encodeColor( mColor2 );
957  map[QStringLiteral( "color_type" )] = QString::number( static_cast< int >( mGradientColorType ) );
958  map[QStringLiteral( "type" )] = QString::number( static_cast<int>( mGradientType ) );
959  map[QStringLiteral( "coordinate_mode" )] = QString::number( static_cast< int >( mCoordinateMode ) );
960  map[QStringLiteral( "spread" )] = QString::number( static_cast< int >( mGradientSpread ) );
961  map[QStringLiteral( "reference_point1" )] = QgsSymbolLayerUtils::encodePoint( mReferencePoint1 );
962  map[QStringLiteral( "reference_point1_iscentroid" )] = QString::number( mReferencePoint1IsCentroid );
963  map[QStringLiteral( "reference_point2" )] = QgsSymbolLayerUtils::encodePoint( mReferencePoint2 );
964  map[QStringLiteral( "reference_point2_iscentroid" )] = QString::number( mReferencePoint2IsCentroid );
965  map[QStringLiteral( "angle" )] = QString::number( mAngle );
966  map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
967  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
968  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
969  if ( mGradientRamp )
970  {
971 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
972  map.unite( mGradientRamp->properties() );
973 #else
974  map.insert( mGradientRamp->properties() );
975 #endif
976  }
977  return map;
978 }
979 
981 {
982  std::unique_ptr< QgsGradientFillSymbolLayer > sl = std::make_unique< QgsGradientFillSymbolLayer >( mColor, mColor2, mGradientColorType, mGradientType, mCoordinateMode, mGradientSpread );
983  if ( mGradientRamp )
984  sl->setColorRamp( mGradientRamp->clone() );
985  sl->setReferencePoint1( mReferencePoint1 );
986  sl->setReferencePoint1IsCentroid( mReferencePoint1IsCentroid );
987  sl->setReferencePoint2( mReferencePoint2 );
988  sl->setReferencePoint2IsCentroid( mReferencePoint2IsCentroid );
989  sl->setAngle( mAngle );
990  sl->setOffset( mOffset );
991  sl->setOffsetUnit( mOffsetUnit );
992  sl->setOffsetMapUnitScale( mOffsetMapUnitScale );
993  copyDataDefinedProperties( sl.get() );
994  copyPaintEffect( sl.get() );
995  return sl.release();
996 }
997 
999 {
1000  double offsetBleed = context.convertToPainterUnits( std::max( std::fabs( mOffset.x() ), std::fabs( mOffset.y() ) ), mOffsetUnit, mOffsetMapUnitScale );
1001  return offsetBleed;
1002 }
1003 
1005 {
1006  return true;
1007 }
1008 
1010 {
1011  mOffsetUnit = unit;
1012 }
1013 
1015 {
1016  return mOffsetUnit;
1017 }
1018 
1020 {
1022 }
1023 
1025 {
1026  mOffsetMapUnitScale = scale;
1027 }
1028 
1030 {
1031  return mOffsetMapUnitScale;
1032 }
1033 
1034 //QgsShapeburstFillSymbolLayer
1035 
1037  int blurRadius, bool useWholeShape, double maxDistance )
1038  : mBlurRadius( blurRadius )
1039  , mUseWholeShape( useWholeShape )
1040  , mMaxDistance( maxDistance )
1041  , mColorType( colorType )
1042  , mColor2( color2 )
1043 {
1044  mColor = color;
1045 }
1046 
1048 
1050 {
1051  //default to a two-color gradient
1053  QColor color = DEFAULT_SIMPLEFILL_COLOR, color2 = Qt::white;
1054  int blurRadius = 0;
1055  bool useWholeShape = true;
1056  double maxDistance = 5;
1057  QPointF offset;
1058 
1059  //update fill properties from props
1060  if ( props.contains( QStringLiteral( "color_type" ) ) )
1061  {
1062  colorType = static_cast< Qgis::GradientColorSource >( props[QStringLiteral( "color_type" )].toInt() );
1063  }
1064  if ( props.contains( QStringLiteral( "shapeburst_color" ) ) )
1065  {
1066  //pre 2.5 projects used "shapeburst_color"
1067  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "shapeburst_color" )].toString() );
1068  }
1069  else if ( props.contains( QStringLiteral( "color" ) ) )
1070  {
1071  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color" )].toString() );
1072  }
1073 
1074  if ( props.contains( QStringLiteral( "shapeburst_color2" ) ) )
1075  {
1076  //pre 2.5 projects used "shapeburst_color2"
1077  color2 = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "shapeburst_color2" )].toString() );
1078  }
1079  else if ( props.contains( QStringLiteral( "gradient_color2" ) ) )
1080  {
1081  color2 = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "gradient_color2" )].toString() );
1082  }
1083  if ( props.contains( QStringLiteral( "blur_radius" ) ) )
1084  {
1085  blurRadius = props[QStringLiteral( "blur_radius" )].toInt();
1086  }
1087  if ( props.contains( QStringLiteral( "use_whole_shape" ) ) )
1088  {
1089  useWholeShape = props[QStringLiteral( "use_whole_shape" )].toInt();
1090  }
1091  if ( props.contains( QStringLiteral( "max_distance" ) ) )
1092  {
1093  maxDistance = props[QStringLiteral( "max_distance" )].toDouble();
1094  }
1095  if ( props.contains( QStringLiteral( "offset" ) ) )
1096  {
1097  offset = QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "offset" )].toString() );
1098  }
1099 
1100  //attempt to create color ramp from props
1101  QgsColorRamp *gradientRamp = nullptr;
1102  if ( props.contains( QStringLiteral( "rampType" ) ) && props[QStringLiteral( "rampType" )] == QgsCptCityColorRamp::typeString() )
1103  {
1104  gradientRamp = QgsCptCityColorRamp::create( props );
1105  }
1106  else
1107  {
1108  gradientRamp = QgsGradientColorRamp::create( props );
1109  }
1110 
1111  //create a new shapeburst fill layer with desired properties
1112  std::unique_ptr< QgsShapeburstFillSymbolLayer > sl = std::make_unique< QgsShapeburstFillSymbolLayer >( color, color2, colorType, blurRadius, useWholeShape, maxDistance );
1113  sl->setOffset( offset );
1114  if ( props.contains( QStringLiteral( "offset_unit" ) ) )
1115  {
1116  sl->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )].toString() ) );
1117  }
1118  if ( props.contains( QStringLiteral( "distance_unit" ) ) )
1119  {
1120  sl->setDistanceUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "distance_unit" )].toString() ) );
1121  }
1122  if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
1123  {
1124  sl->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
1125  }
1126  if ( props.contains( QStringLiteral( "distance_map_unit_scale" ) ) )
1127  {
1128  sl->setDistanceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "distance_map_unit_scale" )].toString() ) );
1129  }
1130  if ( props.contains( QStringLiteral( "ignore_rings" ) ) )
1131  {
1132  sl->setIgnoreRings( props[QStringLiteral( "ignore_rings" )].toInt() );
1133  }
1134  if ( gradientRamp )
1135  {
1136  sl->setColorRamp( gradientRamp );
1137  }
1138 
1139  sl->restoreOldDataDefinedProperties( props );
1140 
1141  return sl.release();
1142 }
1143 
1145 {
1146  return QStringLiteral( "ShapeburstFill" );
1147 }
1148 
1150 {
1151  if ( mGradientRamp.get() == ramp )
1152  return;
1153 
1154  mGradientRamp.reset( ramp );
1155 }
1156 
1157 void QgsShapeburstFillSymbolLayer::applyDataDefinedSymbology( QgsSymbolRenderContext &context, QColor &color, QColor &color2, int &blurRadius, bool &useWholeShape,
1158  double &maxDistance, bool &ignoreRings )
1159 {
1160  //first gradient color
1161  color = mColor;
1163  {
1166  }
1167 
1168  //second gradient color
1169  color2 = mColor2;
1171  {
1174  }
1175 
1176  //blur radius
1177  blurRadius = mBlurRadius;
1179  {
1180  context.setOriginalValueVariable( mBlurRadius );
1182  }
1183 
1184  //use whole shape
1185  useWholeShape = mUseWholeShape;
1187  {
1188  context.setOriginalValueVariable( mUseWholeShape );
1190  }
1191 
1192  //max distance
1193  maxDistance = mMaxDistance;
1195  {
1196  context.setOriginalValueVariable( mMaxDistance );
1198  }
1199 
1200  //ignore rings
1201  ignoreRings = mIgnoreRings;
1203  {
1204  context.setOriginalValueVariable( mIgnoreRings );
1206  }
1207 
1208 }
1209 
1211 {
1212  //TODO - check this
1213  QColor selColor = context.renderContext().selectionColor();
1214  if ( ! SELECTION_IS_OPAQUE )
1215  selColor.setAlphaF( context.opacity() );
1216  mSelBrush = QBrush( selColor );
1217 }
1218 
1220 {
1221  Q_UNUSED( context )
1222 }
1223 
1224 void QgsShapeburstFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
1225 {
1226  QPainter *p = context.renderContext().painter();
1227  if ( !p )
1228  {
1229  return;
1230  }
1231 
1232  if ( context.selected() )
1233  {
1234  //feature is selected, draw using selection style
1235  p->setBrush( mSelBrush );
1236  QPointF offset = mOffset;
1237 
1239  {
1241  const QVariant val = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), QString() );
1242  bool ok = false;
1243  const QPointF res = QgsSymbolLayerUtils::toPoint( val, &ok );
1244  if ( ok )
1245  offset = res;
1246  }
1247 
1248  if ( !offset.isNull() )
1249  {
1250  offset.setX( context.renderContext().convertToPainterUnits( offset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
1251  offset.setY( context.renderContext().convertToPainterUnits( offset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
1252  p->translate( offset );
1253  }
1254  _renderPolygon( p, points, rings, context );
1255  if ( !offset.isNull() )
1256  {
1257  p->translate( -offset );
1258  }
1259  return;
1260  }
1261 
1262  QColor color1, color2;
1263  int blurRadius;
1264  bool useWholeShape;
1265  double maxDistance;
1266  bool ignoreRings;
1267  //calculate data defined symbology
1268  applyDataDefinedSymbology( context, color1, color2, blurRadius, useWholeShape, maxDistance, ignoreRings );
1269 
1270  //calculate max distance for shapeburst fill to extend from polygon boundary, in pixels
1271  int outputPixelMaxDist = 0;
1272  if ( !useWholeShape && !qgsDoubleNear( maxDistance, 0.0 ) )
1273  {
1274  //convert max distance to pixels
1275  outputPixelMaxDist = static_cast< int >( std::round( context.renderContext().convertToPainterUnits( maxDistance, mDistanceUnit, mDistanceMapUnitScale ) ) );
1276  }
1277 
1278  //if we are using the two color mode, create a gradient ramp
1279  std::unique_ptr< QgsGradientColorRamp > twoColorGradientRamp;
1280  if ( mColorType == Qgis::GradientColorSource::SimpleTwoColor )
1281  {
1282  twoColorGradientRamp = std::make_unique< QgsGradientColorRamp >( color1, color2 );
1283  }
1284 
1285  //no stroke for shapeburst fills
1286  p->setPen( QPen( Qt::NoPen ) );
1287 
1288  //calculate margin size in pixels so that QImage of polygon has sufficient space to draw the full blur effect
1289  int sideBuffer = 4 + ( blurRadius + 2 ) * 4;
1290  //create a QImage to draw shapeburst in
1291  int pointsWidth = static_cast< int >( std::round( points.boundingRect().width() ) );
1292  int pointsHeight = static_cast< int >( std::round( points.boundingRect().height() ) );
1293  int imWidth = pointsWidth + ( sideBuffer * 2 );
1294  int imHeight = pointsHeight + ( sideBuffer * 2 );
1295 
1296  // these are all potentially very expensive operations, so check regularly if the job is canceled and abort responsively
1297  if ( context.renderContext().feedback() && context.renderContext().feedback()->isCanceled() )
1298  return;
1299 
1300  std::unique_ptr< QImage > fillImage = std::make_unique< QImage >( imWidth,
1301  imHeight, QImage::Format_ARGB32_Premultiplied );
1302  if ( fillImage->isNull() )
1303  {
1304  QgsMessageLog::logMessage( QObject::tr( "Could not allocate sufficient memory for shapeburst fill" ) );
1305  return;
1306  }
1307 
1308  if ( context.renderContext().feedback() && context.renderContext().feedback()->isCanceled() )
1309  return;
1310 
1311  //also create an image to store the alpha channel
1312  std::unique_ptr< QImage > alphaImage = std::make_unique< QImage >( fillImage->width(), fillImage->height(), QImage::Format_ARGB32_Premultiplied );
1313  if ( alphaImage->isNull() )
1314  {
1315  QgsMessageLog::logMessage( QObject::tr( "Could not allocate sufficient memory for shapeburst fill" ) );
1316  return;
1317  }
1318 
1319  if ( context.renderContext().feedback() && context.renderContext().feedback()->isCanceled() )
1320  return;
1321 
1322  //Fill this image with black. Initially the distance transform is drawn in greyscale, where black pixels have zero distance from the
1323  //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
1324  //polygon in white. The distance transform function then fills in the correct distance values for the white pixels.
1325  fillImage->fill( Qt::black );
1326 
1327  if ( context.renderContext().feedback() && context.renderContext().feedback()->isCanceled() )
1328  return;
1329 
1330  //initially fill the alpha channel image with a transparent color
1331  alphaImage->fill( Qt::transparent );
1332 
1333  if ( context.renderContext().feedback() && context.renderContext().feedback()->isCanceled() )
1334  return;
1335 
1336  //now, draw the polygon in the alpha channel image
1337  QPainter imgPainter;
1338  imgPainter.begin( alphaImage.get() );
1339  imgPainter.setRenderHint( QPainter::Antialiasing, true );
1340  imgPainter.setBrush( QBrush( Qt::white ) );
1341  imgPainter.setPen( QPen( Qt::black ) );
1342  imgPainter.translate( -points.boundingRect().left() + sideBuffer, - points.boundingRect().top() + sideBuffer );
1343  _renderPolygon( &imgPainter, points, rings, context );
1344  imgPainter.end();
1345 
1346  if ( context.renderContext().feedback() && context.renderContext().feedback()->isCanceled() )
1347  return;
1348 
1349  //now that we have a render of the polygon in white, draw this onto the shapeburst fill image too
1350  //(this avoids calling _renderPolygon twice, since that can be slow)
1351  imgPainter.begin( fillImage.get() );
1352  if ( !ignoreRings )
1353  {
1354  imgPainter.drawImage( 0, 0, *alphaImage );
1355  }
1356  else
1357  {
1358  //using ignore rings mode, so the alpha image can't be used
1359  //directly as the alpha channel contains polygon rings and we need
1360  //to draw now without any rings
1361  imgPainter.setBrush( QBrush( Qt::white ) );
1362  imgPainter.setPen( QPen( Qt::black ) );
1363  imgPainter.translate( -points.boundingRect().left() + sideBuffer, - points.boundingRect().top() + sideBuffer );
1364  _renderPolygon( &imgPainter, points, nullptr, context );
1365  }
1366  imgPainter.end();
1367 
1368  if ( context.renderContext().feedback() && context.renderContext().feedback()->isCanceled() )
1369  return;
1370 
1371  //apply distance transform to image, uses the current color ramp to calculate final pixel colors
1372  double *dtArray = distanceTransform( fillImage.get(), context.renderContext() );
1373 
1374  //copy distance transform values back to QImage, shading by appropriate color ramp
1375  dtArrayToQImage( dtArray, fillImage.get(), mColorType == Qgis::GradientColorSource::SimpleTwoColor ? twoColorGradientRamp.get() : mGradientRamp.get(),
1376  context.renderContext(), useWholeShape, outputPixelMaxDist );
1377  if ( context.opacity() < 1 )
1378  {
1379  QgsImageOperation::multiplyOpacity( *fillImage, context.opacity(), context.renderContext().feedback() );
1380  }
1381 
1382  //clean up some variables
1383  delete [] dtArray;
1384 
1385  //apply blur if desired
1386  if ( blurRadius > 0 )
1387  {
1388  QgsImageOperation::stackBlur( *fillImage, blurRadius, false, context.renderContext().feedback() );
1389  }
1390 
1391  //apply alpha channel to distance transform image, so that areas outside the polygon are transparent
1392  imgPainter.begin( fillImage.get() );
1393  imgPainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
1394  imgPainter.drawImage( 0, 0, *alphaImage );
1395  imgPainter.end();
1396  //we're finished with the alpha channel image now
1397  alphaImage.reset();
1398 
1399  //draw shapeburst image in correct place in the destination painter
1400 
1401  QgsScopedQPainterState painterState( p );
1402  QPointF offset = mOffset;
1404  {
1406  const QVariant val = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), QString() );
1407  bool ok = false;
1408  const QPointF res = QgsSymbolLayerUtils::toPoint( val, &ok );
1409  if ( ok )
1410  offset = res;
1411  }
1412  if ( !offset.isNull() )
1413  {
1414  offset.setX( context.renderContext().convertToPainterUnits( offset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
1415  offset.setY( context.renderContext().convertToPainterUnits( offset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
1416  p->translate( offset );
1417  }
1418 
1419  p->drawImage( points.boundingRect().left() - sideBuffer, points.boundingRect().top() - sideBuffer, *fillImage );
1420 
1421  if ( !offset.isNull() )
1422  {
1423  p->translate( -offset );
1424  }
1425 }
1426 
1427 //fast distance transform code, adapted from http://cs.brown.edu/~pff/dt/
1428 
1429 /* distance transform of a 1d function using squared distance */
1430 void QgsShapeburstFillSymbolLayer::distanceTransform1d( double *f, int n, int *v, double *z, double *d )
1431 {
1432  int k = 0;
1433  v[0] = 0;
1434  z[0] = -INF;
1435  z[1] = + INF;
1436  for ( int q = 1; q <= n - 1; q++ )
1437  {
1438  double s = ( ( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
1439  while ( s <= z[k] )
1440  {
1441  k--;
1442  s = ( ( f[q] + q * q ) - ( f[v[k]] + ( v[k] * v[k] ) ) ) / ( 2 * q - 2 * v[k] );
1443  }
1444  k++;
1445  v[k] = q;
1446  z[k] = s;
1447  z[k + 1] = + INF;
1448  }
1449 
1450  k = 0;
1451  for ( int q = 0; q <= n - 1; q++ )
1452  {
1453  while ( z[k + 1] < q )
1454  k++;
1455  d[q] = ( q - v[k] ) * ( q - v[k] ) + f[v[k]];
1456  }
1457 }
1458 
1459 /* distance transform of 2d function using squared distance */
1460 void QgsShapeburstFillSymbolLayer::distanceTransform2d( double *im, int width, int height, QgsRenderContext &context )
1461 {
1462  int maxDimension = std::max( width, height );
1463  double *f = new double[ maxDimension ];
1464  int *v = new int[ maxDimension ];
1465  double *z = new double[ maxDimension + 1 ];
1466  double *d = new double[ maxDimension ];
1467 
1468  // transform along columns
1469  for ( int x = 0; x < width; x++ )
1470  {
1471  if ( context.renderingStopped() )
1472  break;
1473 
1474  for ( int y = 0; y < height; y++ )
1475  {
1476  f[y] = im[ x + y * width ];
1477  }
1478  distanceTransform1d( f, height, v, z, d );
1479  for ( int y = 0; y < height; y++ )
1480  {
1481  im[ x + y * width ] = d[y];
1482  }
1483  }
1484 
1485  // transform along rows
1486  for ( int y = 0; y < height; y++ )
1487  {
1488  if ( context.renderingStopped() )
1489  break;
1490 
1491  for ( int x = 0; x < width; x++ )
1492  {
1493  f[x] = im[ x + y * width ];
1494  }
1495  distanceTransform1d( f, width, v, z, d );
1496  for ( int x = 0; x < width; x++ )
1497  {
1498  im[ x + y * width ] = d[x];
1499  }
1500  }
1501 
1502  delete [] d;
1503  delete [] f;
1504  delete [] v;
1505  delete [] z;
1506 }
1507 
1508 /* distance transform of a binary QImage */
1509 double *QgsShapeburstFillSymbolLayer::distanceTransform( QImage *im, QgsRenderContext &context )
1510 {
1511  int width = im->width();
1512  int height = im->height();
1513 
1514  double *dtArray = new double[width * height];
1515 
1516  //load qImage to array
1517  QRgb tmpRgb;
1518  int idx = 0;
1519  for ( int heightIndex = 0; heightIndex < height; ++heightIndex )
1520  {
1521  if ( context.renderingStopped() )
1522  break;
1523 
1524  const QRgb *scanLine = reinterpret_cast< const QRgb * >( im->constScanLine( heightIndex ) );
1525  for ( int widthIndex = 0; widthIndex < width; ++widthIndex )
1526  {
1527  tmpRgb = scanLine[widthIndex];
1528  if ( qRed( tmpRgb ) == 0 )
1529  {
1530  //black pixel, so zero distance
1531  dtArray[ idx ] = 0;
1532  }
1533  else
1534  {
1535  //white pixel, so initially set distance as infinite
1536  dtArray[ idx ] = INF;
1537  }
1538  idx++;
1539  }
1540  }
1541 
1542  //calculate squared distance transform
1543  distanceTransform2d( dtArray, width, height, context );
1544 
1545  return dtArray;
1546 }
1547 
1548 void QgsShapeburstFillSymbolLayer::dtArrayToQImage( double *array, QImage *im, QgsColorRamp *ramp, QgsRenderContext &context, bool useWholeShape, int maxPixelDistance )
1549 {
1550  int width = im->width();
1551  int height = im->height();
1552 
1553  //find maximum distance value
1554  double maxDistanceValue;
1555 
1556  if ( useWholeShape )
1557  {
1558  //no max distance specified in symbol properties, so calculate from maximum value in distance transform results
1559  double dtMaxValue = array[0];
1560  for ( int i = 1; i < ( width * height ); ++i )
1561  {
1562  if ( array[i] > dtMaxValue )
1563  {
1564  dtMaxValue = array[i];
1565  }
1566  }
1567 
1568  //values in distance transform are squared
1569  maxDistanceValue = std::sqrt( dtMaxValue );
1570  }
1571  else
1572  {
1573  //use max distance set in symbol properties
1574  maxDistanceValue = maxPixelDistance;
1575  }
1576 
1577  //update the pixels in the provided QImage
1578  int idx = 0;
1579  double squaredVal = 0;
1580  double pixVal = 0;
1581 
1582  for ( int heightIndex = 0; heightIndex < height; ++heightIndex )
1583  {
1584  if ( context.renderingStopped() )
1585  break;
1586 
1587  QRgb *scanLine = reinterpret_cast< QRgb * >( im->scanLine( heightIndex ) );
1588  for ( int widthIndex = 0; widthIndex < width; ++widthIndex )
1589  {
1590  //result of distance transform
1591  squaredVal = array[idx];
1592 
1593  //scale result to fit in the range [0, 1]
1594  if ( maxDistanceValue > 0 )
1595  {
1596  pixVal = squaredVal > 0 ? std::min( ( std::sqrt( squaredVal ) / maxDistanceValue ), 1.0 ) : 0;
1597  }
1598  else
1599  {
1600  pixVal = 1.0;
1601  }
1602 
1603  //convert value to color from ramp
1604  //premultiply ramp color since we are storing this in a ARGB32_Premultiplied QImage
1605  scanLine[widthIndex] = qPremultiply( ramp->color( pixVal ).rgba() );
1606  idx++;
1607  }
1608  }
1609 }
1610 
1612 {
1613  QVariantMap map;
1614  map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
1615  map[QStringLiteral( "gradient_color2" )] = QgsSymbolLayerUtils::encodeColor( mColor2 );
1616  map[QStringLiteral( "color_type" )] = QString::number( static_cast< int >( mColorType ) );
1617  map[QStringLiteral( "blur_radius" )] = QString::number( mBlurRadius );
1618  map[QStringLiteral( "use_whole_shape" )] = QString::number( mUseWholeShape );
1619  map[QStringLiteral( "max_distance" )] = QString::number( mMaxDistance );
1620  map[QStringLiteral( "distance_unit" )] = QgsUnitTypes::encodeUnit( mDistanceUnit );
1621  map[QStringLiteral( "distance_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mDistanceMapUnitScale );
1622  map[QStringLiteral( "ignore_rings" )] = QString::number( mIgnoreRings );
1623  map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
1624  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
1625  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
1626  if ( mGradientRamp )
1627  {
1628 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1629  map.unite( mGradientRamp->properties() );
1630 #else
1631  map.insert( mGradientRamp->properties() );
1632 #endif
1633  }
1634 
1635  return map;
1636 }
1637 
1639 {
1640  std::unique_ptr< QgsShapeburstFillSymbolLayer > sl = std::make_unique< QgsShapeburstFillSymbolLayer >( mColor, mColor2, mColorType, mBlurRadius, mUseWholeShape, mMaxDistance );
1641  if ( mGradientRamp )
1642  {
1643  sl->setColorRamp( mGradientRamp->clone() );
1644  }
1645  sl->setDistanceUnit( mDistanceUnit );
1646  sl->setDistanceMapUnitScale( mDistanceMapUnitScale );
1647  sl->setIgnoreRings( mIgnoreRings );
1648  sl->setOffset( mOffset );
1649  sl->setOffsetUnit( mOffsetUnit );
1650  sl->setOffsetMapUnitScale( mOffsetMapUnitScale );
1651  copyDataDefinedProperties( sl.get() );
1652  copyPaintEffect( sl.get() );
1653  return sl.release();
1654 }
1655 
1657 {
1658  double offsetBleed = context.convertToPainterUnits( std::max( std::fabs( mOffset.x() ), std::fabs( mOffset.y() ) ), mOffsetUnit, mOffsetMapUnitScale );
1659  return offsetBleed;
1660 }
1661 
1663 {
1664  return true;
1665 }
1666 
1668 {
1669  mDistanceUnit = unit;
1670  mOffsetUnit = unit;
1671 }
1672 
1674 {
1675  if ( mDistanceUnit == mOffsetUnit )
1676  {
1677  return mDistanceUnit;
1678  }
1680 }
1681 
1683 {
1684  return mDistanceUnit == QgsUnitTypes::RenderMapUnits || mDistanceUnit == QgsUnitTypes::RenderMetersInMapUnits
1685  || mOffsetUnit == QgsUnitTypes::RenderMapUnits || mOffsetUnit == QgsUnitTypes::RenderMetersInMapUnits;
1686 }
1687 
1689 {
1690  mDistanceMapUnitScale = scale;
1691  mOffsetMapUnitScale = scale;
1692 }
1693 
1695 {
1696  if ( mDistanceMapUnitScale == mOffsetMapUnitScale )
1697  {
1698  return mDistanceMapUnitScale;
1699  }
1700  return QgsMapUnitScale();
1701 }
1702 
1703 
1704 //QgsImageFillSymbolLayer
1705 
1707 {
1708 }
1709 
1711 
1712 void QgsImageFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
1713 {
1714  QPainter *p = context.renderContext().painter();
1715  if ( !p )
1716  {
1717  return;
1718  }
1719 
1720  mNextAngle = mAngle;
1721  applyDataDefinedSettings( context );
1722 
1723  p->setPen( QPen( Qt::NoPen ) );
1724 
1725  QTransform bkTransform = mBrush.transform();
1726  if ( applyBrushTransformFromContext( &context ) && !context.renderContext().textureOrigin().isNull() )
1727  {
1728  QPointF leftCorner = context.renderContext().textureOrigin();
1729  QTransform t = mBrush.transform();
1730  t.translate( leftCorner.x(), leftCorner.y() );
1731  mBrush.setTransform( t );
1732  }
1733  else
1734  {
1735  QTransform t = mBrush.transform();
1736  t.translate( 0, 0 );
1737  mBrush.setTransform( t );
1738  }
1739 
1740  if ( context.selected() )
1741  {
1742  QColor selColor = context.renderContext().selectionColor();
1743  p->setBrush( QBrush( selColor ) );
1744  _renderPolygon( p, points, rings, context );
1745  }
1746 
1747  if ( !qgsDoubleNear( mNextAngle, 0.0 ) )
1748  {
1749  QTransform t = mBrush.transform();
1750  t.rotate( mNextAngle );
1751  mBrush.setTransform( t );
1752  }
1753  p->setBrush( mBrush );
1754  _renderPolygon( p, points, rings, context );
1755 
1756  mBrush.setTransform( bkTransform );
1757 }
1758 
1760 {
1761  mStrokeWidthUnit = unit;
1762 }
1763 
1765 {
1766  return mStrokeWidthUnit;
1767 }
1768 
1770 {
1771  mStrokeWidthMapUnitScale = scale;
1772 }
1773 
1775 {
1776  return mStrokeWidthMapUnitScale;
1777 }
1778 
1780 {
1781  double width = mStrokeWidth;
1783  {
1786  }
1788 }
1789 
1791 {
1792  return Qt::SolidLine;
1793 #if 0
1794  if ( !mStroke )
1795  {
1796  return Qt::SolidLine;
1797  }
1798  else
1799  {
1800  return mStroke->dxfPenStyle();
1801  }
1802 #endif //0
1803 }
1804 
1806 {
1807  QVariantMap map;
1808  map.insert( QStringLiteral( "coordinate_reference" ), QgsSymbolLayerUtils::encodeCoordinateReference( mCoordinateReference ) );
1809  return map;
1810 }
1811 
1813 {
1814  //coordinate reference
1817  {
1818  bool ok = false;
1820  if ( ok )
1821  {
1823  if ( !ok )
1825  }
1826  }
1827 
1829 }
1830 
1831 
1832 //QgsSVGFillSymbolLayer
1833 
1834 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QString &svgFilePath, double width, double angle )
1836  , mPatternWidth( width )
1837 {
1838  mStrokeWidth = 0.3;
1839  mAngle = angle;
1840  mColor = QColor( 255, 255, 255 );
1842 }
1843 
1844 QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer( const QByteArray &svgData, double width, double angle )
1846  , mPatternWidth( width )
1847  , mSvgData( svgData )
1848 {
1849  storeViewBox();
1850  mStrokeWidth = 0.3;
1851  mAngle = angle;
1852  mColor = QColor( 255, 255, 255 );
1853  setDefaultSvgParams();
1854 }
1855 
1857 
1859 {
1861  mPatternWidthUnit = unit;
1862  mSvgStrokeWidthUnit = unit;
1863  mStrokeWidthUnit = unit;
1864  if ( mStroke )
1865  mStroke->setOutputUnit( unit );
1866 }
1867 
1869 {
1871  if ( mPatternWidthUnit != unit || mSvgStrokeWidthUnit != unit || mStrokeWidthUnit != unit )
1872  {
1874  }
1875  return unit;
1876 }
1877 
1879 {
1881  mPatternWidthMapUnitScale = scale;
1882  mSvgStrokeWidthMapUnitScale = scale;
1883 }
1884 
1886 {
1887  if ( QgsImageFillSymbolLayer::mapUnitScale() == mPatternWidthMapUnitScale &&
1888  mPatternWidthMapUnitScale == mSvgStrokeWidthMapUnitScale &&
1889  mSvgStrokeWidthMapUnitScale == mStrokeWidthMapUnitScale )
1890  {
1891  return mPatternWidthMapUnitScale;
1892  }
1893  return QgsMapUnitScale();
1894 }
1895 
1896 void QgsSVGFillSymbolLayer::setSvgFilePath( const QString &svgPath )
1897 {
1898  mSvgData = QgsApplication::svgCache()->getImageData( svgPath );
1899  storeViewBox();
1900 
1901  mSvgFilePath = svgPath;
1902  setDefaultSvgParams();
1903 }
1904 
1905 QgsSymbolLayer *QgsSVGFillSymbolLayer::create( const QVariantMap &properties )
1906 {
1907  QByteArray data;
1908  double width = 20;
1909  QString svgFilePath;
1910  double angle = 0.0;
1911 
1912  if ( properties.contains( QStringLiteral( "width" ) ) )
1913  {
1914  width = properties[QStringLiteral( "width" )].toDouble();
1915  }
1916  if ( properties.contains( QStringLiteral( "svgFile" ) ) )
1917  {
1918  svgFilePath = properties[QStringLiteral( "svgFile" )].toString();
1919  }
1920  if ( properties.contains( QStringLiteral( "angle" ) ) )
1921  {
1922  angle = properties[QStringLiteral( "angle" )].toDouble();
1923  }
1924 
1925  std::unique_ptr< QgsSVGFillSymbolLayer > symbolLayer;
1926  if ( !svgFilePath.isEmpty() )
1927  {
1928  symbolLayer = std::make_unique< QgsSVGFillSymbolLayer >( svgFilePath, width, angle );
1929  }
1930  else
1931  {
1932  if ( properties.contains( QStringLiteral( "data" ) ) )
1933  {
1934  data = QByteArray::fromHex( properties[QStringLiteral( "data" )].toString().toLocal8Bit() );
1935  }
1936  symbolLayer = std::make_unique< QgsSVGFillSymbolLayer >( data, width, angle );
1937  }
1938 
1939  //svg parameters
1940  if ( properties.contains( QStringLiteral( "svgFillColor" ) ) )
1941  {
1942  //pre 2.5 projects used "svgFillColor"
1943  symbolLayer->setSvgFillColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "svgFillColor" )].toString() ) );
1944  }
1945  else if ( properties.contains( QStringLiteral( "color" ) ) )
1946  {
1947  symbolLayer->setSvgFillColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "color" )].toString() ) );
1948  }
1949  if ( properties.contains( QStringLiteral( "svgOutlineColor" ) ) )
1950  {
1951  //pre 2.5 projects used "svgOutlineColor"
1952  symbolLayer->setSvgStrokeColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "svgOutlineColor" )].toString() ) );
1953  }
1954  else if ( properties.contains( QStringLiteral( "outline_color" ) ) )
1955  {
1956  symbolLayer->setSvgStrokeColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "outline_color" )].toString() ) );
1957  }
1958  else if ( properties.contains( QStringLiteral( "line_color" ) ) )
1959  {
1960  symbolLayer->setSvgStrokeColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "line_color" )].toString() ) );
1961  }
1962  if ( properties.contains( QStringLiteral( "svgOutlineWidth" ) ) )
1963  {
1964  //pre 2.5 projects used "svgOutlineWidth"
1965  symbolLayer->setSvgStrokeWidth( properties[QStringLiteral( "svgOutlineWidth" )].toDouble() );
1966  }
1967  else if ( properties.contains( QStringLiteral( "outline_width" ) ) )
1968  {
1969  symbolLayer->setSvgStrokeWidth( properties[QStringLiteral( "outline_width" )].toDouble() );
1970  }
1971  else if ( properties.contains( QStringLiteral( "line_width" ) ) )
1972  {
1973  symbolLayer->setSvgStrokeWidth( properties[QStringLiteral( "line_width" )].toDouble() );
1974  }
1975 
1976  //units
1977  if ( properties.contains( QStringLiteral( "pattern_width_unit" ) ) )
1978  {
1979  symbolLayer->setPatternWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "pattern_width_unit" )].toString() ) );
1980  }
1981  if ( properties.contains( QStringLiteral( "pattern_width_map_unit_scale" ) ) )
1982  {
1983  symbolLayer->setPatternWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "pattern_width_map_unit_scale" )].toString() ) );
1984  }
1985  if ( properties.contains( QStringLiteral( "svg_outline_width_unit" ) ) )
1986  {
1987  symbolLayer->setSvgStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "svg_outline_width_unit" )].toString() ) );
1988  }
1989  if ( properties.contains( QStringLiteral( "svg_outline_width_map_unit_scale" ) ) )
1990  {
1991  symbolLayer->setSvgStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "svg_outline_width_map_unit_scale" )].toString() ) );
1992  }
1993  if ( properties.contains( QStringLiteral( "outline_width_unit" ) ) )
1994  {
1995  symbolLayer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "outline_width_unit" )].toString() ) );
1996  }
1997  if ( properties.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
1998  {
1999  symbolLayer->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "outline_width_map_unit_scale" )].toString() ) );
2000  }
2001 
2002  if ( properties.contains( QStringLiteral( "parameters" ) ) )
2003  {
2004  const QVariantMap parameters = properties[QStringLiteral( "parameters" )].toMap();
2005  symbolLayer->setParameters( QgsProperty::variantMapToPropertyMap( parameters ) );
2006  }
2007 
2008  symbolLayer->restoreOldDataDefinedProperties( properties );
2009 
2010  return symbolLayer.release();
2011 }
2012 
2013 void QgsSVGFillSymbolLayer::resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving )
2014 {
2015  QVariantMap::iterator it = properties.find( QStringLiteral( "svgFile" ) );
2016  if ( it != properties.end() )
2017  {
2018  if ( saving )
2019  it.value() = QgsSymbolLayerUtils::svgSymbolPathToName( it.value().toString(), pathResolver );
2020  else
2021  it.value() = QgsSymbolLayerUtils::svgSymbolNameToPath( it.value().toString(), pathResolver );
2022  }
2023 }
2024 
2026 {
2027  return QStringLiteral( "SVGFill" );
2028 }
2029 
2030 void QgsSVGFillSymbolLayer::applyPattern( QBrush &brush, const QString &svgFilePath, double patternWidth, QgsUnitTypes::RenderUnit patternWidthUnit,
2031  const QColor &svgFillColor, const QColor &svgStrokeColor, double svgStrokeWidth,
2032  QgsUnitTypes::RenderUnit svgStrokeWidthUnit, const QgsSymbolRenderContext &context,
2033  const QgsMapUnitScale &patternWidthMapUnitScale, const QgsMapUnitScale &svgStrokeWidthMapUnitScale, const QgsStringMap svgParameters )
2034 {
2035  if ( mSvgViewBox.isNull() )
2036  {
2037  return;
2038  }
2039 
2041 
2042  if ( static_cast< int >( size ) < 1.0 || 10000.0 < size )
2043  {
2044  brush.setTextureImage( QImage() );
2045  }
2046  else
2047  {
2048  bool fitsInCache = true;
2050  QImage patternImage = QgsApplication::svgCache()->svgAsImage( svgFilePath, size, svgFillColor, svgStrokeColor, strokeWidth,
2051  context.renderContext().scaleFactor(), fitsInCache, 0, ( context.renderContext().flags() & Qgis::RenderContextFlag::RenderBlocking ), svgParameters );
2052  if ( !fitsInCache )
2053  {
2054  QPicture patternPict = QgsApplication::svgCache()->svgAsPicture( svgFilePath, size, svgFillColor, svgStrokeColor, strokeWidth,
2055  context.renderContext().scaleFactor(), false, 0, ( context.renderContext().flags() & Qgis::RenderContextFlag::RenderBlocking ) );
2056  double hwRatio = 1.0;
2057  if ( patternPict.width() > 0 )
2058  {
2059  hwRatio = static_cast< double >( patternPict.height() ) / static_cast< double >( patternPict.width() );
2060  }
2061  patternImage = QImage( static_cast< int >( size ), static_cast< int >( size * hwRatio ), QImage::Format_ARGB32_Premultiplied );
2062  patternImage.fill( 0 ); // transparent background
2063 
2064  QPainter p( &patternImage );
2065  p.drawPicture( QPointF( size / 2, size * hwRatio / 2 ), patternPict );
2066  }
2067 
2068  QTransform brushTransform;
2069  if ( !qgsDoubleNear( context.opacity(), 1.0 ) )
2070  {
2071  QImage transparentImage = patternImage.copy();
2072  QgsSymbolLayerUtils::multiplyImageOpacity( &transparentImage, context.opacity() );
2073  brush.setTextureImage( transparentImage );
2074  }
2075  else
2076  {
2077  brush.setTextureImage( patternImage );
2078  }
2079  brush.setTransform( brushTransform );
2080  }
2081 }
2082 
2084 {
2085  QgsStringMap evaluatedParameters = QgsSymbolLayerUtils::evaluatePropertiesMap( mParameters, context.renderContext().expressionContext() );
2086 
2087  applyPattern( mBrush, mSvgFilePath, mPatternWidth, mPatternWidthUnit, mColor, mSvgStrokeColor, mSvgStrokeWidth, mSvgStrokeWidthUnit, context, mPatternWidthMapUnitScale, mSvgStrokeWidthMapUnitScale, evaluatedParameters );
2088 
2089  if ( mStroke )
2090  {
2091  mStroke->startRender( context.renderContext(), context.fields() );
2092  }
2093 }
2094 
2096 {
2097  if ( mStroke )
2098  {
2099  mStroke->stopRender( context.renderContext() );
2100  }
2101 }
2102 
2103 void QgsSVGFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
2104 {
2105  QgsImageFillSymbolLayer::renderPolygon( points, rings, context );
2106 
2107  if ( mStroke )
2108  {
2109  mStroke->renderPolyline( points, context.feature(), context.renderContext(), -1, SELECT_FILL_BORDER && context.selected() );
2110  if ( rings )
2111  {
2112  for ( auto ringIt = rings->constBegin(); ringIt != rings->constEnd(); ++ringIt )
2113  {
2114  mStroke->renderPolyline( *ringIt, context.feature(), context.renderContext(), -1, SELECT_FILL_BORDER && context.selected() );
2115  }
2116  }
2117  }
2118 }
2119 
2121 {
2122  QVariantMap map;
2123  if ( !mSvgFilePath.isEmpty() )
2124  {
2125  map.insert( QStringLiteral( "svgFile" ), mSvgFilePath );
2126  }
2127  else
2128  {
2129  map.insert( QStringLiteral( "data" ), QString( mSvgData.toHex() ) );
2130  }
2131 
2132  map.insert( QStringLiteral( "width" ), QString::number( mPatternWidth ) );
2133  map.insert( QStringLiteral( "angle" ), QString::number( mAngle ) );
2134 
2135  //svg parameters
2136  map.insert( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( mColor ) );
2137  map.insert( QStringLiteral( "outline_color" ), QgsSymbolLayerUtils::encodeColor( mSvgStrokeColor ) );
2138  map.insert( QStringLiteral( "outline_width" ), QString::number( mSvgStrokeWidth ) );
2139 
2140  //units
2141  map.insert( QStringLiteral( "pattern_width_unit" ), QgsUnitTypes::encodeUnit( mPatternWidthUnit ) );
2142  map.insert( QStringLiteral( "pattern_width_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mPatternWidthMapUnitScale ) );
2143  map.insert( QStringLiteral( "svg_outline_width_unit" ), QgsUnitTypes::encodeUnit( mSvgStrokeWidthUnit ) );
2144  map.insert( QStringLiteral( "svg_outline_width_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mSvgStrokeWidthMapUnitScale ) );
2145  map.insert( QStringLiteral( "outline_width_unit" ), QgsUnitTypes::encodeUnit( mStrokeWidthUnit ) );
2146  map.insert( QStringLiteral( "outline_width_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale ) );
2147 
2148  map[QStringLiteral( "parameters" )] = QgsProperty::propertyMapToVariantMap( mParameters );
2149 
2150  return map;
2151 }
2152 
2154 {
2155  std::unique_ptr< QgsSVGFillSymbolLayer > clonedLayer;
2156  if ( !mSvgFilePath.isEmpty() )
2157  {
2158  clonedLayer = std::make_unique< QgsSVGFillSymbolLayer >( mSvgFilePath, mPatternWidth, mAngle );
2159  clonedLayer->setSvgFillColor( mColor );
2160  clonedLayer->setSvgStrokeColor( mSvgStrokeColor );
2161  clonedLayer->setSvgStrokeWidth( mSvgStrokeWidth );
2162  }
2163  else
2164  {
2165  clonedLayer = std::make_unique< QgsSVGFillSymbolLayer >( mSvgData, mPatternWidth, mAngle );
2166  }
2167 
2168  clonedLayer->setPatternWidthUnit( mPatternWidthUnit );
2169  clonedLayer->setPatternWidthMapUnitScale( mPatternWidthMapUnitScale );
2170  clonedLayer->setSvgStrokeWidthUnit( mSvgStrokeWidthUnit );
2171  clonedLayer->setSvgStrokeWidthMapUnitScale( mSvgStrokeWidthMapUnitScale );
2172  clonedLayer->setStrokeWidthUnit( mStrokeWidthUnit );
2173  clonedLayer->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
2174 
2175  clonedLayer->setParameters( mParameters );
2176 
2177  if ( mStroke )
2178  {
2179  clonedLayer->setSubSymbol( mStroke->clone() );
2180  }
2181  copyDataDefinedProperties( clonedLayer.get() );
2182  copyPaintEffect( clonedLayer.get() );
2183  return clonedLayer.release();
2184 }
2185 
2186 void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
2187 {
2188  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PolygonSymbolizer" ) );
2189  if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
2190  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
2191  element.appendChild( symbolizerElem );
2192 
2193  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
2194 
2195  QDomElement fillElem = doc.createElement( QStringLiteral( "se:Fill" ) );
2196  symbolizerElem.appendChild( fillElem );
2197 
2198  QDomElement graphicFillElem = doc.createElement( QStringLiteral( "se:GraphicFill" ) );
2199  fillElem.appendChild( graphicFillElem );
2200 
2201  QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
2202  graphicFillElem.appendChild( graphicElem );
2203 
2204  if ( !mSvgFilePath.isEmpty() )
2205  {
2206  // encode a parametric SVG reference
2207  double patternWidth = QgsSymbolLayerUtils::rescaleUom( mPatternWidth, mPatternWidthUnit, props );
2208  double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mSvgStrokeWidth, mSvgStrokeWidthUnit, props );
2209  QgsSymbolLayerUtils::parametricSvgToSld( doc, graphicElem, mSvgFilePath, mColor, patternWidth, mSvgStrokeColor, strokeWidth );
2210  }
2211  else
2212  {
2213  // TODO: create svg from data
2214  // <se:InlineContent>
2215  symbolizerElem.appendChild( doc.createComment( QStringLiteral( "SVG from data not implemented yet" ) ) );
2216  }
2217 
2218  // <Rotation>
2219  QString angleFunc;
2220  bool ok;
2221  double angle = props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ).toDouble( &ok );
2222  if ( !ok )
2223  {
2224  angleFunc = QStringLiteral( "%1 + %2" ).arg( props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ).toString() ).arg( mAngle );
2225  }
2226  else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
2227  {
2228  angleFunc = QString::number( angle + mAngle );
2229  }
2230  QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
2231 
2232  if ( mStroke )
2233  {
2234  // the stroke sub symbol should be stored within the Stroke element,
2235  // but it will be stored in a separated LineSymbolizer because it could
2236  // have more than one layer
2237  mStroke->toSld( doc, element, props );
2238  }
2239 }
2240 
2242 {
2243  return mPatternWidthUnit == QgsUnitTypes::RenderMapUnits || mPatternWidthUnit == QgsUnitTypes::RenderMetersInMapUnits
2244  || mSvgStrokeWidthUnit == QgsUnitTypes::RenderMapUnits || mSvgStrokeWidthUnit == QgsUnitTypes::RenderMetersInMapUnits;
2245 }
2246 
2248 {
2249  return mStroke.get();
2250 }
2251 
2253 {
2254  if ( !symbol ) //unset current stroke
2255  {
2256  mStroke.reset( nullptr );
2257  return true;
2258  }
2259 
2260  if ( symbol->type() != Qgis::SymbolType::Line )
2261  {
2262  delete symbol;
2263  return false;
2264  }
2265 
2266  QgsLineSymbol *lineSymbol = dynamic_cast<QgsLineSymbol *>( symbol );
2267  if ( lineSymbol )
2268  {
2269  mStroke.reset( lineSymbol );
2270  return true;
2271  }
2272 
2273  delete symbol;
2274  return false;
2275 }
2276 
2278 {
2279  if ( mStroke && mStroke->symbolLayer( 0 ) )
2280  {
2281  double subLayerBleed = mStroke->symbolLayer( 0 )->estimateMaxBleed( context );
2282  return subLayerBleed;
2283  }
2284  return 0;
2285 }
2286 
2288 {
2289  Q_UNUSED( context )
2290  if ( !mStroke )
2291  {
2292  return QColor( Qt::black );
2293  }
2294  return mStroke->color();
2295 }
2296 
2297 QSet<QString> QgsSVGFillSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
2298 {
2299  QSet<QString> attr = QgsImageFillSymbolLayer::usedAttributes( context );
2300  if ( mStroke )
2301  attr.unite( mStroke->usedAttributes( context ) );
2302  return attr;
2303 }
2304 
2306 {
2308  return true;
2309  if ( mStroke && mStroke->hasDataDefinedProperties() )
2310  return true;
2311  return false;
2312 }
2313 
2315 {
2316  QString path, mimeType;
2317  QColor fillColor, strokeColor;
2318  Qt::PenStyle penStyle;
2319  double size, strokeWidth;
2320 
2321  QDomElement fillElem = element.firstChildElement( QStringLiteral( "Fill" ) );
2322  if ( fillElem.isNull() )
2323  return nullptr;
2324 
2325  QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral( "GraphicFill" ) );
2326  if ( graphicFillElem.isNull() )
2327  return nullptr;
2328 
2329  QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral( "Graphic" ) );
2330  if ( graphicElem.isNull() )
2331  return nullptr;
2332 
2333  if ( !QgsSymbolLayerUtils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
2334  return nullptr;
2335 
2336  if ( mimeType != QLatin1String( "image/svg+xml" ) )
2337  return nullptr;
2338 
2339  QgsSymbolLayerUtils::lineFromSld( graphicElem, penStyle, strokeColor, strokeWidth );
2340 
2341  double scaleFactor = 1.0;
2342  const QString uom = element.attribute( QStringLiteral( "uom" ) );
2343  QgsUnitTypes::RenderUnit sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( uom, &scaleFactor );
2344  size = size * scaleFactor;
2345  strokeWidth = strokeWidth * scaleFactor;
2346 
2347  double angle = 0.0;
2348  QString angleFunc;
2349  if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
2350  {
2351  bool ok;
2352  double d = angleFunc.toDouble( &ok );
2353  if ( ok )
2354  angle = d;
2355  }
2356 
2357  std::unique_ptr< QgsSVGFillSymbolLayer > sl = std::make_unique< QgsSVGFillSymbolLayer >( path, size, angle );
2358  sl->setOutputUnit( sldUnitSize );
2359  sl->setSvgFillColor( fillColor );
2360  sl->setSvgStrokeColor( strokeColor );
2361  sl->setSvgStrokeWidth( strokeWidth );
2362 
2363  // try to get the stroke
2364  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
2365  if ( !strokeElem.isNull() )
2366  {
2368  if ( l )
2369  {
2370  QgsSymbolLayerList layers;
2371  layers.append( l );
2372  sl->setSubSymbol( new QgsLineSymbol( layers ) );
2373  }
2374  }
2375 
2376  return sl.release();
2377 }
2378 
2380 {
2384  {
2385  return; //no data defined settings
2386  }
2387 
2389  {
2390  context.setOriginalValueVariable( mAngle );
2392  }
2393 
2394  double width = mPatternWidth;
2396  {
2397  context.setOriginalValueVariable( mPatternWidth );
2399  }
2400  QString svgFile = mSvgFilePath;
2402  {
2403  context.setOriginalValueVariable( mSvgFilePath );
2405  context.renderContext().pathResolver() );
2406  }
2407  QColor svgFillColor = mColor;
2409  {
2412  }
2413  QColor svgStrokeColor = mSvgStrokeColor;
2415  {
2416  context.setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( mSvgStrokeColor ) );
2418  }
2419  double strokeWidth = mSvgStrokeWidth;
2421  {
2422  context.setOriginalValueVariable( mSvgStrokeWidth );
2424  }
2425  QgsStringMap evaluatedParameters = QgsSymbolLayerUtils::evaluatePropertiesMap( mParameters, context.renderContext().expressionContext() );
2426 
2427  applyPattern( mBrush, svgFile, width, mPatternWidthUnit, svgFillColor, svgStrokeColor, strokeWidth,
2428  mSvgStrokeWidthUnit, context, mPatternWidthMapUnitScale, mSvgStrokeWidthMapUnitScale, evaluatedParameters );
2429 
2430 }
2431 
2432 void QgsSVGFillSymbolLayer::storeViewBox()
2433 {
2434  if ( !mSvgData.isEmpty() )
2435  {
2436  QSvgRenderer r( mSvgData );
2437  if ( r.isValid() )
2438  {
2439  mSvgViewBox = r.viewBoxF();
2440  return;
2441  }
2442  }
2443 
2444  mSvgViewBox = QRectF();
2445 }
2446 
2447 void QgsSVGFillSymbolLayer::setDefaultSvgParams()
2448 {
2449  if ( mSvgFilePath.isEmpty() )
2450  {
2451  return;
2452  }
2453 
2454  bool hasFillParam, hasFillOpacityParam, hasStrokeParam, hasStrokeWidthParam, hasStrokeOpacityParam;
2455  bool hasDefaultFillColor, hasDefaultFillOpacity, hasDefaultStrokeColor, hasDefaultStrokeWidth, hasDefaultStrokeOpacity;
2456  QColor defaultFillColor, defaultStrokeColor;
2457  double defaultStrokeWidth, defaultFillOpacity, defaultStrokeOpacity;
2458  QgsApplication::svgCache()->containsParams( mSvgFilePath, hasFillParam, hasDefaultFillColor, defaultFillColor,
2459  hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
2460  hasStrokeParam, hasDefaultStrokeColor, defaultStrokeColor,
2461  hasStrokeWidthParam, hasDefaultStrokeWidth, defaultStrokeWidth,
2462  hasStrokeOpacityParam, hasDefaultStrokeOpacity, defaultStrokeOpacity );
2463 
2464  double newFillOpacity = hasFillOpacityParam ? mColor.alphaF() : 1.0;
2465  double newStrokeOpacity = hasStrokeOpacityParam ? mSvgStrokeColor.alphaF() : 1.0;
2466 
2467  if ( hasDefaultFillColor )
2468  {
2469  mColor = defaultFillColor;
2470  mColor.setAlphaF( newFillOpacity );
2471  }
2472  if ( hasDefaultFillOpacity )
2473  {
2474  mColor.setAlphaF( defaultFillOpacity );
2475  }
2476  if ( hasDefaultStrokeColor )
2477  {
2478  mSvgStrokeColor = defaultStrokeColor;
2479  mSvgStrokeColor.setAlphaF( newStrokeOpacity );
2480  }
2481  if ( hasDefaultStrokeOpacity )
2482  {
2483  mSvgStrokeColor.setAlphaF( defaultStrokeOpacity );
2484  }
2485  if ( hasDefaultStrokeWidth )
2486  {
2487  mSvgStrokeWidth = defaultStrokeWidth;
2488  }
2489 }
2490 
2491 void QgsSVGFillSymbolLayer::setParameters( const QMap<QString, QgsProperty> &parameters )
2492 {
2493  mParameters = parameters;
2494 }
2495 
2496 
2499 {
2500  setSubSymbol( new QgsLineSymbol() );
2501  QgsImageFillSymbolLayer::setSubSymbol( nullptr ); //no stroke
2502 }
2503 
2505 
2507 {
2508  mFillLineSymbol->setWidth( w );
2509  mLineWidth = w;
2510 }
2511 
2513 {
2514  mFillLineSymbol->setColor( c );
2515  mColor = c;
2516 }
2517 
2519 {
2520  return mFillLineSymbol ? mFillLineSymbol->color() : mColor;
2521 }
2522 
2524 {
2525  if ( !symbol )
2526  {
2527  return false;
2528  }
2529 
2530  if ( symbol->type() == Qgis::SymbolType::Line )
2531  {
2532  mFillLineSymbol.reset( qgis::down_cast<QgsLineSymbol *>( symbol ) );
2533  return true;
2534  }
2535  delete symbol;
2536  return false;
2537 }
2538 
2540 {
2541  return mFillLineSymbol.get();
2542 }
2543 
2545 {
2546  QSet<QString> attr = QgsImageFillSymbolLayer::usedAttributes( context );
2547  if ( mFillLineSymbol )
2548  attr.unite( mFillLineSymbol->usedAttributes( context ) );
2549  return attr;
2550 }
2551 
2553 {
2555  return true;
2556  if ( mFillLineSymbol && mFillLineSymbol->hasDataDefinedProperties() )
2557  return true;
2558  return false;
2559 }
2560 
2562 {
2563  // deliberately don't pass this on to subsymbol here
2564 }
2565 
2567 {
2568  // deliberately don't pass this on to subsymbol here
2569 }
2570 
2572 {
2573  return 0;
2574 }
2575 
2577 {
2579  mDistanceUnit = unit;
2580  mLineWidthUnit = unit;
2581  mOffsetUnit = unit;
2582 
2583  if ( mFillLineSymbol )
2584  mFillLineSymbol->setOutputUnit( unit );
2585 }
2586 
2588 {
2590  if ( mDistanceUnit != unit || mLineWidthUnit != unit || ( mOffsetUnit != unit && mOffsetUnit != QgsUnitTypes::RenderPercentage ) )
2591  {
2593  }
2594  return unit;
2595 }
2596 
2598 {
2599  return mDistanceUnit == QgsUnitTypes::RenderMapUnits || mDistanceUnit == QgsUnitTypes::RenderMetersInMapUnits
2600  || mLineWidthUnit == QgsUnitTypes::RenderMapUnits || mLineWidthUnit == QgsUnitTypes::RenderMetersInMapUnits
2601  || mOffsetUnit == QgsUnitTypes::RenderMapUnits || mOffsetUnit == QgsUnitTypes::RenderMetersInMapUnits;
2602 }
2603 
2605 {
2607  mDistanceMapUnitScale = scale;
2608  mLineWidthMapUnitScale = scale;
2609  mOffsetMapUnitScale = scale;
2610 }
2611 
2613 {
2614  if ( QgsImageFillSymbolLayer::mapUnitScale() == mDistanceMapUnitScale &&
2615  mDistanceMapUnitScale == mLineWidthMapUnitScale &&
2616  mLineWidthMapUnitScale == mOffsetMapUnitScale )
2617  {
2618  return mDistanceMapUnitScale;
2619  }
2620  return QgsMapUnitScale();
2621 }
2622 
2624 {
2625  std::unique_ptr< QgsLinePatternFillSymbolLayer > patternLayer = std::make_unique< QgsLinePatternFillSymbolLayer >();
2626 
2627  //default values
2628  double lineAngle = 45;
2629  double distance = 5;
2630  double lineWidth = 0.5;
2631  QColor color( Qt::black );
2632  double offset = 0.0;
2633 
2634  if ( properties.contains( QStringLiteral( "lineangle" ) ) )
2635  {
2636  //pre 2.5 projects used "lineangle"
2637  lineAngle = properties[QStringLiteral( "lineangle" )].toDouble();
2638  }
2639  else if ( properties.contains( QStringLiteral( "angle" ) ) )
2640  {
2641  lineAngle = properties[QStringLiteral( "angle" )].toDouble();
2642  }
2643  patternLayer->setLineAngle( lineAngle );
2644 
2645  if ( properties.contains( QStringLiteral( "distance" ) ) )
2646  {
2647  distance = properties[QStringLiteral( "distance" )].toDouble();
2648  }
2649  patternLayer->setDistance( distance );
2650 
2651  if ( properties.contains( QStringLiteral( "linewidth" ) ) )
2652  {
2653  //pre 2.5 projects used "linewidth"
2654  lineWidth = properties[QStringLiteral( "linewidth" )].toDouble();
2655  }
2656  else if ( properties.contains( QStringLiteral( "outline_width" ) ) )
2657  {
2658  lineWidth = properties[QStringLiteral( "outline_width" )].toDouble();
2659  }
2660  else if ( properties.contains( QStringLiteral( "line_width" ) ) )
2661  {
2662  lineWidth = properties[QStringLiteral( "line_width" )].toDouble();
2663  }
2664  patternLayer->setLineWidth( lineWidth );
2665 
2666  if ( properties.contains( QStringLiteral( "color" ) ) )
2667  {
2668  color = QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "color" )].toString() );
2669  }
2670  else if ( properties.contains( QStringLiteral( "outline_color" ) ) )
2671  {
2672  color = QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "outline_color" )].toString() );
2673  }
2674  else if ( properties.contains( QStringLiteral( "line_color" ) ) )
2675  {
2676  color = QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "line_color" )].toString() );
2677  }
2678  patternLayer->setColor( color );
2679 
2680  if ( properties.contains( QStringLiteral( "offset" ) ) )
2681  {
2682  offset = properties[QStringLiteral( "offset" )].toDouble();
2683  }
2684  patternLayer->setOffset( offset );
2685 
2686 
2687  if ( properties.contains( QStringLiteral( "distance_unit" ) ) )
2688  {
2689  patternLayer->setDistanceUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "distance_unit" )].toString() ) );
2690  }
2691  if ( properties.contains( QStringLiteral( "distance_map_unit_scale" ) ) )
2692  {
2693  patternLayer->setDistanceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "distance_map_unit_scale" )].toString() ) );
2694  }
2695  if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
2696  {
2697  patternLayer->setLineWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "line_width_unit" )].toString() ) );
2698  }
2699  else if ( properties.contains( QStringLiteral( "outline_width_unit" ) ) )
2700  {
2701  patternLayer->setLineWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "outline_width_unit" )].toString() ) );
2702  }
2703  if ( properties.contains( QStringLiteral( "line_width_map_unit_scale" ) ) )
2704  {
2705  patternLayer->setLineWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "line_width_map_unit_scale" )].toString() ) );
2706  }
2707  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
2708  {
2709  patternLayer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
2710  }
2711  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
2712  {
2713  patternLayer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
2714  }
2715  if ( properties.contains( QStringLiteral( "outline_width_unit" ) ) )
2716  {
2717  patternLayer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "outline_width_unit" )].toString() ) );
2718  }
2719  if ( properties.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
2720  {
2721  patternLayer->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "outline_width_map_unit_scale" )].toString() ) );
2722  }
2723  if ( properties.contains( QStringLiteral( "coordinate_reference" ) ) )
2724  {
2725  patternLayer->setCoordinateReference( QgsSymbolLayerUtils::decodeCoordinateReference( properties[QStringLiteral( "coordinate_reference" )].toString() ) );
2726  }
2727  if ( properties.contains( QStringLiteral( "clip_mode" ) ) )
2728  {
2729  patternLayer->setClipMode( QgsSymbolLayerUtils::decodeLineClipMode( properties.value( QStringLiteral( "clip_mode" ) ).toString() ) );
2730  }
2731 
2732  patternLayer->restoreOldDataDefinedProperties( properties );
2733 
2734  return patternLayer.release();
2735 }
2736 
2738 {
2739  return QStringLiteral( "LinePatternFill" );
2740 }
2741 
2742 void QgsLinePatternFillSymbolLayer::applyPattern( const QgsSymbolRenderContext &context, QBrush &brush, double lineAngle, double distance )
2743 {
2744  mBrush.setTextureImage( QImage() ); // set empty in case we have to return
2745 
2746  if ( !mFillLineSymbol )
2747  {
2748  return;
2749  }
2750  // We have to make a copy because marker intervals will have to be adjusted
2751  std::unique_ptr< QgsLineSymbol > fillLineSymbol( mFillLineSymbol->clone() );
2752  if ( !fillLineSymbol )
2753  {
2754  return;
2755  }
2756 
2757  const QgsRenderContext &ctx = context.renderContext();
2758  //double strokePixelWidth = lineWidth * QgsSymbolLayerUtils::pixelSizeScaleFactor( ctx, mLineWidthUnit, mLineWidthMapUnitScale );
2759  double outputPixelDist = ctx.convertToPainterUnits( distance, mDistanceUnit, mDistanceMapUnitScale );
2760  double outputPixelOffset = mOffsetUnit == QgsUnitTypes::RenderPercentage ? outputPixelDist * mOffset / 100
2761  : ctx.convertToPainterUnits( mOffset, mOffsetUnit, mOffsetMapUnitScale );
2762 
2763  // NOTE: this may need to be modified if we ever change from a forced rasterized/brush approach,
2764  // because potentially we may want to allow vector based line pattern fills where the first line
2765  // is offset by a large distance
2766 
2767  // fix truncated pattern with larger offsets
2768  outputPixelOffset = std::fmod( outputPixelOffset, outputPixelDist );
2769  if ( outputPixelOffset > outputPixelDist / 2.0 )
2770  outputPixelOffset -= outputPixelDist;
2771 
2772  // To get all patterns into image, we have to consider symbols size (estimateMaxBleed()).
2773  // For marker lines we have to get markers interval.
2774  double outputPixelBleed = 0;
2775  double outputPixelInterval = 0; // maximum interval
2776  for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2777  {
2778  QgsSymbolLayer *layer = fillLineSymbol->symbolLayer( i );
2779  double outputPixelLayerBleed = layer->estimateMaxBleed( context.renderContext() );
2780  outputPixelBleed = std::max( outputPixelBleed, outputPixelLayerBleed );
2781 
2782  QgsMarkerLineSymbolLayer *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayer *>( layer );
2783  if ( markerLineLayer )
2784  {
2785  double outputPixelLayerInterval = ctx.convertToPainterUnits( markerLineLayer->interval(), markerLineLayer->intervalUnit(), markerLineLayer->intervalMapUnitScale() );
2786 
2787  // There may be multiple marker lines with different intervals.
2788  // In theory we should find the least common multiple, but that could be too
2789  // big (multiplication of intervals in the worst case).
2790  // Because patterns without small common interval would look strange, we
2791  // believe that the longest interval should usually be sufficient.
2792  outputPixelInterval = std::max( outputPixelInterval, outputPixelLayerInterval );
2793  }
2794  }
2795 
2796  if ( outputPixelInterval > 0 )
2797  {
2798  // We have to adjust marker intervals to integer pixel size to get
2799  // repeatable pattern.
2800  double intervalScale = std::round( outputPixelInterval ) / outputPixelInterval;
2801  outputPixelInterval = std::round( outputPixelInterval );
2802 
2803  for ( int i = 0; i < fillLineSymbol->symbolLayerCount(); i++ )
2804  {
2805  QgsSymbolLayer *layer = fillLineSymbol->symbolLayer( i );
2806 
2807  QgsMarkerLineSymbolLayer *markerLineLayer = dynamic_cast<QgsMarkerLineSymbolLayer *>( layer );
2808  if ( markerLineLayer )
2809  {
2810  markerLineLayer->setInterval( intervalScale * markerLineLayer->interval() );
2811  }
2812  }
2813  }
2814 
2815  //create image
2816  int height, width;
2817  lineAngle = std::fmod( lineAngle, 360 );
2818  if ( lineAngle < 0 )
2819  lineAngle += 360;
2820  if ( qgsDoubleNear( lineAngle, 0 ) || qgsDoubleNear( lineAngle, 360 ) || qgsDoubleNear( lineAngle, 180 ) )
2821  {
2822  height = outputPixelDist;
2823  width = outputPixelInterval > 0 ? outputPixelInterval : height;
2824  }
2825  else if ( qgsDoubleNear( lineAngle, 90 ) || qgsDoubleNear( lineAngle, 270 ) )
2826  {
2827  width = outputPixelDist;
2828  height = outputPixelInterval > 0 ? outputPixelInterval : width;
2829  }
2830  else
2831  {
2832  height = outputPixelDist / std::cos( lineAngle * M_PI / 180 ); //keep perpendicular distance between lines constant
2833  width = outputPixelDist / std::sin( lineAngle * M_PI / 180 );
2834 
2835  // recalculate real angle and distance after rounding to pixels
2836  lineAngle = 180 * std::atan2( static_cast< double >( height ), static_cast< double >( width ) ) / M_PI;
2837  if ( lineAngle < 0 )
2838  {
2839  lineAngle += 360.;
2840  }
2841 
2842  height = std::abs( height );
2843  width = std::abs( width );
2844 
2845  outputPixelDist = std::abs( height * std::cos( lineAngle * M_PI / 180 ) );
2846 
2847  // Round offset to correspond to one pixel height, otherwise lines may
2848  // be shifted on tile border if offset falls close to pixel center
2849  int offsetHeight = static_cast< int >( std::round( outputPixelOffset / std::cos( lineAngle * M_PI / 180 ) ) );
2850  outputPixelOffset = offsetHeight * std::cos( lineAngle * M_PI / 180 );
2851  }
2852 
2853  //depending on the angle, we might need to render into a larger image and use a subset of it
2854  double dx = 0;
2855  double dy = 0;
2856 
2857  // Add buffer based on bleed but keep precisely the height/width ratio (angle)
2858  // thus we add integer multiplications of width and height covering the bleed
2859  int bufferMulti = static_cast< int >( std::max( std::ceil( outputPixelBleed / width ), std::ceil( outputPixelBleed / width ) ) );
2860 
2861  // Always buffer at least once so that center of line marker in upper right corner
2862  // does not fall outside due to representation error
2863  bufferMulti = std::max( bufferMulti, 1 );
2864 
2865  int xBuffer = width * bufferMulti;
2866  int yBuffer = height * bufferMulti;
2867  int innerWidth = width;
2868  int innerHeight = height;
2869  width += 2 * xBuffer;
2870  height += 2 * yBuffer;
2871 
2872  //protect from zero width/height image and symbol layer from eating too much memory
2873  if ( width > 10000 || height > 10000 || width == 0 || height == 0 )
2874  {
2875  return;
2876  }
2877 
2878  QImage patternImage( width, height, QImage::Format_ARGB32 );
2879  patternImage.fill( 0 );
2880 
2881  QPointF p1, p2, p3, p4, p5, p6;
2882  if ( qgsDoubleNear( lineAngle, 0.0 ) || qgsDoubleNear( lineAngle, 360.0 ) || qgsDoubleNear( lineAngle, 180.0 ) )
2883  {
2884  p1 = QPointF( 0, yBuffer );
2885  p2 = QPointF( width, yBuffer );
2886  p3 = QPointF( 0, yBuffer + innerHeight );
2887  p4 = QPointF( width, yBuffer + innerHeight );
2888  }
2889  else if ( qgsDoubleNear( lineAngle, 90.0 ) || qgsDoubleNear( lineAngle, 270.0 ) )
2890  {
2891  p1 = QPointF( xBuffer, height );
2892  p2 = QPointF( xBuffer, 0 );
2893  p3 = QPointF( xBuffer + innerWidth, height );
2894  p4 = QPointF( xBuffer + innerWidth, 0 );
2895  }
2896  else if ( lineAngle > 0 && lineAngle < 90 )
2897  {
2898  dx = outputPixelDist * std::cos( ( 90 - lineAngle ) * M_PI / 180.0 );
2899  dy = outputPixelDist * std::sin( ( 90 - lineAngle ) * M_PI / 180.0 );
2900  p1 = QPointF( 0, height );
2901  p2 = QPointF( width, 0 );
2902  p3 = QPointF( -dx, height - dy );
2903  p4 = QPointF( width - dx, -dy );
2904  p5 = QPointF( dx, height + dy );
2905  p6 = QPointF( width + dx, dy );
2906  }
2907  else if ( lineAngle > 180 && lineAngle < 270 )
2908  {
2909  dx = outputPixelDist * std::cos( ( 90 - lineAngle ) * M_PI / 180.0 );
2910  dy = outputPixelDist * std::sin( ( 90 - lineAngle ) * M_PI / 180.0 );
2911  p1 = QPointF( width, 0 );
2912  p2 = QPointF( 0, height );
2913  p3 = QPointF( width - dx, -dy );
2914  p4 = QPointF( -dx, height - dy );
2915  p5 = QPointF( width + dx, dy );
2916  p6 = QPointF( dx, height + dy );
2917  }
2918  else if ( lineAngle > 90 && lineAngle < 180 )
2919  {
2920  dy = outputPixelDist * std::cos( ( 180 - lineAngle ) * M_PI / 180 );
2921  dx = outputPixelDist * std::sin( ( 180 - lineAngle ) * M_PI / 180 );
2922  p1 = QPointF( 0, 0 );
2923  p2 = QPointF( width, height );
2924  p5 = QPointF( dx, -dy );
2925  p6 = QPointF( width + dx, height - dy );
2926  p3 = QPointF( -dx, dy );
2927  p4 = QPointF( width - dx, height + dy );
2928  }
2929  else if ( lineAngle > 270 && lineAngle < 360 )
2930  {
2931  dy = outputPixelDist * std::cos( ( 180 - lineAngle ) * M_PI / 180 );
2932  dx = outputPixelDist * std::sin( ( 180 - lineAngle ) * M_PI / 180 );
2933  p1 = QPointF( width, height );
2934  p2 = QPointF( 0, 0 );
2935  p5 = QPointF( width + dx, height - dy );
2936  p6 = QPointF( dx, -dy );
2937  p3 = QPointF( width - dx, height + dy );
2938  p4 = QPointF( -dx, dy );
2939  }
2940 
2941  if ( !qgsDoubleNear( mOffset, 0.0 ) ) //shift everything
2942  {
2943  QPointF tempPt;
2944  tempPt = QgsSymbolLayerUtils::pointOnLineWithDistance( p1, p3, outputPixelDist + outputPixelOffset );
2945  p3 = QPointF( tempPt.x(), tempPt.y() );
2946  tempPt = QgsSymbolLayerUtils::pointOnLineWithDistance( p2, p4, outputPixelDist + outputPixelOffset );
2947  p4 = QPointF( tempPt.x(), tempPt.y() );
2948  tempPt = QgsSymbolLayerUtils::pointOnLineWithDistance( p1, p5, outputPixelDist - outputPixelOffset );
2949  p5 = QPointF( tempPt.x(), tempPt.y() );
2950  tempPt = QgsSymbolLayerUtils::pointOnLineWithDistance( p2, p6, outputPixelDist - outputPixelOffset );
2951  p6 = QPointF( tempPt.x(), tempPt.y() );
2952 
2953  //update p1, p2 last
2954  tempPt = QgsSymbolLayerUtils::pointOnLineWithDistance( p1, p3, outputPixelOffset );
2955  p1 = QPointF( tempPt.x(), tempPt.y() );
2956  tempPt = QgsSymbolLayerUtils::pointOnLineWithDistance( p2, p4, outputPixelOffset );
2957  p2 = QPointF( tempPt.x(), tempPt.y() );
2958  }
2959 
2960  QPainter p( &patternImage );
2961 
2962 #if 0
2963  // DEBUG: Draw rectangle
2964  p.setRenderHint( QPainter::Antialiasing, false ); // get true rect
2965  QPen pen( QColor( Qt::black ) );
2966  pen.setWidthF( 0.1 );
2967  pen.setCapStyle( Qt::FlatCap );
2968  p.setPen( pen );
2969 
2970  // To see this rectangle, comment buffer cut below.
2971  // Subtract 1 because not antialiased are rendered to the right/down by 1 pixel
2972  QPolygon polygon = QPolygon() << QPoint( 0, 0 ) << QPoint( width - 1, 0 ) << QPoint( width - 1, height - 1 ) << QPoint( 0, height - 1 ) << QPoint( 0, 0 );
2973  p.drawPolygon( polygon );
2974 
2975  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 );
2976  p.drawPolygon( polygon );
2977 #endif
2978 
2979  // Use antialiasing because without antialiasing lines are rendered to the
2980  // right and below the mathematically defined points (not symmetrical)
2981  // and such tiles become useless for are filling
2982  p.setRenderHint( QPainter::Antialiasing, true );
2983 
2984  // line rendering needs context for drawing on patternImage
2985  QgsRenderContext lineRenderContext;
2986  lineRenderContext.setPainter( &p );
2987  lineRenderContext.setScaleFactor( context.renderContext().scaleFactor() );
2989  lineRenderContext.setMapToPixel( mtp );
2990  lineRenderContext.setForceVectorOutput( false );
2991  lineRenderContext.setExpressionContext( context.renderContext().expressionContext() );
2993 
2994  fillLineSymbol->startRender( lineRenderContext, context.fields() );
2995 
2996  QVector<QPolygonF> polygons;
2997  polygons.append( QPolygonF() << p1 << p2 );
2998  polygons.append( QPolygonF() << p3 << p4 );
2999  if ( !qgsDoubleNear( lineAngle, 0 ) && !qgsDoubleNear( lineAngle, 360 ) && !qgsDoubleNear( lineAngle, 90 ) && !qgsDoubleNear( lineAngle, 180 ) && !qgsDoubleNear( lineAngle, 270 ) )
3000  {
3001  polygons.append( QPolygonF() << p5 << p6 );
3002  }
3003 
3004  for ( const QPolygonF &polygon : std::as_const( polygons ) )
3005  {
3006  fillLineSymbol->renderPolyline( polygon, context.feature(), lineRenderContext, -1, context.selected() );
3007  }
3008 
3009  fillLineSymbol->stopRender( lineRenderContext );
3010  p.end();
3011 
3012  // Cut off the buffer
3013  patternImage = patternImage.copy( xBuffer, yBuffer, patternImage.width() - 2 * xBuffer, patternImage.height() - 2 * yBuffer );
3014 
3015  //set image to mBrush
3016  if ( !qgsDoubleNear( context.opacity(), 1.0 ) )
3017  {
3018  QImage transparentImage = patternImage.copy();
3019  QgsSymbolLayerUtils::multiplyImageOpacity( &transparentImage, context.opacity() );
3020  brush.setTextureImage( transparentImage );
3021  }
3022  else
3023  {
3024  brush.setTextureImage( patternImage );
3025  }
3026 
3027  QTransform brushTransform;
3028  brush.setTransform( brushTransform );
3029 }
3030 
3032 {
3033  // if we are using a vector based output, we need to render points as vectors
3034  // (OR if the line has data defined symbology, in which case we need to evaluate this line-by-line)
3035  mRenderUsingLines = context.renderContext().forceVectorOutput()
3036  || mFillLineSymbol->hasDataDefinedProperties()
3037  || mClipMode != Qgis::LineClipMode::ClipPainterOnly
3039 
3040  if ( mRenderUsingLines )
3041  {
3042  if ( mFillLineSymbol )
3043  mFillLineSymbol->startRender( context.renderContext(), context.fields() );
3044  }
3045  else
3046  {
3047  // optimised render for screen only, use image based brush
3048  applyPattern( context, mBrush, mLineAngle, mDistance );
3049  }
3050 }
3051 
3053 {
3054  if ( mRenderUsingLines && mFillLineSymbol )
3055  {
3056  mFillLineSymbol->stopRender( context.renderContext() );
3057  }
3058 }
3059 
3060 void QgsLinePatternFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
3061 {
3062  if ( !mRenderUsingLines )
3063  {
3064  // use image based brush for speed
3065  QgsImageFillSymbolLayer::renderPolygon( points, rings, context );
3066  return;
3067  }
3068 
3069  // vector based output - so draw line by line!
3070  QPainter *p = context.renderContext().painter();
3071  if ( !p )
3072  {
3073  return;
3074  }
3075 
3076  double lineAngle = mLineAngle;
3078  {
3079  context.setOriginalValueVariable( mLineAngle );
3081  }
3082 
3083  double distance = mDistance;
3085  {
3086  context.setOriginalValueVariable( mDistance );
3088  }
3089  const double outputPixelDistance = context.renderContext().convertToPainterUnits( distance, mDistanceUnit, mDistanceMapUnitScale );
3090 
3091  double offset = mOffset;
3092  double outputPixelOffset = mOffsetUnit == QgsUnitTypes::RenderPercentage ? outputPixelDistance * offset / 100
3093  : context.renderContext().convertToPainterUnits( offset, mOffsetUnit, mOffsetMapUnitScale );
3094 
3095  // fix truncated pattern with larger offsets
3096  outputPixelOffset = std::fmod( outputPixelOffset, outputPixelDistance );
3097  if ( outputPixelOffset > outputPixelDistance / 2.0 )
3098  outputPixelOffset -= outputPixelDistance;
3099 
3100  p->setPen( QPen( Qt::NoPen ) );
3101 
3102  if ( context.selected() )
3103  {
3104  QColor selColor = context.renderContext().selectionColor();
3105  p->setBrush( QBrush( selColor ) );
3106  _renderPolygon( p, points, rings, context );
3107  }
3108 
3109  // if invalid parameters, skip out
3110  if ( qgsDoubleNear( distance, 0 ) )
3111  return;
3112 
3113  p->save();
3114 
3115  Qgis::LineClipMode clipMode = mClipMode;
3117  {
3119  bool ok = false;
3120  const QString valueString = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyLineClipping, context.renderContext().expressionContext(), QString(), &ok );
3121  if ( ok )
3122  {
3123  Qgis::LineClipMode decodedMode = QgsSymbolLayerUtils::decodeLineClipMode( valueString, &ok );
3124  if ( ok )
3125  clipMode = decodedMode;
3126  }
3127  }
3128 
3129  std::unique_ptr< QgsPolygon > shapePolygon;
3130  std::unique_ptr< QgsGeometryEngine > shapeEngine;
3131  switch ( clipMode )
3132  {
3134  break;
3135 
3137  {
3138  shapePolygon = std::make_unique< QgsPolygon >();
3139  shapePolygon->setExteriorRing( QgsLineString::fromQPolygonF( points ) );
3140  if ( rings )
3141  {
3142  for ( const QPolygonF &ring : *rings )
3143  {
3144  shapePolygon->addInteriorRing( QgsLineString::fromQPolygonF( ring ) );
3145  }
3146  }
3147  shapeEngine.reset( QgsGeometry::createGeometryEngine( shapePolygon.get() ) );
3148  shapeEngine->prepareGeometry();
3149  break;
3150  }
3151 
3153  {
3154  QPainterPath path;
3155  path.addPolygon( points );
3156  if ( rings )
3157  {
3158  for ( const QPolygonF &ring : *rings )
3159  {
3160  path.addPolygon( ring );
3161  }
3162  }
3163  p->setClipPath( path, Qt::IntersectClip );
3164  break;
3165  }
3166  }
3167 
3168  const bool applyBrushTransform = applyBrushTransformFromContext( &context );
3169  const QRectF boundingRect = points.boundingRect();
3170 
3171  QTransform invertedRotateTransform;
3172  double left;
3173  double top;
3174  double right;
3175  double bottom;
3176 
3177  QTransform transform;
3178  if ( applyBrushTransform )
3179  {
3180  // rotation applies around center of feature
3181  transform.translate( -boundingRect.center().x(),
3182  -boundingRect.center().y() );
3183  transform.rotate( lineAngle );
3184  transform.translate( boundingRect.center().x(),
3185  boundingRect.center().y() );
3186  }
3187  else
3188  {
3189  // rotation applies around top of viewport
3190  transform.rotate( lineAngle );
3191  }
3192 
3193  const QRectF transformedBounds = transform.map( points ).boundingRect();
3194 
3195  // bounds are expanded out a bit to account for maximum line width
3196  const double buffer = QgsSymbolLayerUtils::estimateMaxSymbolBleed( mFillLineSymbol.get(), context.renderContext() );
3197  left = transformedBounds.left() - buffer * 2;
3198  top = transformedBounds.top() - buffer * 2;
3199  right = transformedBounds.right() + buffer * 2;
3200  bottom = transformedBounds.bottom() + buffer * 2;
3201  invertedRotateTransform = transform.inverted();
3202 
3203  if ( !applyBrushTransform )
3204  {
3205  top -= transformedBounds.top() - ( outputPixelDistance * std::floor( transformedBounds.top() / outputPixelDistance ) );
3206  }
3207 
3209  QgsExpressionContextScopePopper scopePopper( context.renderContext().expressionContext(), scope );
3210  const bool needsExpressionContext = mFillLineSymbol->hasDataDefinedProperties();
3211 
3212  const bool prevIsSubsymbol = context.renderContext().flags() & Qgis::RenderContextFlag::RenderingSubSymbol;
3214 
3215  int currentLine = 0;
3216  for ( double currentY = top; currentY <= bottom; currentY += outputPixelDistance )
3217  {
3218  if ( context.renderContext().renderingStopped() )
3219  break;
3220 
3221  if ( needsExpressionContext )
3222  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_line_number" ), ++currentLine, true ) );
3223 
3224  double x1 = left;
3225  double y1 = currentY;
3226  double x2 = left;
3227  double y2 = currentY;
3228  invertedRotateTransform.map( left, currentY - outputPixelOffset, &x1, &y1 );
3229  invertedRotateTransform.map( right, currentY - outputPixelOffset, &x2, &y2 );
3230 
3231  if ( shapeEngine )
3232  {
3233  QgsLineString ls( QgsPoint( x1, y1 ), QgsPoint( x2, y2 ) );
3234  std::unique_ptr< QgsAbstractGeometry > intersection( shapeEngine->intersection( &ls ) );
3235  for ( auto it = intersection->const_parts_begin(); it != intersection->const_parts_end(); ++it )
3236  {
3237  if ( const QgsLineString *ls = qgsgeometry_cast< const QgsLineString * >( *it ) )
3238  {
3239  mFillLineSymbol->renderPolyline( ls->asQPolygonF(), context.feature(), context.renderContext() );
3240  }
3241  }
3242  }
3243  else
3244  {
3245  mFillLineSymbol->renderPolyline( QPolygonF() << QPointF( x1, y1 ) << QPointF( x2, y2 ), context.feature(), context.renderContext() );
3246  }
3247  }
3248 
3249  p->restore();
3250 
3252 }
3253 
3255 {
3256  QVariantMap map = QgsImageFillSymbolLayer::properties();
3257  map.insert( QStringLiteral( "angle" ), QString::number( mLineAngle ) );
3258  map.insert( QStringLiteral( "distance" ), QString::number( mDistance ) );
3259  map.insert( QStringLiteral( "line_width" ), QString::number( mLineWidth ) );
3260  map.insert( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( mColor ) );
3261  map.insert( QStringLiteral( "offset" ), QString::number( mOffset ) );
3262  map.insert( QStringLiteral( "distance_unit" ), QgsUnitTypes::encodeUnit( mDistanceUnit ) );
3263  map.insert( QStringLiteral( "line_width_unit" ), QgsUnitTypes::encodeUnit( mLineWidthUnit ) );
3264  map.insert( QStringLiteral( "offset_unit" ), QgsUnitTypes::encodeUnit( mOffsetUnit ) );
3265  map.insert( QStringLiteral( "distance_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mDistanceMapUnitScale ) );
3266  map.insert( QStringLiteral( "line_width_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mLineWidthMapUnitScale ) );
3267  map.insert( QStringLiteral( "offset_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale ) );
3268  map.insert( QStringLiteral( "outline_width_unit" ), QgsUnitTypes::encodeUnit( mStrokeWidthUnit ) );
3269  map.insert( QStringLiteral( "outline_width_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale ) );
3270  map.insert( QStringLiteral( "clip_mode" ), QgsSymbolLayerUtils::encodeLineClipMode( mClipMode ) );
3271  return map;
3272 }
3273 
3275 {
3277  if ( mFillLineSymbol )
3278  {
3279  clonedLayer->setSubSymbol( mFillLineSymbol->clone() );
3280  }
3281  copyPaintEffect( clonedLayer );
3282  copyDataDefinedProperties( clonedLayer );
3283  return clonedLayer;
3284 }
3285 
3286 void QgsLinePatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
3287 {
3288  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PolygonSymbolizer" ) );
3289  if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
3290  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
3291  element.appendChild( symbolizerElem );
3292 
3293  // <Geometry>
3294  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
3295 
3296  QDomElement fillElem = doc.createElement( QStringLiteral( "se:Fill" ) );
3297  symbolizerElem.appendChild( fillElem );
3298 
3299  QDomElement graphicFillElem = doc.createElement( QStringLiteral( "se:GraphicFill" ) );
3300  fillElem.appendChild( graphicFillElem );
3301 
3302  QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
3303  graphicFillElem.appendChild( graphicElem );
3304 
3305  //line properties must be inside the graphic definition
3306  QColor lineColor = mFillLineSymbol ? mFillLineSymbol->color() : QColor();
3307  double lineWidth = mFillLineSymbol ? mFillLineSymbol->width() : 0.0;
3308  lineWidth = QgsSymbolLayerUtils::rescaleUom( lineWidth, mLineWidthUnit, props );
3309  double distance = QgsSymbolLayerUtils::rescaleUom( mDistance, mDistanceUnit, props );
3310  QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, QStringLiteral( "horline" ), QColor(), lineColor, Qt::SolidLine, lineWidth, distance );
3311 
3312  // <Rotation>
3313  QString angleFunc;
3314  bool ok;
3315  double angle = props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ).toDouble( &ok );
3316  if ( !ok )
3317  {
3318  angleFunc = QStringLiteral( "%1 + %2" ).arg( props.value( QStringLiteral( "angle" ), QStringLiteral( "0" ) ).toString() ).arg( mLineAngle );
3319  }
3320  else if ( !qgsDoubleNear( angle + mLineAngle, 0.0 ) )
3321  {
3322  angleFunc = QString::number( angle + mLineAngle );
3323  }
3324  QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
3325 
3326  // <se:Displacement>
3327  QPointF lineOffset( std::sin( mLineAngle ) * mOffset, std::cos( mLineAngle ) * mOffset );
3328  lineOffset = QgsSymbolLayerUtils::rescaleUom( lineOffset, mOffsetUnit, props );
3329  QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, lineOffset );
3330 }
3331 
3332 QString QgsLinePatternFillSymbolLayer::ogrFeatureStyleWidth( double widthScaleFactor ) const
3333 {
3334  QString featureStyle;
3335  featureStyle.append( "Brush(" );
3336  featureStyle.append( QStringLiteral( "fc:%1" ).arg( mColor.name() ) );
3337  featureStyle.append( QStringLiteral( ",bc:%1" ).arg( QLatin1String( "#00000000" ) ) ); //transparent background
3338  featureStyle.append( ",id:\"ogr-brush-2\"" );
3339  featureStyle.append( QStringLiteral( ",a:%1" ).arg( mLineAngle ) );
3340  featureStyle.append( QStringLiteral( ",s:%1" ).arg( mLineWidth * widthScaleFactor ) );
3341  featureStyle.append( ",dx:0mm" );
3342  featureStyle.append( QStringLiteral( ",dy:%1mm" ).arg( mDistance * widthScaleFactor ) );
3343  featureStyle.append( ')' );
3344  return featureStyle;
3345 }
3346 
3348 {
3350  && ( !mFillLineSymbol || !mFillLineSymbol->hasDataDefinedProperties() ) )
3351  {
3352  return; //no data defined settings
3353  }
3354 
3355  double lineAngle = mLineAngle;
3357  {
3358  context.setOriginalValueVariable( mLineAngle );
3360  }
3361  double distance = mDistance;
3363  {
3364  context.setOriginalValueVariable( mDistance );
3366  }
3367  applyPattern( context, mBrush, lineAngle, distance );
3368 }
3369 
3371 {
3372  QString name;
3373  QColor fillColor, lineColor;
3374  double size, lineWidth;
3375  Qt::PenStyle lineStyle;
3376 
3377  QDomElement fillElem = element.firstChildElement( QStringLiteral( "Fill" ) );
3378  if ( fillElem.isNull() )
3379  return nullptr;
3380 
3381  QDomElement graphicFillElem = fillElem.firstChildElement( QStringLiteral( "GraphicFill" ) );
3382  if ( graphicFillElem.isNull() )
3383  return nullptr;
3384 
3385  QDomElement graphicElem = graphicFillElem.firstChildElement( QStringLiteral( "Graphic" ) );
3386  if ( graphicElem.isNull() )
3387  return nullptr;
3388 
3389  if ( !QgsSymbolLayerUtils::wellKnownMarkerFromSld( graphicElem, name, fillColor, lineColor, lineStyle, lineWidth, size ) )
3390  return nullptr;
3391 
3392  if ( name != QLatin1String( "horline" ) )
3393  return nullptr;
3394 
3395  double angle = 0.0;
3396  QString angleFunc;
3397  if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
3398  {
3399  bool ok;
3400  double d = angleFunc.toDouble( &ok );
3401  if ( ok )
3402  angle = d;
3403  }
3404 
3405  double offset = 0.0;
3406  QPointF vectOffset;
3407  if ( QgsSymbolLayerUtils::displacementFromSldElement( graphicElem, vectOffset ) )
3408  {
3409  offset = std::sqrt( std::pow( vectOffset.x(), 2 ) + std::pow( vectOffset.y(), 2 ) );
3410  }
3411 
3412  double scaleFactor = 1.0;
3413  const QString uom = element.attribute( QStringLiteral( "uom" ) );
3414  QgsUnitTypes::RenderUnit sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( uom, &scaleFactor );
3415  size = size * scaleFactor;
3416  lineWidth = lineWidth * scaleFactor;
3417 
3418  std::unique_ptr< QgsLinePatternFillSymbolLayer > sl = std::make_unique< QgsLinePatternFillSymbolLayer >();
3419  sl->setOutputUnit( sldUnitSize );
3420  sl->setColor( lineColor );
3421  sl->setLineWidth( lineWidth );
3422  sl->setLineAngle( angle );
3423  sl->setOffset( offset );
3424  sl->setDistance( size );
3425 
3426  // try to get the stroke
3427  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
3428  if ( !strokeElem.isNull() )
3429  {
3431  if ( l )
3432  {
3433  QgsSymbolLayerList layers;
3434  layers.append( l );
3435  sl->setSubSymbol( new QgsLineSymbol( layers ) );
3436  }
3437  }
3438 
3439  return sl.release();
3440 }
3441 
3442 
3444 
3447 {
3448  setSubSymbol( new QgsMarkerSymbol() );
3449  QgsImageFillSymbolLayer::setSubSymbol( nullptr ); //no stroke
3450 }
3451 
3453 
3455 {
3457  mDistanceXUnit = unit;
3458  mDistanceYUnit = unit;
3459  // don't change "percentage" units -- since they adapt directly to whatever other unit is set
3461  mDisplacementXUnit = unit;
3463  mDisplacementYUnit = unit;
3465  mOffsetXUnit = unit;
3467  mOffsetYUnit = unit;
3469  mRandomDeviationXUnit = unit;
3471  mRandomDeviationYUnit = unit;
3472 
3473  if ( mMarkerSymbol )
3474  {
3475  mMarkerSymbol->setOutputUnit( unit );
3476  }
3477 }
3478 
3480 {
3482  if ( mDistanceXUnit != unit ||
3483  mDistanceYUnit != unit ||
3490  {
3492  }
3493  return unit;
3494 }
3495 
3497 {
3506 }
3507 
3509 {
3511  mDistanceXMapUnitScale = scale;
3512  mDistanceYMapUnitScale = scale;
3515  mOffsetXMapUnitScale = scale;
3516  mOffsetYMapUnitScale = scale;
3519 }
3520 
3522 {
3531  {
3532  return mDistanceXMapUnitScale;
3533  }
3534  return QgsMapUnitScale();
3535 }
3536 
3538 {
3539  std::unique_ptr< QgsPointPatternFillSymbolLayer > layer = std::make_unique< QgsPointPatternFillSymbolLayer >();
3540  if ( properties.contains( QStringLiteral( "distance_x" ) ) )
3541  {
3542  layer->setDistanceX( properties[QStringLiteral( "distance_x" )].toDouble() );
3543  }
3544  if ( properties.contains( QStringLiteral( "distance_y" ) ) )
3545  {
3546  layer->setDistanceY( properties[QStringLiteral( "distance_y" )].toDouble() );
3547  }
3548  if ( properties.contains( QStringLiteral( "displacement_x" ) ) )
3549  {
3550  layer->setDisplacementX( properties[QStringLiteral( "displacement_x" )].toDouble() );
3551  }
3552  if ( properties.contains( QStringLiteral( "displacement_y" ) ) )
3553  {
3554  layer->setDisplacementY( properties[QStringLiteral( "displacement_y" )].toDouble() );
3555  }
3556  if ( properties.contains( QStringLiteral( "offset_x" ) ) )
3557  {
3558  layer->setOffsetX( properties[QStringLiteral( "offset_x" )].toDouble() );
3559  }
3560  if ( properties.contains( QStringLiteral( "offset_y" ) ) )
3561  {
3562  layer->setOffsetY( properties[QStringLiteral( "offset_y" )].toDouble() );
3563  }
3564 
3565  if ( properties.contains( QStringLiteral( "distance_x_unit" ) ) )
3566  {
3567  layer->setDistanceXUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "distance_x_unit" )].toString() ) );
3568  }
3569  if ( properties.contains( QStringLiteral( "distance_x_map_unit_scale" ) ) )
3570  {
3571  layer->setDistanceXMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "distance_x_map_unit_scale" )].toString() ) );
3572  }
3573  if ( properties.contains( QStringLiteral( "distance_y_unit" ) ) )
3574  {
3575  layer->setDistanceYUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "distance_y_unit" )].toString() ) );
3576  }
3577  if ( properties.contains( QStringLiteral( "distance_y_map_unit_scale" ) ) )
3578  {
3579  layer->setDistanceYMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "distance_y_map_unit_scale" )].toString() ) );
3580  }
3581  if ( properties.contains( QStringLiteral( "displacement_x_unit" ) ) )
3582  {
3583  layer->setDisplacementXUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "displacement_x_unit" )].toString() ) );
3584  }
3585  if ( properties.contains( QStringLiteral( "displacement_x_map_unit_scale" ) ) )
3586  {
3587  layer->setDisplacementXMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "displacement_x_map_unit_scale" )].toString() ) );
3588  }
3589  if ( properties.contains( QStringLiteral( "displacement_y_unit" ) ) )
3590  {
3591  layer->setDisplacementYUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "displacement_y_unit" )].toString() ) );
3592  }
3593  if ( properties.contains( QStringLiteral( "displacement_y_map_unit_scale" ) ) )
3594  {
3595  layer->setDisplacementYMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "displacement_y_map_unit_scale" )].toString() ) );
3596  }
3597  if ( properties.contains( QStringLiteral( "offset_x_unit" ) ) )
3598  {
3599  layer->setOffsetXUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_x_unit" )].toString() ) );
3600  }
3601  if ( properties.contains( QStringLiteral( "offset_x_map_unit_scale" ) ) )
3602  {
3603  layer->setOffsetXMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_x_map_unit_scale" )].toString() ) );
3604  }
3605  if ( properties.contains( QStringLiteral( "offset_y_unit" ) ) )
3606  {
3607  layer->setOffsetYUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_y_unit" )].toString() ) );
3608  }
3609  if ( properties.contains( QStringLiteral( "offset_y_map_unit_scale" ) ) )
3610  {
3611  layer->setOffsetYMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_y_map_unit_scale" )].toString() ) );
3612  }
3613 
3614  if ( properties.contains( QStringLiteral( "random_deviation_x" ) ) )
3615  {
3616  layer->setMaximumRandomDeviationX( properties[QStringLiteral( "random_deviation_x" )].toDouble() );
3617  }
3618  if ( properties.contains( QStringLiteral( "random_deviation_y" ) ) )
3619  {
3620  layer->setMaximumRandomDeviationY( properties[QStringLiteral( "random_deviation_y" )].toDouble() );
3621  }
3622  if ( properties.contains( QStringLiteral( "random_deviation_x_unit" ) ) )
3623  {
3624  layer->setRandomDeviationXUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "random_deviation_x_unit" )].toString() ) );
3625  }
3626  if ( properties.contains( QStringLiteral( "random_deviation_x_map_unit_scale" ) ) )
3627  {
3628  layer->setRandomDeviationXMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "random_deviation_x_map_unit_scale" )].toString() ) );
3629  }
3630  if ( properties.contains( QStringLiteral( "random_deviation_y_unit" ) ) )
3631  {
3632  layer->setRandomDeviationYUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "random_deviation_y_unit" )].toString() ) );
3633  }
3634  if ( properties.contains( QStringLiteral( "random_deviation_y_map_unit_scale" ) ) )
3635  {
3636  layer->setRandomDeviationYMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "random_deviation_y_map_unit_scale" )].toString() ) );
3637  }
3638  unsigned long seed = 0;
3639  if ( properties.contains( QStringLiteral( "seed" ) ) )
3640  seed = properties.value( QStringLiteral( "seed" ) ).toUInt();
3641  else
3642  {
3643  // if we a creating a new point pattern fill from scratch, we default to a random seed
3644  // because seed based fills are just nicer for users vs seeing points jump around with every map refresh
3645  std::random_device rd;
3646  std::mt19937 mt( seed == 0 ? rd() : seed );
3647  std::uniform_int_distribution<> uniformDist( 1, 999999999 );
3648  seed = uniformDist( mt );
3649  }
3650  layer->setSeed( seed );
3651 
3652  if ( properties.contains( QStringLiteral( "outline_width_unit" ) ) )
3653  {
3654  layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "outline_width_unit" )].toString() ) );
3655  }
3656  if ( properties.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
3657  {
3658  layer->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "outline_width_map_unit_scale" )].toString() ) );
3659  }
3660  if ( properties.contains( QStringLiteral( "clip_mode" ) ) )
3661  {
3662  layer->setClipMode( QgsSymbolLayerUtils::decodeMarkerClipMode( properties.value( QStringLiteral( "clip_mode" ) ).toString() ) );
3663  }
3664  if ( properties.contains( QStringLiteral( "coordinate_reference" ) ) )
3665  {
3666  layer->setCoordinateReference( QgsSymbolLayerUtils::decodeCoordinateReference( properties[QStringLiteral( "coordinate_reference" )].toString() ) );
3667  }
3668 
3669  if ( properties.contains( QStringLiteral( "angle" ) ) )
3670  {
3671  layer->setAngle( properties[QStringLiteral( "angle" )].toDouble() );
3672  }
3673 
3674  layer->restoreOldDataDefinedProperties( properties );
3675 
3676  return layer.release();
3677 }
3678 
3680 {
3681  return QStringLiteral( "PointPatternFill" );
3682 }
3683 
3684 void QgsPointPatternFillSymbolLayer::applyPattern( const QgsSymbolRenderContext &context, QBrush &brush, double distanceX, double distanceY,
3685  double displacementX, double displacementY, double offsetX, double offsetY )
3686 {
3687  //render 3 rows and columns in one go to easily incorporate displacement
3688  const QgsRenderContext &ctx = context.renderContext();
3691 
3692  double widthOffset = std::fmod(
3694  width );
3695  double heightOffset = std::fmod(
3697  height );
3698 
3699  if ( width > 10000 || height > 10000 ) //protect symbol layer from eating too much memory
3700  {
3701  QImage img;
3702  brush.setTextureImage( img );
3703  return;
3704  }
3705 
3706  QImage patternImage( width, height, QImage::Format_ARGB32 );
3707  patternImage.fill( 0 );
3708  if ( patternImage.isNull() )
3709  {
3710  brush.setTextureImage( QImage() );
3711  return;
3712  }
3713  if ( mMarkerSymbol )
3714  {
3715  QPainter p( &patternImage );
3716 
3717  //marker rendering needs context for drawing on patternImage
3718  QgsRenderContext pointRenderContext;
3719  pointRenderContext.setRendererScale( context.renderContext().rendererScale() );
3720  pointRenderContext.setPainter( &p );
3721  pointRenderContext.setScaleFactor( context.renderContext().scaleFactor() );
3722 
3725  pointRenderContext.setMapToPixel( mtp );
3726  pointRenderContext.setForceVectorOutput( false );
3727  pointRenderContext.setExpressionContext( context.renderContext().expressionContext() );
3729 
3730  mMarkerSymbol->startRender( pointRenderContext, context.fields() );
3731 
3732  //render points on distance grid
3733  for ( double currentX = -width; currentX <= width * 2.0; currentX += width )
3734  {
3735  for ( double currentY = -height; currentY <= height * 2.0; currentY += height )
3736  {
3737  mMarkerSymbol->renderPoint( QPointF( currentX + widthOffset, currentY + heightOffset ), context.feature(), pointRenderContext );
3738  }
3739  }
3740 
3741  //render displaced points
3742  double displacementPixelX = mDisplacementXUnit == QgsUnitTypes::RenderPercentage
3743  ? ( width * displacementX / 200 )
3745  double displacementPixelY = mDisplacementYUnit == QgsUnitTypes::RenderPercentage
3746  ? ( height * displacementY / 200 )
3748  for ( double currentX = -width; currentX <= width * 2.0; currentX += width )
3749  {
3750  for ( double currentY = -height / 2.0; currentY <= height * 2.0; currentY += height )
3751  {
3752  mMarkerSymbol->renderPoint( QPointF( currentX + widthOffset + displacementPixelX, currentY + heightOffset ), context.feature(), pointRenderContext );
3753  }
3754  }
3755 
3756  for ( double currentX = -width / 2.0; currentX <= width * 2.0; currentX += width )
3757  {
3758  for ( double currentY = -height; currentY <= height * 2.0; currentY += height / 2.0 )
3759  {
3760  mMarkerSymbol->renderPoint( QPointF( currentX + widthOffset + ( std::fmod( currentY, height ) != 0 ? displacementPixelX : 0 ), currentY + heightOffset - displacementPixelY ), context.feature(), pointRenderContext );
3761  }
3762  }
3763 
3764  mMarkerSymbol->stopRender( pointRenderContext );
3765  }
3766 
3767  if ( !qgsDoubleNear( context.opacity(), 1.0 ) )
3768  {
3769  QImage transparentImage = patternImage.copy();
3770  QgsSymbolLayerUtils::multiplyImageOpacity( &transparentImage, context.opacity() );
3771  brush.setTextureImage( transparentImage );
3772  }
3773  else
3774  {
3775  brush.setTextureImage( patternImage );
3776  }
3777  QTransform brushTransform;
3778  brush.setTransform( brushTransform );
3779 }
3780 
3782 {
3783  // if we are using a vector based output, we need to render points as vectors
3784  // (OR if the marker has data defined symbology, in which case we need to evaluate this point-by-point)
3785  mRenderUsingMarkers = context.renderContext().forceVectorOutput()
3786  || mMarkerSymbol->hasDataDefinedProperties()
3790  || mClipMode != Qgis::MarkerClipMode::Shape
3793  || !qgsDoubleNear( mAngle, 0 )
3795 
3796  if ( mRenderUsingMarkers )
3797  {
3798  mMarkerSymbol->startRender( context.renderContext() );
3799  }
3800  else
3801  {
3802  // optimised render for screen only, use image based brush
3804  }
3805 }
3806 
3808 {
3809  if ( mRenderUsingMarkers )
3810  {
3811  mMarkerSymbol->stopRender( context.renderContext() );
3812  }
3813 }
3814 
3816 {
3817  // The base class version passes this on to the subsymbol, but we deliberately don't do that here.
3818  // Otherwise generators used in the subsymbol will only render a single point per feature (they
3819  // have logic to only render once per paired call to startFeatureRender/stopFeatureRender).
3820 }
3821 
3823 {
3824  // The base class version passes this on to the subsymbol, but we deliberately don't do that here.
3825  // Otherwise generators used in the subsymbol will only render a single point per feature (they
3826  // have logic to only render once per paired call to startFeatureRender/stopFeatureRender).
3827 }
3828 
3829 void QgsPointPatternFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
3830 {
3831  if ( !mRenderUsingMarkers )
3832  {
3833  // use image based brush for speed
3834  QgsImageFillSymbolLayer::renderPolygon( points, rings, context );
3835  return;
3836  }
3837 
3838  // vector based output - so draw dot by dot!
3839  QPainter *p = context.renderContext().painter();
3840  if ( !p )
3841  {
3842  return;
3843  }
3844 
3845  double angle = mAngle;
3847  {
3848  context.setOriginalValueVariable( angle );
3850  }
3851 
3852  double distanceX = mDistanceX;
3854  {
3857  }
3859 
3860  double distanceY = mDistanceY;
3862  {
3865  }
3867 
3868  double offsetX = mOffsetX;
3870  {
3873  }
3874  const double widthOffset = std::fmod(
3876  ? ( offsetX * width / 100 )
3878  width );
3879 
3880  double offsetY = mOffsetY;
3882  {
3885  }
3886  const double heightOffset = std::fmod(
3888  ? ( offsetY * height / 100 )
3890  height );
3891 
3892  double displacementX = mDisplacementX;
3894  {
3897  }
3898  const double displacementPixelX = mDisplacementXUnit == QgsUnitTypes::RenderPercentage
3899  ? ( displacementX * width / 100 )
3901 
3902  double displacementY = mDisplacementY;
3904  {
3907  }
3908  const double displacementPixelY = mDisplacementYUnit == QgsUnitTypes::RenderPercentage
3909  ? ( displacementY * height / 100 )
3911 
3912  p->setPen( QPen( Qt::NoPen ) );
3913 
3914  if ( context.selected() )
3915  {
3916  QColor selColor = context.renderContext().selectionColor();
3917  p->setBrush( QBrush( selColor ) );
3918  _renderPolygon( p, points, rings, context );
3919  }
3920 
3921  // if invalid parameters, skip out
3922  if ( qgsDoubleNear( width, 0 ) || qgsDoubleNear( height, 0 ) || width < 0 || height < 0 )
3923  return;
3924 
3925  p->save();
3926 
3927  Qgis::MarkerClipMode clipMode = mClipMode;
3929  {
3931  bool ok = false;
3932  const QString valueString = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyMarkerClipping, context.renderContext().expressionContext(), QString(), &ok );
3933  if ( ok )
3934  {
3935  Qgis::MarkerClipMode decodedMode = QgsSymbolLayerUtils::decodeMarkerClipMode( valueString, &ok );
3936  if ( ok )
3937  clipMode = decodedMode;
3938  }
3939  }
3940 
3941  std::unique_ptr< QgsPolygon > shapePolygon;
3942  std::unique_ptr< QgsGeometryEngine > shapeEngine;
3943  switch ( clipMode )
3944  {
3948  {
3949  shapePolygon = std::make_unique< QgsPolygon >();
3950  shapePolygon->setExteriorRing( QgsLineString::fromQPolygonF( points ) );
3951  if ( rings )
3952  {
3953  for ( const QPolygonF &ring : *rings )
3954  {
3955  shapePolygon->addInteriorRing( QgsLineString::fromQPolygonF( ring ) );
3956  }
3957  }
3958  shapeEngine.reset( QgsGeometry::createGeometryEngine( shapePolygon.get() ) );
3959  shapeEngine->prepareGeometry();
3960  break;
3961  }
3962 
3964  {
3965  QPainterPath path;
3966  path.addPolygon( points );
3967  if ( rings )
3968  {
3969  for ( const QPolygonF &ring : *rings )
3970  {
3971  path.addPolygon( ring );
3972  }
3973  }
3974  p->setClipPath( path, Qt::IntersectClip );
3975  break;
3976  }
3977  }
3978 
3979  const bool applyBrushTransform = applyBrushTransformFromContext( &context );
3980  const QRectF boundingRect = points.boundingRect();
3981 
3982  QTransform invertedRotateTransform;
3983  double left;
3984  double top;
3985  double right;
3986  double bottom;
3987 
3988  if ( !qgsDoubleNear( angle, 0 ) )
3989  {
3990  QTransform transform;
3991  if ( applyBrushTransform )
3992  {
3993  // rotation applies around center of feature
3994  transform.translate( -boundingRect.center().x(),
3995  -boundingRect.center().y() );
3996  transform.rotate( -angle );
3997  transform.translate( boundingRect.center().x(),
3998  boundingRect.center().y() );
3999  }
4000  else
4001  {
4002  // rotation applies around top of viewport
4003  transform.rotate( -angle );
4004  }
4005 
4006  const QRectF transformedBounds = transform.map( points ).boundingRect();
4007  left = transformedBounds.left() - 2 * width;
4008  top = transformedBounds.top() - 2 * height;
4009  right = transformedBounds.right() + 2 * width;
4010  bottom = transformedBounds.bottom() + 2 * height;
4011  invertedRotateTransform = transform.inverted();
4012 
4013  if ( !applyBrushTransform )
4014  {
4015  left -= transformedBounds.left() - ( width * std::floor( transformedBounds.left() / width ) );
4016  top -= transformedBounds.top() - ( height * std::floor( transformedBounds.top() / height ) );
4017  }
4018  }
4019  else
4020  {
4021  left = boundingRect.left() - 2 * width;
4022  top = boundingRect.top() - 2 * height;
4023  right = boundingRect.right() + 2 * width;
4024  bottom = boundingRect.bottom() + 2 * height;
4025 
4026  if ( !applyBrushTransform )
4027  {
4028  left -= boundingRect.left() - ( width * std::floor( boundingRect.left() / width ) );
4029  top -= boundingRect.top() - ( height * std::floor( boundingRect.top() / height ) );
4030  }
4031  }
4032 
4033  unsigned long seed = mSeed;
4035  {
4036  context.renderContext().expressionContext().setOriginalValueVariable( static_cast< unsigned long long >( seed ) );
4038  }
4039 
4040  double maxRandomDeviationX = mRandomDeviationX;
4042  {
4043  context.setOriginalValueVariable( maxRandomDeviationX );
4044  maxRandomDeviationX = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyRandomOffsetX, context.renderContext().expressionContext(), maxRandomDeviationX );
4045  }
4046  const double maxRandomDeviationPixelX = mRandomDeviationXUnit == QgsUnitTypes::RenderPercentage ? ( maxRandomDeviationX * width / 100 )
4048 
4049  double maxRandomDeviationY = mRandomDeviationY;
4051  {
4052  context.setOriginalValueVariable( maxRandomDeviationY );
4053  maxRandomDeviationY = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::PropertyRandomOffsetY, context.renderContext().expressionContext(), maxRandomDeviationY );
4054  }
4055  const double maxRandomDeviationPixelY = mRandomDeviationYUnit == QgsUnitTypes::RenderPercentage ? ( maxRandomDeviationY * height / 100 )
4057 
4058  std::random_device rd;
4059  std::mt19937 mt( seed == 0 ? rd() : seed );
4060  std::uniform_real_distribution<> uniformDist( 0, 1 );
4061  const bool useRandomShift = !qgsDoubleNear( maxRandomDeviationPixelX, 0 ) || !qgsDoubleNear( maxRandomDeviationPixelY, 0 );
4062 
4064  QgsExpressionContextScopePopper scopePopper( context.renderContext().expressionContext(), scope );
4065  int pointNum = 0;
4066  const bool needsExpressionContext = mMarkerSymbol->hasDataDefinedProperties();
4067 
4068  const bool prevIsSubsymbol = context.renderContext().flags() & Qgis::RenderContextFlag::RenderingSubSymbol;
4070 
4071  bool alternateColumn = false;
4072  int currentCol = -3; // because we actually render a few rows/cols outside the bounds, try to align the col/row numbers to start at 1 for the first visible row/col
4073  for ( double currentX = left; currentX <= right; currentX += width, alternateColumn = !alternateColumn )
4074  {
4075  if ( context.renderContext().renderingStopped() )
4076  break;
4077 
4078  if ( needsExpressionContext )
4079  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_marker_column" ), ++currentCol, true ) );
4080 
4081  bool alternateRow = false;
4082  const double columnX = currentX + widthOffset;
4083  int currentRow = -3;
4084  for ( double currentY = top; currentY <= bottom; currentY += height, alternateRow = !alternateRow )
4085  {
4086  if ( context.renderContext().renderingStopped() )
4087  break;
4088 
4089  double y = currentY + heightOffset;
4090  double x = columnX;
4091  if ( alternateRow )
4092  x += displacementPixelX;
4093 
4094  if ( !alternateColumn )
4095  y -= displacementPixelY;
4096 
4097  if ( !qgsDoubleNear( angle, 0 ) )
4098  {
4099  double xx = x;
4100  double yy = y;
4101  invertedRotateTransform.map( xx, yy, &x, &y );
4102  }
4103 
4104  if ( useRandomShift )
4105  {
4106  x += ( 2 * uniformDist( mt ) - 1 ) * maxRandomDeviationPixelX;
4107  y += ( 2 * uniformDist( mt ) - 1 ) * maxRandomDeviationPixelY;
4108  }
4109 
4110  if ( needsExpressionContext )
4111  {
4113  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_marker_row" ), ++currentRow, true ) );
4114  }
4115 
4116  if ( shapeEngine )
4117  {
4118  bool renderPoint = true;
4119  switch ( clipMode )
4120  {
4122  {
4123  // we test using the marker bounds here and NOT just the x,y point, as the marker symbol may have offsets or other data defined properties which affect its visual placement
4124  const QgsRectangle markerRect = QgsRectangle( mMarkerSymbol->bounds( QPointF( x, y ), context.renderContext(), context.feature() ? *context.feature() : QgsFeature() ) );
4125  QgsPoint p( markerRect.center() );
4126  renderPoint = shapeEngine->intersects( &p );
4127  break;
4128  }
4129 
4132  {
4133  const QgsGeometry markerBounds = QgsGeometry::fromRect( QgsRectangle( mMarkerSymbol->bounds( QPointF( x, y ), context.renderContext(), context.feature() ? *context.feature() : QgsFeature() ) ) );
4134 
4136  renderPoint = shapeEngine->contains( markerBounds.constGet() );
4137  else
4138  renderPoint = shapeEngine->intersects( markerBounds.constGet() );
4139  break;
4140  }
4141 
4143  break;
4144  }
4145 
4146  if ( !renderPoint )
4147  continue;
4148  }
4149 
4150  mMarkerSymbol->renderPoint( QPointF( x, y ), context.feature(), context.renderContext() );
4151  }
4152  }
4153 
4154  p->restore();
4155 
4157 }
4158 
4160 {
4161  QVariantMap map = QgsImageFillSymbolLayer::properties();
4162  map.insert( QStringLiteral( "distance_x" ), QString::number( mDistanceX ) );
4163  map.insert( QStringLiteral( "distance_y" ), QString::number( mDistanceY ) );
4164  map.insert( QStringLiteral( "displacement_x" ), QString::number( mDisplacementX ) );
4165  map.insert( QStringLiteral( "displacement_y" ), QString::number( mDisplacementY ) );
4166  map.insert( QStringLiteral( "offset_x" ), QString::number( mOffsetX ) );
4167  map.insert( QStringLiteral( "offset_y" ), QString::number( mOffsetY ) );
4168  map.insert( QStringLiteral( "distance_x_unit" ), QgsUnitTypes::encodeUnit( mDistanceXUnit ) );
4169  map.insert( QStringLiteral( "distance_y_unit" ), QgsUnitTypes::encodeUnit( mDistanceYUnit ) );
4170  map.insert( QStringLiteral( "displacement_x_unit" ), QgsUnitTypes::encodeUnit( mDisplacementXUnit ) );
4171  map.insert( QStringLiteral( "displacement_y_unit" ), QgsUnitTypes::encodeUnit( mDisplacementYUnit ) );
4172  map.insert( QStringLiteral( "offset_x_unit" ), QgsUnitTypes::encodeUnit( mOffsetXUnit ) );
4173  map.insert( QStringLiteral( "offset_y_unit" ), QgsUnitTypes::encodeUnit( mOffsetYUnit ) );
4174  map.insert( QStringLiteral( "distance_x_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mDistanceXMapUnitScale ) );
4175  map.insert( QStringLiteral( "distance_y_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mDistanceYMapUnitScale ) );
4176  map.insert( QStringLiteral( "displacement_x_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mDisplacementXMapUnitScale ) );
4177  map.insert( QStringLiteral( "displacement_y_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mDisplacementYMapUnitScale ) );
4178  map.insert( QStringLiteral( "offset_x_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetXMapUnitScale ) );
4179  map.insert( QStringLiteral( "offset_y_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetYMapUnitScale ) );
4180  map.insert( QStringLiteral( "outline_width_unit" ), QgsUnitTypes::encodeUnit( mStrokeWidthUnit ) );
4181  map.insert( QStringLiteral( "outline_width_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale ) );
4182  map.insert( QStringLiteral( "clip_mode" ), QgsSymbolLayerUtils::encodeMarkerClipMode( mClipMode ) );
4183  map.insert( QStringLiteral( "random_deviation_x" ), QString::number( mRandomDeviationX ) );
4184  map.insert( QStringLiteral( "random_deviation_y" ), QString::number( mRandomDeviationY ) );
4185  map.insert( QStringLiteral( "random_deviation_x_unit" ), QgsUnitTypes::encodeUnit( mRandomDeviationXUnit ) );
4186  map.insert( QStringLiteral( "random_deviation_y_unit" ), QgsUnitTypes::encodeUnit( mRandomDeviationYUnit ) );
4187  map.insert( QStringLiteral( "random_deviation_x_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mRandomDeviationXMapUnitScale ) );
4188  map.insert( QStringLiteral( "random_deviation_y_map_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mRandomDeviationYMapUnitScale ) );
4189  map.insert( QStringLiteral( "seed" ), QString::number( mSeed ) );
4190  map.insert( QStringLiteral( "angle" ), mAngle );
4191  return map;
4192 }
4193 
4195 {
4197  if ( mMarkerSymbol )
4198  {
4199  clonedLayer->setSubSymbol( mMarkerSymbol->clone() );
4200  }
4201  clonedLayer->setClipMode( mClipMode );
4202  copyDataDefinedProperties( clonedLayer );
4203  copyPaintEffect( clonedLayer );
4204  return clonedLayer;
4205 }
4206 
4207 void QgsPointPatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
4208 {
4209  for ( int i = 0; i < mMarkerSymbol->symbolLayerCount(); i++ )
4210  {
4211  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PolygonSymbolizer" ) );
4212  if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
4213  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
4214  element.appendChild( symbolizerElem );
4215 
4216  // <Geometry>
4217  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
4218 
4219  QDomElement fillElem = doc.createElement( QStringLiteral( "se:Fill" ) );
4220  symbolizerElem.appendChild( fillElem );
4221 
4222  QDomElement graphicFillElem = doc.createElement( QStringLiteral( "se:GraphicFill" ) );
4223  fillElem.appendChild( graphicFillElem );
4224 
4225  // store distanceX, distanceY, displacementX, displacementY in a <VendorOption>
4228  QString dist = QgsSymbolLayerUtils::encodePoint( QPointF( dx, dy ) );
4229  QDomElement distanceElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "distance" ), dist );
4230  symbolizerElem.appendChild( distanceElem );
4231 
4232  QgsSymbolLayer *layer = mMarkerSymbol->symbolLayer( i );
4233  if ( QgsMarkerSymbolLayer *markerLayer = dynamic_cast<QgsMarkerSymbolLayer *>( layer ) )
4234  {
4235  markerLayer->writeSldMarker( doc, graphicFillElem, props );
4236  }
4237  else if ( layer )
4238  {
4239  QString errorMsg = QStringLiteral( "QgsMarkerSymbolLayer expected, %1 found. Skip it." ).arg( layer->layerType() );
4240  graphicFillElem.appendChild( doc.createComment( errorMsg ) );
4241  }
4242  else
4243  {
4244  QString errorMsg = QStringLiteral( "Missing point pattern symbol layer. Skip it." );
4245  graphicFillElem.appendChild( doc.createComment( errorMsg ) );
4246  }
4247  }
4248 }
4249 
4251 {
4252  Q_UNUSED( element )
4253  return nullptr;
4254 }
4255 
4257 {
4258  if ( !symbol )
4259  {
4260  return false;
4261  }
4262 
4263  if ( symbol->type() == Qgis::SymbolType::Marker )
4264  {
4265  QgsMarkerSymbol *markerSymbol = static_cast<QgsMarkerSymbol *>( symbol );
4266  mMarkerSymbol.reset( markerSymbol );
4267  }
4268  return true;
4269 }
4270 
4272 {
4273  return mMarkerSymbol.get();
4274 }
4275 
4277 {
4281  && ( !mMarkerSymbol || !mMarkerSymbol->hasDataDefinedProperties() ) )
4282  {
4283  return;
4284  }
4285 
4286  double distanceX = mDistanceX;
4288  {
4291  }
4292  double distanceY = mDistanceY;
4294  {
4297  }
4298  double displacementX = mDisplacementX;
4300  {
4303  }
4304  double displacementY = mDisplacementY;
4306  {
4309  }
4310  double offsetX = mOffsetX;
4312  {
4315  }
4316  double offsetY = mOffsetY;
4318  {
4321  }
4322  applyPattern( context, mBrush, distanceX, distanceY, displacementX, displacementY, offsetX, offsetY );
4323 }
4324 
4326 {
4327  return 0;
4328 }
4329 
4331 {
4332  QSet<QString> attributes = QgsImageFillSymbolLayer::usedAttributes( context );
4333 
4334  if ( mMarkerSymbol )
4335  attributes.unite( mMarkerSymbol->usedAttributes( context ) );
4336 
4337  return attributes;
4338 }
4339 
4341 {
4343  return true;
4344  if ( mMarkerSymbol && mMarkerSymbol->hasDataDefinedProperties() )
4345  return true;
4346  return false;
4347 }
4348 
4350 {
4351  mColor = c;
4352  if ( mMarkerSymbol )
4353  mMarkerSymbol->setColor( c );
4354 }
4355 
4357 {
4358  return mMarkerSymbol ? mMarkerSymbol->color() : mColor;
4359 }
4360 
4362 
4363 
4365 {
4366  setSubSymbol( new QgsMarkerSymbol() );
4367 }
4368 
4370 
4371 QgsSymbolLayer *QgsCentroidFillSymbolLayer::create( const QVariantMap &properties )
4372 {
4373  std::unique_ptr< QgsCentroidFillSymbolLayer > sl = std::make_unique< QgsCentroidFillSymbolLayer >();
4374 
4375  if ( properties.contains( QStringLiteral( "point_on_surface" ) ) )
4376  sl->setPointOnSurface( properties[QStringLiteral( "point_on_surface" )].toInt() != 0 );
4377  if ( properties.contains( QStringLiteral( "point_on_all_parts" ) ) )
4378  sl->setPointOnAllParts( properties[QStringLiteral( "point_on_all_parts" )].toInt() != 0 );
4379  if ( properties.contains( QStringLiteral( "clip_points" ) ) )
4380  sl->setClipPoints( properties[QStringLiteral( "clip_points" )].toInt() != 0 );
4381  if ( properties.contains( QStringLiteral( "clip_on_current_part_only" ) ) )
4382  sl->setClipOnCurrentPartOnly( properties[QStringLiteral( "clip_on_current_part_only" )].toInt() != 0 );
4383 
4384  sl->restoreOldDataDefinedProperties( properties );
4385 
4386  return sl.release();
4387 }
4388 
4390 {
4391  return QStringLiteral( "CentroidFill" );
4392 }
4393 
4394 void QgsCentroidFillSymbolLayer::setColor( const QColor &color )
4395 {
4396  mMarker->setColor( color );
4397  mColor = color;
4398 }
4399 
4401 {
4402  return mMarker ? mMarker->color() : mColor;
4403 }
4404 
4406 {
4407  mMarker->startRender( context.renderContext(), context.fields() );
4408 }
4409 
4411 {
4412  mMarker->stopRender( context.renderContext() );
4413 }
4414 
4415 void QgsCentroidFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
4416 {
4417  Part part;
4418  part.exterior = points;
4419  if ( rings )
4420  part.rings = *rings;
4421 
4422  if ( mRenderingFeature )
4423  {
4424  // in the middle of rendering a possibly multi-part feature, so we collect all the parts and defer the actual rendering
4425  // until after we've received the final part
4426  mFeatureSymbolOpacity = context.opacity();
4427  mCurrentParts << part;
4428  }
4429  else
4430  {
4431  // not rendering a feature, so we can just render the polygon immediately
4432  const double prevOpacity = mMarker->opacity();
4433  mMarker->setOpacity( mMarker->opacity() * context.opacity() );
4434  render( context.renderContext(), QVector<Part>() << part, context.feature() ? *context.feature() : QgsFeature(), context.selected() );
4435  mMarker->setOpacity( prevOpacity );
4436  }
4437 }
4438 
4440 {
4441  mRenderingFeature = true;
4442  mCurrentParts.clear();
4443 }
4444 
4446 {
4447  mRenderingFeature = false;
4448 
4449  const double prevOpacity = mMarker->opacity();
4450  mMarker->setOpacity( mMarker->opacity() * mFeatureSymbolOpacity );
4451 
4452  render( context, mCurrentParts, feature, false );
4454  mMarker->setOpacity( prevOpacity );
4455 }
4456 
4457 void QgsCentroidFillSymbolLayer::render( QgsRenderContext &context, const QVector<QgsCentroidFillSymbolLayer::Part> &parts, const QgsFeature &feature, bool selected )
4458 {
4461  bool clipPoints = mClipPoints;
4463 
4464  // TODO add expressions support
4465 
4466  QVector< QgsGeometry > geometryParts;
4467  geometryParts.reserve( parts.size() );
4468  QPainterPath globalPath;
4469 
4470  int maxArea = 0;
4471  int maxAreaPartIdx = 0;
4472 
4473  for ( int i = 0; i < parts.size(); i++ )
4474  {
4475  const Part part = parts[i];
4476  QgsGeometry geom = QgsGeometry::fromQPolygonF( part.exterior );
4477 
4478  if ( !geom.isNull() && !part.rings.empty() )
4479  {
4480  QgsPolygon *poly = qgsgeometry_cast< QgsPolygon * >( geom.get() );
4481 
4482  if ( !pointOnAllParts )
4483  {
4484  int area = poly->area();
4485 
4486  if ( area > maxArea )
4487  {
4488  maxArea = area;
4489  maxAreaPartIdx = i;
4490  }
4491  }
4492  }
4493 
4495  {
4496  globalPath.addPolygon( part.exterior );
4497  for ( const QPolygonF &ring : part.rings )
4498  {
4499  globalPath.addPolygon( ring );
4500  }
4501  }
4502  }
4503 
4504  for ( int i = 0; i < parts.size(); i++ )
4505  {
4506  if ( !pointOnAllParts && i != maxAreaPartIdx )
4507  continue;
4508 
4509  const Part part = parts[i];
4510 
4511  if ( clipPoints )
4512  {
4513  QPainterPath path;
4514 
4515  if ( clipOnCurrentPartOnly )
4516  {
4517  path.addPolygon( part.exterior );
4518  for ( const QPolygonF &ring : part.rings )
4519  {
4520  path.addPolygon( ring );
4521  }
4522  }
4523  else
4524  {
4525  path = globalPath;
4526  }
4527 
4528  context.painter()->save();
4529  context.painter()->setClipPath( path );
4530  }
4531 
4532  QPointF centroid = pointOnSurface ? QgsSymbolLayerUtils::polygonPointOnSurface( part.exterior, &part.rings ) : QgsSymbolLayerUtils::polygonCentroid( part.exterior );
4533 
4534  const bool prevIsSubsymbol = context.flags() & Qgis::RenderContextFlag::RenderingSubSymbol;
4536  mMarker->renderPoint( centroid, feature.isValid() ? &feature : nullptr, context, -1, selected );
4537  context.setFlag( Qgis::RenderContextFlag::RenderingSubSymbol, prevIsSubsymbol );
4538 
4539  if ( clipPoints )
4540  {
4541  context.painter()->restore();
4542  }
4543  }
4544 }
4545 
4547 {
4548  QVariantMap map;
4549  map[QStringLiteral( "point_on_surface" )] = QString::number( mPointOnSurface );
4550  map[QStringLiteral( "point_on_all_parts" )] = QString::number( mPointOnAllParts );
4551  map[QStringLiteral( "clip_points" )] = QString::number( mClipPoints );
4552  map[QStringLiteral( "clip_on_current_part_only" )] = QString::number( mClipOnCurrentPartOnly );
4553  return map;
4554 }
4555 
4557 {
4558  std::unique_ptr< QgsCentroidFillSymbolLayer > x = std::make_unique< QgsCentroidFillSymbolLayer >();
4559  x->mAngle = mAngle;
4560  x->mColor = mColor;
4561  x->setSubSymbol( mMarker->clone() );
4562  x->setPointOnSurface( mPointOnSurface );
4563  x->setPointOnAllParts( mPointOnAllParts );
4564  x->setClipPoints( mClipPoints );
4565  x->setClipOnCurrentPartOnly( mClipOnCurrentPartOnly );
4566  copyDataDefinedProperties( x.get() );
4567  copyPaintEffect( x.get() );
4568  return x.release();
4569 }
4570 
4571 void QgsCentroidFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
4572 {
4573  // SLD 1.0 specs says: "if a line, polygon, or raster geometry is
4574  // used with PointSymbolizer, then the semantic is to use the centroid
4575  // of the geometry, or any similar representative point.
4576  mMarker->toSld( doc, element, props );
4577 }
4578 
4580 {
4582  if ( !l )
4583  return nullptr;
4584 
4585  QgsSymbolLayerList layers;
4586  layers.append( l );
4587  std::unique_ptr< QgsMarkerSymbol > marker( new QgsMarkerSymbol( layers ) );
4588 
4589  std::unique_ptr< QgsCentroidFillSymbolLayer > sl = std::make_unique< QgsCentroidFillSymbolLayer >();
4590  sl->setSubSymbol( marker.release() );
4591  sl->setPointOnAllParts( false );
4592  return sl.release();
4593 }
4594 
4595 
4597 {
4598  return mMarker.get();
4599 }
4600 
4602 {
4603  if ( !symbol || symbol->type() != Qgis::SymbolType::Marker )
4604  {
4605  delete symbol;
4606  return false;
4607  }
4608 
4609  mMarker.reset( static_cast<QgsMarkerSymbol *>( symbol ) );
4610  mColor = mMarker->color();
4611  return true;
4612 }
4613 
4615 {
4616  QSet<QString> attributes = QgsFillSymbolLayer::usedAttributes( context );
4617 
4618  if ( mMarker )
4619  attributes.unite( mMarker->usedAttributes( context ) );
4620 
4621  return attributes;
4622 }
4623 
4625 {
4627  return true;
4628  if ( mMarker && mMarker->hasDataDefinedProperties() )
4629  return true;
4630  return false;
4631 }
4632 
4634 {
4635  return true;
4636 }
4637 
4639 {
4640  if ( mMarker )
4641  {
4642  mMarker->setOutputUnit( unit );
4643  }
4644 }
4645 
4647 {
4648  if ( mMarker )
4649  {
4650  return mMarker->outputUnit();
4651  }
4652  return QgsUnitTypes::RenderUnknownUnit; //mOutputUnit;
4653 }
4654 
4656 {
4657  if ( mMarker )
4658  {
4659  return mMarker->usesMapUnits();
4660  }
4661  return false;
4662 }
4663 
4665 {
4666  if ( mMarker )
4667  {
4668  mMarker->setMapUnitScale( scale );
4669  }
4670 }
4671 
4673 {
4674  if ( mMarker )
4675  {
4676  return mMarker->mapUnitScale();
4677  }
4678  return QgsMapUnitScale();
4679 }
4680 
4681 
4682 
4683 
4686  , mImageFilePath( imageFilePath )
4687 {
4688  QgsImageFillSymbolLayer::setSubSymbol( nullptr ); //disable sub symbol
4690 }
4691 
4693 
4694 QgsSymbolLayer *QgsRasterFillSymbolLayer::create( const QVariantMap &properties )
4695 {
4697  double alpha = 1.0;
4698  QPointF offset;
4699  double angle = 0.0;
4700  double width = 0.0;
4701 
4702  QString imagePath;
4703  if ( properties.contains( QStringLiteral( "imageFile" ) ) )
4704  {
4705  imagePath = properties[QStringLiteral( "imageFile" )].toString();
4706  }
4707  if ( properties.contains( QStringLiteral( "coordinate_mode" ) ) )
4708  {
4709  mode = static_cast< Qgis::SymbolCoordinateReference >( properties[QStringLiteral( "coordinate_mode" )].toInt() );
4710  }
4711  if ( properties.contains( QStringLiteral( "alpha" ) ) )
4712  {
4713  alpha = properties[QStringLiteral( "alpha" )].toDouble();
4714  }
4715  if ( properties.contains( QStringLiteral( "offset" ) ) )
4716  {
4717  offset = QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )].toString() );
4718  }
4719  if ( properties.contains( QStringLiteral( "angle" ) ) )
4720  {
4721  angle = properties[QStringLiteral( "angle" )].toDouble();
4722  }
4723  if ( properties.contains( QStringLiteral( "width" ) ) )
4724  {
4725  width = properties[QStringLiteral( "width" )].toDouble();
4726  }
4727  std::unique_ptr< QgsRasterFillSymbolLayer > symbolLayer = std::make_unique< QgsRasterFillSymbolLayer >( imagePath );
4728  symbolLayer->setCoordinateMode( mode );
4729  symbolLayer->setOpacity( alpha );
4730  symbolLayer->setOffset( offset );
4731  symbolLayer->setAngle( angle );
4732  symbolLayer->setWidth( width );
4733  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
4734  {
4735  symbolLayer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
4736  }
4737  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
4738  {
4739  symbolLayer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
4740  }
4741  if ( properties.contains( QStringLiteral( "width_unit" ) ) )
4742  {
4743  symbolLayer->setWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "width_unit" )].toString() ) );
4744  }
4745  if ( properties.contains( QStringLiteral( "width_map_unit_scale" ) ) )
4746  {
4747  symbolLayer->setWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "width_map_unit_scale" )].toString() ) );
4748  }
4749 
4750  symbolLayer->restoreOldDataDefinedProperties( properties );
4751 
4752  return symbolLayer.release();
4753 }
4754 
4755 void QgsRasterFillSymbolLayer::resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving )
4756 {
4757  QVariantMap::iterator it = properties.find( QStringLiteral( "imageFile" ) );
4758  if ( it != properties.end() )
4759  {
4760  if ( saving )
4761  it.value() = pathResolver.writePath( it.value().toString() );
4762  else
4763  it.value() = pathResolver.readPath( it.value().toString() );
4764  }
4765 }
4766 
4768 {
4769  Q_UNUSED( symbol )
4770  return true;
4771 }
4772 
4774 {
4775  return QStringLiteral( "RasterFill" );
4776 }
4777 
4778 void QgsRasterFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
4779 {
4780  QPainter *p = context.renderContext().painter();
4781  if ( !p )
4782  {
4783  return;
4784  }
4785 
4786  QPointF offset = mOffset;
4788  {
4790  const QVariant val = mDataDefinedProperties.value( QgsSymbolLayer::PropertyOffset, context.renderContext().expressionContext(), QString() );
4791  bool ok = false;
4792  const QPointF res = QgsSymbolLayerUtils::toPoint( val, &ok );
4793  if ( ok )
4794  offset = res;
4795  }
4796  if ( !offset.isNull() )
4797  {
4798  offset.setX( context.renderContext().convertToPainterUnits( offset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
4799  offset.setY( context.renderContext().convertToPainterUnits( offset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
4800  p->translate( offset );
4801  }
4802  if ( mCoordinateMode == Qgis::SymbolCoordinateReference::Feature )
4803  {
4804  QRectF boundingRect = points.boundingRect();
4805  mBrush.setTransform( mBrush.transform().translate( boundingRect.left() - mBrush.transform().dx(),
4806  boundingRect.top() - mBrush.transform().dy() ) );
4807  }
4808 
4809  QgsImageFillSymbolLayer::renderPolygon( points, rings, context );
4810  if ( !offset.isNull() )
4811  {
4812  p->translate( -offset );
4813  }
4814 }
4815 
4817 {
4818  applyPattern( mBrush, mImageFilePath, mWidth, mOpacity * context.opacity(), context );
4819 }
4820 
4822 {
4823  Q_UNUSED( context )
4824 }
4825 
4827 {
4828  QVariantMap map;
4829  map[QStringLiteral( "imageFile" )] = mImageFilePath;
4830  map[QStringLiteral( "coordinate_mode" )] = QString::number( static_cast< int >( mCoordinateMode ) );
4831  map[QStringLiteral( "alpha" )] = QString::number( mOpacity );
4832  map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
4833  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
4834  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
4835  map[QStringLiteral( "angle" )] = QString::number( mAngle );
4836  map[QStringLiteral( "width" )] = QString::number( mWidth );
4837  map[QStringLiteral( "width_unit" )] = QgsUnitTypes::encodeUnit( mWidthUnit );
4838  map[QStringLiteral( "width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mWidthMapUnitScale );
4839  return map;
4840 }
4841 
4843 {
4844  std::unique_ptr< QgsRasterFillSymbolLayer > sl = std::make_unique< QgsRasterFillSymbolLayer >( mImageFilePath );
4845  sl->setCoordinateMode( mCoordinateMode );
4846  sl->setOpacity( mOpacity );
4847  sl->setOffset( mOffset );
4848  sl->setOffsetUnit( mOffsetUnit );
4849  sl->setOffsetMapUnitScale( mOffsetMapUnitScale );
4850  sl->setAngle( mAngle );
4851  sl->setWidth( mWidth );
4852  sl->setWidthUnit( mWidthUnit );
4853  sl->setWidthMapUnitScale( mWidthMapUnitScale );
4854  copyDataDefinedProperties( sl.get() );
4855  copyPaintEffect( sl.get() );
4856  return sl.release();
4857 }
4858 
4860 {
4861  return context.convertToPainterUnits( std::max( std::fabs( mOffset.x() ), std::fabs( mOffset.y() ) ), mOffsetUnit, mOffsetMapUnitScale );
4862 }
4863 
4865 {
4866  return mWidthUnit == QgsUnitTypes::RenderMapUnits || mWidthUnit == QgsUnitTypes::RenderMetersInMapUnits
4867  || mOffsetUnit == QgsUnitTypes::RenderMapUnits || mOffsetUnit == QgsUnitTypes::RenderMetersInMapUnits;
4868 }
4869 
4871 {
4872  return QColor();
4873 }
4874 
4876 {
4878  mOffsetUnit = unit;
4879  mWidthUnit = unit;
4880 }
4881 
4882 void QgsRasterFillSymbolLayer::setImageFilePath( const QString &imagePath )
4883 {
4884  mImageFilePath = imagePath;
4885 }
4886 
4888 {
4889  mCoordinateMode = mode;
4890 }
4891 
4892 void QgsRasterFillSymbolLayer::setOpacity( const double opacity )
4893 {
4894  mOpacity = opacity;
4895 }
4896 
4898 {
4899  if ( !dataDefinedProperties().hasActiveProperties() )
4900  return; // shortcut
4901 
4902  bool hasWidthExpression = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth );
4903  bool hasFileExpression = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFile );
4904  bool hasOpacityExpression = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyOpacity );
4905  bool hasAngleExpression = mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyAngle );
4906 
4907  if ( !hasWidthExpression && !hasAngleExpression && !hasOpacityExpression && !hasFileExpression )
4908  {
4909  return; //no data defined settings
4910  }
4911 
4912  bool ok;
4913  if ( hasAngleExpression )
4914  {
4915  context.setOriginalValueVariable( mAngle );
4917  if ( ok )
4918  mNextAngle = nextAngle;
4919  }
4920 
4921  if ( !hasWidthExpression && !hasOpacityExpression && !hasFileExpression )
4922  {
4923  return; //nothing further to do
4924  }
4925 
4926  double width = mWidth;
4927  if ( hasWidthExpression )
4928  {
4929  context.setOriginalValueVariable( mWidth );
4931  }
4932  double opacity = mOpacity;
4933  if ( hasOpacityExpression )
4934  {
4935  context.setOriginalValueVariable( mOpacity );
4937  }
4938  QString file = mImageFilePath;
4939  if ( hasFileExpression )
4940  {
4941  context.setOriginalValueVariable( mImageFilePath );
4943  }
4944  applyPattern( mBrush, file, width, opacity, context );
4945 }
4946 
4948 {
4949  return false;
4950 }
4951 
4952 void QgsRasterFillSymbolLayer::applyPattern( QBrush &brush, const QString &imageFilePath, const double width, const double alpha, const QgsSymbolRenderContext &context )
4953 {
4954  QSize size;
4955  if ( width > 0 )
4956  {
4957  if ( mWidthUnit != QgsUnitTypes::RenderPercentage )
4958  {
4959  size.setWidth( context.renderContext().convertToPainterUnits( width, mWidthUnit, mWidthMapUnitScale ) );
4960  }
4961  else
4962  {
4963  // RenderPercentage Unit Type takes original image size
4965  if ( size.isEmpty() )
4966  return;
4967 
4968  size.setWidth( ( width * size.width() ) / 100.0 );
4969 
4970  // don't render symbols with size below one or above 10,000 pixels
4971  if ( static_cast< int >( size.width() ) < 1 || 10000.0 < size.width() )
4972  return;
4973  }
4974 
4975  size.setHeight( 0 );
4976  }
4977 
4978  bool cached;
4979  QImage img = QgsApplication::imageCache()->pathAsImage( imageFilePath, size, true, alpha, cached, ( context.renderContext().flags() & Qgis::RenderContextFlag::RenderBlocking ) );
4980  if ( img.isNull() )
4981  return;
4982 
4983  brush.setTextureImage( img );
4984 }
4985 
4986 
4987 //
4988 // QgsRandomMarkerFillSymbolLayer
4989 //
4990 
4991 QgsRandomMarkerFillSymbolLayer::QgsRandomMarkerFillSymbolLayer( int pointCount, Qgis::PointCountMethod method, double densityArea, unsigned long seed )
4992  : mCountMethod( method )
4993  , mPointCount( pointCount )
4994  , mDensityArea( densityArea )
4995  , mSeed( seed )
4996 {
4997  setSubSymbol( new QgsMarkerSymbol() );
4998 }
4999 
5001 
5003 {
5004  const Qgis::PointCountMethod countMethod = static_cast< Qgis::PointCountMethod >( properties.value( QStringLiteral( "count_method" ), QStringLiteral( "0" ) ).toInt() );
5005  const int pointCount = properties.value( QStringLiteral( "point_count" ), QStringLiteral( "10" ) ).toInt();
5006  const double densityArea = properties.value( QStringLiteral( "density_area" ), QStringLiteral( "250.0" ) ).toDouble();
5007 
5008  unsigned long seed = 0;
5009  if ( properties.contains( QStringLiteral( "seed" ) ) )
5010  seed = properties.value( QStringLiteral( "seed" ) ).toUInt();
5011  else
5012  {
5013  // if we a creating a new random marker fill from scratch, we default to a random seed
5014  // because seed based fills are just nicer for users vs seeing points jump around with every map refresh
5015  std::random_device rd;
5016  std::mt19937 mt( seed == 0 ? rd() : seed );
5017  std::uniform_int_distribution<> uniformDist( 1, 999999999 );
5018  seed = uniformDist( mt );
5019  }
5020 
5021  std::unique_ptr< QgsRandomMarkerFillSymbolLayer > sl = std::make_unique< QgsRandomMarkerFillSymbolLayer >( pointCount, countMethod, densityArea, seed );
5022 
5023  if ( properties.contains( QStringLiteral( "density_area_unit" ) ) )
5024  sl->setDensityAreaUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "density_area_unit" )].toString() ) );
5025  if ( properties.contains( QStringLiteral( "density_area_unit_scale" ) ) )
5026  sl->setDensityAreaUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "density_area_unit_scale" )].toString() ) );
5027 
5028  if ( properties.contains( QStringLiteral( "clip_points" ) ) )
5029  {
5030  sl->setClipPoints( properties[QStringLiteral( "clip_points" )].toInt() );
5031  }
5032 
5033  return sl.release();
5034 }
5035 
5037 {
5038  return QStringLiteral( "RandomMarkerFill" );
5039 }
5040 
5041 void QgsRandomMarkerFillSymbolLayer::setColor( const QColor &color )
5042 {
5043  mMarker->setColor( color );
5044  mColor = color;
5045 }
5046 
5048 {
5049  return mMarker ? mMarker->color() : mColor;
5050 }
5051 
5053 {
5054  mMarker->startRender( context.renderContext(), context.fields() );
5055 }
5056 
5058 {
5059  mMarker->stopRender( context.renderContext() );
5060 }
5061 
5062 void QgsRandomMarkerFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
5063 {
5064  Part part;
5065  part.exterior = points;
5066  if ( rings )
5067  part.rings = *rings;
5068 
5069  if ( mRenderingFeature )
5070  {
5071  // in the middle of rendering a possibly multi-part feature, so we collect all the parts and defer the actual rendering
5072  // until after we've received the final part
5073  mFeatureSymbolOpacity = context.opacity();
5074  mCurrentParts << part;
5075  }
5076  else
5077  {
5078  // not rendering a feature, so we can just render the polygon immediately
5079  const double prevOpacity = mMarker->opacity();
5080  mMarker->setOpacity( mMarker->opacity() * context.opacity() );
5081  render( context.renderContext(), QVector< Part>() << part, context.feature() ? *context.feature() : QgsFeature(), context.selected() );
5082  mMarker->setOpacity( prevOpacity );
5083  }
5084 }
5085 
5086 void QgsRandomMarkerFillSymbolLayer::render( QgsRenderContext &context, const QVector<QgsRandomMarkerFillSymbolLayer::Part> &parts, const QgsFeature &feature, bool selected )
5087 {
5088  bool clipPoints = mClipPoints;
5090  {
5093  }
5094 
5095  QVector< QgsGeometry > geometryParts;
5096  geometryParts.reserve( parts.size() );
5097  QPainterPath path;
5098 
5099  for ( const Part &part : parts )
5100  {
5101  QgsGeometry geom = QgsGeometry::fromQPolygonF( part.exterior );
5102  if ( !geom.isNull() && !part.rings.empty() )
5103  {
5104  QgsPolygon *poly = qgsgeometry_cast< QgsPolygon * >( geom.get() );
5105  for ( const QPolygonF &ring : part.rings )
5106  {
5108  }
5109  }
5110  if ( !geom.isGeosValid() )
5111  {
5112  geom = geom.buffer( 0, 0 );
5113  }
5114  geometryParts << geom;
5115 
5116  if ( clipPoints )
5117  {
5118  path.addPolygon( part.exterior );
5119  for ( const QPolygonF &ring : part.rings )
5120  {
5121  path.addPolygon( ring );
5122  }
5123  }
5124  }
5125 
5126  const QgsGeometry geom = geometryParts.count() != 1 ? QgsGeometry::unaryUnion( geometryParts ) : geometryParts.at( 0 );
5127 
5128  if ( clipPoints )
5129  {
5130  context.painter()->save();
5131  context.painter()->setClipPath( path );
5132  }
5133 
5134 
5135  int count = mPointCount;
5137  {
5138  context.expressionContext().setOriginalValueVariable( count );
5140  }
5141 
5142  switch ( mCountMethod )
5143  {
5144  case Qgis::PointCountMethod::DensityBased:
5145  {
5146  double densityArea = mDensityArea;
5148  {
5151  }
5152  densityArea = context.convertToPainterUnits( std::sqrt( densityArea ), mDensityAreaUnit, mDensityAreaUnitScale );
5153  densityArea = std::pow( densityArea, 2 );
5154  count = std::max( 0.0, std::ceil( count * ( geom.area() / densityArea ) ) );
5155  break;
5156  }
5157  case Qgis::PointCountMethod::Absolute:
5158  break;
5159  }
5160 
5161  unsigned long seed = mSeed;
5163  {
5164  context.expressionContext().setOriginalValueVariable( static_cast< unsigned long long >( seed ) );
5166  }
5167 
5168  QVector< QgsPointXY > randomPoints = geom.randomPointsInPolygon( count, seed );
5169 #if 0
5170  // in some cases rendering from top to bottom is nice (e.g. randomised tree markers), but in other cases it's not wanted..
5171  // TODO consider exposing this as an option
5172  std::sort( randomPoints.begin(), randomPoints.end(), []( const QgsPointXY & a, const QgsPointXY & b )->bool
5173  {
5174  return a.y() < b.y();
5175  } );
5176 #endif
5178  QgsExpressionContextScopePopper scopePopper( context.expressionContext(), scope );
5179  int pointNum = 0;
5180  const bool needsExpressionContext = mMarker->hasDataDefinedProperties();
5181 
5182  const bool prevIsSubsymbol = context.flags() & Qgis::RenderContextFlag::RenderingSubSymbol;
5184 
5185  for ( const QgsPointXY &p : std::as_const( randomPoints ) )
5186  {
5187  if ( needsExpressionContext )
5189  mMarker->renderPoint( QPointF( p.x(), p.y() ), feature.isValid() ? &feature : nullptr, context, -1, selected );
5190  }
5191 
5192  context.setFlag( Qgis::RenderContextFlag::RenderingSubSymbol, prevIsSubsymbol );
5193 
5194  if ( clipPoints )
5195  {
5196  context.painter()->restore();
5197  }
5198 }
5199 
5201 {
5202  QVariantMap map;
5203  map.insert( QStringLiteral( "count_method" ), QString::number( static_cast< int >( mCountMethod ) ) );
5204  map.insert( QStringLiteral( "point_count" ), QString::number( mPointCount ) );
5205  map.insert( QStringLiteral( "density_area" ), QString::number( mDensityArea ) );
5206  map.insert( QStringLiteral( "density_area_unit" ), QgsUnitTypes::encodeUnit( mDensityAreaUnit ) );
5207  map.insert( QStringLiteral( "density_area_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mDensityAreaUnitScale ) );
5208  map.insert( QStringLiteral( "seed" ), QString::number( mSeed ) );
5209  map.insert( QStringLiteral( "clip_points" ), QString::number( mClipPoints ) );
5210  return map;
5211 }
5212 
5214 {
5215  std::unique_ptr< QgsRandomMarkerFillSymbolLayer > res = std::make_unique< QgsRandomMarkerFillSymbolLayer >( mPointCount, mCountMethod, mDensityArea, mSeed );
5216  res->mAngle = mAngle;
5217  res->mColor = mColor;
5218  res->setDensityAreaUnit( mDensityAreaUnit );
5219  res->setDensityAreaUnitScale( mDensityAreaUnitScale );
5220  res->mClipPoints = mClipPoints;
5221  res->setSubSymbol( mMarker->clone() );
5222  copyDataDefinedProperties( res.get() );
5223  copyPaintEffect( res.get() );
5224  return res.release();
5225 }
5226 
5228 {
5229  return true;
5230 }
5231 
5233 {
5234  return mMarker.get();
5235 }
5236 
5238 {
5239  if ( !symbol || symbol->type() != Qgis::SymbolType::Marker )
5240  {
5241  delete symbol;
5242  return false;
5243  }
5244 
5245  mMarker.reset( static_cast<QgsMarkerSymbol *>( symbol ) );
5246  mColor = mMarker->color();
5247  return true;
5248 }
5249 
5251 {
5252  QSet<QString> attributes = QgsFillSymbolLayer::usedAttributes( context );
5253 
5254  if ( mMarker )
5255  attributes.unite( mMarker->usedAttributes( context ) );
5256 
5257  return attributes;
5258 }
5259 
5261 {
5263  return true;
5264  if ( mMarker && mMarker->hasDataDefinedProperties() )
5265  return true;
5266  return false;
5267 }
5268 
5270 {
5271  return mPointCount;
5272 }
5273 
5275 {
5276  mPointCount = pointCount;
5277 }
5278 
5280 {
5281  return mSeed;
5282 }
5283 
5285 {
5286  mSeed = seed;
5287 }
5288 
5290 {
5291  return mClipPoints;
5292 }
5293 
5295 {
5296  mClipPoints = clipPoints;
5297 }
5298 
5300 {
5301  return mCountMethod;
5302 }
5303 
5305 {
5306  mCountMethod = method;
5307 }
5308 
5310 {
5311  return mDensityArea;
5312 }
5313 
5315 {
5316  mDensityArea = area;
5317 }
5318 
5320 {
5321  mRenderingFeature = true;
5322  mCurrentParts.clear();
5323 }
5324 
5326 {
5327  mRenderingFeature = false;
5328 
5329  const double prevOpacity = mMarker->opacity();
5330  mMarker->setOpacity( mMarker->opacity() * mFeatureSymbolOpacity );
5331 
5332  render( context, mCurrentParts, feature, false );
5333 
5334  mFeatureSymbolOpacity = 1;
5335  mMarker->setOpacity( prevOpacity );
5336 }
5337 
5338 
5340 {
5341  mDensityAreaUnit = unit;
5342  if ( mMarker )
5343  {
5344  mMarker->setOutputUnit( unit );
5345  }
5346 }
5347 
5349 {
5350  if ( mMarker )
5351  {
5352  return mMarker->outputUnit();
5353  }
5354  return QgsUnitTypes::RenderUnknownUnit; //mOutputUnit;
5355 }
5356 
5358 {
5359  if ( mMarker )
5360  {
5361  return mMarker->usesMapUnits();
5362  }
5363  return false;
5364 }
5365 
5367 {
5368  if ( mMarker )
5369  {
5370  mMarker->setMapUnitScale( scale );
5371  }
5372 }
5373 
5375 {
5376  if ( mMarker )
5377  {
5378  return mMarker->mapUnitScale();
5379  }
5380  return QgsMapUnitScale();
5381 }
5382 
QgsCentroidFillSymbolLayer::~QgsCentroidFillSymbolLayer
~QgsCentroidFillSymbolLayer() override
QgsSVGFillSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgsfillsymbollayer.cpp:2095
QgsCentroidFillSymbolLayer::pointOnAllParts
bool pointOnAllParts() const
Returns whether a point is drawn for all parts or only on the biggest part of multi-part features.
Definition: qgsfillsymbollayer.h:2479
qgspolygon.h
QgsLinePatternFillSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgsfillsymbollayer.cpp:2604
QgsShapeburstFillSymbolLayer::canCauseArtifactsBetweenAdjacentTiles
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
Definition: qgsfillsymbollayer.cpp:1662
QgsSimpleFillSymbolLayer::renderPolygon
void renderPolygon(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the fill symbol layer for the polygon whose outer ring is defined by points,...
Definition: qgsfillsymbollayer.cpp:293
QgsSymbolRenderContext::setOriginalValueVariable
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
Definition: qgssymbolrendercontext.cpp:36
QgsSimpleFillSymbolLayer::strokeColor
QColor strokeColor() const override
Returns the stroke color for the symbol layer.
Definition: qgsfillsymbollayer.h:87
QgsGradientFillSymbolLayer::QgsGradientFillSymbolLayer
QgsGradientFillSymbolLayer(const QColor &color=DEFAULT_SIMPLEFILL_COLOR, const QColor &color2=Qt::white, Qgis::GradientColorSource gradientColorType=Qgis::GradientColorSource::SimpleTwoColor, Qgis::GradientType gradientType=Qgis::GradientType::Linear, Qgis::SymbolCoordinateReference coordinateMode=Qgis::SymbolCoordinateReference::Feature, Qgis::GradientSpread gradientSpread=Qgis::GradientSpread::Pad)
Constructor for QgsGradientFillSymbolLayer.
Definition: qgsfillsymbollayer.cpp:526
QgsRasterFillSymbolLayer::color
QColor color() const override
Returns the "representative" color of the symbol layer.
Definition: qgsfillsymbollayer.cpp:4870
QgsPointPatternFillSymbolLayer
A fill symbol layer which fills polygon shapes with repeating marker symbols.
Definition: qgsfillsymbollayer.h:1668
QgsGradientFillSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgsfillsymbollayer.cpp:635
QgsPointPatternFillSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgsfillsymbollayer.cpp:4159
QgsLinePatternFillSymbolLayer::ogrFeatureStyleWidth
QString ogrFeatureStyleWidth(double widthScaleFactor) const
Definition: qgsfillsymbollayer.cpp:3332
QgsSimpleFillSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgsfillsymbollayer.cpp:258
QgsCentroidFillSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:4638
QgsColorRamp
Abstract base class for color ramps.
Definition: qgscolorramp.h:29
Qgis::MarkerClipMode::CompletelyWithin
@ CompletelyWithin
Render complete markers wherever the completely fall within the polygon shape.
qgsexpressioncontextutils.h
QgsPointPatternFillSymbolLayer::displacementY
double displacementY() const
Returns the vertical displacement for odd numbered columns in the pattern.
Definition: qgsfillsymbollayer.h:1872
qgscolorrampimpl.h
QgsGradientFillSymbolLayer::gradientType
Qgis::GradientType gradientType() const
Returns the type of gradient, e.g., linear or radial.
Definition: qgsfillsymbollayer.h:253
qgssvgcache.h
QgsSimpleFillSymbolLayer::createFromSld
static QgsSymbolLayer * createFromSld(QDomElement &element)
Definition: qgsfillsymbollayer.cpp:435
QgsPointPatternFillSymbolLayer::mOffsetXMapUnitScale
QgsMapUnitScale mOffsetXMapUnitScale
Definition: qgsfillsymbollayer.h:2201
QgsPointPatternFillSymbolLayer::mDisplacementXMapUnitScale
QgsMapUnitScale mDisplacementXMapUnitScale
Definition: qgsfillsymbollayer.h:2195
QgsPointPatternFillSymbolLayer::mDistanceXUnit
QgsUnitTypes::RenderUnit mDistanceXUnit
Definition: qgsfillsymbollayer.h:2188
QgsExpressionContextScopePopper
RAII class to pop scope from an expression context on destruction.
Definition: qgsexpressioncontextutils.h:361
QgsLinePatternFillSymbolLayer::createFromSld
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsLinePatternFillSymbolLayer from a SLD element.
Definition: qgsfillsymbollayer.cpp:3370
QgsAbstractPropertyCollection::valueAsDouble
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
Definition: qgspropertycollection.cpp:66
QgsProperty::variantMapToPropertyMap
static QMap< QString, QgsProperty > variantMapToPropertyMap(const QVariantMap &variantMap)
Convert a map of QVariant to a map of QgsProperty This is useful to restore a map of properties.
Definition: qgsproperty.cpp:217
QgsRasterFillSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgsfillsymbollayer.cpp:4816
QgsSymbolLayerUtils::encodeColor
static QString encodeColor(const QColor &color)
Definition: qgssymbollayerutils.cpp:64
QgsSVGFillSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgsfillsymbollayer.cpp:2083
QgsSymbolLayer::strokeColor
virtual QColor strokeColor() const
Returns the stroke color for the symbol layer.
Definition: qgssymbollayer.cpp:262
QgsSymbolLayer::PropertyBlurRadius
@ PropertyBlurRadius
Shapeburst blur radius.
Definition: qgssymbollayer.h:170
QgsGradientFillSymbolLayer::offset
QPointF offset() const
Returns the offset by which polygons will be translated during rendering.
Definition: qgsfillsymbollayer.h:410
QgsRasterFillSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:4875
QgsSVGFillSymbolLayer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
Definition: qgsfillsymbollayer.cpp:2297
QgsSymbolLayer::PropertyLineDistance
@ PropertyLineDistance
Distance between lines, or length of lines for hash line symbols.
Definition: qgssymbollayer.h:160
QgsSymbolLayer::mColor
QColor mColor
Definition: qgssymbollayer.h:648
QgsRenderContext::setPainterFlagsUsingContext
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
Definition: qgsrendercontext.cpp:169
QgsSymbolLayer::PropertyShapeburstUseWholeShape
@ PropertyShapeburstUseWholeShape
Shapeburst use whole shape.
Definition: qgssymbollayer.h:171
QgsRandomMarkerFillSymbolLayer::clone
QgsRandomMarkerFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgsfillsymbollayer.cpp:5213
QgsLinePatternFillSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgsfillsymbollayer.cpp:2737
QgsSimpleFillSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsSimpleFillSymbolLayer using the specified properties map containing symbol propertie...
Definition: qgsfillsymbollayer.cpp:171
QgsGradientFillSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgsfillsymbollayer.cpp:1024
QgsRenderContext::mapToPixel
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
Definition: qgsrendercontext.h:258
Qgis::GradientType
GradientType
Gradient types.
Definition: qgis.h:1447
QgsPointPatternFillSymbolLayer::mDisplacementXUnit
QgsUnitTypes::RenderUnit mDisplacementXUnit
Definition: qgsfillsymbollayer.h:2194
QgsSymbolLayerUtils::polygonPointOnSurface
static QPointF polygonPointOnSurface(const QPolygonF &points, const QVector< QPolygonF > *rings=nullptr)
Calculate a point on the surface of a QPolygonF.
Definition: qgssymbollayerutils.cpp:4370
QgsImageCache::originalSize
QSize originalSize(const QString &path, bool blocking=false) const
Returns the original size (in pixels) of the image at the specified path.
Definition: qgsimagecache.cpp:208
QgsLinePatternFillSymbolLayer::startFeatureRender
void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called before the layer will be rendered for a particular feature.
Definition: qgsfillsymbollayer.cpp:2561
QgsSymbolLayer::dataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
Definition: qgssymbollayer.h:595
QgsCentroidFillSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgsfillsymbollayer.cpp:4410
QgsGradientColorRamp
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Definition: qgscolorrampimpl.h:136
QgsSymbolLayer::PropertyClipPoints
@ PropertyClipPoints
Whether markers should be clipped to polygon boundaries.
Definition: qgssymbollayer.h:199
QgsImageFillSymbolLayer::QgsImageFillSymbolLayer
QgsImageFillSymbolLayer()
Definition: qgsfillsymbollayer.cpp:1706
QgsSymbolLayer::PropertyGradientReference2IsCentroid
@ PropertyGradientReference2IsCentroid
Gradient reference point 2 is centroid.
Definition: qgssymbollayer.h:169
QgsGradientFillSymbolLayer::mOffsetUnit
QgsUnitTypes::RenderUnit mOffsetUnit
Definition: qgsfillsymbollayer.h:464
QgsRasterFillSymbolLayer::opacity
double opacity() const
Returns the opacity for the raster image used in the fill.
Definition: qgsfillsymbollayer.h:961
QgsUnitTypes::RenderUnit
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:167
QgsDxfExport
Exports QGIS layers to the DXF format.
Definition: qgsdxfexport.h:64
QgsImageCache::pathAsImage
QImage pathAsImage(const QString &path, const QSize size, const bool keepAspectRatio, const double opacity, bool &fitsInCache, bool blocking=false, double targetDpi=96, int frameNumber=-1, bool *isMissing=nullptr)
Returns the specified path rendered as an image.
Definition: qgsimagecache.cpp:137
QgsGradientFillSymbolLayer::mCoordinateMode
Qgis::SymbolCoordinateReference mCoordinateMode
Definition: qgsfillsymbollayer.h:455
QgsSymbolLayerUtils::encodeMarkerClipMode
static QString encodeMarkerClipMode(Qgis::MarkerClipMode mode)
Encodes a marker clip mode to a string.
Definition: qgssymbollayerutils.cpp:490
QgsSimpleFillSymbolLayer::ogrFeatureStyle
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
Definition: qgsfillsymbollayer.cpp:424
QgsCentroidFillSymbolLayer::mPointOnSurface
bool mPointOnSurface
Definition: qgsfillsymbollayer.h:2519
QgsAbstractPropertyCollection::valueAsInt
int valueAsInt(int key, const QgsExpressionContext &context, int defaultValue=0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an integer.
Definition: qgspropertycollection.cpp:77
Qgis::SymbolType::Line
@ Line
Line symbol.
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:625
QgsMapToPixel::mapUnitsPerPixel
double mapUnitsPerPixel() const
Returns the current map units per pixel.
Definition: qgsmaptopixel.h:229
QgsSVGFillSymbolLayer::svgStrokeWidth
double svgStrokeWidth() const
Returns the stroke width used for rendering the SVG content.
Definition: qgsfillsymbollayer.h:1259
QgsSymbolLayerUtils::externalGraphicFromSld
static bool externalGraphicFromSld(QDomElement &element, QString &path, QString &mime, QColor &color, double &size)
Definition: qgssymbollayerutils.cpp:2525
QgsPolygon
Polygon geometry type.
Definition: qgspolygon.h:33
qgslinestring.h
Qgis::LineClipMode
LineClipMode
Line clipping modes.
Definition: qgis.h:1518
QgsSymbolLayerUtils::wellKnownMarkerFromSld
static bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &strokeColor, Qt::PenStyle &strokeStyle, double &strokeWidth, double &size)
Definition: qgssymbollayerutils.cpp:2660
QgsSVGFillSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgsfillsymbollayer.cpp:2252
QgsRandomMarkerFillSymbolLayer::stopFeatureRender
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called after the layer has been rendered for a particular feature.
Definition: qgsfillsymbollayer.cpp:5325
QgsSVGFillSymbolLayer::QgsSVGFillSymbolLayer
QgsSVGFillSymbolLayer(const QString &svgFilePath, double width=20, double rotation=0.0)
Constructor for QgsSVGFillSymbolLayer, using the SVG picture at the specified absolute file path.
Definition: qgsfillsymbollayer.cpp:1834
QgsImageFillSymbolLayer::applyBrushTransformFromContext
virtual bool applyBrushTransformFromContext(QgsSymbolRenderContext *context=nullptr) const
Returns true if the image brush should be transformed using the render context's texture origin.
Definition: qgsfillsymbollayer.cpp:1812
QgsPointPatternFillSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgsfillsymbollayer.cpp:3807
QgsExpressionContextScope::addVariable
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Definition: qgsexpressioncontext.cpp:97
QgsLinePatternFillSymbolLayer::~QgsLinePatternFillSymbolLayer
~QgsLinePatternFillSymbolLayer() override
QgsRandomMarkerFillSymbolLayer::subSymbol
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
Definition: qgsfillsymbollayer.cpp:5232
QgsGradientFillSymbolLayer::mReferencePoint2IsCentroid
bool mReferencePoint2IsCentroid
Definition: qgsfillsymbollayer.h:461
QgsSymbolLayerUtils::encodeMapUnitScale
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
Definition: qgssymbollayerutils.cpp:666
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:48
QgsCentroidFillSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgsfillsymbollayer.cpp:4601
QgsRandomMarkerFillSymbolLayer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
Definition: qgsfillsymbollayer.cpp:5250
QgsImageFillSymbolLayer::dxfPenStyle
Qt::PenStyle dxfPenStyle() const override
Gets pen style.
Definition: qgsfillsymbollayer.cpp:1790
QgsSimpleFillSymbolLayer::dxfPenStyle
Qt::PenStyle dxfPenStyle() const override
Gets pen style.
Definition: qgsfillsymbollayer.cpp:504
QgsPointPatternFillSymbolLayer::mDistanceYMapUnitScale
QgsMapUnitScale mDistanceYMapUnitScale
Definition: qgsfillsymbollayer.h:2192
QgsSymbolRenderContext::feature
const QgsFeature * feature() const
Returns the current feature being rendered.
Definition: qgssymbolrendercontext.h:143
QgsPointPatternFillSymbolLayer::angle
double angle() const
Returns the rotation angle of the pattern, in degrees clockwise.
Definition: qgsfillsymbollayer.h:2175
QgsGradientFillSymbolLayer
Definition: qgsfillsymbollayer.h:211
QgsSimpleFillSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgsfillsymbollayer.cpp:288
QgsMeshUtils::centroid
CORE_EXPORT QgsMeshVertex centroid(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns the centroid of the face.
Definition: qgstriangularmesh.cpp:955
qgsexpression.h
QgsLinePatternFillSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgsfillsymbollayer.cpp:2523
QgsSVGFillSymbolLayer::svgStrokeWidthUnit
QgsUnitTypes::RenderUnit svgStrokeWidthUnit() const
Returns the units for the stroke width.
Definition: qgsfillsymbollayer.h:1313
QgsCentroidFillSymbolLayer::setColor
void setColor(const QColor &color) override
Sets the "representative" color for the symbol layer.
Definition: qgsfillsymbollayer.cpp:4394
QgsShapeburstFillSymbolLayer::renderPolygon
void renderPolygon(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the fill symbol layer for the polygon whose outer ring is defined by points,...
Definition: qgsfillsymbollayer.cpp:1224
QgsPointPatternFillSymbolLayer::mDisplacementX
double mDisplacementX
Definition: qgsfillsymbollayer.h:2193
QgsSimpleFillSymbolLayer::mOffset
QPointF mOffset
Definition: qgsfillsymbollayer.h:196
QgsLinePatternFillSymbolLayer::distance
double distance() const
Returns the distance between lines in the fill pattern.
Definition: qgsfillsymbollayer.h:1455
QgsRectangle::center
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
Definition: qgsrectangle.h:251
QgsGradientFillSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:1009
QgsSVGFillSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgsfillsymbollayer.cpp:2025
QgsSymbolLayer::PropertyFillStyle
@ PropertyFillStyle
Fill style (eg solid, dots)
Definition: qgssymbollayer.h:156
QgsSymbolLayer::PropertyGradientReference2Y
@ PropertyGradientReference2Y
Gradient reference point 2 y.
Definition: qgssymbollayer.h:167
Qgis::LineClipMode::NoClipping
@ NoClipping
Lines are not clipped, will extend to shape's bounding box.
QgsShapeburstFillSymbolLayer::colorType
Qgis::GradientColorSource colorType() const
Returns the color mode used for the shapeburst fill.
Definition: qgsfillsymbollayer.h:629
QgsShapeburstFillSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgsfillsymbollayer.cpp:1611
QgsShapeburstFillSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgsfillsymbollayer.cpp:1682
QgsImageFillSymbolLayer::applyDataDefinedSettings
virtual void applyDataDefinedSettings(QgsSymbolRenderContext &context)
Applies data defined settings prior to generating the fill symbol brush.
Definition: qgsfillsymbollayer.h:857
QgsGradientFillSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgsfillsymbollayer.cpp:1019
QgsPointPatternFillSymbolLayer::mRandomDeviationXMapUnitScale
QgsMapUnitScale mRandomDeviationXMapUnitScale
Definition: qgsfillsymbollayer.h:2208
QgsGradientFillSymbolLayer::mSelBrush
QBrush mSelBrush
Definition: qgsfillsymbollayer.h:449
QgsSimpleFillSymbolLayer::mOffsetMapUnitScale
QgsMapUnitScale mOffsetMapUnitScale
Definition: qgsfillsymbollayer.h:198
QgsSymbolLayer::PropertyFillColor
@ PropertyFillColor
Fill color.
Definition: qgssymbollayer.h:147
QgsImageFillSymbolLayer::mStrokeWidthUnit
QgsUnitTypes::RenderUnit mStrokeWidthUnit
Definition: qgsfillsymbollayer.h:851
QgsSymbolLayerUtils::lineToSld
static void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, const QColor &color, double width=-1, const Qt::PenJoinStyle *penJoinStyle=nullptr, const Qt::PenCapStyle *penCapStyle=nullptr, const QVector< qreal > *customDashPattern=nullptr, double dashOffset=0.0)
Definition: qgssymbollayerutils.cpp:2227
QgsPointPatternFillSymbolLayer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
Definition: qgsfillsymbollayer.cpp:4330
QgsLinePatternFillSymbolLayer::lineAngle
double lineAngle() const
Returns the angle for the parallel lines used to fill the symbol.
Definition: qgsfillsymbollayer.h:1440
QgsRenderContext::setPainter
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
Definition: qgsrendercontext.h:512
QgsGradientFillSymbolLayer::mBrush
QBrush mBrush
Definition: qgsfillsymbollayer.h:448
QgsGradientFillSymbolLayer::coordinateMode
Qgis::SymbolCoordinateReference coordinateMode() const
Returns the coordinate mode for gradient, which controls how the gradient stops are positioned.
Definition: qgsfillsymbollayer.h:312
QgsExpressionContext::EXPR_GEOMETRY_POINT_NUM
static const QString EXPR_GEOMETRY_POINT_NUM
Inbuilt variable name for point number variable.
Definition: qgsexpressioncontext.h:823
QgsExpressionContext::setOriginalValueVariable
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
Definition: qgsexpressioncontext.cpp:600
qgssymbollayerutils.h
Qgis::MarkerClipMode
MarkerClipMode
Marker clipping modes.
Definition: qgis.h:1504
QgsImageFillSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgsfillsymbollayer.cpp:1774
QgsPointPatternFillSymbolLayer::mRandomDeviationYUnit
QgsUnitTypes::RenderUnit mRandomDeviationYUnit
Definition: qgsfillsymbollayer.h:2210
QgsGradientFillSymbolLayer::mGradientType
Qgis::GradientType mGradientType
Definition: qgsfillsymbollayer.h:454
QgsCentroidFillSymbolLayer::subSymbol
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
Definition: qgsfillsymbollayer.cpp:4596
QgsImageFillSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:1764
QgsPointPatternFillSymbolLayer::mOffsetY
double mOffsetY
Definition: qgsfillsymbollayer.h:2202
QgsSymbolRenderContext::opacity
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbolrendercontext.h:105
Qgis::GradientSpread::Pad
@ Pad
Pad out gradient using colors at endpoint of gradient.
QgsSimpleFillSymbolLayer::mStrokeWidthMapUnitScale
QgsMapUnitScale mStrokeWidthMapUnitScale
Definition: qgsfillsymbollayer.h:191
QgsPointPatternFillSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:3454
QgsSymbolLayerUtils::createMarkerLayerFromSld
static QgsSymbolLayer * createMarkerLayerFromSld(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1656
QgsSymbolLayer::hasDataDefinedProperties
virtual bool hasDataDefinedProperties() const
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
Definition: qgssymbollayer.cpp:287
QgsRasterFillSymbolLayer::applyBrushTransformFromContext
bool applyBrushTransformFromContext(QgsSymbolRenderContext *context=nullptr) const override
Returns true if the image brush should be transformed using the render context's texture origin.
Definition: qgsfillsymbollayer.cpp:4947
QgsRandomMarkerFillSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgsfillsymbollayer.cpp:5366
QgsSymbolLayer::PropertyGradientReference1IsCentroid
@ PropertyGradientReference1IsCentroid
Gradient reference point 1 is centroid.
Definition: qgssymbollayer.h:168
QgsRasterFillSymbolLayer::setOpacity
void setOpacity(double opacity)
Sets the opacity for the raster image used in the fill.
Definition: qgsfillsymbollayer.cpp:4892
QgsRenderContext::flags
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
Definition: qgsrendercontext.cpp:224
qgsmarkersymbollayer.h
QgsRandomMarkerFillSymbolLayer::hasDataDefinedProperties
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
Definition: qgsfillsymbollayer.cpp:5260
QgsSVGFillSymbolLayer::svgFillColor
QColor svgFillColor() const
Returns the fill color used for rendering the SVG content.
Definition: qgsfillsymbollayer.h:1214
QgsRandomMarkerFillSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:5348
QgsUnitTypes::RenderPercentage
@ RenderPercentage
Percentage of another measurement (e.g., canvas size, feature size)
Definition: qgsunittypes.h:172
QgsSymbolLayer::PropertyDisplacementX
@ PropertyDisplacementX
Horizontal displacement.
Definition: qgssymbollayer.h:177
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsFillSymbolLayer::_renderPolygon
void _renderPolygon(QPainter *p, const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context)
Default method to render polygon.
Definition: qgssymbollayer.cpp:847
QgsSVGFillSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgsfillsymbollayer.cpp:1885
DEFAULT_SIMPLEFILL_COLOR
#define DEFAULT_SIMPLEFILL_COLOR
Definition: qgsfillsymbollayer.h:23
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsPointPatternFillSymbolLayer::clone
QgsPointPatternFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgsfillsymbollayer.cpp:4194
QgsRasterFillSymbolLayer
A class for filling symbols with a repeated raster image.
Definition: qgsfillsymbollayer.h:878
QgsGradientFillSymbolLayer::mColor2
QColor mColor2
Definition: qgsfillsymbollayer.h:452
QgsSymbolLayerUtils::multiplyImageOpacity
static void multiplyImageOpacity(QImage *image, qreal opacity)
Multiplies opacity of image pixel values with a (global) transparency value.
Definition: qgssymbollayerutils.cpp:3988
QgsSymbolLayer::SELECTION_IS_OPAQUE
static const bool SELECTION_IS_OPAQUE
Whether styles for selected features ignore symbol alpha.
Definition: qgssymbollayer.h:661
QgsCentroidFillSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgsfillsymbollayer.cpp:4655
qgsunittypes.h
QgsLinePatternFillSymbolLayer::offset
double offset() const
Returns the offset distance for lines within the fill, which is the distance to offset the parallel l...
Definition: qgsfillsymbollayer.h:1500
QgsSimpleFillSymbolLayer::dxfBrushStyle
Qt::BrushStyle dxfBrushStyle() const override
Gets brush/fill style.
Definition: qgsfillsymbollayer.cpp:519
QgsSymbolLayerUtils::encodeBrushStyle
static QString encodeBrushStyle(Qt::BrushStyle style)
Definition: qgssymbollayerutils.cpp:281
QgsSymbolLayerUtils::decodeMarkerClipMode
static Qgis::MarkerClipMode decodeMarkerClipMode(const QString &string, bool *ok=nullptr)
Decodes a string representing a marker clip mode.
Definition: qgssymbollayerutils.cpp:470
QgsPointPatternFillSymbolLayer::offsetY
double offsetY() const
Returns the vertical offset values for points in the pattern.
Definition: qgsfillsymbollayer.h:1948
QgsLinePatternFillSymbolLayer::clone
QgsLinePatternFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgsfillsymbollayer.cpp:3274
QgsMarkerSymbolLayer
Abstract base class for marker symbol layers.
Definition: qgssymbollayer.h:705
QgsSymbolLayer::estimateMaxBleed
virtual double estimateMaxBleed(const QgsRenderContext &context) const
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
Definition: qgssymbollayer.h:475
QgsPointPatternFillSymbolLayer::startFeatureRender
void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called before the layer will be rendered for a particular feature.
Definition: qgsfillsymbollayer.cpp:3815
QgsLinePatternFillSymbolLayer::toSld
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
Definition: qgsfillsymbollayer.cpp:3286
QgsImageFillSymbolLayer::mNextAngle
double mNextAngle
Definition: qgsfillsymbollayer.h:847
QgsRasterFillSymbolLayer::width
double width() const
Returns the width used for scaling the image used in the fill.
Definition: qgsfillsymbollayer.h:1035
QgsImageFillSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:1759
QgsSymbolLayerUtils::encodePenStyle
static QString encodePenStyle(Qt::PenStyle style)
Definition: qgssymbollayerutils.cpp:153
QgsRasterFillSymbolLayer::resolvePaths
static void resolvePaths(QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving)
Turns relative paths in properties map to absolute when reading and vice versa when writing.
Definition: qgsfillsymbollayer.cpp:4755
QgsSymbol
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:92
Qgis::GradientColorSource::SimpleTwoColor
@ SimpleTwoColor
Simple two color gradient.
qgsimageoperation.h
QgsSVGFillSymbolLayer::parameters
QMap< QString, QgsProperty > parameters() const
Returns the dynamic SVG parameters.
Definition: qgsfillsymbollayer.h:1343
QgsSymbolLayerUtils::svgSymbolPathToName
static QString svgSymbolPathToName(const QString &path, const QgsPathResolver &pathResolver)
Determines an SVG symbol's name from its path.
Definition: qgssymbollayerutils.cpp:4303
QgsMarkerLineSymbolLayer
Line symbol layer type which draws repeating marker symbols along a line feature.
Definition: qgslinesymbollayer.h:915
QgsSimpleFillSymbolLayer::~QgsSimpleFillSymbolLayer
~QgsSimpleFillSymbolLayer() override
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsRenderContext::scaleFactor
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:266
QgsSimpleFillSymbolLayer::estimateMaxBleed
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
Definition: qgsfillsymbollayer.cpp:464
DEFAULT_SIMPLEFILL_STYLE
#define DEFAULT_SIMPLEFILL_STYLE
Definition: qgsfillsymbollayer.h:24
QgsSimpleFillSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgsfillsymbollayer.cpp:96
QgsLinePatternFillSymbolLayer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
Definition: qgsfillsymbollayer.cpp:2544
QgsSymbolLayer::PropertyStrokeColor
@ PropertyStrokeColor
Stroke color.
Definition: qgssymbollayer.h:148
QgsSVGFillSymbolLayer::patternWidth
double patternWidth() const
Returns the width of the rendered SVG content within the fill (i.e.
Definition: qgsfillsymbollayer.h:1193
QgsGradientFillSymbolLayer::renderPolygon
void renderPolygon(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the fill symbol layer for the polygon whose outer ring is defined by points,...
Definition: qgsfillsymbollayer.cpp:913
QgsLinePatternFillSymbolLayer::hasDataDefinedProperties
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
Definition: qgsfillsymbollayer.cpp:2552
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:69
QgsPointPatternFillSymbolLayer::mRandomDeviationYMapUnitScale
QgsMapUnitScale mRandomDeviationYMapUnitScale
Definition: qgsfillsymbollayer.h:2211
QgsGeometry::buffer
QgsGeometry buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
Definition: qgsgeometry.cpp:2050
QgsDxfExport::mapUnitScaleFactor
static double mapUnitScaleFactor(double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits, double mapUnitsPerPixel=1.0)
Returns scale factor for conversion to map units.
Definition: qgsdxfexport.cpp:1823
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsSimpleFillSymbolLayer::mSelPen
QPen mSelPen
Definition: qgsfillsymbollayer.h:194
QgsPointPatternFillSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:3479
QgsSymbolLayerUtils::wellKnownMarkerToSld
static void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &strokeColor, Qt::PenStyle strokeStyle, double strokeWidth=-1, double size=-1)
Definition: qgssymbollayerutils.cpp:2624
QgsImageFillSymbolLayer::dxfWidth
double dxfWidth(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets line width.
Definition: qgsfillsymbollayer.cpp:1779
QgsGradientFillSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgsfillsymbollayer.cpp:1029
Qgis::MarkerClipMode::CentroidWithin
@ CentroidWithin
Render complete markers wherever their centroid falls within the polygon shape.
QgsSvgCache::containsParams
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasStrokeParam, QColor &defaultStrokeColor, bool &hasStrokeWidthParam, double &defaultStrokeWidth, bool blocking=false) const
Tests if an SVG file contains parameters for fill, stroke color, stroke width.
Definition: qgssvgcache.cpp:228
QgsSymbolLayerUtils::createGeometryElement
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
Definition: qgssymbollayerutils.cpp:2923
QgsPointPatternFillSymbolLayer::distanceY
double distanceY() const
Returns the vertical distance between rendered markers in the fill.
Definition: qgsfillsymbollayer.h:1766
Qgis::LineClipMode::ClipPainterOnly
@ ClipPainterOnly
Applying clipping on the painter only (i.e. line endpoints will coincide with polygon bounding box,...
QgsPointPatternFillSymbolLayer::color
QColor color() const override
Returns the "representative" color of the symbol layer.
Definition: qgsfillsymbollayer.cpp:4356
QgsGradientFillSymbolLayer::referencePoint1
QPointF referencePoint1() const
Returns the starting point of gradient fill, in the range [0,0] - [1,1].
Definition: qgsfillsymbollayer.h:347
Qgis::GradientColorSource
GradientColorSource
Gradient color sources.
Definition: qgis.h:1433
QgsSymbolLayerUtils::createLineLayerFromSld
static QgsSymbolLayer * createLineLayerFromSld(QDomElement &element)
Definition: qgssymbollayerutils.cpp:1637
QgsSymbolLayerUtils::fillToSld
static void fillToSld(QDomDocument &doc, QDomElement &element, Qt::BrushStyle brushStyle, const QColor &color=QColor())
Definition: qgssymbollayerutils.cpp:2122
QgsGradientFillSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:1014
Qgis::GradientType::Radial
@ Radial
Radial (circular) gradient.
QgsSymbolRenderContext::selected
bool selected() const
Returns true if symbols should be rendered using the selected symbol coloring and style.
Definition: qgssymbolrendercontext.h:118
QgsTemplatedLineSymbolLayerBase::setInterval
void setInterval(double interval)
Sets the interval between individual symbols.
Definition: qgslinesymbollayer.h:593
QgsSymbolLayerUtils::createDisplacementElement
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
Definition: qgssymbollayerutils.cpp:2748
QgsGradientFillSymbolLayer::gradientColorType
Qgis::GradientColorSource gradientColorType() const
Returns the gradient color mode, which controls how gradient color stops are created.
Definition: qgsfillsymbollayer.h:267
qgsapplication.h
QgsUnitTypes::decodeRenderUnit
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
Definition: qgsunittypes.cpp:2948
QgsSymbolLayer::PropertyGradientSpread
@ PropertyGradientSpread
Gradient spread mode.
Definition: qgssymbollayer.h:163
QgsRandomMarkerFillSymbolLayer::setSeed
void setSeed(unsigned long seed)
Sets the random number seed to use when generating points, or 0 if a truly random sequence will be us...
Definition: qgsfillsymbollayer.cpp:5284
QgsSymbolRenderContext
Definition: qgssymbolrendercontext.h:35
QgsCptCityColorRamp::typeString
static QString typeString()
Returns the string identifier for QgsCptCityColorRamp.
Definition: qgscolorrampimpl.h:750
QgsSymbolLayerUtils::evaluatePropertiesMap
static QgsStringMap evaluatePropertiesMap(const QMap< QString, QgsProperty > &propertiesMap, const QgsExpressionContext &context)
Evaluates a map of properties using the given context and returns a variant map with evaluated expres...
Definition: qgssymbollayerutils.cpp:5078
QgsRasterFillSymbolLayer::renderPolygon
void renderPolygon(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the fill symbol layer for the polygon whose outer ring is defined by points,...
Definition: qgsfillsymbollayer.cpp:4778
QgsRasterFillSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgsfillsymbollayer.cpp:4821
QgsGradientColorRamp::typeString
static QString typeString()
Returns the string identifier for QgsGradientColorRamp.
Definition: qgscolorrampimpl.h:165
QgsCentroidFillSymbolLayer::renderPolygon
void renderPolygon(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the fill symbol layer for the polygon whose outer ring is defined by points,...
Definition: qgsfillsymbollayer.cpp:4415
QgsSymbolLayerUtils::toPoint
static QPointF toPoint(const QVariant &value, bool *ok=nullptr)
Converts a value to a point.
Definition: qgssymbollayerutils.cpp:551
QgsRandomMarkerFillSymbolLayer::countMethod
Qgis::PointCountMethod countMethod() const
Returns the count method used to randomly fill the polygon.
Definition: qgsfillsymbollayer.cpp:5299
QgsRasterFillSymbolLayer::setCoordinateMode
void setCoordinateMode(Qgis::SymbolCoordinateReference mode)
Set the coordinate mode for fill.
Definition: qgsfillsymbollayer.cpp:4887
QgsSVGFillSymbolLayer::svgStrokeWidthMapUnitScale
const QgsMapUnitScale & svgStrokeWidthMapUnitScale() const
Returns the map unit scale for the pattern's stroke.
Definition: qgsfillsymbollayer.h:1331
QgsSimpleFillSymbolLayer::offset
QPointF offset() const
Returns the offset by which polygons will be translated during rendering.
Definition: qgsfillsymbollayer.h:120
QgsRenderContext::renderingStopped
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Definition: qgsrendercontext.h:285
QgsLinePatternFillSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgsfillsymbollayer.cpp:2612
QgsSymbolLayerUtils::polygonCentroid
static QPointF polygonCentroid(const QPolygonF &points)
Calculate the centroid point of a QPolygonF.
Definition: qgssymbollayerutils.cpp:4338
QgsPoint::y
double y
Definition: qgspoint.h:70
QgsCentroidFillSymbolLayer::pointOnSurface
bool pointOnSurface() const
Definition: qgsfillsymbollayer.h:2465
QgsRandomMarkerFillSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgsfillsymbollayer.cpp:5036
QgsPathResolver::writePath
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
Definition: qgspathresolver.cpp:225
Qgis::LineClipMode::ClipToIntersection
@ ClipToIntersection
Clip lines to intersection with polygon shape (slower) (i.e. line endpoints will coincide with polygo...
QgsRasterFillSymbolLayer::QgsRasterFillSymbolLayer
QgsRasterFillSymbolLayer(const QString &imageFilePath=QString())
Constructor for QgsRasterFillSymbolLayer, using a raster fill from the specified imageFilePath.
Definition: qgsfillsymbollayer.cpp:4684
QgsCentroidFillSymbolLayer::QgsCentroidFillSymbolLayer
QgsCentroidFillSymbolLayer()
Definition: qgsfillsymbollayer.cpp:4364
QgsImageFillSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgsfillsymbollayer.cpp:1769
QgsSymbolLayer::PropertyOffset
@ PropertyOffset
Symbol offset.
Definition: qgssymbollayer.h:151
qgsgeometryengine.h
QgsRandomMarkerFillSymbolLayer::setCountMethod
void setCountMethod(Qgis::PointCountMethod method)
Sets the count method used to randomly fill the polygon.
Definition: qgsfillsymbollayer.cpp:5304
QgsProperty::propertyMapToVariantMap
static QVariantMap propertyMapToVariantMap(const QMap< QString, QgsProperty > &propertyMap)
Convert a map of QgsProperty to a map of QVariant This is useful to save a map of properties.
Definition: qgsproperty.cpp:208
QgsSymbolLayer
Definition: qgssymbollayer.h:54
QgsSymbolLayer::PropertyMarkerClipping
@ PropertyMarkerClipping
Marker clipping mode (since QGIS 3.24)
Definition: qgssymbollayer.h:210
QgsRandomMarkerFillSymbolLayer::clipPoints
bool clipPoints() const
Returns true if point markers should be clipped to the polygon boundary.
Definition: qgsfillsymbollayer.cpp:5289
QgsSymbolLayer::PropertyGradientType
@ PropertyGradientType
Gradient fill type.
Definition: qgssymbollayer.h:161
QgsRenderContext::forceVectorOutput
bool forceVectorOutput() const
Returns true if rendering operations should use vector operations instead of any faster raster shortc...
Definition: qgsrendercontext.cpp:295
QgsCentroidFillSymbolLayer::mFeatureSymbolOpacity
double mFeatureSymbolOpacity
Definition: qgsfillsymbollayer.h:2525
QgsPointPatternFillSymbolLayer::clipMode
Qgis::MarkerClipMode clipMode() const
Returns the marker clipping mode, which defines how markers are clipped at the edges of shapes.
Definition: qgsfillsymbollayer.h:2024
QgsGradientFillSymbolLayer::color2
QColor color2() const
Returns the color for endpoint of gradient, only used if the gradient color type is set to SimpleTwoC...
Definition: qgsfillsymbollayer.h:298
QgsDxfExport::mapUnits
QgsUnitTypes::DistanceUnit mapUnits() const
Retrieve map units.
Definition: qgsdxfexport.cpp:262
QgsUnitTypes::encodeUnit
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
Definition: qgsunittypes.cpp:122
QgsRandomMarkerFillSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgsfillsymbollayer.cpp:5052
QgsGeometry::randomPointsInPolygon
QVector< QgsPointXY > randomPointsInPolygon(int count, const std::function< bool(const QgsPointXY &) > &acceptPoint, unsigned long seed=0, QgsFeedback *feedback=nullptr, int maxTriesPerPoint=0) const
Returns a list of count random points generated inside a (multi)polygon geometry (if acceptPoint is s...
DEFAULT_SIMPLEFILL_BORDERWIDTH
#define DEFAULT_SIMPLEFILL_BORDERWIDTH
Definition: qgsfillsymbollayer.h:27
QgsSimpleFillSymbolLayer::mBrush
QBrush mBrush
Definition: qgsfillsymbollayer.h:184
QgsGradientFillSymbolLayer::mOffsetMapUnitScale
QgsMapUnitScale mOffsetMapUnitScale
Definition: qgsfillsymbollayer.h:465
QgsSymbolLayer::PropertyRandomSeed
@ PropertyRandomSeed
Random number seed.
Definition: qgssymbollayer.h:198
QgsShapeburstFillSymbolLayer::maxDistance
double maxDistance() const
Returns the maximum distance from the shape's boundary which is shaded.
Definition: qgsfillsymbollayer.h:584
QgsSymbolLayer::setSubSymbol
virtual bool setSubSymbol(QgsSymbol *symbol)
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgssymbollayer.cpp:159
QgsGradientColorRamp::create
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsColorRamp from a map of properties.
Definition: qgscolorrampimpl.cpp:216
QgsImageFillSymbolLayer::renderPolygon
void renderPolygon(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the fill symbol layer for the polygon whose outer ring is defined by points,...
Definition: qgsfillsymbollayer.cpp:1712
QgsSymbolRenderContext::fields
QgsFields fields() const
Fields of the layer.
Definition: qgssymbolrendercontext.h:168
QgsImageFillSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgsfillsymbollayer.cpp:1805
QgsSvgCache::svgAsPicture
QPicture svgAsPicture(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, bool forceVectorOutput=false, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > &parameters=QMap< QString, QString >())
Returns an SVG drawing as a QPicture.
Definition: qgssvgcache.cpp:185
QgsPointPatternFillSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgsfillsymbollayer.cpp:3496
QgsCentroidFillSymbolLayer::stopFeatureRender
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called after the layer has been rendered for a particular feature.
Definition: qgsfillsymbollayer.cpp:4445
QgsSymbol::type
Qgis::SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:152
QgsRandomMarkerFillSymbolLayer::pointCount
int pointCount() const
Returns the count of random points to render in the fill.
Definition: qgsfillsymbollayer.cpp:5269
QgsFeature::isValid
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:216
QgsSimpleFillSymbolLayer::clone
QgsSimpleFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgsfillsymbollayer.cpp:376
QgsSVGFillSymbolLayer::~QgsSVGFillSymbolLayer
~QgsSVGFillSymbolLayer() override
QgsSVGFillSymbolLayer::applyDataDefinedSettings
void applyDataDefinedSettings(QgsSymbolRenderContext &context) override
Applies data defined settings prior to generating the fill symbol brush.
Definition: qgsfillsymbollayer.cpp:2379
QgsLinePatternFillSymbolLayer::stopFeatureRender
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called after the layer has been rendered for a particular feature.
Definition: qgsfillsymbollayer.cpp:2566
QgsSimpleFillSymbolLayer::mStrokeColor
QColor mStrokeColor
Definition: qgsfillsymbollayer.h:187
QgsRandomMarkerFillSymbolLayer::densityArea
double densityArea() const
Returns the density area used to count the number of points to randomly fill the polygon.
Definition: qgsfillsymbollayer.cpp:5309
QgsCentroidFillSymbolLayer::toSld
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
Definition: qgsfillsymbollayer.cpp:4571
qgscolorramp.h
QgsMarkerSymbol
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgsmarkersymbol.h:30
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsPointPatternFillSymbolLayer::mDistanceXMapUnitScale
QgsMapUnitScale mDistanceXMapUnitScale
Definition: qgsfillsymbollayer.h:2189
QgsSimpleFillSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgsfillsymbollayer.cpp:84
QgsPointPatternFillSymbolLayer::displacementX
double displacementX() const
Returns the horizontal displacement for odd numbered rows in the pattern.
Definition: qgsfillsymbollayer.h:1819
QgsRasterFillSymbolLayer::estimateMaxBleed
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
Definition: qgsfillsymbollayer.cpp:4859
QgsSimpleFillSymbolLayer::mOffsetUnit
QgsUnitTypes::RenderUnit mOffsetUnit
Definition: qgsfillsymbollayer.h:197
QgsShapeburstFillSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:1667
QgsSimpleFillSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgsfillsymbollayer.cpp:263
QgsSVGFillSymbolLayer::clone
QgsSVGFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgsfillsymbollayer.cpp:2153
QgsRenderContext::setFlag
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Definition: qgsrendercontext.cpp:216
QgsSimpleFillSymbolLayer::dxfAngle
double dxfAngle(QgsSymbolRenderContext &context) const override
Gets angle.
Definition: qgsfillsymbollayer.cpp:493
QgsLineString::asQPolygonF
QPolygonF asQPolygonF() const override
Returns a QPolygonF representing the points.
Definition: qgslinestring.cpp:545
QgsSimpleFillSymbolLayer::penJoinStyle
Qt::PenJoinStyle penJoinStyle() const
Definition: qgsfillsymbollayer.h:99
QgsSymbolLayer::PropertyGradientReference1Y
@ PropertyGradientReference1Y
Gradient reference point 1 y.
Definition: qgssymbollayer.h:165
QgsCurvePolygon::area
double area() const override SIP_HOLDGIL
Returns the planar, 2-dimensional area of the geometry.
Definition: qgscurvepolygon.cpp:488
QgsLinePatternFillSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:2576
QgsRasterFillSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgsfillsymbollayer.cpp:4767
QgsTemplatedLineSymbolLayerBase::intervalMapUnitScale
const QgsMapUnitScale & intervalMapUnitScale() const
Returns the map unit scale for the interval between symbols.
Definition: qgslinesymbollayer.h:624
QgsSimpleFillSymbolLayer::strokeWidth
double strokeWidth() const
Definition: qgsfillsymbollayer.h:96
QgsShapeburstFillSymbolLayer::QgsShapeburstFillSymbolLayer
QgsShapeburstFillSymbolLayer(const QColor &color=DEFAULT_SIMPLEFILL_COLOR, const QColor &color2=Qt::white, Qgis::GradientColorSource colorType=Qgis::GradientColorSource::SimpleTwoColor, int blurRadius=0, bool useWholeShape=true, double maxDistance=5)
Constructor for QgsShapeburstFillSymbolLayer.
Definition: qgsfillsymbollayer.cpp:1036
QgsLinePatternFillSymbolLayer::clipMode
Qgis::LineClipMode clipMode() const
Returns the line clipping mode, which defines how lines are clipped at the edges of shapes.
Definition: qgsfillsymbollayer.h:1606
QgsLinePatternFillSymbolLayer
A symbol fill consisting of repeated parallel lines.
Definition: qgsfillsymbollayer.h:1395
QgsPointPatternFillSymbolLayer::mAngle
double mAngle
Definition: qgsfillsymbollayer.h:2214
QgsSimpleFillSymbolLayer::mPen
QPen mPen
Definition: qgsfillsymbollayer.h:193
QgsColorRamp::properties
virtual QVariantMap properties() const =0
Returns a string map containing all the color ramp's properties.
QgsRandomMarkerFillSymbolLayer::startFeatureRender
void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called before the layer will be rendered for a particular feature.
Definition: qgsfillsymbollayer.cpp:5319
QgsPointPatternFillSymbolLayer::subSymbol
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
Definition: qgsfillsymbollayer.cpp:4271
QgsRandomMarkerFillSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:5339
QgsCentroidFillSymbolLayer::clipPoints
bool clipPoints() const
Returns true if point markers should be clipped to the polygon boundary.
Definition: qgsfillsymbollayer.h:2487
QgsShapeburstFillSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgsfillsymbollayer.cpp:1219
QgsLineString::fromQPolygonF
static QgsLineString * fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
Definition: qgslinestring.cpp:248
QgsRasterFillSymbolLayer::offset
QPointF offset() const
Returns the offset for the fill.
Definition: qgsfillsymbollayer.h:979
QgsSimpleFillSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:68
QgsSymbolLayer::copyPaintEffect
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
Definition: qgssymbollayer.cpp:491
QgsSymbolLayerUtils::decodePoint
static QPointF decodePoint(const QString &string)
Decodes a QSizeF from a string.
Definition: qgssymbollayerutils.cpp:543
QgsRandomMarkerFillSymbolLayer::seed
unsigned long seed() const
Returns the random number seed to use when generating points, or 0 if a truly random sequence will be...
Definition: qgsfillsymbollayer.cpp:5279
QgsGradientFillSymbolLayer::mOffset
QPointF mOffset
Definition: qgsfillsymbollayer.h:463
QgsSVGFillSymbolLayer::dxfColor
QColor dxfColor(QgsSymbolRenderContext &context) const override
Gets color.
Definition: qgsfillsymbollayer.cpp:2287
QgsSimpleFillSymbolLayer::mBrushStyle
Qt::BrushStyle mBrushStyle
Definition: qgsfillsymbollayer.h:186
QgsSymbolLayer::PropertyStrokeStyle
@ PropertyStrokeStyle
Stroke style (eg solid, dashed)
Definition: qgssymbollayer.h:150
QgsSymbolLayerUtils::rescaleUom
static double rescaleUom(double size, QgsUnitTypes::RenderUnit unit, const QVariantMap &props)
Rescales the given size based on the uomScale found in the props, if any is found,...
Definition: qgssymbollayerutils.cpp:4742
QgsSymbolLayer::PropertyRandomOffsetX
@ PropertyRandomOffsetX
Random offset X (since QGIS 3.24)
Definition: qgssymbollayer.h:211
QgsLinePatternFillSymbolLayer::setLineWidth
void setLineWidth(double w)
Sets the width of the line subsymbol used to render the parallel lines in the fill.
Definition: qgsfillsymbollayer.cpp:2506
QgsGradientFillSymbolLayer::mReferencePoint1
QPointF mReferencePoint1
Definition: qgsfillsymbollayer.h:458
QgsCentroidFillSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:4646
QgsApplication::imageCache
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
Definition: qgsapplication.cpp:2365
qgsrendercontext.h
QgsTemplatedLineSymbolLayerBase::interval
double interval() const
Returns the interval between individual symbols.
Definition: qgslinesymbollayer.h:585
QgsSVGFillSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgsfillsymbollayer.cpp:2120
QgsSimpleFillSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:74
QgsImageFillSymbolLayer::coordinateReference
Qgis::SymbolCoordinateReference coordinateReference() const
Returns the coordinate reference mode for fill which controls how the top left corner of the image fi...
Definition: qgsfillsymbollayer.h:834
QgsGradientFillSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgsfillsymbollayer.cpp:908
QgsLinePatternFillSymbolLayer::renderPolygon
void renderPolygon(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the fill symbol layer for the polygon whose outer ring is defined by points,...
Definition: qgsfillsymbollayer.cpp:3060
QgsLineSymbol
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:29
QgsSymbolLayer::PropertyLineClipping
@ PropertyLineClipping
Line clipping mode (since QGIS 3.24)
Definition: qgssymbollayer.h:213
QgsSVGFillSymbolLayer
A class for filling symbols with a repeated SVG file.
Definition: qgsfillsymbollayer.h:1101
QgsSVGFillSymbolLayer::setSvgFilePath
void setSvgFilePath(const QString &svgPath)
Sets the path to the SVG file to render in the fill.
Definition: qgsfillsymbollayer.cpp:1896
QgsSVGFillSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsSVGFillSymbolLayer from a properties map.
Definition: qgsfillsymbollayer.cpp:1905
QgsRenderContext::setMapToPixel
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context's map to pixel transform, which transforms between map coordinates and device coordi...
Definition: qgsrendercontext.h:412
QgsPointPatternFillSymbolLayer::mSeed
unsigned long mSeed
Definition: qgsfillsymbollayer.h:2212
QgsGradientFillSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsGradientFillSymbolLayer using the specified properties map containing symbol propert...
Definition: qgsfillsymbollayer.cpp:545
QgsCentroidFillSymbolLayer::canCauseArtifactsBetweenAdjacentTiles
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
Definition: qgsfillsymbollayer.cpp:4633
QgsShapeburstFillSymbolLayer
Definition: qgsfillsymbollayer.h:486
QgsShapeburstFillSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgsfillsymbollayer.cpp:1210
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
QgsSVGFillSymbolLayer::estimateMaxBleed
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
Definition: qgsfillsymbollayer.cpp:2277
QgsSimpleFillSymbolLayer::mSelBrush
QBrush mSelBrush
Definition: qgsfillsymbollayer.h:185
QgsSvgCache::getImageData
QByteArray getImageData(const QString &path, bool blocking=false) const
Gets the SVG content corresponding to the given path.
Definition: qgssvgcache.cpp:401
QgsRasterFillSymbolLayer::imageFilePath
QString imageFilePath() const
The path to the raster image used for the fill.
Definition: qgsfillsymbollayer.h:931
QgsLinePatternFillSymbolLayer::color
QColor color() const override
Returns the "representative" color of the symbol layer.
Definition: qgsfillsymbollayer.cpp:2518
Qgis::GradientSpread::Reflect
@ Reflect
Reflect gradient.
QgsSymbolLayer::PropertyDensityArea
@ PropertyDensityArea
Density area.
Definition: qgssymbollayer.h:200
QgsPointPatternFillSymbolLayer::applyDataDefinedSettings
void applyDataDefinedSettings(QgsSymbolRenderContext &context) override
Applies data defined settings prior to generating the fill symbol brush.
Definition: qgsfillsymbollayer.cpp:4276
QgsCentroidFillSymbolLayer::color
QColor color() const override
Returns the "representative" color of the symbol layer.
Definition: qgsfillsymbollayer.cpp:4400
QgsRandomMarkerFillSymbolLayer::renderPolygon
void renderPolygon(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the fill symbol layer for the polygon whose outer ring is defined by points,...
Definition: qgsfillsymbollayer.cpp:5062
QgsSymbolLayerUtils::createVendorOptionElement
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
Definition: qgssymbollayerutils.cpp:3115
QgsShapeburstFillSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgsfillsymbollayer.cpp:1688
QgsGeometry::isNull
bool isNull
Definition: qgsgeometry.h:127
QgsPointPatternFillSymbolLayer::mOffsetYUnit
QgsUnitTypes::RenderUnit mOffsetYUnit
Definition: qgsfillsymbollayer.h:2203
DEFAULT_SIMPLEFILL_BORDERSTYLE
#define DEFAULT_SIMPLEFILL_BORDERSTYLE
Definition: qgsfillsymbollayer.h:26
QgsGradientFillSymbolLayer::mGradientSpread
Qgis::GradientSpread mGradientSpread
Definition: qgsfillsymbollayer.h:456
QgsMapUnitScale
Struct for storing maximum and minimum scales for measurements in map units.
Definition: qgsmapunitscale.h:36
QgsSimpleFillSymbolLayer::dxfBrushColor
QColor dxfBrushColor(QgsSymbolRenderContext &context) const override
Gets brush/fill color.
Definition: qgsfillsymbollayer.cpp:509
QgsSymbolLayer::PropertyPointCount
@ PropertyPointCount
Point count.
Definition: qgssymbollayer.h:197
QgsSymbolLayerUtils::decodeBrushStyle
static Qt::BrushStyle decodeBrushStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:320
QgsSVGFillSymbolLayer::svgStrokeColor
QColor svgStrokeColor() const
Returns the stroke color used for rendering the SVG content.
Definition: qgsfillsymbollayer.h:1235
QgsSVGFillSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:1868
QgsRasterFillSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgsfillsymbollayer.cpp:4864
QgsCentroidFillSymbolLayer::mRenderingFeature
bool mRenderingFeature
Definition: qgsfillsymbollayer.h:2524
QgsRandomMarkerFillSymbolLayer::~QgsRandomMarkerFillSymbolLayer
~QgsRandomMarkerFillSymbolLayer() override
QgsCentroidFillSymbolLayer::startFeatureRender
void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called before the layer will be rendered for a particular feature.
Definition: qgsfillsymbollayer.cpp:4439
QgsPointPatternFillSymbolLayer::mDisplacementY
double mDisplacementY
Definition: qgsfillsymbollayer.h:2196
QgsCentroidFillSymbolLayer::clipOnCurrentPartOnly
bool clipOnCurrentPartOnly() const
Returns true if point markers should be clipped to the current part boundary only.
Definition: qgsfillsymbollayer.h:2503
QgsGradientFillSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgsfillsymbollayer.cpp:900
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1336
QgsRasterFillSymbolLayer::applyDataDefinedSettings
void applyDataDefinedSettings(QgsSymbolRenderContext &context) override
Applies data defined settings prior to generating the fill symbol brush.
Definition: qgsfillsymbollayer.cpp:4897
QgsPointPatternFillSymbolLayer::stopFeatureRender
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called after the layer has been rendered for a particular feature.
Definition: qgsfillsymbollayer.cpp:3822
QgsPointPatternFillSymbolLayer::mOffsetYMapUnitScale
QgsMapUnitScale mOffsetYMapUnitScale
Definition: qgsfillsymbollayer.h:2204
QgsCptCityColorRamp::create
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates the symbol layer.
Definition: qgscolorrampimpl.cpp:944
QgsLinePatternFillSymbolLayer::setColor
void setColor(const QColor &c) override
Sets the "representative" color for the symbol layer.
Definition: qgsfillsymbollayer.cpp:2512
qgsfillsymbollayer.h
QgsPointPatternFillSymbolLayer::mDistanceY
double mDistanceY
Definition: qgsfillsymbollayer.h:2190
QgsSymbolLayer::mDataDefinedProperties
QgsPropertyCollection mDataDefinedProperties
Definition: qgssymbollayer.h:651
QgsSymbolLayer::PropertyStrokeWidth
@ PropertyStrokeWidth
Stroke width.
Definition: qgssymbollayer.h:149
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:136
QgsRandomMarkerFillSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgsfillsymbollayer.cpp:5237
QgsPointPatternFillSymbolLayer::toSld
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
Definition: qgsfillsymbollayer.cpp:4207
QgsSymbolLayer::PropertyShapeburstIgnoreRings
@ PropertyShapeburstIgnoreRings
Shapeburst ignore rings.
Definition: qgssymbollayer.h:173
QgsGradientFillSymbolLayer::referencePoint2
QPointF referencePoint2() const
Returns the end point of gradient fill, in the range [0,0] - [1,1].
Definition: qgsfillsymbollayer.h:375
QgsPointPatternFillSymbolLayer::estimateMaxBleed
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
Definition: qgsfillsymbollayer.cpp:4325
QgsPointPatternFillSymbolLayer::mDistanceX
double mDistanceX
Definition: qgsfillsymbollayer.h:2187
QgsSymbolLayerUtils::encodePoint
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
Definition: qgssymbollayerutils.cpp:538
QgsShapeburstFillSymbolLayer::blurRadius
int blurRadius() const
Returns the blur radius, which controls the amount of blurring applied to the fill.
Definition: qgsfillsymbollayer.h:545
QgsCentroidFillSymbolLayer::mMarker
std::unique_ptr< QgsMarkerSymbol > mMarker
Definition: qgsfillsymbollayer.h:2518
QgsSymbolLayerUtils::ogrFeatureStylePen
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=nullptr)
Create ogr feature style string for pen.
Definition: qgssymbollayerutils.cpp:2839
QgsGradientFillSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgsfillsymbollayer.cpp:952
QgsRasterFillSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsRasterFillSymbolLayer from a properties map.
Definition: qgsfillsymbollayer.cpp:4694
QgsPointPatternFillSymbolLayer::seed
unsigned long seed() const
Returns the random number seed to use when randomly shifting points, or 0 if a truly random sequence ...
Definition: qgsfillsymbollayer.h:2157
QgsColorRamp::clone
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
QgsGradientFillSymbolLayer::clone
QgsGradientFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgsfillsymbollayer.cpp:980
QgsLinePatternFillSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgsfillsymbollayer.cpp:2597
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:113
QgsApplication::svgCache
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
Definition: qgsapplication.cpp:2360
QgsPointPatternFillSymbolLayer::setColor
void setColor(const QColor &c) override
Sets the "representative" color for the symbol layer.
Definition: qgsfillsymbollayer.cpp:4349
QgsAbstractPropertyCollection::valueAsString
QString valueAsString(int key, const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a string.
Definition: qgspropertycollection.cpp:42
QgsSymbolLayer::usedAttributes
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the set of attributes referenced by the layer.
Definition: qgssymbollayer.cpp:328
QgsLinePatternFillSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgsfillsymbollayer.cpp:3052
QgsSymbolLayerUtils::encodeCoordinateReference
static QString encodeCoordinateReference(Qgis::SymbolCoordinateReference coordinateReference)
Encodes a symbol coordinate reference mode to a string.
Definition: qgssymbollayerutils.cpp:408
QgsRandomMarkerFillSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgsfillsymbollayer.cpp:5357
QgsSymbolLayerUtils::decodeSldUom
static QgsUnitTypes::RenderUnit decodeSldUom(const QString &str, double *scaleFactor=nullptr)
Decodes a SLD unit of measure string to a render unit.
Definition: qgssymbollayerutils.cpp:740
QgsRenderContext::setRendererScale
void setRendererScale(double scale)
Sets the renderer map scale.
Definition: qgsrendercontext.h:487
QgsPointPatternFillSymbolLayer::distanceX
double distanceX() const
Returns the horizontal distance between rendered markers in the fill.
Definition: qgsfillsymbollayer.h:1713
QgsSymbolLayer::PropertyOffsetY
@ PropertyOffsetY
Vertical offset.
Definition: qgssymbollayer.h:196
QgsShapeburstFillSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:1673
QgsPointPatternFillSymbolLayer::hasDataDefinedProperties
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
Definition: qgsfillsymbollayer.cpp:4340
QgsPointPatternFillSymbolLayer::mRandomDeviationXUnit
QgsUnitTypes::RenderUnit mRandomDeviationXUnit
Definition: qgsfillsymbollayer.h:2207
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsRenderContext::convertToPainterUnits
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
Definition: qgsrendercontext.cpp:367
QgsRenderContext::setForceVectorOutput
void setForceVectorOutput(bool force)
Sets whether rendering operations should use vector operations instead of any faster raster shortcuts...
Definition: qgsrendercontext.cpp:330
QgsSimpleFillSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgsfillsymbollayer.cpp:359
QgsGradientFillSymbolLayer::mReferencePoint2
QPointF mReferencePoint2
Definition: qgsfillsymbollayer.h:460
QgsCentroidFillSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgsfillsymbollayer.cpp:4389
QgsRandomMarkerFillSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgsfillsymbollayer.cpp:5374
Qgis::GradientColorSource::ColorRamp
@ ColorRamp
Gradient color ramp.
QgsPointPatternFillSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgsfillsymbollayer.cpp:3508
QgsSymbolLayerUtils::pointOnLineWithDistance
static QPointF pointOnLineWithDistance(QPointF startPoint, QPointF directionPoint, double distance)
Returns a point on the line from startPoint to directionPoint that is a certain distance away from th...
Definition: qgssymbollayerutils.cpp:4174
QgsRenderContext::selectionColor
QColor selectionColor() const
Returns the color to use when rendering selected features.
Definition: qgsrendercontext.h:382
QgsSimpleFillSymbolLayer::mStrokeWidth
double mStrokeWidth
Definition: qgsfillsymbollayer.h:189
QgsPathResolver::readPath
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
Definition: qgspathresolver.cpp:37
QgsSymbolLayer::SELECT_FILL_STYLE
static const bool SELECT_FILL_STYLE
Whether fill styles for selected features uses symbol layer style.
Definition: qgssymbollayer.h:665
QgsPointPatternFillSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgsfillsymbollayer.cpp:3781
QgsSVGFillSymbolLayer::setParameters
void setParameters(const QMap< QString, QgsProperty > &parameters)
Sets the dynamic SVG parameters.
Definition: qgsfillsymbollayer.cpp:2491
QgsGeometry::get
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:141
QgsGeometry::createGeometryEngine
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
Definition: qgsgeometry.cpp:3972
Qgis::RenderContextFlag::RenderBlocking
@ RenderBlocking
Render and load remote sources in the same thread to ensure rendering remote sources (svg and images)...
QgsStringMap
QMap< QString, QString > QgsStringMap
Definition: qgis.h:2781
QgsRenderContext::textureOrigin
QPointF textureOrigin() const
Returns the texture origin, which should be used as a brush transform when rendering using QBrush obj...
Definition: qgsrendercontext.cpp:640
QgsRandomMarkerFillSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsRandomMarkerFillSymbolLayer using the specified properties map containing symbol pro...
Definition: qgsfillsymbollayer.cpp:5002
QgsRenderContext::feedback
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly during rendering to check if rendering shou...
Definition: qgsrendercontext.cpp:206
QgsGradientFillSymbolLayer::~QgsGradientFillSymbolLayer
~QgsGradientFillSymbolLayer() override
Definition: qgsfillsymbollayer.cpp:540
QgsRandomMarkerFillSymbolLayer::setClipPoints
void setClipPoints(bool clipped)
Sets whether point markers should be clipped to the polygon boundary.
Definition: qgsfillsymbollayer.cpp:5294
Qgis::MarkerClipMode::Shape
@ Shape
Clip to polygon shape.
QgsSymbolLayer::PropertyGradientReference2X
@ PropertyGradientReference2X
Gradient reference point 2 x.
Definition: qgssymbollayer.h:166
QgsSimpleFillSymbolLayer::mStrokeWidthUnit
QgsUnitTypes::RenderUnit mStrokeWidthUnit
Definition: qgsfillsymbollayer.h:190
QgsFillSymbolLayer::mAngle
double mAngle
Definition: qgssymbollayer.h:1249
QgsGradientFillSymbolLayer::mGradientRamp
QgsColorRamp * mGradientRamp
Definition: qgsfillsymbollayer.h:453
QgsGradientColorRamp::addStopsToGradient
void addStopsToGradient(QGradient *gradient, double opacity=1) const
Copy color ramp stops to a QGradient.
Definition: qgscolorrampimpl.cpp:540
QgsCentroidFillSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgsfillsymbollayer.cpp:4546
qgsgeometry.h
qgslinesymbollayer.h
QgsPointPatternFillSymbolLayer::mOffsetX
double mOffsetX
Definition: qgsfillsymbollayer.h:2199
QgsSymbolLayerUtils::fillFromSld
static bool fillFromSld(QDomElement &element, Qt::BrushStyle &brushStyle, QColor &color)
Definition: qgssymbollayerutils.cpp:2173
QgsRandomMarkerFillSymbolLayer::setColor
void setColor(const QColor &color) override
Sets the "representative" color for the symbol layer.
Definition: qgsfillsymbollayer.cpp:5041
INF
#define INF
Definition: qgsimageoperation.cpp:31
QgsLinePatternFillSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgsfillsymbollayer.cpp:3254
QgsGradientFillSymbolLayer::mReferencePoint1IsCentroid
bool mReferencePoint1IsCentroid
Definition: qgsfillsymbollayer.h:459
QgsSVGFillSymbolLayer::renderPolygon
void renderPolygon(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the fill symbol layer for the polygon whose outer ring is defined by points,...
Definition: qgsfillsymbollayer.cpp:2103
QgsSymbolLayer::PropertyCoordinateMode
@ PropertyCoordinateMode
Gradient coordinate mode.
Definition: qgssymbollayer.h:162
QgsPropertyCollection::value
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the property with the specified key from within the collection.
Definition: qgspropertycollection.cpp:228
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsPointPatternFillSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgsfillsymbollayer.cpp:3679
QgsAbstractPropertyCollection::valueAsBool
bool valueAsBool(int key, const QgsExpressionContext &context, bool defaultValue=false, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an boolean.
Definition: qgspropertycollection.cpp:88
QgsShapeburstFillSymbolLayer::estimateMaxBleed
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
Definition: qgsfillsymbollayer.cpp:1656
QgsSymbolLayer::type
Qgis::SymbolType type() const
Definition: qgssymbollayer.h:437
QgsMapToPixel
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:38
QgsFillSymbolLayer::angle
double angle() const
Definition: qgssymbollayer.h:1242
QgsRasterFillSymbolLayer::clone
QgsRasterFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgsfillsymbollayer.cpp:4842
QgsShapeburstFillSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgsfillsymbollayer.cpp:1144
QgsPointPatternFillSymbolLayer::~QgsPointPatternFillSymbolLayer
~QgsPointPatternFillSymbolLayer() override
QgsSVGFillSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:1858
QgsRandomMarkerFillSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgsfillsymbollayer.cpp:5200
QgsSymbolLayer::PropertyDistanceY
@ PropertyDistanceY
Vertical distance between points.
Definition: qgssymbollayer.h:176
qgsimagecache.h
QgsLinePatternFillSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgsfillsymbollayer.cpp:2587
QgsRandomMarkerFillSymbolLayer::canCauseArtifactsBetweenAdjacentTiles
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
Definition: qgsfillsymbollayer.cpp:5227
QgsSymbolLayerList
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:27
QgsImageFillSymbolLayer::mCoordinateReference
Qgis::SymbolCoordinateReference mCoordinateReference
Definition: qgsfillsymbollayer.h:846
QgsSVGFillSymbolLayer::patternWidthMapUnitScale
const QgsMapUnitScale & patternWidthMapUnitScale() const
Returns the map unit scale for the pattern's width.
Definition: qgsfillsymbollayer.h:1295
QgsSymbolLayerUtils::svgSymbolNameToPath
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol's path from its name.
Definition: qgssymbollayerutils.cpp:4237
qgsmarkersymbol.h
QgsShapeburstFillSymbolLayer::color2
QColor color2() const
Returns the color used for the endpoint of the shapeburst fill.
Definition: qgsfillsymbollayer.h:667
QgsSymbolLayer::PropertyDistanceX
@ PropertyDistanceX
Horizontal distance between points.
Definition: qgssymbollayer.h:175
QgsRandomMarkerFillSymbolLayer::setDensityArea
void setDensityArea(double area)
Sets the density area used to count the number of points to randomly fill the polygon.
Definition: qgsfillsymbollayer.cpp:5314
QgsRasterFillSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgsfillsymbollayer.cpp:4773
QgsCentroidFillSymbolLayer::hasDataDefinedProperties
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
Definition: qgsfillsymbollayer.cpp:4624
QgsColorRamp::type
virtual QString type() const =0
Returns a string representing the color ramp type.
QgsRasterFillSymbolLayer::~QgsRasterFillSymbolLayer
~QgsRasterFillSymbolLayer() override
QgsSymbolLayerUtils::rotationFromSldElement
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
Definition: qgssymbollayerutils.cpp:2717
Qgis::GradientType::Conical
@ Conical
Conical (polar) gradient.
QgsSymbolLayer::PropertyFile
@ PropertyFile
Filename, eg for svg files.
Definition: qgssymbollayer.h:174
Qgis::PointCountMethod
PointCountMethod
Methods which define the number of points randomly filling a polygon.
Definition: qgis.h:1492
QgsGeometry::fromRect
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
Definition: qgsgeometry.cpp:241
QgsSVGFillSymbolLayer::subSymbol
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
Definition: qgsfillsymbollayer.cpp:2247
QgsRandomMarkerFillSymbolLayer
A fill symbol layer which places markers at random locations within polygons.
Definition: qgsfillsymbollayer.h:2239
QgsSimpleFillSymbolLayer
Definition: qgsfillsymbollayer.h:43
QgsSymbolLayer::PropertyAngle
@ PropertyAngle
Symbol angle.
Definition: qgssymbollayer.h:145
QgsColorRamp::color
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
QgsCentroidFillSymbolLayer::mClipOnCurrentPartOnly
bool mClipOnCurrentPartOnly
Definition: qgsfillsymbollayer.h:2522
QgsSymbolLayerUtils::encodeLineClipMode
static QString encodeLineClipMode(Qgis::LineClipMode mode)
Encodes a line clip mode to a string.
Definition: qgssymbollayerutils.cpp:524
QgsUnitTypes::RenderMetersInMapUnits
@ RenderMetersInMapUnits
Meters value as Map units.
Definition: qgsunittypes.h:176
QgsImageFillSymbolLayer::~QgsImageFillSymbolLayer
~QgsImageFillSymbolLayer() override
QgsRenderContext::pathResolver
const QgsPathResolver & pathResolver() const
Returns the path resolver for conversion between relative and absolute paths during rendering operati...
Definition: qgsrendercontext.h:213
QgsCentroidFillSymbolLayer::clone
QgsCentroidFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgsfillsymbollayer.cpp:4556
QgsUnitTypes::RenderUnknownUnit
@ RenderUnknownUnit
Mixed or unknown units.
Definition: qgsunittypes.h:175
QgsPointPatternFillSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgsfillsymbollayer.cpp:3521
QgsSimpleFillSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgsfillsymbollayer.cpp:90
QgsSymbolLayer::PropertyShapeburstMaxDistance
@ PropertyShapeburstMaxDistance
Shapeburst fill from edge distance.
Definition: qgssymbollayer.h:172
QgsSVGFillSymbolLayer::hasDataDefinedProperties
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
Definition: qgsfillsymbollayer.cpp:2305
QgsRandomMarkerFillSymbolLayer::setPointCount
void setPointCount(int count)
Sets the count of random points to render in the fill.
Definition: qgsfillsymbollayer.cpp:5274
QgsImageOperation::multiplyOpacity
static void multiplyOpacity(QImage &image, double factor, QgsFeedback *feedback=nullptr)
Multiplies opacity of image pixel values by a factor.
Definition: qgsimageoperation.cpp:335
QgsSVGFillSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgsfillsymbollayer.cpp:2241
QgsSVGFillSymbolLayer::patternWidthUnit
QgsUnitTypes::RenderUnit patternWidthUnit() const
Returns the units for the width of the SVG images in the pattern.
Definition: qgsfillsymbollayer.h:1277
QgsSVGFillSymbolLayer::toSld
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
Definition: qgsfillsymbollayer.cpp:2186
QgsGradientFillSymbolLayer::setColorRamp
void setColorRamp(QgsColorRamp *ramp)
Sets the color ramp used for the gradient fill.
Definition: qgsfillsymbollayer.cpp:629
QgsSymbolLayerUtils::decodePenJoinStyle
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:200
QgsRandomMarkerFillSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgsfillsymbollayer.cpp:5057
Qgis::SymbolCoordinateReference::Feature
@ Feature
Relative to feature/shape being rendered.
QgsSymbolLayer::PropertyRandomOffsetY
@ PropertyRandomOffsetY
Random offset Y (since QGIS 3.24)
Definition: qgssymbollayer.h:212
QgsSymbolLayerUtils::createRotationElement
static void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
Definition: qgssymbollayerutils.cpp:2707
QgsShapeburstFillSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgsfillsymbollayer.cpp:1694
QgsRandomMarkerFillSymbolLayer::QgsRandomMarkerFillSymbolLayer
QgsRandomMarkerFillSymbolLayer(int pointCount=10, Qgis::PointCountMethod method=Qgis::PointCountMethod::Absolute, double densityArea=250.0, unsigned long seed=0)
Constructor for QgsRandomMarkerFillSymbolLayer, with the specified pointCount.
Definition: qgsfillsymbollayer.cpp:4991
QgsGradientFillSymbolLayer::estimateMaxBleed
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
Definition: qgsfillsymbollayer.cpp:998
QgsPointPatternFillSymbolLayer::mDisplacementYUnit
QgsUnitTypes::RenderUnit mDisplacementYUnit
Definition: qgsfillsymbollayer.h:2197
QgsRenderContext::setExpressionContext
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
Definition: qgsrendercontext.h:617
QgsSVGFillSymbolLayer::svgFilePath
QString svgFilePath() const
Returns the path to the SVG file used to render the fill.
Definition: qgsfillsymbollayer.h:1171
Qgis::GradientSpread
GradientSpread
Gradient spread options, which control how gradients are rendered outside of their start and end poin...
Definition: qgis.h:1477
QgsSymbolLayer::fillColor
virtual QColor fillColor() const
Returns the fill color for the symbol layer.
Definition: qgssymbollayer.cpp:271
QgsImageFillSymbolLayer::mStrokeWidthMapUnitScale
QgsMapUnitScale mStrokeWidthMapUnitScale
Definition: qgsfillsymbollayer.h:852
QgsSimpleFillSymbolLayer::fillColor
QColor fillColor() const override
Returns the fill color for the symbol layer.
Definition: qgsfillsymbollayer.h:90
qgsdxfexport.h
QgsPointPatternFillSymbolLayer::renderPolygon
void renderPolygon(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the fill symbol layer for the polygon whose outer ring is defined by points,...
Definition: qgsfillsymbollayer.cpp:3829
DEFAULT_SIMPLEFILL_JOINSTYLE
#define DEFAULT_SIMPLEFILL_JOINSTYLE
Definition: qgsfillsymbollayer.h:28
qgsgeometrycollection.h
QgsLinePatternFillSymbolLayer::subSymbol
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
Definition: qgsfillsymbollayer.cpp:2539
QgsCentroidFillSymbolLayer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
Definition: qgsfillsymbollayer.cpp:4614
QgsSymbolLayerUtils
Definition: qgssymbollayerutils.h:57
QgsSymbolLayer::layerType
virtual QString layerType() const =0
Returns a string that represents this layer type.
QgsSymbolLayer::color
virtual QColor color() const
Returns the "representative" color of the symbol layer.
Definition: qgssymbollayer.cpp:247
QgsSymbolLayer::PropertyGradientReference1X
@ PropertyGradientReference1X
Gradient reference point 1 x.
Definition: qgssymbollayer.h:164
QgsLinePatternFillSymbolLayer::estimateMaxBleed
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
Definition: qgsfillsymbollayer.cpp:2571
QgsPointPatternFillSymbolLayer::mDistanceYUnit
QgsUnitTypes::RenderUnit mDistanceYUnit
Definition: qgsfillsymbollayer.h:2191
QgsSymbolLayerUtils::encodePenJoinStyle
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
Definition: qgssymbollayerutils.cpp:185
QgsGeometry::fromQPolygonF
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
Definition: qgsgeometry.cpp:3408
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsSymbolLayer::PropertyOpacity
@ PropertyOpacity
Opacity.
Definition: qgssymbollayer.h:179
QgsPointPatternFillSymbolLayer::QgsPointPatternFillSymbolLayer
QgsPointPatternFillSymbolLayer()
Definition: qgsfillsymbollayer.cpp:3445
QgsSymbolRenderContext::renderContext
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgssymbolrendercontext.h:62
QgsDxfExport::symbologyScale
double symbologyScale() const
Returns the reference scale for output.
Definition: qgsdxfexport.h:229
Qgis::SymbolCoordinateReference
SymbolCoordinateReference
Symbol coordinate reference modes.
Definition: qgis.h:1462
QgsImageFillSymbolLayer
Base class for polygon renderers generating texture images.
Definition: qgsfillsymbollayer.h:777
QgsSymbolLayerUtils::estimateMaxSymbolBleed
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
Definition: qgssymbollayerutils.cpp:934
QgsRasterFillSymbolLayer::setImageFilePath
void setImageFilePath(const QString &imagePath)
Sets the path to the raster image used for the fill.
Definition: qgsfillsymbollayer.cpp:4882
QgsGradientFillSymbolLayer::canCauseArtifactsBetweenAdjacentTiles
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
Definition: qgsfillsymbollayer.cpp:1004
QgsImageOperation::stackBlur
static void stackBlur(QImage &image, int radius, bool alphaOnly=false, QgsFeedback *feedback=nullptr)
Performs a stack blur on an image.
Definition: qgsimageoperation.cpp:585
QgsShapeburstFillSymbolLayer::offset
QPointF offset() const
Returns the offset for the shapeburst fill.
Definition: qgsfillsymbollayer.h:702
QgsSymbolLayerUtils::parametricSvgToSld
static void parametricSvgToSld(QDomDocument &doc, QDomElement &graphicElem, const QString &path, const QColor &fillColor, double size, const QColor &strokeColor, double strokeWidth)
Encodes a reference to a parametric SVG into SLD, as a succession of parametric SVG using URL paramet...
Definition: qgssymbollayerutils.cpp:2462
QgsShapeburstFillSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsShapeburstFillSymbolLayer using the specified properties map containing symbol prope...
Definition: qgsfillsymbollayer.cpp:1049
QgsLinePatternFillSymbolLayer::lineWidth
double lineWidth() const
Returns the width of the line subsymbol used to render the parallel lines in the fill.
Definition: qgsfillsymbollayer.h:1471
QgsSimpleFillSymbolLayer::strokeStyle
Qt::PenStyle strokeStyle() const
Definition: qgsfillsymbollayer.h:93
QgsSymbolLayerUtils::lineFromSld
static bool lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=nullptr, Qt::PenCapStyle *penCapStyle=nullptr, QVector< qreal > *customDashPattern=nullptr, double *dashOffset=nullptr)
Definition: qgssymbollayerutils.cpp:2311
QgsPointPatternFillSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsPointPatternFillSymbolLayer using the specified properties map containing symbol pro...
Definition: qgsfillsymbollayer.cpp:3537
QgsTemplatedLineSymbolLayerBase::intervalUnit
QgsUnitTypes::RenderUnit intervalUnit() const
Returns the units for the interval between symbols.
Definition: qgslinesymbollayer.h:608
QgsSymbolLayerUtils::ogrFeatureStyleBrush
static QString ogrFeatureStyleBrush(const QColor &fillColr)
Create ogr feature style string for brush.
Definition: qgssymbollayerutils.cpp:2913
qgslogger.h
Qgis::GradientSpread::Repeat
@ Repeat
Repeat gradient.
Qgis::RenderContextFlag::RenderingSubSymbol
@ RenderingSubSymbol
Set whenever a sub-symbol of a parent symbol is currently being rendered. Can be used during symbol a...
QgsSimpleFillSymbolLayer::dxfWidth
double dxfWidth(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets line width.
Definition: qgsfillsymbollayer.cpp:471
QgsSymbolLayer::PropertyOffsetX
@ PropertyOffsetX
Horizontal offset.
Definition: qgssymbollayer.h:195
QgsShapeburstFillSymbolLayer::useWholeShape
bool useWholeShape() const
Returns whether the shapeburst fill is set to cover the entire shape.
Definition: qgsfillsymbollayer.h:564
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:112
QgsShapeburstFillSymbolLayer::clone
QgsShapeburstFillSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgsfillsymbollayer.cpp:1638
QgsPointPatternFillSymbolLayer::mDisplacementYMapUnitScale
QgsMapUnitScale mDisplacementYMapUnitScale
Definition: qgsfillsymbollayer.h:2198
QgsSimpleFillSymbolLayer::dxfColor
QColor dxfColor(QgsSymbolRenderContext &context) const override
Gets color.
Definition: qgsfillsymbollayer.cpp:482
QgsRasterFillSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgsfillsymbollayer.cpp:4826
QgsCentroidFillSymbolLayer
Definition: qgsfillsymbollayer.h:2426
QgsRandomMarkerFillSymbolLayer::color
QColor color() const override
Returns the "representative" color of the symbol layer.
Definition: qgsfillsymbollayer.cpp:5047
QgsPointPatternFillSymbolLayer::mRandomDeviationX
double mRandomDeviationX
Definition: qgsfillsymbollayer.h:2206
QgsRenderContext::rendererScale
double rendererScale() const
Returns the renderer map scale.
Definition: qgsrendercontext.h:344
QgsPointPatternFillSymbolLayer::createFromSld
static QgsSymbolLayer * createFromSld(QDomElement &element)
Definition: qgsfillsymbollayer.cpp:4250
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:120
QgsImageFillSymbolLayer::mStrokeWidth
double mStrokeWidth
Stroke width.
Definition: qgsfillsymbollayer.h:850
QgsPointPatternFillSymbolLayer::mRandomDeviationY
double mRandomDeviationY
Definition: qgsfillsymbollayer.h:2209
QgsSymbolLayerUtils::decodePenStyle
static Qt::PenStyle decodePenStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:174
QgsCentroidFillSymbolLayer::mPointOnAllParts
bool mPointOnAllParts
Definition: qgsfillsymbollayer.h:2520
QgsSymbolLayerUtils::displacementFromSldElement
static bool displacementFromSldElement(QDomElement &element, QPointF &offset)
Definition: qgssymbollayerutils.cpp:2783
QgsShapeburstFillSymbolLayer::setColorRamp
void setColorRamp(QgsColorRamp *ramp)
Sets the color ramp used to draw the shapeburst fill.
Definition: qgsfillsymbollayer.cpp:1149
QgsPropertyCollection::isActive
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
Definition: qgspropertycollection.cpp:268
QgsImageFillSymbolLayer::mBrush
QBrush mBrush
Definition: qgsfillsymbollayer.h:845
QgsSimpleFillSymbolLayer::mPenJoinStyle
Qt::PenJoinStyle mPenJoinStyle
Definition: qgsfillsymbollayer.h:192
QgsShapeburstFillSymbolLayer::ignoreRings
bool ignoreRings() const
Returns whether the shapeburst fill is set to ignore polygon interior rings.
Definition: qgsfillsymbollayer.h:684
QgsCentroidFillSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsCentroidFillSymbolLayer using the specified properties map containing symbol propert...
Definition: qgsfillsymbollayer.cpp:4371
qgsfeedback.h
QgsPointPatternFillSymbolLayer::mMarkerSymbol
std::unique_ptr< QgsMarkerSymbol > mMarkerSymbol
Definition: qgsfillsymbollayer.h:2186
QgsSymbolLayer::PropertyDisplacementY
@ PropertyDisplacementY
Vertical displacement.
Definition: qgssymbollayer.h:178
QgsSymbolLayerUtils::decodeLineClipMode
static Qgis::LineClipMode decodeLineClipMode(const QString &string, bool *ok=nullptr)
Decodes a string representing a line clip mode.
Definition: qgssymbollayerutils.cpp:506
MathUtils::angle
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
QgsSymbolLayer::copyDataDefinedProperties
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
Definition: qgssymbollayer.cpp:483
QgsGeometry::area
double area() const
Returns the planar, 2-dimensional area of the geometry.
Definition: qgsgeometry.cpp:1880
QgsCentroidFillSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgsfillsymbollayer.cpp:4664
QgsSimpleFillSymbolLayer::mStrokeStyle
Qt::PenStyle mStrokeStyle
Definition: qgsfillsymbollayer.h:188
QgsSimpleFillSymbolLayer::QgsSimpleFillSymbolLayer
QgsSimpleFillSymbolLayer(const QColor &color=DEFAULT_SIMPLEFILL_COLOR, Qt::BrushStyle style=DEFAULT_SIMPLEFILL_STYLE, const QColor &strokeColor=DEFAULT_SIMPLEFILL_BORDERCOLOR, Qt::PenStyle strokeStyle=DEFAULT_SIMPLEFILL_BORDERSTYLE, double strokeWidth=DEFAULT_SIMPLEFILL_BORDERWIDTH, Qt::PenJoinStyle penJoinStyle=DEFAULT_SIMPLEFILL_JOINSTYLE)
Definition: qgsfillsymbollayer.cpp:55
QgsCentroidFillSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgsfillsymbollayer.cpp:4405
QgsSVGFillSymbolLayer::createFromSld
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsSVGFillSymbolLayer from a SLD element.
Definition: qgsfillsymbollayer.cpp:2314
qgssymbol.h
QgsPolygon::addInteriorRing
void addInteriorRing(QgsCurve *ring) override
Adds an interior ring to the geometry (takes ownership)
Definition: qgspolygon.cpp:188
QgsLinePatternFillSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgsfillsymbollayer.cpp:3031
QgsPathResolver
Resolves relative paths into absolute paths and vice versa. Used for writing.
Definition: qgspathresolver.h:31
QgsSymbolLayer::PropertyLineAngle
@ PropertyLineAngle
Line angle, or angle of hash lines for hash line symbols.
Definition: qgssymbollayer.h:159
QgsSVGFillSymbolLayer::resolvePaths
static void resolvePaths(QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving)
Turns relative paths in properties map to absolute when reading and vice versa when writing.
Definition: qgsfillsymbollayer.cpp:2013
QgsUnitTypes::RenderMapUnits
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:170
QgsPoint::x
double x
Definition: qgspoint.h:69
QgsPointPatternFillSymbolLayer::setClipMode
void setClipMode(Qgis::MarkerClipMode mode)
Sets the marker clipping mode, which defines how markers are clipped at the edges of shapes.
Definition: qgsfillsymbollayer.h:2032
QgsSymbolLayerUtils::decodeMapUnitScale
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Definition: qgssymbollayerutils.cpp:676
QgsPointPatternFillSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgsfillsymbollayer.cpp:4256
QgsSvgCache::svgAsImage
QImage svgAsImage(const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, bool &fitsInCache, double fixedAspectRatio=0, bool blocking=false, const QMap< QString, QString > &parameters=QMap< QString, QString >())
Returns an SVG drawing as a QImage.
Definition: qgssvgcache.cpp:125
qgsproject.h
QgsRenderContext::setScaleFactor
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:472
QgsSymbolLayer::PropertySecondaryColor
@ PropertySecondaryColor
Secondary color (eg for gradient fills)
Definition: qgssymbollayer.h:158
QgsSVGFillSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgsfillsymbollayer.cpp:1878
Qgis::SymbolType::Marker
@ Marker
Marker symbol.
QgsLinePatternFillSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsLinePatternFillSymbolLayer from a properties map.
Definition: qgsfillsymbollayer.cpp:2623
QgsSymbolLayer::SELECT_FILL_BORDER
static const bool SELECT_FILL_BORDER
Whether fill styles for selected features also highlight symbol stroke.
Definition: qgssymbollayer.h:663
QgsCentroidFillSymbolLayer::createFromSld
static QgsSymbolLayer * createFromSld(QDomElement &element)
Definition: qgsfillsymbollayer.cpp:4579
QgsPointPatternFillSymbolLayer::offsetX
double offsetX() const
Returns the horizontal offset values for points in the pattern.
Definition: qgsfillsymbollayer.h:1931
QgsCentroidFillSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgsfillsymbollayer.cpp:4672
QgsSymbolLayerUtils::decodeCoordinateReference
static Qgis::SymbolCoordinateReference decodeCoordinateReference(const QString &string, bool *ok=nullptr)
Decodes a string representing a symbol coordinate reference mode.
Definition: qgssymbollayerutils.cpp:392
QgsLinePatternFillSymbolLayer::applyDataDefinedSettings
void applyDataDefinedSettings(QgsSymbolRenderContext &context) override
Applies data defined settings prior to generating the fill symbol brush.
Definition: qgsfillsymbollayer.cpp:3347
QgsSimpleFillSymbolLayer::toSld
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
Definition: qgsfillsymbollayer.cpp:389
QgsGradientFillSymbolLayer::mGradientColorType
Qgis::GradientColorSource mGradientColorType
Definition: qgsfillsymbollayer.h:451
DEFAULT_SIMPLEFILL_BORDERCOLOR
#define DEFAULT_SIMPLEFILL_BORDERCOLOR
Definition: qgsfillsymbollayer.h:25
QgsGeometry::unaryUnion
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries)
Compute the unary union on a list of geometries.
Definition: qgsgeometry.cpp:3079
QgsAbstractPropertyCollection::valueAsColor
QColor valueAsColor(int key, const QgsExpressionContext &context, const QColor &defaultColor=QColor(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a color.
Definition: qgspropertycollection.cpp:54
QgsShapeburstFillSymbolLayer::~QgsShapeburstFillSymbolLayer
~QgsShapeburstFillSymbolLayer() override
QgsSymbolLayer::PropertyJoinStyle
@ PropertyJoinStyle
Line join style.
Definition: qgssymbollayer.h:157
qgslinesymbol.h
QgsCentroidFillSymbolLayer::mClipPoints
bool mClipPoints
Definition: qgsfillsymbollayer.h:2521
Qgis::MarkerClipMode::NoClipping
@ NoClipping
No clipping, render complete markers.
Qgis::GradientType::Linear
@ Linear
Linear gradient.
qgsmessagelog.h
QgsGeometry::isGeosValid
bool isGeosValid(Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Checks validity of the geometry using GEOS.
Definition: qgsgeometry.cpp:3019
QgsLinePatternFillSymbolLayer::QgsLinePatternFillSymbolLayer
QgsLinePatternFillSymbolLayer()
Definition: qgsfillsymbollayer.cpp:2497
QgsSymbolLayer::PropertyWidth
@ PropertyWidth
Symbol width.
Definition: qgssymbollayer.h:153
QgsPointPatternFillSymbolLayer::mOffsetXUnit
QgsUnitTypes::RenderUnit mOffsetXUnit
Definition: qgsfillsymbollayer.h:2200
QgsGradientFillSymbolLayer::gradientSpread
Qgis::GradientSpread gradientSpread() const
Returns the gradient spread mode, which controls how the gradient behaves outside of the predefined s...
Definition: qgsfillsymbollayer.h:326
Qgis::SymbolCoordinateReference::Viewport
@ Viewport
Relative to the whole viewport/output device.