QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgslinesymbollayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslinesymbollayer.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 "qgslinesymbollayer.h"
17 #include "qgscurve.h"
18 #include "qgscurvepolygon.h"
19 #include "qgsdxfexport.h"
20 #include "qgssymbollayerutils.h"
21 #include "qgsexpression.h"
22 #include "qgsrendercontext.h"
23 #include "qgslogger.h"
24 #include "qgsvectorlayer.h"
25 #include "qgsgeometrysimplifier.h"
26 #include "qgsunittypes.h"
27 #include "qgsproperty.h"
29 #include "qgsmarkersymbol.h"
30 #include "qgslinesymbol.h"
31 #include "qgsapplication.h"
32 #include "qgsimagecache.h"
33 #include "qgsfeedback.h"
34 #include "qgsimageoperation.h"
35 #include "qgscolorrampimpl.h"
36 
37 #include <algorithm>
38 #include <QPainter>
39 #include <QDomDocument>
40 #include <QDomElement>
41 
42 #include <cmath>
43 
44 QgsSimpleLineSymbolLayer::QgsSimpleLineSymbolLayer( const QColor &color, double width, Qt::PenStyle penStyle )
45  : mPenStyle( penStyle )
46 {
47  mColor = color;
48  mWidth = width;
49  mCustomDashVector << 5 << 2;
50 }
51 
53 
55 {
57  mWidthUnit = unit;
58  mOffsetUnit = unit;
59  mCustomDashPatternUnit = unit;
60  mDashPatternOffsetUnit = unit;
61  mTrimDistanceStartUnit = unit;
62  mTrimDistanceEndUnit = unit;
63 }
64 
66 {
68  if ( mWidthUnit != unit || mOffsetUnit != unit || mCustomDashPatternUnit != unit )
69  {
71  }
72  return unit;
73 }
74 
76 {
79 }
80 
82 {
84  mWidthMapUnitScale = scale;
85  mOffsetMapUnitScale = scale;
86  mCustomDashPatternMapUnitScale = scale;
87 }
88 
90 {
93  mOffsetMapUnitScale == mCustomDashPatternMapUnitScale )
94  {
95  return mWidthMapUnitScale;
96  }
97  return QgsMapUnitScale();
98 }
99 
101 {
104  Qt::PenStyle penStyle = DEFAULT_SIMPLELINE_PENSTYLE;
105 
106  if ( props.contains( QStringLiteral( "line_color" ) ) )
107  {
108  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "line_color" )].toString() );
109  }
110  else if ( props.contains( QStringLiteral( "outline_color" ) ) )
111  {
112  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "outline_color" )].toString() );
113  }
114  else if ( props.contains( QStringLiteral( "color" ) ) )
115  {
116  //pre 2.5 projects used "color"
117  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color" )].toString() );
118  }
119  if ( props.contains( QStringLiteral( "line_width" ) ) )
120  {
121  width = props[QStringLiteral( "line_width" )].toDouble();
122  }
123  else if ( props.contains( QStringLiteral( "outline_width" ) ) )
124  {
125  width = props[QStringLiteral( "outline_width" )].toDouble();
126  }
127  else if ( props.contains( QStringLiteral( "width" ) ) )
128  {
129  //pre 2.5 projects used "width"
130  width = props[QStringLiteral( "width" )].toDouble();
131  }
132  if ( props.contains( QStringLiteral( "line_style" ) ) )
133  {
134  penStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "line_style" )].toString() );
135  }
136  else if ( props.contains( QStringLiteral( "outline_style" ) ) )
137  {
138  penStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "outline_style" )].toString() );
139  }
140  else if ( props.contains( QStringLiteral( "penstyle" ) ) )
141  {
142  penStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "penstyle" )].toString() );
143  }
144 
146  if ( props.contains( QStringLiteral( "line_width_unit" ) ) )
147  {
148  l->setWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "line_width_unit" )].toString() ) );
149  }
150  else if ( props.contains( QStringLiteral( "outline_width_unit" ) ) )
151  {
152  l->setWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "outline_width_unit" )].toString() ) );
153  }
154  else if ( props.contains( QStringLiteral( "width_unit" ) ) )
155  {
156  //pre 2.5 projects used "width_unit"
157  l->setWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "width_unit" )].toString() ) );
158  }
159  if ( props.contains( QStringLiteral( "width_map_unit_scale" ) ) )
160  l->setWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "width_map_unit_scale" )].toString() ) );
161  if ( props.contains( QStringLiteral( "offset" ) ) )
162  l->setOffset( props[QStringLiteral( "offset" )].toDouble() );
163  if ( props.contains( QStringLiteral( "offset_unit" ) ) )
164  l->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )].toString() ) );
165  if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
166  l->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
167  if ( props.contains( QStringLiteral( "joinstyle" ) ) )
168  l->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( props[QStringLiteral( "joinstyle" )].toString() ) );
169  if ( props.contains( QStringLiteral( "capstyle" ) ) )
170  l->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( props[QStringLiteral( "capstyle" )].toString() ) );
171 
172  if ( props.contains( QStringLiteral( "use_custom_dash" ) ) )
173  {
174  l->setUseCustomDashPattern( props[QStringLiteral( "use_custom_dash" )].toInt() );
175  }
176  if ( props.contains( QStringLiteral( "customdash" ) ) )
177  {
178  l->setCustomDashVector( QgsSymbolLayerUtils::decodeRealVector( props[QStringLiteral( "customdash" )].toString() ) );
179  }
180  if ( props.contains( QStringLiteral( "customdash_unit" ) ) )
181  {
182  l->setCustomDashPatternUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "customdash_unit" )].toString() ) );
183  }
184  if ( props.contains( QStringLiteral( "customdash_map_unit_scale" ) ) )
185  {
186  l->setCustomDashPatternMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "customdash_map_unit_scale" )].toString() ) );
187  }
188 
189  if ( props.contains( QStringLiteral( "draw_inside_polygon" ) ) )
190  {
191  l->setDrawInsidePolygon( props[QStringLiteral( "draw_inside_polygon" )].toInt() );
192  }
193 
194  if ( props.contains( QStringLiteral( "ring_filter" ) ) )
195  {
196  l->setRingFilter( static_cast< RenderRingFilter>( props[QStringLiteral( "ring_filter" )].toInt() ) );
197  }
198 
199  if ( props.contains( QStringLiteral( "dash_pattern_offset" ) ) )
200  l->setDashPatternOffset( props[QStringLiteral( "dash_pattern_offset" )].toDouble() );
201  if ( props.contains( QStringLiteral( "dash_pattern_offset_unit" ) ) )
202  l->setDashPatternOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "dash_pattern_offset_unit" )].toString() ) );
203  if ( props.contains( QStringLiteral( "dash_pattern_offset_map_unit_scale" ) ) )
204  l->setDashPatternOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "dash_pattern_offset_map_unit_scale" )].toString() ) );
205 
206  if ( props.contains( QStringLiteral( "trim_distance_start" ) ) )
207  l->setTrimDistanceStart( props[QStringLiteral( "trim_distance_start" )].toDouble() );
208  if ( props.contains( QStringLiteral( "trim_distance_start_unit" ) ) )
209  l->setTrimDistanceStartUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "trim_distance_start_unit" )].toString() ) );
210  if ( props.contains( QStringLiteral( "trim_distance_start_map_unit_scale" ) ) )
211  l->setTrimDistanceStartMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "trim_distance_start_map_unit_scale" )].toString() ) );
212  if ( props.contains( QStringLiteral( "trim_distance_end" ) ) )
213  l->setTrimDistanceEnd( props[QStringLiteral( "trim_distance_end" )].toDouble() );
214  if ( props.contains( QStringLiteral( "trim_distance_end_unit" ) ) )
215  l->setTrimDistanceEndUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "trim_distance_end_unit" )].toString() ) );
216  if ( props.contains( QStringLiteral( "trim_distance_end_map_unit_scale" ) ) )
217  l->setTrimDistanceEndMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "trim_distance_end_map_unit_scale" )].toString() ) );
218 
219  if ( props.contains( QStringLiteral( "align_dash_pattern" ) ) )
220  l->setAlignDashPattern( props[ QStringLiteral( "align_dash_pattern" )].toInt() );
221 
222  if ( props.contains( QStringLiteral( "tweak_dash_pattern_on_corners" ) ) )
223  l->setTweakDashPatternOnCorners( props[ QStringLiteral( "tweak_dash_pattern_on_corners" )].toInt() );
224 
226 
227  return l;
228 }
229 
231 {
232  return QStringLiteral( "SimpleLine" );
233 }
234 
236 {
237  QColor penColor = mColor;
238  penColor.setAlphaF( mColor.alphaF() * context.opacity() );
239  mPen.setColor( penColor );
240  double scaledWidth = context.renderContext().convertToPainterUnits( mWidth, mWidthUnit, mWidthMapUnitScale );
241  mPen.setWidthF( scaledWidth );
242 
243  //note that Qt seems to have issues with scaling dash patterns with very small pen widths.
244  //treating the pen as having no less than a 1 pixel size avoids the worst of these issues
245  const double dashWidthDiv = std::max( 1.0, scaledWidth );
246  if ( mUseCustomDashPattern )
247  {
248  mPen.setStyle( Qt::CustomDashLine );
249 
250  //scale pattern vector
251 
252  QVector<qreal> scaledVector;
253  QVector<qreal>::const_iterator it = mCustomDashVector.constBegin();
254  for ( ; it != mCustomDashVector.constEnd(); ++it )
255  {
256  //the dash is specified in terms of pen widths, therefore the division
257  scaledVector << context.renderContext().convertToPainterUnits( ( *it ), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv;
258  }
259  mPen.setDashPattern( scaledVector );
260  }
261  else
262  {
263  mPen.setStyle( mPenStyle );
264  }
265 
266  if ( mDashPatternOffset && mPen.style() != Qt::SolidLine )
267  {
268  mPen.setDashOffset( context.renderContext().convertToPainterUnits( mDashPatternOffset, mDashPatternOffsetUnit, mDashPatternOffsetMapUnitScale ) / dashWidthDiv ) ;
269  }
270 
271  mPen.setJoinStyle( mPenJoinStyle );
272  mPen.setCapStyle( mPenCapStyle );
273 
274  mSelPen = mPen;
275  QColor selColor = context.renderContext().selectionColor();
276  if ( ! SELECTION_IS_OPAQUE )
277  selColor.setAlphaF( context.opacity() );
278  mSelPen.setColor( selColor );
279 }
280 
282 {
283  Q_UNUSED( context )
284 }
285 
286 void QgsSimpleLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
287 {
288  QPainter *p = context.renderContext().painter();
289  if ( !p )
290  {
291  return;
292  }
293 
294  QgsExpressionContextScope *scope = nullptr;
295  std::unique_ptr< QgsExpressionContextScopePopper > scopePopper;
296  if ( hasDataDefinedProperties() )
297  {
298  scope = new QgsExpressionContextScope();
299  scopePopper = std::make_unique< QgsExpressionContextScopePopper >( context.renderContext().expressionContext(), scope );
300  }
301 
302  if ( mDrawInsidePolygon )
303  p->save();
304 
305  switch ( mRingFilter )
306  {
307  case AllRings:
308  case ExteriorRingOnly:
309  {
310  if ( mDrawInsidePolygon )
311  {
312  //only drawing the line on the interior of the polygon, so set clip path for painter
313  QPainterPath clipPath;
314  clipPath.addPolygon( points );
315 
316  if ( rings )
317  {
318  //add polygon rings
319  for ( auto it = rings->constBegin(); it != rings->constEnd(); ++it )
320  {
321  QPolygonF ring = *it;
322  clipPath.addPolygon( ring );
323  }
324  }
325 
326  //use intersect mode, as a clip path may already exist (e.g., for composer maps)
327  p->setClipPath( clipPath, Qt::IntersectClip );
328  }
329 
330  if ( scope )
332 
333  renderPolyline( points, context );
334  }
335  break;
336 
337  case InteriorRingsOnly:
338  break;
339  }
340 
341  if ( rings )
342  {
343  switch ( mRingFilter )
344  {
345  case AllRings:
346  case InteriorRingsOnly:
347  {
348  mOffset = -mOffset; // invert the offset for rings!
349  int ringIndex = 1;
350  for ( const QPolygonF &ring : std::as_const( *rings ) )
351  {
352  if ( scope )
354 
355  renderPolyline( ring, context );
356  ringIndex++;
357  }
358  mOffset = -mOffset;
359  }
360  break;
361  case ExteriorRingOnly:
362  break;
363  }
364  }
365 
366  if ( mDrawInsidePolygon )
367  {
368  //restore painter to reset clip path
369  p->restore();
370  }
371 
372 }
373 
375 {
376  QPainter *p = context.renderContext().painter();
377  if ( !p )
378  {
379  return;
380  }
381 
382  QPolygonF points = pts;
383 
384  double startTrim = mTrimDistanceStart;
386  {
387  context.setOriginalValueVariable( startTrim );
389  }
390  double endTrim = mTrimDistanceEnd;
392  {
393  context.setOriginalValueVariable( endTrim );
395  }
396 
397  double totalLength = -1;
398  if ( mTrimDistanceStartUnit == QgsUnitTypes::RenderPercentage )
399  {
400  totalLength = QgsSymbolLayerUtils::polylineLength( points );
401  startTrim = startTrim * 0.01 * totalLength;
402  }
403  else
404  {
405  startTrim = context.renderContext().convertToPainterUnits( startTrim, mTrimDistanceStartUnit, mTrimDistanceStartMapUnitScale );
406  }
407  if ( mTrimDistanceEndUnit == QgsUnitTypes::RenderPercentage )
408  {
409  if ( totalLength < 0 ) // only recalculate if we didn't already work this out for the start distance!
410  totalLength = QgsSymbolLayerUtils::polylineLength( points );
411  endTrim = endTrim * 0.01 * totalLength;
412  }
413  else
414  {
415  endTrim = context.renderContext().convertToPainterUnits( endTrim, mTrimDistanceEndUnit, mTrimDistanceEndMapUnitScale );
416  }
417  if ( !qgsDoubleNear( startTrim, 0 ) || !qgsDoubleNear( endTrim, 0 ) )
418  {
419  points = QgsSymbolLayerUtils::polylineSubstring( points, startTrim, -endTrim );
420  }
421 
422  QColor penColor = mColor;
423  penColor.setAlphaF( mColor.alphaF() * context.opacity() );
424  mPen.setColor( penColor );
425 
426  double offset = mOffset;
427  applyDataDefinedSymbology( context, mPen, mSelPen, offset );
428 
429  const QPen pen = context.selected() ? mSelPen : mPen;
430 
431  if ( !pen.dashPattern().isEmpty() )
432  {
433  // check for a null (all 0) dash component, and shortcut out early if so -- these lines are rendered as "no pen"
434  const QVector<double> pattern = pen.dashPattern();
435  bool foundNonNull = false;
436  for ( int i = 0; i < pattern.size(); ++i )
437  {
438  if ( i % 2 == 0 && !qgsDoubleNear( pattern[i], 0 ) )
439  {
440  foundNonNull = true;
441  break;
442  }
443  }
444  if ( !foundNonNull )
445  return;
446  }
447 
448  p->setBrush( Qt::NoBrush );
449 
450  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #2 points).
451  std::unique_ptr< QgsScopedQPainterState > painterState;
452  if ( points.size() <= 2 &&
455  ( p->renderHints() & QPainter::Antialiasing ) )
456  {
457  painterState = std::make_unique< QgsScopedQPainterState >( p );
458  p->setRenderHint( QPainter::Antialiasing, false );
459  }
460 
461  const bool applyPatternTweaks = mAlignDashPattern
462  && ( pen.style() != Qt::SolidLine || !pen.dashPattern().empty() )
463  && pen.dashOffset() == 0;
464 
465  if ( qgsDoubleNear( offset, 0 ) )
466  {
467  if ( applyPatternTweaks )
468  {
469  drawPathWithDashPatternTweaks( p, points, pen );
470  }
471  else
472  {
473  p->setPen( pen );
474  QPainterPath path;
475  path.addPolygon( points );
476  p->drawPath( path );
477  }
478  }
479  else
480  {
481  double scaledOffset = context.renderContext().convertToPainterUnits( offset, mOffsetUnit, mOffsetMapUnitScale );
483  {
484  // rendering for symbol previews -- a size in meters in map units can't be calculated, so treat the size as millimeters
485  // and clamp it to a reasonable range. It's the best we can do in this situation!
486  scaledOffset = std::min( std::max( context.renderContext().convertToPainterUnits( offset, QgsUnitTypes::RenderMillimeters ), 3.0 ), 100.0 );
487  }
488 
489  QList<QPolygonF> mline = ::offsetLine( points, scaledOffset, context.originalGeometryType() != QgsWkbTypes::UnknownGeometry ? context.originalGeometryType() : QgsWkbTypes::LineGeometry );
490  for ( const QPolygonF &part : mline )
491  {
492  if ( applyPatternTweaks )
493  {
494  drawPathWithDashPatternTweaks( p, part, pen );
495  }
496  else
497  {
498  p->setPen( pen );
499  QPainterPath path;
500  path.addPolygon( part );
501  p->drawPath( path );
502  }
503  }
504  }
505 }
506 
508 {
509  QVariantMap map;
510  map[QStringLiteral( "line_color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
511  map[QStringLiteral( "line_width" )] = QString::number( mWidth );
512  map[QStringLiteral( "line_width_unit" )] = QgsUnitTypes::encodeUnit( mWidthUnit );
513  map[QStringLiteral( "width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mWidthMapUnitScale );
514  map[QStringLiteral( "line_style" )] = QgsSymbolLayerUtils::encodePenStyle( mPenStyle );
515  map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
516  map[QStringLiteral( "capstyle" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
517  map[QStringLiteral( "offset" )] = QString::number( mOffset );
518  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
519  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
520  map[QStringLiteral( "use_custom_dash" )] = ( mUseCustomDashPattern ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
521  map[QStringLiteral( "customdash" )] = QgsSymbolLayerUtils::encodeRealVector( mCustomDashVector );
522  map[QStringLiteral( "customdash_unit" )] = QgsUnitTypes::encodeUnit( mCustomDashPatternUnit );
523  map[QStringLiteral( "customdash_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mCustomDashPatternMapUnitScale );
524  map[QStringLiteral( "dash_pattern_offset" )] = QString::number( mDashPatternOffset );
525  map[QStringLiteral( "dash_pattern_offset_unit" )] = QgsUnitTypes::encodeUnit( mDashPatternOffsetUnit );
526  map[QStringLiteral( "dash_pattern_offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mDashPatternOffsetMapUnitScale );
527  map[QStringLiteral( "trim_distance_start" )] = QString::number( mTrimDistanceStart );
528  map[QStringLiteral( "trim_distance_start_unit" )] = QgsUnitTypes::encodeUnit( mTrimDistanceStartUnit );
529  map[QStringLiteral( "trim_distance_start_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mTrimDistanceStartMapUnitScale );
530  map[QStringLiteral( "trim_distance_end" )] = QString::number( mTrimDistanceEnd );
531  map[QStringLiteral( "trim_distance_end_unit" )] = QgsUnitTypes::encodeUnit( mTrimDistanceEndUnit );
532  map[QStringLiteral( "trim_distance_end_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mTrimDistanceEndMapUnitScale );
533  map[QStringLiteral( "draw_inside_polygon" )] = ( mDrawInsidePolygon ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
534  map[QStringLiteral( "ring_filter" )] = QString::number( static_cast< int >( mRingFilter ) );
535  map[QStringLiteral( "align_dash_pattern" )] = mAlignDashPattern ? QStringLiteral( "1" ) : QStringLiteral( "0" );
536  map[QStringLiteral( "tweak_dash_pattern_on_corners" )] = mPatternCartographicTweakOnSharpCorners ? QStringLiteral( "1" ) : QStringLiteral( "0" );
537  return map;
538 }
539 
541 {
543  l->setWidthUnit( mWidthUnit );
547  l->setCustomDashPatternUnit( mCustomDashPatternUnit );
548  l->setCustomDashPatternMapUnitScale( mCustomDashPatternMapUnitScale );
549  l->setOffset( mOffset );
550  l->setPenJoinStyle( mPenJoinStyle );
551  l->setPenCapStyle( mPenCapStyle );
552  l->setUseCustomDashPattern( mUseCustomDashPattern );
553  l->setCustomDashVector( mCustomDashVector );
554  l->setDrawInsidePolygon( mDrawInsidePolygon );
556  l->setDashPatternOffset( mDashPatternOffset );
557  l->setDashPatternOffsetUnit( mDashPatternOffsetUnit );
558  l->setDashPatternOffsetMapUnitScale( mDashPatternOffsetMapUnitScale );
559  l->setTrimDistanceStart( mTrimDistanceStart );
560  l->setTrimDistanceStartUnit( mTrimDistanceStartUnit );
561  l->setTrimDistanceStartMapUnitScale( mTrimDistanceStartMapUnitScale );
562  l->setTrimDistanceEnd( mTrimDistanceEnd );
563  l->setTrimDistanceEndUnit( mTrimDistanceEndUnit );
564  l->setTrimDistanceEndMapUnitScale( mTrimDistanceEndMapUnitScale );
565  l->setAlignDashPattern( mAlignDashPattern );
566  l->setTweakDashPatternOnCorners( mPatternCartographicTweakOnSharpCorners );
567 
569  copyPaintEffect( l );
570  return l;
571 }
572 
573 void QgsSimpleLineSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
574 {
575  if ( mPenStyle == Qt::NoPen )
576  return;
577 
578  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:LineSymbolizer" ) );
579  if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
580  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
581  element.appendChild( symbolizerElem );
582 
583  // <Geometry>
584  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
585 
586  // <Stroke>
587  QDomElement strokeElem = doc.createElement( QStringLiteral( "se:Stroke" ) );
588  symbolizerElem.appendChild( strokeElem );
589 
590  Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
592  QVector<qreal> customDashVector = QgsSymbolLayerUtils::rescaleUom( mCustomDashVector, mCustomDashPatternUnit, props );
594  &mPenJoinStyle, &mPenCapStyle, &customDashVector );
595 
596  // <se:PerpendicularOffset>
597  if ( !qgsDoubleNear( mOffset, 0.0 ) )
598  {
599  QDomElement perpOffsetElem = doc.createElement( QStringLiteral( "se:PerpendicularOffset" ) );
601  perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
602  symbolizerElem.appendChild( perpOffsetElem );
603  }
604 }
605 
606 QString QgsSimpleLineSymbolLayer::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
607 {
608  if ( mUseCustomDashPattern )
609  {
610  return QgsSymbolLayerUtils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor,
611  mPen.color(), mPenJoinStyle,
612  mPenCapStyle, mOffset, &mCustomDashVector );
613  }
614  else
615  {
616  return QgsSymbolLayerUtils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor, mPen.color(), mPenJoinStyle,
617  mPenCapStyle, mOffset );
618  }
619 }
620 
622 {
623  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
624 
625  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
626  if ( strokeElem.isNull() )
627  return nullptr;
628 
629  Qt::PenStyle penStyle;
630  QColor color;
631  double width;
632  Qt::PenJoinStyle penJoinStyle;
633  Qt::PenCapStyle penCapStyle;
634  QVector<qreal> customDashVector;
635 
636  if ( !QgsSymbolLayerUtils::lineFromSld( strokeElem, penStyle,
637  color, width,
639  &customDashVector ) )
640  return nullptr;
641 
642  double offset = 0.0;
643  QDomElement perpOffsetElem = element.firstChildElement( QStringLiteral( "PerpendicularOffset" ) );
644  if ( !perpOffsetElem.isNull() )
645  {
646  bool ok;
647  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
648  if ( ok )
649  offset = d;
650  }
651 
652  double scaleFactor = 1.0;
653  const QString uom = element.attribute( QStringLiteral( "uom" ) );
654  QgsUnitTypes::RenderUnit sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( uom, &scaleFactor );
655  width = width * scaleFactor;
656  offset = offset * scaleFactor;
657 
659  l->setOutputUnit( sldUnitSize );
660  l->setOffset( offset );
663  l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
665  return l;
666 }
667 
668 void QgsSimpleLineSymbolLayer::applyDataDefinedSymbology( QgsSymbolRenderContext &context, QPen &pen, QPen &selPen, double &offset )
669 {
670  if ( !dataDefinedProperties().hasActiveProperties() )
671  return; // shortcut
672 
673  //data defined properties
674  bool hasStrokeWidthExpression = false;
676  {
677  context.setOriginalValueVariable( mWidth );
678  double scaledWidth = context.renderContext().convertToPainterUnits(
681  pen.setWidthF( scaledWidth );
682  selPen.setWidthF( scaledWidth );
683  hasStrokeWidthExpression = true;
684  }
685 
686  //color
688  {
690 
692  penColor.setAlphaF( context.opacity() * penColor.alphaF() );
693  pen.setColor( penColor );
694  }
695 
696  //offset
698  {
701  }
702 
703  //dash dot vector
704 
705  //note that Qt seems to have issues with scaling dash patterns with very small pen widths.
706  //treating the pen as having no less than a 1 pixel size avoids the worst of these issues
707  const double dashWidthDiv = std::max( hasStrokeWidthExpression ? pen.widthF() : mPen.widthF(), 1.0 );
708 
710  {
711  QVector<qreal> dashVector;
713  if ( !exprVal.isNull() )
714  {
715  QStringList dashList = exprVal.toString().split( ';' );
716  QStringList::const_iterator dashIt = dashList.constBegin();
717  for ( ; dashIt != dashList.constEnd(); ++dashIt )
718  {
719  dashVector.push_back( context.renderContext().convertToPainterUnits( dashIt->toDouble(), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv );
720  }
721  pen.setDashPattern( dashVector );
722  }
723  }
724  else if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) && mUseCustomDashPattern )
725  {
726  //re-scale pattern vector after data defined pen width was applied
727 
728  QVector<qreal> scaledVector;
729  for ( double v : std::as_const( mCustomDashVector ) )
730  {
731  //the dash is specified in terms of pen widths, therefore the division
732  scaledVector << context.renderContext().convertToPainterUnits( v, mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv;
733  }
734  mPen.setDashPattern( scaledVector );
735  }
736 
737  // dash pattern offset
738  double patternOffset = mDashPatternOffset;
739  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyDashPatternOffset ) && pen.style() != Qt::SolidLine )
740  {
741  context.setOriginalValueVariable( patternOffset );
743  pen.setDashOffset( context.renderContext().convertToPainterUnits( patternOffset, mDashPatternOffsetUnit, mDashPatternOffsetMapUnitScale ) / dashWidthDiv );
744  }
745 
746  //line style
748  {
751  if ( !exprVal.isNull() )
752  pen.setStyle( QgsSymbolLayerUtils::decodePenStyle( exprVal.toString() ) );
753  }
754 
755  //join style
757  {
760  if ( !exprVal.isNull() )
761  pen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( exprVal.toString() ) );
762  }
763 
764  //cap style
766  {
769  if ( !exprVal.isNull() )
770  pen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( exprVal.toString() ) );
771  }
772 }
773 
774 void QgsSimpleLineSymbolLayer::drawPathWithDashPatternTweaks( QPainter *painter, const QPolygonF &points, QPen pen ) const
775 {
776  if ( pen.dashPattern().empty() || points.size() < 2 )
777  return;
778 
779  QVector< qreal > sourcePattern = pen.dashPattern();
780  const double dashWidthDiv = std::max( 1.0001, pen.widthF() );
781  // back to painter units
782  for ( int i = 0; i < sourcePattern.size(); ++ i )
783  sourcePattern[i] *= pen.widthF();
784 
785  if ( pen.widthF() <= 1.0 )
786  pen.setWidthF( 1.0001 );
787 
788  QVector< qreal > buffer;
789  QPolygonF bufferedPoints;
790  QPolygonF previousSegmentBuffer;
791  // we iterate through the line points, building a custom dash pattern and adding it to the buffer
792  // as soon as we hit a sharp bend, we scale the buffered pattern in order to nicely place a dash component over the bend
793  // and then append the buffer to the output pattern.
794 
795  auto ptIt = points.constBegin();
796  double totalBufferLength = 0;
797  int patternIndex = 0;
798  double currentRemainingDashLength = 0;
799  double currentRemainingGapLength = 0;
800 
801  auto compressPattern = []( const QVector< qreal > &buffer ) -> QVector< qreal >
802  {
803  QVector< qreal > result;
804  result.reserve( buffer.size() );
805  for ( auto it = buffer.begin(); it != buffer.end(); )
806  {
807  qreal dash = *it++;
808  qreal gap = *it++;
809  while ( dash == 0 && !result.empty() )
810  {
811  result.last() += gap;
812 
813  if ( it == buffer.end() )
814  return result;
815  dash = *it++;
816  gap = *it++;
817  }
818  while ( gap == 0 && it != buffer.end() )
819  {
820  dash += *it++;
821  gap = *it++;
822  }
823  result << dash << gap;
824  }
825  return result;
826  };
827 
828  double currentBufferLineLength = 0;
829  auto flushBuffer = [pen, painter, &buffer, &bufferedPoints, &previousSegmentBuffer, &currentRemainingDashLength, &currentRemainingGapLength, &currentBufferLineLength, &totalBufferLength,
830  dashWidthDiv, &compressPattern]( QPointF * nextPoint )
831  {
832  if ( buffer.empty() || bufferedPoints.size() < 2 )
833  {
834  return;
835  }
836 
837  if ( currentRemainingDashLength )
838  {
839  // ended midway through a dash -- we want to finish this off
840  buffer << currentRemainingDashLength << 0.0;
841  totalBufferLength += currentRemainingDashLength;
842  }
843  QVector< qreal > compressed = compressPattern( buffer );
844  if ( !currentRemainingDashLength )
845  {
846  // ended midway through a gap -- we don't want this, we want to end at previous dash
847  totalBufferLength -= compressed.last();
848  compressed.last() = 0;
849  }
850 
851  // rescale buffer for final bit of line -- we want to end at the end of a dash, not a gap
852  const double scaleFactor = currentBufferLineLength / totalBufferLength;
853 
854  bool shouldFlushPreviousSegmentBuffer = false;
855 
856  if ( !previousSegmentBuffer.empty() )
857  {
858  // add first dash from current buffer
859  QPolygonF firstDashSubstring = QgsSymbolLayerUtils::polylineSubstring( bufferedPoints, 0, compressed.first() * scaleFactor );
860  if ( !firstDashSubstring.empty() )
861  QgsSymbolLayerUtils::appendPolyline( previousSegmentBuffer, firstDashSubstring );
862 
863  // then we skip over the first dash and gap for this segment
864  bufferedPoints = QgsSymbolLayerUtils::polylineSubstring( bufferedPoints, ( compressed.first() + compressed.at( 1 ) ) * scaleFactor, 0 );
865 
866  compressed = compressed.mid( 2 );
867  shouldFlushPreviousSegmentBuffer = !compressed.empty();
868  }
869 
870  if ( !previousSegmentBuffer.empty() && ( shouldFlushPreviousSegmentBuffer || !nextPoint ) )
871  {
872  QPen adjustedPen = pen;
873  adjustedPen.setStyle( Qt::SolidLine );
874  painter->setPen( adjustedPen );
875  QPainterPath path;
876  path.addPolygon( previousSegmentBuffer );
877  painter->drawPath( path );
878  previousSegmentBuffer.clear();
879  }
880 
881  double finalDash = 0;
882  if ( nextPoint )
883  {
884  // sharp bend:
885  // 1. rewind buffered points line by final dash and gap length
886  // (later) 2. draw the bend with a solid line of length 2 * final dash size
887 
888  if ( !compressed.empty() )
889  {
890  finalDash = compressed.at( compressed.size() - 2 );
891  const double finalGap = compressed.size() > 2 ? compressed.at( compressed.size() - 3 ) : 0;
892 
893  const QPolygonF thisPoints = bufferedPoints;
894  bufferedPoints = QgsSymbolLayerUtils::polylineSubstring( thisPoints, 0, -( finalDash + finalGap ) * scaleFactor );
895  previousSegmentBuffer = QgsSymbolLayerUtils::polylineSubstring( thisPoints, - finalDash * scaleFactor, 0 );
896  }
897  else
898  {
899  previousSegmentBuffer << bufferedPoints;
900  }
901  }
902 
903  currentBufferLineLength = 0;
904  currentRemainingDashLength = 0;
905  currentRemainingGapLength = 0;
906  totalBufferLength = 0;
907  buffer.clear();
908 
909  if ( !bufferedPoints.empty() && ( !compressed.empty() || !nextPoint ) )
910  {
911  QPen adjustedPen = pen;
912  if ( !compressed.empty() )
913  {
914  // maximum size of dash pattern is 32 elements
915  compressed = compressed.mid( 0, 32 );
916  std::for_each( compressed.begin(), compressed.end(), [scaleFactor, dashWidthDiv]( qreal & element ) { element *= scaleFactor / dashWidthDiv; } );
917  adjustedPen.setDashPattern( compressed );
918  }
919  else
920  {
921  adjustedPen.setStyle( Qt::SolidLine );
922  }
923 
924  painter->setPen( adjustedPen );
925  QPainterPath path;
926  path.addPolygon( bufferedPoints );
927  painter->drawPath( path );
928  }
929 
930  bufferedPoints.clear();
931  };
932 
933  QPointF p1;
934  QPointF p2 = *ptIt;
935  ptIt++;
936  bufferedPoints << p2;
937  for ( ; ptIt != points.constEnd(); ++ptIt )
938  {
939  p1 = *ptIt;
940  if ( qgsDoubleNear( p1.y(), p2.y() ) && qgsDoubleNear( p1.x(), p2.x() ) )
941  {
942  continue;
943  }
944 
945  double remainingSegmentDistance = std::sqrt( std::pow( p2.x() - p1.x(), 2.0 ) + std::pow( p2.y() - p1.y(), 2.0 ) );
946  currentBufferLineLength += remainingSegmentDistance;
947  while ( true )
948  {
949  // handle currentRemainingDashLength/currentRemainingGapLength
950  if ( currentRemainingDashLength > 0 )
951  {
952  // bit more of dash to insert
953  if ( remainingSegmentDistance >= currentRemainingDashLength )
954  {
955  // all of dash fits in
956  buffer << currentRemainingDashLength << 0.0;
957  totalBufferLength += currentRemainingDashLength;
958  remainingSegmentDistance -= currentRemainingDashLength;
959  patternIndex++;
960  currentRemainingDashLength = 0.0;
961  currentRemainingGapLength = sourcePattern.at( patternIndex );
962  }
963  else
964  {
965  // only part of remaining dash fits in
966  buffer << remainingSegmentDistance << 0.0;
967  totalBufferLength += remainingSegmentDistance;
968  currentRemainingDashLength -= remainingSegmentDistance;
969  break;
970  }
971  }
972  if ( currentRemainingGapLength > 0 )
973  {
974  // bit more of gap to insert
975  if ( remainingSegmentDistance >= currentRemainingGapLength )
976  {
977  // all of gap fits in
978  buffer << 0.0 << currentRemainingGapLength;
979  totalBufferLength += currentRemainingGapLength;
980  remainingSegmentDistance -= currentRemainingGapLength;
981  currentRemainingGapLength = 0.0;
982  patternIndex++;
983  }
984  else
985  {
986  // only part of remaining gap fits in
987  buffer << 0.0 << remainingSegmentDistance;
988  totalBufferLength += remainingSegmentDistance;
989  currentRemainingGapLength -= remainingSegmentDistance;
990  break;
991  }
992  }
993 
994  if ( patternIndex >= sourcePattern.size() )
995  patternIndex = 0;
996 
997  const double nextPatternDashLength = sourcePattern.at( patternIndex );
998  const double nextPatternGapLength = sourcePattern.at( patternIndex + 1 );
999  if ( nextPatternDashLength + nextPatternGapLength <= remainingSegmentDistance )
1000  {
1001  buffer << nextPatternDashLength << nextPatternGapLength;
1002  remainingSegmentDistance -= nextPatternDashLength + nextPatternGapLength;
1003  totalBufferLength += nextPatternDashLength + nextPatternGapLength;
1004  patternIndex += 2;
1005  }
1006  else if ( nextPatternDashLength <= remainingSegmentDistance )
1007  {
1008  // can fit in "dash", but not "gap"
1009  buffer << nextPatternDashLength << remainingSegmentDistance - nextPatternDashLength;
1010  totalBufferLength += remainingSegmentDistance;
1011  currentRemainingGapLength = nextPatternGapLength - ( remainingSegmentDistance - nextPatternDashLength );
1012  currentRemainingDashLength = 0;
1013  patternIndex++;
1014  break;
1015  }
1016  else
1017  {
1018  // can't fit in "dash"
1019  buffer << remainingSegmentDistance << 0.0;
1020  totalBufferLength += remainingSegmentDistance;
1021  currentRemainingGapLength = 0;
1022  currentRemainingDashLength = nextPatternDashLength - remainingSegmentDistance;
1023  break;
1024  }
1025  }
1026 
1027  bufferedPoints << p1;
1028  if ( mPatternCartographicTweakOnSharpCorners && ptIt + 1 != points.constEnd() )
1029  {
1030  QPointF nextPoint = *( ptIt + 1 );
1031 
1032  // extreme angles form more than 45 degree angle at a node
1033  if ( QgsSymbolLayerUtils::isSharpCorner( p2, p1, nextPoint ) )
1034  {
1035  // extreme angle. Rescale buffer and flush
1036  flushBuffer( &nextPoint );
1037  bufferedPoints << p1;
1038  // restart the line with the full length of the most recent dash element -- see
1039  // "Cartographic Generalization" (Swiss Society of Cartography) p33, example #8
1040  if ( patternIndex % 2 == 1 )
1041  {
1042  patternIndex--;
1043  }
1044  currentRemainingDashLength = sourcePattern.at( patternIndex );
1045  }
1046  }
1047 
1048  p2 = p1;
1049  }
1050 
1051  flushBuffer( nullptr );
1052  if ( !previousSegmentBuffer.empty() )
1053  {
1054  QPen adjustedPen = pen;
1055  adjustedPen.setStyle( Qt::SolidLine );
1056  painter->setPen( adjustedPen );
1057  QPainterPath path;
1058  path.addPolygon( previousSegmentBuffer );
1059  painter->drawPath( path );
1060  previousSegmentBuffer.clear();
1061  }
1062 }
1063 
1065 {
1066  if ( mDrawInsidePolygon )
1067  {
1068  //set to clip line to the interior of polygon, so we expect no bleed
1069  return 0;
1070  }
1071  else
1072  {
1073  return context.convertToPainterUnits( ( mWidth / 2.0 ), mWidthUnit, mWidthMapUnitScale ) +
1075  }
1076 }
1077 
1079 {
1080  unit = mCustomDashPatternUnit;
1081  return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>();
1082 }
1083 
1085 {
1086  return mPenStyle;
1087 }
1088 
1090 {
1091  double width = mWidth;
1093  {
1094  context.setOriginalValueVariable( mWidth );
1096  }
1097 
1100  {
1102  }
1103  return width;
1104 }
1105 
1107 {
1109  {
1112  }
1113  return mColor;
1114 }
1115 
1117 {
1118  return mPenStyle != Qt::SolidLine || mUseCustomDashPattern;
1119 }
1120 
1122 {
1123  return mAlignDashPattern;
1124 }
1125 
1127 {
1128  mAlignDashPattern = enabled;
1129 }
1130 
1132 {
1133  return mPatternCartographicTweakOnSharpCorners;
1134 }
1135 
1137 {
1138  mPatternCartographicTweakOnSharpCorners = enabled;
1139 }
1140 
1142 {
1143  double offset = mOffset;
1144 
1146  {
1147  context.setOriginalValueVariable( mOffset );
1149  }
1150 
1153  {
1155  }
1156  return -offset; //direction seems to be inverse to symbology offset
1157 }
1158 
1160 
1162 
1163 class MyLine
1164 {
1165  public:
1166  MyLine( QPointF p1, QPointF p2 )
1167  : mVertical( false )
1168  , mIncreasing( false )
1169  , mT( 0.0 )
1170  , mLength( 0.0 )
1171  {
1172  if ( p1 == p2 )
1173  return; // invalid
1174 
1175  // tangent and direction
1176  if ( qgsDoubleNear( p1.x(), p2.x() ) )
1177  {
1178  // vertical line - tangent undefined
1179  mVertical = true;
1180  mIncreasing = ( p2.y() > p1.y() );
1181  }
1182  else
1183  {
1184  mVertical = false;
1185  mT = ( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
1186  mIncreasing = ( p2.x() > p1.x() );
1187  }
1188 
1189  // length
1190  double x = ( p2.x() - p1.x() );
1191  double y = ( p2.y() - p1.y() );
1192  mLength = std::sqrt( x * x + y * y );
1193  }
1194 
1195  // return angle in radians
1196  double angle()
1197  {
1198  double a = ( mVertical ? M_PI_2 : std::atan( mT ) );
1199 
1200  if ( !mIncreasing )
1201  a += M_PI;
1202  return a;
1203  }
1204 
1205  // return difference for x,y when going along the line with specified interval
1206  QPointF diffForInterval( double interval )
1207  {
1208  if ( mVertical )
1209  return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
1210 
1211  double alpha = std::atan( mT );
1212  double dx = std::cos( alpha ) * interval;
1213  double dy = std::sin( alpha ) * interval;
1214  return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
1215  }
1216 
1217  double length() const { return mLength; }
1218 
1219  protected:
1220  bool mVertical;
1221  bool mIncreasing;
1222  double mT;
1223  double mLength;
1224 };
1225 
1227 
1228 //
1229 // QgsTemplatedLineSymbolLayerBase
1230 //
1232  : mRotateSymbols( rotateSymbol )
1233  , mInterval( interval )
1234 {
1235 
1236 }
1237 
1239 {
1240  if ( mPlacements & Qgis::MarkerLinePlacement::Interval )
1242  else if ( mPlacements & Qgis::MarkerLinePlacement::Vertex )
1244  else if ( ( mPlacements & Qgis::MarkerLinePlacement::FirstVertex )
1245  && ( mPlacements & Qgis::MarkerLinePlacement::InnerVertices )
1246  && ( mPlacements & Qgis::MarkerLinePlacement::LastVertex ) )
1247  return Qgis::MarkerLinePlacement::Vertex; // retain round trip for deprecated old API
1248  else if ( mPlacements & Qgis::MarkerLinePlacement::LastVertex )
1250  else if ( mPlacements & Qgis::MarkerLinePlacement::FirstVertex )
1252  else if ( mPlacements & Qgis::MarkerLinePlacement::CentralPoint )
1254  else if ( mPlacements & Qgis::MarkerLinePlacement::CurvePoint )
1256  else if ( mPlacements & Qgis::MarkerLinePlacement::SegmentCenter )
1258  else
1260 }
1261 
1263 {
1264  mPlacements = placement;
1265 }
1266 
1268 
1270 {
1271  if ( mRenderingFeature )
1272  {
1273  // in the middle of rendering a possibly multi-part feature, so we collect all the parts and defer the actual rendering
1274  // until after we've received the final part
1275  mFeatureSymbolOpacity = context.opacity();
1276  mCurrentFeatureIsSelected = context.selected();
1277  }
1278 
1279  double offset = mOffset;
1280 
1282  {
1283  context.setOriginalValueVariable( mOffset );
1285  }
1286 
1287  Qgis::MarkerLinePlacements placements = QgsTemplatedLineSymbolLayerBase::placements();
1288 
1290  {
1292  if ( !exprVal.isNull() )
1293  {
1294  QString placementString = exprVal.toString();
1295  if ( placementString.compare( QLatin1String( "interval" ), Qt::CaseInsensitive ) == 0 )
1296  {
1298  }
1299  else if ( placementString.compare( QLatin1String( "vertex" ), Qt::CaseInsensitive ) == 0 )
1300  {
1302  }
1303  else if ( placementString.compare( QLatin1String( "innervertices" ), Qt::CaseInsensitive ) == 0 )
1304  {
1306  }
1307  else if ( placementString.compare( QLatin1String( "lastvertex" ), Qt::CaseInsensitive ) == 0 )
1308  {
1310  }
1311  else if ( placementString.compare( QLatin1String( "firstvertex" ), Qt::CaseInsensitive ) == 0 )
1312  {
1314  }
1315  else if ( placementString.compare( QLatin1String( "centerpoint" ), Qt::CaseInsensitive ) == 0 )
1316  {
1318  }
1319  else if ( placementString.compare( QLatin1String( "curvepoint" ), Qt::CaseInsensitive ) == 0 )
1320  {
1322  }
1323  else if ( placementString.compare( QLatin1String( "segmentcenter" ), Qt::CaseInsensitive ) == 0 )
1324  {
1326  }
1327  else
1328  {
1330  }
1331  }
1332  }
1333 
1334  QgsScopedQPainterState painterState( context.renderContext().painter() );
1335 
1336  double averageOver = mAverageAngleLength;
1338  {
1339  context.setOriginalValueVariable( mAverageAngleLength );
1341  }
1342  averageOver = context.renderContext().convertToPainterUnits( averageOver, mAverageAngleLengthUnit, mAverageAngleLengthMapUnitScale ) / 2.0;
1343 
1344  if ( qgsDoubleNear( offset, 0.0 ) )
1345  {
1347  renderPolylineInterval( points, context, averageOver );
1349  renderPolylineCentral( points, context, averageOver );
1351  renderPolylineVertex( points, context, Qgis::MarkerLinePlacement::Vertex );
1353  && ( mPlaceOnEveryPart || !mHasRenderedFirstPart ) )
1354  {
1355  renderPolylineVertex( points, context, Qgis::MarkerLinePlacement::FirstVertex );
1356  mHasRenderedFirstPart = mRenderingFeature;
1357  }
1359  renderPolylineVertex( points, context, Qgis::MarkerLinePlacement::InnerVertices );
1361  renderPolylineVertex( points, context, Qgis::MarkerLinePlacement::CurvePoint );
1363  renderPolylineVertex( points, context, Qgis::MarkerLinePlacement::SegmentCenter );
1365  renderPolylineVertex( points, context, Qgis::MarkerLinePlacement::LastVertex );
1366  }
1367  else
1368  {
1369  context.renderContext().setGeometry( nullptr ); //always use segmented geometry with offset
1371 
1372  for ( int part = 0; part < mline.count(); ++part )
1373  {
1374  const QPolygonF &points2 = mline[ part ];
1375 
1377  renderPolylineInterval( points2, context, averageOver );
1379  renderPolylineCentral( points2, context, averageOver );
1381  renderPolylineVertex( points2, context, Qgis::MarkerLinePlacement::Vertex );
1383  renderPolylineVertex( points2, context, Qgis::MarkerLinePlacement::InnerVertices );
1385  renderPolylineVertex( points2, context, Qgis::MarkerLinePlacement::LastVertex );
1387  && ( mPlaceOnEveryPart || !mHasRenderedFirstPart ) )
1388  {
1389  renderPolylineVertex( points2, context, Qgis::MarkerLinePlacement::FirstVertex );
1390  mHasRenderedFirstPart = mRenderingFeature;
1391  }
1393  renderPolylineVertex( points2, context, Qgis::MarkerLinePlacement::CurvePoint );
1395  renderPolylineVertex( points2, context, Qgis::MarkerLinePlacement::SegmentCenter );
1396  }
1397  }
1398 }
1399 
1400 void QgsTemplatedLineSymbolLayerBase::renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
1401 {
1402  const QgsCurvePolygon *curvePolygon = dynamic_cast<const QgsCurvePolygon *>( context.renderContext().geometry() );
1403 
1404  if ( curvePolygon )
1405  {
1406  context.renderContext().setGeometry( curvePolygon->exteriorRing() );
1407  }
1408 
1409  QgsExpressionContextScope *scope = nullptr;
1410  std::unique_ptr< QgsExpressionContextScopePopper > scopePopper;
1411  if ( hasDataDefinedProperties() )
1412  {
1413  scope = new QgsExpressionContextScope();
1414  scopePopper = std::make_unique< QgsExpressionContextScopePopper >( context.renderContext().expressionContext(), scope );
1415  }
1416 
1417  switch ( mRingFilter )
1418  {
1419  case AllRings:
1420  case ExteriorRingOnly:
1421  {
1422  if ( scope )
1424 
1425  renderPolyline( points, context );
1426  break;
1427  }
1428  case InteriorRingsOnly:
1429  break;
1430  }
1431 
1432  if ( rings )
1433  {
1434  switch ( mRingFilter )
1435  {
1436  case AllRings:
1437  case InteriorRingsOnly:
1438  {
1439  mOffset = -mOffset; // invert the offset for rings!
1440  for ( int i = 0; i < rings->size(); ++i )
1441  {
1442  if ( curvePolygon )
1443  {
1444  context.renderContext().setGeometry( curvePolygon->interiorRing( i ) );
1445  }
1446  if ( scope )
1448 
1449  renderPolyline( rings->at( i ), context );
1450  }
1451  mOffset = -mOffset;
1452  }
1453  break;
1454  case ExteriorRingOnly:
1455  break;
1456  }
1457  }
1458 }
1459 
1461 {
1463  if ( intervalUnit() != unit || mOffsetUnit != unit || offsetAlongLineUnit() != unit )
1464  {
1466  }
1467  return unit;
1468 }
1469 
1471 {
1473  mIntervalUnit = unit;
1474  mOffsetAlongLineUnit = unit;
1475  mAverageAngleLengthUnit = unit;
1476 }
1477 
1479 {
1481  setIntervalMapUnitScale( scale );
1482  mOffsetMapUnitScale = scale;
1484 }
1485 
1487 {
1491  {
1492  return mOffsetMapUnitScale;
1493  }
1494  return QgsMapUnitScale();
1495 }
1496 
1498 {
1499  QVariantMap map;
1500  map[QStringLiteral( "rotate" )] = ( rotateSymbols() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1501  map[QStringLiteral( "interval" )] = QString::number( interval() );
1502  map[QStringLiteral( "offset" )] = QString::number( mOffset );
1503  map[QStringLiteral( "offset_along_line" )] = QString::number( offsetAlongLine() );
1504  map[QStringLiteral( "offset_along_line_unit" )] = QgsUnitTypes::encodeUnit( offsetAlongLineUnit() );
1505  map[QStringLiteral( "offset_along_line_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( offsetAlongLineMapUnitScale() );
1506  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
1507  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
1508  map[QStringLiteral( "interval_unit" )] = QgsUnitTypes::encodeUnit( intervalUnit() );
1509  map[QStringLiteral( "interval_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( intervalMapUnitScale() );
1510  map[QStringLiteral( "average_angle_length" )] = QString::number( mAverageAngleLength );
1511  map[QStringLiteral( "average_angle_unit" )] = QgsUnitTypes::encodeUnit( mAverageAngleLengthUnit );
1512  map[QStringLiteral( "average_angle_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mAverageAngleLengthMapUnitScale );
1513 
1514  map[QStringLiteral( "placements" )] = qgsFlagValueToKeys( mPlacements );
1515 
1516  map[QStringLiteral( "ring_filter" )] = QString::number( static_cast< int >( mRingFilter ) );
1517  map[QStringLiteral( "place_on_every_part" )] = mPlaceOnEveryPart;
1518  return map;
1519 }
1520 
1522 {
1523  return mPlaceOnEveryPart
1524  || ( mPlacements & Qgis::MarkerLinePlacement::Interval )
1525  || ( mPlacements & Qgis::MarkerLinePlacement::CentralPoint )
1526  || ( mPlacements & Qgis::MarkerLinePlacement::SegmentCenter );
1527 }
1528 
1530 {
1531  mRenderingFeature = true;
1532  mHasRenderedFirstPart = false;
1533 }
1534 
1536 {
1537  mRenderingFeature = false;
1538  if ( mPlaceOnEveryPart || !( mPlacements & Qgis::MarkerLinePlacement::LastVertex ) )
1539  return;
1540 
1541  const double prevOpacity = subSymbol()->opacity();
1542  subSymbol()->setOpacity( prevOpacity * mFeatureSymbolOpacity );
1543 
1544  // render final point
1545  renderSymbol( mFinalVertex, &feature, context, -1, mCurrentFeatureIsSelected );
1546  mFeatureSymbolOpacity = 1;
1547  subSymbol()->setOpacity( prevOpacity );
1548 }
1549 
1551 {
1552  destLayer->setSubSymbol( const_cast< QgsTemplatedLineSymbolLayerBase * >( this )->subSymbol()->clone() );
1553  destLayer->setOffset( mOffset );
1554  destLayer->setPlacements( placements() );
1555  destLayer->setOffsetUnit( mOffsetUnit );
1557  destLayer->setIntervalUnit( intervalUnit() );
1559  destLayer->setOffsetAlongLine( offsetAlongLine() );
1562  destLayer->setAverageAngleLength( mAverageAngleLength );
1563  destLayer->setAverageAngleUnit( mAverageAngleLengthUnit );
1564  destLayer->setAverageAngleMapUnitScale( mAverageAngleLengthMapUnitScale );
1565  destLayer->setRingFilter( mRingFilter );
1566  destLayer->setPlaceOnEveryPart( mPlaceOnEveryPart );
1567  copyDataDefinedProperties( destLayer );
1568  copyPaintEffect( destLayer );
1569 }
1570 
1572 {
1573  if ( properties.contains( QStringLiteral( "offset" ) ) )
1574  {
1575  destLayer->setOffset( properties[QStringLiteral( "offset" )].toDouble() );
1576  }
1577  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
1578  {
1579  destLayer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
1580  }
1581  if ( properties.contains( QStringLiteral( "interval_unit" ) ) )
1582  {
1583  destLayer->setIntervalUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "interval_unit" )].toString() ) );
1584  }
1585  if ( properties.contains( QStringLiteral( "offset_along_line" ) ) )
1586  {
1587  destLayer->setOffsetAlongLine( properties[QStringLiteral( "offset_along_line" )].toDouble() );
1588  }
1589  if ( properties.contains( QStringLiteral( "offset_along_line_unit" ) ) )
1590  {
1591  destLayer->setOffsetAlongLineUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_along_line_unit" )].toString() ) );
1592  }
1593  if ( properties.contains( ( QStringLiteral( "offset_along_line_map_unit_scale" ) ) ) )
1594  {
1595  destLayer->setOffsetAlongLineMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_along_line_map_unit_scale" )].toString() ) );
1596  }
1597 
1598  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
1599  {
1600  destLayer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
1601  }
1602  if ( properties.contains( QStringLiteral( "interval_map_unit_scale" ) ) )
1603  {
1604  destLayer->setIntervalMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "interval_map_unit_scale" )].toString() ) );
1605  }
1606 
1607  if ( properties.contains( QStringLiteral( "average_angle_length" ) ) )
1608  {
1609  destLayer->setAverageAngleLength( properties[QStringLiteral( "average_angle_length" )].toDouble() );
1610  }
1611  if ( properties.contains( QStringLiteral( "average_angle_unit" ) ) )
1612  {
1613  destLayer->setAverageAngleUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "average_angle_unit" )].toString() ) );
1614  }
1615  if ( properties.contains( ( QStringLiteral( "average_angle_map_unit_scale" ) ) ) )
1616  {
1617  destLayer->setAverageAngleMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "average_angle_map_unit_scale" )].toString() ) );
1618  }
1619 
1620  if ( properties.contains( QStringLiteral( "placement" ) ) )
1621  {
1622  if ( properties[QStringLiteral( "placement" )] == QLatin1String( "vertex" ) )
1624  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "lastvertex" ) )
1626  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "firstvertex" ) )
1628  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "centralpoint" ) )
1630  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "curvepoint" ) )
1632  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "segmentcenter" ) )
1634  else
1636  }
1637  else if ( properties.contains( QStringLiteral( "placements" ) ) )
1638  {
1639  Qgis::MarkerLinePlacements placements = qgsFlagKeysToValue( properties.value( QStringLiteral( "placements" ) ).toString(), Qgis::MarkerLinePlacements() );
1640  destLayer->setPlacements( placements );
1641  }
1642 
1643  if ( properties.contains( QStringLiteral( "ring_filter" ) ) )
1644  {
1645  destLayer->setRingFilter( static_cast< RenderRingFilter>( properties[QStringLiteral( "ring_filter" )].toInt() ) );
1646  }
1647 
1648  destLayer->setPlaceOnEveryPart( properties.value( QStringLiteral( "place_on_every_part" ), true ).toBool() );
1649 
1651 }
1652 
1653 void QgsTemplatedLineSymbolLayerBase::renderPolylineInterval( const QPolygonF &points, QgsSymbolRenderContext &context, double averageOver )
1654 {
1655  if ( points.isEmpty() )
1656  return;
1657 
1658  double lengthLeft = 0; // how much is left until next marker
1659 
1660  QgsRenderContext &rc = context.renderContext();
1661  double interval = mInterval;
1662 
1664  QgsExpressionContextScopePopper scopePopper( context.renderContext().expressionContext(), scope );
1665 
1667  {
1668  context.setOriginalValueVariable( mInterval );
1670  }
1671  if ( interval <= 0 )
1672  {
1673  interval = 0.1;
1674  }
1675  double offsetAlongLine = mOffsetAlongLine;
1677  {
1678  context.setOriginalValueVariable( mOffsetAlongLine );
1680  }
1681 
1682  double painterUnitInterval = rc.convertToPainterUnits( interval, intervalUnit(), intervalMapUnitScale() );
1684  {
1685  // rendering for symbol previews -- an interval in meters in map units can't be calculated, so treat the size as millimeters
1686  // and clamp it to a reasonable range. It's the best we can do in this situation!
1687  painterUnitInterval = std::min( std::max( rc.convertToPainterUnits( interval, QgsUnitTypes::RenderMillimeters ), 10.0 ), 100.0 );
1688  }
1689 
1690  if ( painterUnitInterval < 0 )
1691  return;
1692 
1693  double painterUnitOffsetAlongLine = 0;
1694 
1695  // only calculated if we need it!
1696  double totalLength = -1;
1697 
1698  if ( !qgsDoubleNear( offsetAlongLine, 0 ) )
1699  {
1700  switch ( offsetAlongLineUnit() )
1701  {
1710  break;
1712  totalLength = QgsSymbolLayerUtils::polylineLength( points );
1713  painterUnitOffsetAlongLine = offsetAlongLine / 100 * totalLength;
1714  break;
1715  }
1716 
1717  if ( points.isClosed() )
1718  {
1719  if ( painterUnitOffsetAlongLine > 0 )
1720  {
1721  if ( totalLength < 0 )
1722  totalLength = QgsSymbolLayerUtils::polylineLength( points );
1723  painterUnitOffsetAlongLine = std::fmod( painterUnitOffsetAlongLine, totalLength );
1724  }
1725  else if ( painterUnitOffsetAlongLine < 0 )
1726  {
1727  if ( totalLength < 0 )
1728  totalLength = QgsSymbolLayerUtils::polylineLength( points );
1729  painterUnitOffsetAlongLine = totalLength - std::fmod( -painterUnitOffsetAlongLine, totalLength );
1730  }
1731  }
1732  }
1733 
1735  {
1736  // rendering for symbol previews -- an offset in meters in map units can't be calculated, so treat the size as millimeters
1737  // and clamp it to a reasonable range. It's the best we can do in this situation!
1738  painterUnitOffsetAlongLine = std::min( std::max( rc.convertToPainterUnits( offsetAlongLine, QgsUnitTypes::RenderMillimeters ), 3.0 ), 100.0 );
1739  }
1740 
1741  lengthLeft = painterUnitInterval - painterUnitOffsetAlongLine;
1742 
1743  if ( averageOver > 0 && !qgsDoubleNear( averageOver, 0.0 ) )
1744  {
1745  QVector< QPointF > angleStartPoints;
1746  QVector< QPointF > symbolPoints;
1747  QVector< QPointF > angleEndPoints;
1748 
1749  // we collect 3 arrays of points. These correspond to
1750  // 1. the actual point at which to render the symbol
1751  // 2. the start point of a line averaging the angle over the desired distance (i.e. -averageOver distance from the points in array 1)
1752  // 3. the end point of a line averaging the angle over the desired distance (i.e. +averageOver distance from the points in array 2)
1753  // it gets quite tricky, because for closed rings we need to trace backwards from the initial point to calculate this
1754  // (or trace past the final point)
1755  collectOffsetPoints( points, symbolPoints, painterUnitInterval, lengthLeft );
1756 
1757  if ( symbolPoints.empty() )
1758  {
1759  // no symbols to draw, shortcut out early
1760  return;
1761  }
1762 
1763  if ( symbolPoints.count() > 1 && symbolPoints.constFirst() == symbolPoints.constLast() )
1764  {
1765  // avoid duplicate points at start and end of closed rings
1766  symbolPoints.pop_back();
1767  }
1768 
1769  angleEndPoints.reserve( symbolPoints.size() );
1770  angleStartPoints.reserve( symbolPoints.size() );
1771  if ( averageOver <= painterUnitOffsetAlongLine )
1772  {
1773  collectOffsetPoints( points, angleStartPoints, painterUnitInterval, lengthLeft + averageOver, 0, symbolPoints.size() );
1774  }
1775  else
1776  {
1777  collectOffsetPoints( points, angleStartPoints, painterUnitInterval, 0, averageOver - painterUnitOffsetAlongLine, symbolPoints.size() );
1778  }
1779  collectOffsetPoints( points, angleEndPoints, painterUnitInterval, lengthLeft - averageOver, 0, symbolPoints.size() );
1780 
1781  int pointNum = 0;
1782  for ( int i = 0; i < symbolPoints.size(); ++ i )
1783  {
1784  if ( context.renderContext().renderingStopped() )
1785  break;
1786 
1787  const QPointF pt = symbolPoints[i];
1788  const QPointF startPt = angleStartPoints[i];
1789  const QPointF endPt = angleEndPoints[i];
1790 
1791  MyLine l( startPt, endPt );
1792  // rotate marker (if desired)
1793  if ( rotateSymbols() )
1794  {
1795  setSymbolLineAngle( l.angle() * 180 / M_PI );
1796  }
1797 
1799  renderSymbol( pt, context.feature(), rc, -1, context.selected() );
1800  }
1801  }
1802  else
1803  {
1804  // not averaging line angle -- always use exact section angle
1805  int pointNum = 0;
1806  QPointF lastPt = points[0];
1807  for ( int i = 1; i < points.count(); ++i )
1808  {
1809  if ( context.renderContext().renderingStopped() )
1810  break;
1811 
1812  const QPointF &pt = points[i];
1813 
1814  if ( lastPt == pt ) // must not be equal!
1815  continue;
1816 
1817  // for each line, find out dx and dy, and length
1818  MyLine l( lastPt, pt );
1819  QPointF diff = l.diffForInterval( painterUnitInterval );
1820 
1821  // if there's some length left from previous line
1822  // use only the rest for the first point in new line segment
1823  double c = 1 - lengthLeft / painterUnitInterval;
1824 
1825  lengthLeft += l.length();
1826 
1827  // rotate marker (if desired)
1828  if ( rotateSymbols() )
1829  {
1830  setSymbolLineAngle( l.angle() * 180 / M_PI );
1831  }
1832 
1833  // while we're not at the end of line segment, draw!
1834  while ( lengthLeft > painterUnitInterval )
1835  {
1836  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
1837  lastPt += c * diff;
1838  lengthLeft -= painterUnitInterval;
1840  renderSymbol( lastPt, context.feature(), rc, -1, context.selected() );
1841  c = 1; // reset c (if wasn't 1 already)
1842  }
1843 
1844  lastPt = pt;
1845  }
1846 
1847  }
1848 }
1849 
1850 static double _averageAngle( QPointF prevPt, QPointF pt, QPointF nextPt )
1851 {
1852  // calc average angle between the previous and next point
1853  double a1 = MyLine( prevPt, pt ).angle();
1854  double a2 = MyLine( pt, nextPt ).angle();
1855  double unitX = std::cos( a1 ) + std::cos( a2 ), unitY = std::sin( a1 ) + std::sin( a2 );
1856 
1857  return std::atan2( unitY, unitX );
1858 }
1859 
1860 void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex( const QPolygonF &points, QgsSymbolRenderContext &context, Qgis::MarkerLinePlacement placement )
1861 {
1862  if ( points.isEmpty() )
1863  return;
1864 
1865  QgsRenderContext &rc = context.renderContext();
1866 
1867  int i = -1, maxCount = 0;
1868  bool isRing = false;
1869 
1871  QgsExpressionContextScopePopper scopePopper( context.renderContext().expressionContext(), scope );
1873 
1874  double offsetAlongLine = mOffsetAlongLine;
1876  {
1877  context.setOriginalValueVariable( mOffsetAlongLine );
1879  }
1880 
1881  // only calculated if we need it!!
1882  double totalLength = -1;
1883  if ( !qgsDoubleNear( offsetAlongLine, 0.0 ) )
1884  {
1885  //scale offset along line
1886  switch ( offsetAlongLineUnit() )
1887  {
1896  break;
1898  totalLength = QgsSymbolLayerUtils::polylineLength( points );
1899  offsetAlongLine = offsetAlongLine / 100 * totalLength;
1900  break;
1901  }
1902  if ( points.isClosed() )
1903  {
1904  if ( offsetAlongLine > 0 )
1905  {
1906  if ( totalLength < 0 )
1907  totalLength = QgsSymbolLayerUtils::polylineLength( points );
1908  offsetAlongLine = std::fmod( offsetAlongLine, totalLength );
1909  }
1910  else if ( offsetAlongLine < 0 )
1911  {
1912  if ( totalLength < 0 )
1913  totalLength = QgsSymbolLayerUtils::polylineLength( points );
1914  offsetAlongLine = totalLength - std::fmod( -offsetAlongLine, totalLength );
1915  }
1916  }
1917  }
1918 
1919  if ( qgsDoubleNear( offsetAlongLine, 0.0 ) && context.renderContext().geometry()
1923  {
1925  const QgsMapToPixel &mtp = context.renderContext().mapToPixel();
1926 
1927  QgsVertexId vId;
1928  QgsPoint vPoint;
1929  double x, y, z;
1930  QPointF mapPoint;
1931  int pointNum = 0;
1932  const int numPoints = context.renderContext().geometry()->nCoordinates();
1933  while ( context.renderContext().geometry()->nextVertex( vId, vPoint ) )
1934  {
1935  if ( context.renderContext().renderingStopped() )
1936  break;
1937 
1939 
1940  if ( pointNum == 1 && placement == Qgis::MarkerLinePlacement::InnerVertices )
1941  continue;
1942 
1943  if ( pointNum == numPoints && placement == Qgis::MarkerLinePlacement::InnerVertices )
1944  continue;
1945 
1946  if ( ( ( placement == Qgis::MarkerLinePlacement::Vertex || placement == Qgis::MarkerLinePlacement::InnerVertices ) && vId.type == Qgis::VertexType::Segment )
1947  || ( placement == Qgis::MarkerLinePlacement::CurvePoint && vId.type == Qgis::VertexType::Curve ) )
1948  {
1949  //transform
1950  x = vPoint.x();
1951  y = vPoint.y();
1952  z = 0.0;
1953  if ( ct.isValid() )
1954  {
1955  ct.transformInPlace( x, y, z );
1956  }
1957  mapPoint.setX( x );
1958  mapPoint.setY( y );
1959  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1960  if ( rotateSymbols() )
1961  {
1962  double angle = context.renderContext().geometry()->vertexAngle( vId );
1963  setSymbolLineAngle( angle * 180 / M_PI );
1964  }
1965  renderSymbol( mapPoint, context.feature(), rc, -1, context.selected() );
1966  }
1967  }
1968 
1969  return;
1970  }
1971 
1972  int pointNum = 0;
1973 
1974  switch ( placement )
1975  {
1977  {
1978  i = 0;
1979  maxCount = 1;
1980  break;
1981  }
1982 
1984  {
1985  i = points.count() - 1;
1986  pointNum = i;
1987  maxCount = points.count();
1988  break;
1989  }
1990 
1992  {
1993  i = 1;
1994  pointNum = 1;
1995  maxCount = points.count() - 1;
1996  break;
1997  }
1998 
2001  {
2003  maxCount = points.count();
2004  if ( points.first() == points.last() )
2005  isRing = true;
2006  break;
2007  }
2008 
2012  {
2013  return;
2014  }
2015  }
2016 
2018  {
2019  double distance;
2021  renderOffsetVertexAlongLine( points, i, distance, context, placement );
2022 
2023  return;
2024  }
2025 
2026  QPointF prevPoint;
2027  if ( placement == Qgis::MarkerLinePlacement::SegmentCenter && !points.empty() )
2028  prevPoint = points.at( 0 );
2029 
2030  QPointF symbolPoint;
2031  for ( ; i < maxCount; ++i )
2032  {
2034 
2035  if ( isRing && placement == Qgis::MarkerLinePlacement::Vertex && i == points.count() - 1 )
2036  {
2037  continue; // don't draw the last marker - it has been drawn already
2038  }
2039 
2041  {
2042  QPointF currentPoint = points.at( i );
2043  symbolPoint = QPointF( 0.5 * ( currentPoint.x() + prevPoint.x() ),
2044  0.5 * ( currentPoint.y() + prevPoint.y() ) );
2045  if ( rotateSymbols() )
2046  {
2047  double angle = std::atan2( currentPoint.y() - prevPoint.y(),
2048  currentPoint.x() - prevPoint.x() );
2049  setSymbolLineAngle( angle * 180 / M_PI );
2050  }
2051  prevPoint = currentPoint;
2052  }
2053  else
2054  {
2055  symbolPoint = points.at( i );
2056  // rotate marker (if desired)
2057  if ( rotateSymbols() )
2058  {
2059  double angle = markerAngle( points, isRing, i );
2060  setSymbolLineAngle( angle * 180 / M_PI );
2061  }
2062  }
2063 
2064  mFinalVertex = symbolPoint;
2065  if ( i != points.count() - 1 || placement != Qgis::MarkerLinePlacement::LastVertex || mPlaceOnEveryPart || !mRenderingFeature )
2066  renderSymbol( symbolPoint, context.feature(), rc, -1, context.selected() );
2067  }
2068 }
2069 
2070 double QgsTemplatedLineSymbolLayerBase::markerAngle( const QPolygonF &points, bool isRing, int vertex )
2071 {
2072  double angle = 0;
2073  const QPointF &pt = points[vertex];
2074 
2075  if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
2076  {
2077  int prevIndex = vertex - 1;
2078  int nextIndex = vertex + 1;
2079 
2080  if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
2081  {
2082  prevIndex = points.count() - 2;
2083  nextIndex = 1;
2084  }
2085 
2086  QPointF prevPoint, nextPoint;
2087  while ( prevIndex >= 0 )
2088  {
2089  prevPoint = points[ prevIndex ];
2090  if ( prevPoint != pt )
2091  {
2092  break;
2093  }
2094  --prevIndex;
2095  }
2096 
2097  while ( nextIndex < points.count() )
2098  {
2099  nextPoint = points[ nextIndex ];
2100  if ( nextPoint != pt )
2101  {
2102  break;
2103  }
2104  ++nextIndex;
2105  }
2106 
2107  if ( prevIndex >= 0 && nextIndex < points.count() )
2108  {
2109  angle = _averageAngle( prevPoint, pt, nextPoint );
2110  }
2111  }
2112  else //no ring and vertex is at start / at end
2113  {
2114  if ( vertex == 0 )
2115  {
2116  while ( vertex < points.size() - 1 )
2117  {
2118  const QPointF &nextPt = points[vertex + 1];
2119  if ( pt != nextPt )
2120  {
2121  angle = MyLine( pt, nextPt ).angle();
2122  return angle;
2123  }
2124  ++vertex;
2125  }
2126  }
2127  else
2128  {
2129  // use last segment's angle
2130  while ( vertex >= 1 ) //in case of duplicated vertices, take the next suitable one
2131  {
2132  const QPointF &prevPt = points[vertex - 1];
2133  if ( pt != prevPt )
2134  {
2135  angle = MyLine( prevPt, pt ).angle();
2136  return angle;
2137  }
2138  --vertex;
2139  }
2140  }
2141  }
2142  return angle;
2143 }
2144 
2145 void QgsTemplatedLineSymbolLayerBase::renderOffsetVertexAlongLine( const QPolygonF &points, int vertex, double distance, QgsSymbolRenderContext &context, Qgis::MarkerLinePlacement placement )
2146 {
2147  if ( points.isEmpty() )
2148  return;
2149 
2150  QgsRenderContext &rc = context.renderContext();
2151  if ( qgsDoubleNear( distance, 0.0 ) )
2152  {
2153  // rotate marker (if desired)
2154  if ( rotateSymbols() )
2155  {
2156  bool isRing = false;
2157  if ( points.first() == points.last() )
2158  isRing = true;
2159  double angle = markerAngle( points, isRing, vertex );
2160  setSymbolLineAngle( angle * 180 / M_PI );
2161  }
2162  mFinalVertex = points[vertex];
2163  if ( placement != Qgis::MarkerLinePlacement::LastVertex || mPlaceOnEveryPart || !mRenderingFeature )
2164  renderSymbol( points[vertex], context.feature(), rc, -1, context.selected() );
2165  return;
2166  }
2167 
2168  int pointIncrement = distance > 0 ? 1 : -1;
2169  QPointF previousPoint = points[vertex];
2170  int startPoint = distance > 0 ? std::min( vertex + 1, static_cast<int>( points.count() ) - 1 ) : std::max( vertex - 1, 0 );
2171  int endPoint = distance > 0 ? points.count() - 1 : 0;
2172  double distanceLeft = std::fabs( distance );
2173 
2174  for ( int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
2175  {
2176  const QPointF &pt = points[i];
2177 
2178  if ( previousPoint == pt ) // must not be equal!
2179  continue;
2180 
2181  // create line segment
2182  MyLine l( previousPoint, pt );
2183 
2184  if ( distanceLeft < l.length() )
2185  {
2186  //destination point is in current segment
2187  QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
2188  // rotate marker (if desired)
2189  if ( rotateSymbols() )
2190  {
2191  setSymbolLineAngle( l.angle() * 180 / M_PI );
2192  }
2193  mFinalVertex = markerPoint;
2194  if ( placement != Qgis::MarkerLinePlacement::LastVertex || mPlaceOnEveryPart || !mRenderingFeature )
2195  renderSymbol( markerPoint, context.feature(), rc, -1, context.selected() );
2196  return;
2197  }
2198 
2199  distanceLeft -= l.length();
2200  previousPoint = pt;
2201  }
2202 
2203  //didn't find point
2204 }
2205 
2206 void QgsTemplatedLineSymbolLayerBase::collectOffsetPoints( const QVector<QPointF> &p, QVector<QPointF> &dest, double intervalPainterUnits, double initialOffset, double initialLag, int numberPointsRequired )
2207 {
2208  if ( p.empty() )
2209  return;
2210 
2211  QVector< QPointF > points = p;
2212  const bool closedRing = points.first() == points.last();
2213 
2214  double lengthLeft = initialOffset;
2215 
2216  double initialLagLeft = initialLag > 0 ? -initialLag : 1; // an initialLagLeft of > 0 signifies end of lagging start points
2217  if ( initialLagLeft < 0 && closedRing )
2218  {
2219  // tracking back around the ring from the first point, insert pseudo vertices before the first vertex
2220  QPointF lastPt = points.constLast();
2221  QVector< QPointF > pseudoPoints;
2222  for ( int i = points.count() - 2; i > 0; --i )
2223  {
2224  if ( initialLagLeft >= 0 )
2225  {
2226  break;
2227  }
2228 
2229  const QPointF &pt = points[i];
2230 
2231  if ( lastPt == pt ) // must not be equal!
2232  continue;
2233 
2234  MyLine l( lastPt, pt );
2235  initialLagLeft += l.length();
2236  lastPt = pt;
2237 
2238  pseudoPoints << pt;
2239  }
2240  std::reverse( pseudoPoints.begin(), pseudoPoints.end() );
2241 
2242  points = pseudoPoints;
2243  points.append( p );
2244  }
2245  else
2246  {
2247  while ( initialLagLeft < 0 )
2248  {
2249  dest << points.constFirst();
2250  initialLagLeft += intervalPainterUnits;
2251  }
2252  }
2253  if ( initialLag > 0 )
2254  {
2255  lengthLeft += intervalPainterUnits - initialLagLeft;
2256  }
2257 
2258  QPointF lastPt = points[0];
2259  for ( int i = 1; i < points.count(); ++i )
2260  {
2261  const QPointF &pt = points[i];
2262 
2263  if ( lastPt == pt ) // must not be equal!
2264  {
2265  if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2266  {
2267  lastPt = points[0];
2268  i = 0;
2269  }
2270  continue;
2271  }
2272 
2273  // for each line, find out dx and dy, and length
2274  MyLine l( lastPt, pt );
2275  QPointF diff = l.diffForInterval( intervalPainterUnits );
2276 
2277  // if there's some length left from previous line
2278  // use only the rest for the first point in new line segment
2279  double c = 1 - lengthLeft / intervalPainterUnits;
2280 
2281  lengthLeft += l.length();
2282 
2283 
2284  while ( lengthLeft > intervalPainterUnits || qgsDoubleNear( lengthLeft, intervalPainterUnits, 0.000000001 ) )
2285  {
2286  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
2287  lastPt += c * diff;
2288  lengthLeft -= intervalPainterUnits;
2289  dest << lastPt;
2290  c = 1; // reset c (if wasn't 1 already)
2291  if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2292  break;
2293  }
2294  lastPt = pt;
2295 
2296  if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2297  break;
2298 
2299  // if a closed ring, we keep looping around the ring until we hit the required number of points
2300  if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2301  {
2302  lastPt = points[0];
2303  i = 0;
2304  }
2305  }
2306 
2307  if ( !closedRing && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2308  {
2309  // pad with repeating last point to match desired size
2310  while ( dest.size() < numberPointsRequired )
2311  dest << points.constLast();
2312  }
2313 }
2314 
2315 void QgsTemplatedLineSymbolLayerBase::renderPolylineCentral( const QPolygonF &points, QgsSymbolRenderContext &context, double averageAngleOver )
2316 {
2317  if ( !points.isEmpty() )
2318  {
2319  // calc length
2320  qreal length = 0;
2321  QPolygonF::const_iterator it = points.constBegin();
2322  QPointF last = *it;
2323  for ( ++it; it != points.constEnd(); ++it )
2324  {
2325  length += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2326  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2327  last = *it;
2328  }
2329  if ( qgsDoubleNear( length, 0.0 ) )
2330  return;
2331 
2332  const double midPoint = length / 2;
2333 
2334  QPointF pt;
2335  double thisSymbolAngle = 0;
2336 
2337  if ( averageAngleOver > 0 && !qgsDoubleNear( averageAngleOver, 0.0 ) )
2338  {
2339  QVector< QPointF > angleStartPoints;
2340  QVector< QPointF > symbolPoints;
2341  QVector< QPointF > angleEndPoints;
2342  // collectOffsetPoints will have the first point in the line as the first result -- we don't want this, we need the second
2343  collectOffsetPoints( points, symbolPoints, midPoint, midPoint, 0.0, 2 );
2344  collectOffsetPoints( points, angleStartPoints, midPoint, 0, averageAngleOver, 2 );
2345  collectOffsetPoints( points, angleEndPoints, midPoint, midPoint - averageAngleOver, 0, 2 );
2346 
2347  pt = symbolPoints.at( 1 );
2348  MyLine l( angleStartPoints.at( 1 ), angleEndPoints.at( 1 ) );
2349  thisSymbolAngle = l.angle();
2350  }
2351  else
2352  {
2353  // find the segment where the central point lies
2354  it = points.constBegin();
2355  last = *it;
2356  qreal last_at = 0, next_at = 0;
2357  QPointF next;
2358  int segment = 0;
2359  for ( ++it; it != points.constEnd(); ++it )
2360  {
2361  next = *it;
2362  next_at += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2363  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2364  if ( next_at >= midPoint )
2365  break; // we have reached the center
2366  last = *it;
2367  last_at = next_at;
2368  segment++;
2369  }
2370 
2371  // find out the central point on segment
2372  MyLine l( last, next ); // for line angle
2373  qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
2374  pt = last + ( next - last ) * k;
2375  thisSymbolAngle = l.angle();
2376  }
2377 
2378  // draw the marker
2379  // rotate marker (if desired)
2380  if ( rotateSymbols() )
2381  {
2382  setSymbolLineAngle( thisSymbolAngle * 180 / M_PI );
2383  }
2384 
2385  renderSymbol( pt, context.feature(), context.renderContext(), -1, context.selected() );
2386 
2387  }
2388 }
2389 
2391 {
2392  return mMarker.get();
2393 }
2394 
2396 {
2397  if ( !symbol || symbol->type() != Qgis::SymbolType::Marker )
2398  {
2399  delete symbol;
2400  return false;
2401  }
2402 
2403  mMarker.reset( static_cast<QgsMarkerSymbol *>( symbol ) );
2404  mColor = mMarker->color();
2405  return true;
2406 }
2407 
2408 
2409 
2410 //
2411 // QgsMarkerLineSymbolLayer
2412 //
2413 
2414 QgsMarkerLineSymbolLayer::QgsMarkerLineSymbolLayer( bool rotateMarker, double interval )
2415  : QgsTemplatedLineSymbolLayerBase( rotateMarker, interval )
2416 {
2417  setSubSymbol( new QgsMarkerSymbol() );
2418 }
2419 
2421 
2423 {
2424  bool rotate = DEFAULT_MARKERLINE_ROTATE;
2426 
2427  if ( props.contains( QStringLiteral( "interval" ) ) )
2428  interval = props[QStringLiteral( "interval" )].toDouble();
2429  if ( props.contains( QStringLiteral( "rotate" ) ) )
2430  rotate = ( props[QStringLiteral( "rotate" )].toString() == QLatin1String( "1" ) );
2431 
2432  std::unique_ptr< QgsMarkerLineSymbolLayer > x = std::make_unique< QgsMarkerLineSymbolLayer >( rotate, interval );
2433  setCommonProperties( x.get(), props );
2434  return x.release();
2435 }
2436 
2438 {
2439  return QStringLiteral( "MarkerLine" );
2440 }
2441 
2442 void QgsMarkerLineSymbolLayer::setColor( const QColor &color )
2443 {
2444  mMarker->setColor( color );
2445  mColor = color;
2446 }
2447 
2449 {
2450  return mMarker ? mMarker->color() : mColor;
2451 }
2452 
2454 {
2455  // if being rotated, it gets initialized with every line segment
2456  Qgis::SymbolRenderHints hints = Qgis::SymbolRenderHints();
2457  if ( rotateSymbols() )
2459  mMarker->setRenderHints( hints );
2460 
2461  mMarker->startRender( context.renderContext(), context.fields() );
2462 }
2463 
2465 {
2466  mMarker->stopRender( context.renderContext() );
2467 }
2468 
2469 
2471 {
2472  std::unique_ptr< QgsMarkerLineSymbolLayer > x = std::make_unique< QgsMarkerLineSymbolLayer >( rotateSymbols(), interval() );
2473  copyTemplateSymbolProperties( x.get() );
2474  return x.release();
2475 }
2476 
2477 void QgsMarkerLineSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
2478 {
2479  for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
2480  {
2481  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:LineSymbolizer" ) );
2482  if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
2483  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
2484  element.appendChild( symbolizerElem );
2485 
2486  // <Geometry>
2487  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
2488 
2489  QString gap;
2491  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "firstPoint" ) ) );
2493  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "lastPoint" ) ) );
2495  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "centralPoint" ) ) );
2497  // no way to get line/polygon's vertices, use a VendorOption
2498  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "points" ) ) );
2499 
2501  {
2503  gap = qgsDoubleToString( interval );
2504  }
2505 
2506  if ( !rotateSymbols() )
2507  {
2508  // markers in LineSymbolizer must be drawn following the line orientation,
2509  // use a VendorOption when no marker rotation
2510  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "rotateMarker" ), QStringLiteral( "0" ) ) );
2511  }
2512 
2513  // <Stroke>
2514  QDomElement strokeElem = doc.createElement( QStringLiteral( "se:Stroke" ) );
2515  symbolizerElem.appendChild( strokeElem );
2516 
2517  // <GraphicStroke>
2518  QDomElement graphicStrokeElem = doc.createElement( QStringLiteral( "se:GraphicStroke" ) );
2519  strokeElem.appendChild( graphicStrokeElem );
2520 
2521  QgsSymbolLayer *layer = mMarker->symbolLayer( i );
2522  if ( QgsMarkerSymbolLayer *markerLayer = dynamic_cast<QgsMarkerSymbolLayer *>( layer ) )
2523  {
2524  markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
2525  }
2526  else if ( layer )
2527  {
2528  graphicStrokeElem.appendChild( doc.createComment( QStringLiteral( "QgsMarkerSymbolLayer expected, %1 found. Skip it." ).arg( layer->layerType() ) ) );
2529  }
2530  else
2531  {
2532  graphicStrokeElem.appendChild( doc.createComment( QStringLiteral( "Missing marker line symbol layer. Skip it." ) ) );
2533  }
2534 
2535  if ( !gap.isEmpty() )
2536  {
2537  QDomElement gapElem = doc.createElement( QStringLiteral( "se:Gap" ) );
2538  QgsSymbolLayerUtils::createExpressionElement( doc, gapElem, gap );
2539  graphicStrokeElem.appendChild( gapElem );
2540  }
2541 
2542  if ( !qgsDoubleNear( mOffset, 0.0 ) )
2543  {
2544  QDomElement perpOffsetElem = doc.createElement( QStringLiteral( "se:PerpendicularOffset" ) );
2546  perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
2547  symbolizerElem.appendChild( perpOffsetElem );
2548  }
2549  }
2550 }
2551 
2553 {
2554  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
2555 
2556  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
2557  if ( strokeElem.isNull() )
2558  return nullptr;
2559 
2560  QDomElement graphicStrokeElem = strokeElem.firstChildElement( QStringLiteral( "GraphicStroke" ) );
2561  if ( graphicStrokeElem.isNull() )
2562  return nullptr;
2563 
2564  // retrieve vendor options
2565  bool rotateMarker = true;
2567 
2568  QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( element );
2569  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
2570  {
2571  if ( it.key() == QLatin1String( "placement" ) )
2572  {
2573  if ( it.value() == QLatin1String( "points" ) )
2575  else if ( it.value() == QLatin1String( "firstPoint" ) )
2577  else if ( it.value() == QLatin1String( "lastPoint" ) )
2579  else if ( it.value() == QLatin1String( "centralPoint" ) )
2581  }
2582  else if ( it.value() == QLatin1String( "rotateMarker" ) )
2583  {
2584  rotateMarker = it.value() == QLatin1String( "0" );
2585  }
2586  }
2587 
2588  std::unique_ptr< QgsMarkerSymbol > marker;
2589 
2591  if ( l )
2592  {
2593  QgsSymbolLayerList layers;
2594  layers.append( l );
2595  marker.reset( new QgsMarkerSymbol( layers ) );
2596  }
2597 
2598  if ( !marker )
2599  return nullptr;
2600 
2601  double interval = 0.0;
2602  QDomElement gapElem = graphicStrokeElem.firstChildElement( QStringLiteral( "Gap" ) );
2603  if ( !gapElem.isNull() )
2604  {
2605  bool ok;
2606  double d = gapElem.firstChild().nodeValue().toDouble( &ok );
2607  if ( ok )
2608  interval = d;
2609  }
2610 
2611  double offset = 0.0;
2612  QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( QStringLiteral( "PerpendicularOffset" ) );
2613  if ( !perpOffsetElem.isNull() )
2614  {
2615  bool ok;
2616  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
2617  if ( ok )
2618  offset = d;
2619  }
2620 
2621  double scaleFactor = 1.0;
2622  const QString uom = element.attribute( QStringLiteral( "uom" ) );
2623  QgsUnitTypes::RenderUnit sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( uom, &scaleFactor );
2624  interval = interval * scaleFactor;
2625  offset = offset * scaleFactor;
2626 
2628  x->setOutputUnit( sldUnitSize );
2629  x->setPlacements( placement );
2630  x->setInterval( interval );
2631  x->setSubSymbol( marker.release() );
2632  x->setOffset( offset );
2633  return x;
2634 }
2635 
2637 {
2638  mMarker->setSize( width );
2639 }
2640 
2642 {
2643  if ( key == QgsSymbolLayer::PropertyWidth && mMarker && property )
2644  {
2645  mMarker->setDataDefinedSize( property );
2646  }
2648 }
2649 
2650 void QgsMarkerLineSymbolLayer::renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context )
2651 {
2652  const double prevOpacity = mMarker->opacity();
2653  mMarker->setOpacity( mMarker->opacity() * context.opacity() );
2655  mMarker->setOpacity( prevOpacity );
2656 }
2657 
2659 {
2660  mMarker->setLineAngle( angle );
2661 }
2662 
2664 {
2665  return mMarker->angle();
2666 }
2667 
2669 {
2670  mMarker->setAngle( angle );
2671 }
2672 
2673 void QgsMarkerLineSymbolLayer::renderSymbol( const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer, bool selected )
2674 {
2675  const bool prevIsSubsymbol = context.flags() & Qgis::RenderContextFlag::RenderingSubSymbol;
2677 
2678  mMarker->renderPoint( point, feature, context, layer, selected );
2679 
2680  context.setFlag( Qgis::RenderContextFlag::RenderingSubSymbol, prevIsSubsymbol );
2681 }
2682 
2684 {
2685  return mMarker->size();
2686 }
2687 
2689 {
2690  return mMarker->size( context );
2691 }
2692 
2694 {
2696  mMarker->setOutputUnit( unit );
2697 }
2698 
2700 {
2706  || ( mMarker && mMarker->usesMapUnits() );
2707 }
2708 
2709 QSet<QString> QgsMarkerLineSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
2710 {
2711  QSet<QString> attr = QgsLineSymbolLayer::usedAttributes( context );
2712  if ( mMarker )
2713  attr.unite( mMarker->usedAttributes( context ) );
2714  return attr;
2715 }
2716 
2718 {
2720  return true;
2721  if ( mMarker && mMarker->hasDataDefinedProperties() )
2722  return true;
2723  return false;
2724 }
2725 
2727 {
2728  return ( mMarker->size( context ) / 2.0 ) +
2730 }
2731 
2732 
2733 //
2734 // QgsHashedLineSymbolLayer
2735 //
2736 
2737 QgsHashedLineSymbolLayer::QgsHashedLineSymbolLayer( bool rotateSymbol, double interval )
2738  : QgsTemplatedLineSymbolLayerBase( rotateSymbol, interval )
2739 {
2740  setSubSymbol( new QgsLineSymbol() );
2741 }
2742 
2744 
2746 {
2747  bool rotate = DEFAULT_MARKERLINE_ROTATE;
2749 
2750  if ( props.contains( QStringLiteral( "interval" ) ) )
2751  interval = props[QStringLiteral( "interval" )].toDouble();
2752  if ( props.contains( QStringLiteral( "rotate" ) ) )
2753  rotate = ( props[QStringLiteral( "rotate" )] == QLatin1String( "1" ) );
2754 
2755  std::unique_ptr< QgsHashedLineSymbolLayer > x = std::make_unique< QgsHashedLineSymbolLayer >( rotate, interval );
2756  setCommonProperties( x.get(), props );
2757  if ( props.contains( QStringLiteral( "hash_angle" ) ) )
2758  {
2759  x->setHashAngle( props[QStringLiteral( "hash_angle" )].toDouble() );
2760  }
2761 
2762  if ( props.contains( QStringLiteral( "hash_length" ) ) )
2763  x->setHashLength( props[QStringLiteral( "hash_length" )].toDouble() );
2764 
2765  if ( props.contains( QStringLiteral( "hash_length_unit" ) ) )
2766  x->setHashLengthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "hash_length_unit" )].toString() ) );
2767 
2768  if ( props.contains( QStringLiteral( "hash_length_map_unit_scale" ) ) )
2769  x->setHashLengthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "hash_length_map_unit_scale" )].toString() ) );
2770 
2771  return x.release();
2772 }
2773 
2775 {
2776  return QStringLiteral( "HashLine" );
2777 }
2778 
2780 {
2781  // if being rotated, it gets initialized with every line segment
2782  Qgis::SymbolRenderHints hints = Qgis::SymbolRenderHints();
2783  if ( rotateSymbols() )
2785  mHashSymbol->setRenderHints( hints );
2786 
2787  mHashSymbol->startRender( context.renderContext(), context.fields() );
2788 }
2789 
2791 {
2792  mHashSymbol->stopRender( context.renderContext() );
2793 }
2794 
2796 {
2797  QVariantMap map = QgsTemplatedLineSymbolLayerBase::properties();
2798  map[ QStringLiteral( "hash_angle" ) ] = QString::number( mHashAngle );
2799 
2800  map[QStringLiteral( "hash_length" )] = QString::number( mHashLength );
2801  map[QStringLiteral( "hash_length_unit" )] = QgsUnitTypes::encodeUnit( mHashLengthUnit );
2802  map[QStringLiteral( "hash_length_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mHashLengthMapUnitScale );
2803 
2804  return map;
2805 }
2806 
2808 {
2809  std::unique_ptr< QgsHashedLineSymbolLayer > x = std::make_unique< QgsHashedLineSymbolLayer >( rotateSymbols(), interval() );
2810  copyTemplateSymbolProperties( x.get() );
2811  x->setHashAngle( mHashAngle );
2812  x->setHashLength( mHashLength );
2813  x->setHashLengthUnit( mHashLengthUnit );
2814  x->setHashLengthMapUnitScale( mHashLengthMapUnitScale );
2815  return x.release();
2816 }
2817 
2818 void QgsHashedLineSymbolLayer::setColor( const QColor &color )
2819 {
2820  mHashSymbol->setColor( color );
2821  mColor = color;
2822 }
2823 
2825 {
2826  return mHashSymbol ? mHashSymbol->color() : mColor;
2827 }
2828 
2830 {
2831  return mHashSymbol.get();
2832 }
2833 
2835 {
2836  if ( !symbol || symbol->type() != Qgis::SymbolType::Line )
2837  {
2838  delete symbol;
2839  return false;
2840  }
2841 
2842  mHashSymbol.reset( static_cast<QgsLineSymbol *>( symbol ) );
2843  mColor = mHashSymbol->color();
2844  return true;
2845 }
2846 
2847 void QgsHashedLineSymbolLayer::setWidth( const double width )
2848 {
2849  mHashLength = width;
2850 }
2851 
2853 {
2854  return mHashLength;
2855 }
2856 
2858 {
2859  return context.convertToPainterUnits( mHashLength, mHashLengthUnit, mHashLengthMapUnitScale );
2860 }
2861 
2863 {
2864  return ( mHashSymbol->width( context ) / 2.0 )
2865  + context.convertToPainterUnits( mHashLength, mHashLengthUnit, mHashLengthMapUnitScale )
2866  + context.convertToPainterUnits( std::fabs( mOffset ), mOffsetUnit, mOffsetMapUnitScale );
2867 }
2868 
2870 {
2872  mHashSymbol->setOutputUnit( unit );
2873 }
2874 
2875 QSet<QString> QgsHashedLineSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
2876 {
2877  QSet<QString> attr = QgsLineSymbolLayer::usedAttributes( context );
2878  if ( mHashSymbol )
2879  attr.unite( mHashSymbol->usedAttributes( context ) );
2880  return attr;
2881 }
2882 
2884 {
2886  return true;
2887  if ( mHashSymbol && mHashSymbol->hasDataDefinedProperties() )
2888  return true;
2889  return false;
2890 }
2891 
2893 {
2894  if ( key == QgsSymbolLayer::PropertyWidth && mHashSymbol && property )
2895  {
2896  mHashSymbol->setDataDefinedWidth( property );
2897  }
2899 }
2900 
2902 {
2903  return mHashLengthUnit == QgsUnitTypes::RenderMapUnits || mHashLengthUnit == QgsUnitTypes::RenderMetersInMapUnits
2909  || ( mHashSymbol && mHashSymbol->usesMapUnits() );
2910 }
2911 
2913 {
2914  mSymbolLineAngle = angle;
2915 }
2916 
2918 {
2919  return mSymbolAngle;
2920 }
2921 
2923 {
2924  mSymbolAngle = angle;
2925 }
2926 
2927 void QgsHashedLineSymbolLayer::renderSymbol( const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer, bool selected )
2928 {
2929  double lineLength = mHashLength;
2931  {
2932  context.expressionContext().setOriginalValueVariable( mHashLength );
2934  }
2935  const double w = context.convertToPainterUnits( lineLength, mHashLengthUnit, mHashLengthMapUnitScale ) / 2.0;
2936 
2937  double hashAngle = mHashAngle;
2939  {
2940  context.expressionContext().setOriginalValueVariable( mHashAngle );
2942  }
2943 
2944  QgsPointXY center( point );
2945  QgsPointXY start = center.project( w, 180 - ( mSymbolAngle + mSymbolLineAngle + hashAngle ) );
2946  QgsPointXY end = center.project( -w, 180 - ( mSymbolAngle + mSymbolLineAngle + hashAngle ) );
2947 
2948  QPolygonF points;
2949  points << QPointF( start.x(), start.y() ) << QPointF( end.x(), end.y() );
2950 
2951  const bool prevIsSubsymbol = context.flags() & Qgis::RenderContextFlag::RenderingSubSymbol;
2953 
2954  mHashSymbol->renderPolyline( points, feature, context, layer, selected );
2955 
2956  context.setFlag( Qgis::RenderContextFlag::RenderingSubSymbol, prevIsSubsymbol );
2957 }
2958 
2960 {
2961  return mHashAngle;
2962 }
2963 
2965 {
2966  mHashAngle = angle;
2967 }
2968 
2969 void QgsHashedLineSymbolLayer::renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context )
2970 {
2971  const double prevOpacity = mHashSymbol->opacity();
2972  mHashSymbol->setOpacity( mHashSymbol->opacity() * context.opacity() );
2974  mHashSymbol->setOpacity( prevOpacity );
2975 }
2976 
2977 //
2978 // QgsAbstractBrushedLineSymbolLayer
2979 //
2980 
2981 void QgsAbstractBrushedLineSymbolLayer::renderPolylineUsingBrush( const QPolygonF &points, QgsSymbolRenderContext &context, const QBrush &brush, double patternThickness, double patternLength )
2982 {
2983  if ( !context.renderContext().painter() )
2984  return;
2985 
2986  double offset = mOffset;
2988  {
2989  context.setOriginalValueVariable( offset );
2991  }
2992 
2993  QPolygonF offsetPoints;
2994  if ( qgsDoubleNear( offset, 0 ) )
2995  {
2996  renderLine( points, context, patternThickness, patternLength, brush );
2997  }
2998  else
2999  {
3000  const double scaledOffset = context.renderContext().convertToPainterUnits( offset, mOffsetUnit, mOffsetMapUnitScale );
3001 
3002  const QList<QPolygonF> offsetLine = ::offsetLine( points, scaledOffset, context.originalGeometryType() != QgsWkbTypes::UnknownGeometry ? context.originalGeometryType() : QgsWkbTypes::LineGeometry );
3003  for ( const QPolygonF &part : offsetLine )
3004  {
3005  renderLine( part, context, patternThickness, patternLength, brush );
3006  }
3007  }
3008 }
3009 
3010 void QgsAbstractBrushedLineSymbolLayer::renderLine( const QPolygonF &points, QgsSymbolRenderContext &context, const double lineThickness,
3011  const double patternLength, const QBrush &sourceBrush )
3012 {
3013  QPainter *p = context.renderContext().painter();
3014  if ( !p )
3015  return;
3016 
3017  QBrush brush = sourceBrush;
3018 
3019  // duplicate points mess up the calculations, we need to remove them first
3020  // we'll calculate the min/max coordinate at the same time, since we're already looping
3021  // through the points
3022  QPolygonF inputPoints;
3023  inputPoints.reserve( points.size() );
3024  QPointF prev;
3025  double minX = std::numeric_limits< double >::max();
3026  double minY = std::numeric_limits< double >::max();
3027  double maxX = std::numeric_limits< double >::lowest();
3028  double maxY = std::numeric_limits< double >::lowest();
3029 
3030  for ( const QPointF &pt : std::as_const( points ) )
3031  {
3032  if ( !inputPoints.empty() && qgsDoubleNear( prev.x(), pt.x(), 0.01 ) && qgsDoubleNear( prev.y(), pt.y(), 0.01 ) )
3033  continue;
3034 
3035  inputPoints << pt;
3036  prev = pt;
3037  minX = std::min( minX, pt.x() );
3038  minY = std::min( minY, pt.y() );
3039  maxX = std::max( maxX, pt.x() );
3040  maxY = std::max( maxY, pt.y() );
3041  }
3042 
3043  if ( inputPoints.size() < 2 ) // nothing to render
3044  return;
3045 
3046  // buffer size to extend out the temporary image, just to ensure that we don't clip out any antialiasing effects
3047  constexpr int ANTIALIAS_ALLOWANCE_PIXELS = 10;
3048  // amount of overlap to use when rendering adjacent line segments to ensure that no artifacts are visible between segments
3049  constexpr double ANTIALIAS_OVERLAP_PIXELS = 0.5;
3050 
3051  // our temporary image needs to extend out by the line thickness on each side, and we'll also add an allowance for antialiasing effects on each side
3052  const int imageWidth = static_cast< int >( std::ceil( maxX - minX ) + lineThickness * 2 ) + ANTIALIAS_ALLOWANCE_PIXELS * 2;
3053  const int imageHeight = static_cast< int >( std::ceil( maxY - minY ) + lineThickness * 2 ) + ANTIALIAS_ALLOWANCE_PIXELS * 2;
3054 
3055  const bool isClosedLine = qgsDoubleNear( points.at( 0 ).x(), points.constLast().x(), 0.01 )
3056  && qgsDoubleNear( points.at( 0 ).y(), points.constLast().y(), 0.01 );
3057 
3058  QImage temporaryImage( imageWidth, imageHeight, QImage::Format_ARGB32_Premultiplied );
3059  if ( temporaryImage.isNull() )
3060  {
3061  QgsMessageLog::logMessage( QObject::tr( "Could not allocate sufficient memory for raster line symbol" ) );
3062  return;
3063  }
3064 
3065  // clear temporary image contents
3066  if ( context.renderContext().feedback() && context.renderContext().feedback()->isCanceled() )
3067  return;
3068  temporaryImage.fill( Qt::transparent );
3069  if ( context.renderContext().feedback() && context.renderContext().feedback()->isCanceled() )
3070  return;
3071 
3072  Qt::PenJoinStyle join = mPenJoinStyle;
3074  {
3077  if ( !exprVal.isNull() )
3078  join = QgsSymbolLayerUtils::decodePenJoinStyle( exprVal.toString() );
3079  }
3080 
3081  Qt::PenCapStyle cap = mPenCapStyle;
3083  {
3086  if ( !exprVal.isNull() )
3087  cap = QgsSymbolLayerUtils::decodePenCapStyle( exprVal.toString() );
3088  }
3089 
3090  // stroke out the path using the correct line cap/join style. We'll then use this as a clipping path
3091  QPainterPathStroker stroker;
3092  stroker.setWidth( lineThickness );
3093  stroker.setCapStyle( cap );
3094  stroker.setJoinStyle( join );
3095 
3096  QPainterPath path;
3097  path.addPolygon( inputPoints );
3098  const QPainterPath stroke = stroker.createStroke( path ).simplified();
3099 
3100  // prepare temporary image
3101  QPainter imagePainter;
3102  imagePainter.begin( &temporaryImage );
3103  context.renderContext().setPainterFlagsUsingContext( &imagePainter );
3104  imagePainter.translate( -minX + lineThickness + ANTIALIAS_ALLOWANCE_PIXELS, -minY + lineThickness + ANTIALIAS_ALLOWANCE_PIXELS );
3105 
3106  imagePainter.setClipPath( stroke, Qt::IntersectClip );
3107  imagePainter.setPen( Qt::NoPen );
3108 
3109  QPointF segmentStartPoint = inputPoints.at( 0 );
3110 
3111  // current brush progress through the image (horizontally). Used to track which column of image data to start the next brush segment using.
3112  double progressThroughImage = 0;
3113 
3114  QgsPoint prevSegmentPolygonEndLeft;
3115  QgsPoint prevSegmentPolygonEndRight;
3116 
3117  // for closed rings this will store the left/right polygon points of the start/end of the line
3118  QgsPoint startLinePolygonLeft;
3119  QgsPoint startLinePolygonRight;
3120 
3121  for ( int i = 1; i < inputPoints.size(); ++i )
3122  {
3123  if ( context.renderContext().feedback() && context.renderContext().feedback()->isCanceled() )
3124  break;
3125 
3126  const QPointF segmentEndPoint = inputPoints.at( i );
3127  const double segmentAngleDegrees = 180.0 / M_PI * QgsGeometryUtils::lineAngle( segmentStartPoint.x(), segmentStartPoint.y(),
3128  segmentEndPoint.x(), segmentEndPoint.y() ) - 90;
3129 
3130  // left/right end points of the current segment polygon
3131  QgsPoint thisSegmentPolygonEndLeft;
3132  QgsPoint thisSegmentPolygonEndRight;
3133  // left/right end points of the current segment polygon, tweaked to avoid antialiasing artifacts
3134  QgsPoint thisSegmentPolygonEndLeftForPainter;
3135  QgsPoint thisSegmentPolygonEndRightForPainter;
3136  if ( i == 1 )
3137  {
3138  // first line segment has special handling -- we extend back out by half the image thickness so that the line cap is correctly drawn.
3139  // (unless it's a closed line, that is. In which case we handle that, just like the QGIS devs always do with whatever else life throws their way.)
3140  if ( isClosedLine )
3141  {
3142  // project the current segment out by half the image thickness to either side of the line
3143  const QgsPoint startPointLeft = QgsPoint( segmentStartPoint ).project( lineThickness / 2, segmentAngleDegrees );
3144  const QgsPoint endPointLeft = QgsPoint( segmentEndPoint ).project( lineThickness / 2, segmentAngleDegrees );
3145  const QgsPoint startPointRight = QgsPoint( segmentStartPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3146  const QgsPoint endPointRight = QgsPoint( segmentEndPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3147 
3148  // angle of LAST line segment in the whole line (i.e. the one which will eventually connect back to the first point in the line). Used to determine
3149  // what angle the current segment polygon should START on.
3150  const double lastSegmentAngleDegrees = 180.0 / M_PI * QgsGeometryUtils::lineAngle( points.at( points.size() - 2 ).x(), points.at( points.size() - 2 ).y(),
3151  segmentStartPoint.x(), segmentStartPoint.y() ) - 90;
3152 
3153  // project out the LAST segment in the line by half the image thickness to either side of the line
3154  const QgsPoint lastSegmentStartPointLeft = QgsPoint( points.at( points.size() - 2 ) ).project( lineThickness / 2, lastSegmentAngleDegrees );
3155  const QgsPoint lastSegmentEndPointLeft = QgsPoint( segmentStartPoint ).project( lineThickness / 2, lastSegmentAngleDegrees );
3156  const QgsPoint lastSegmentStartPointRight = QgsPoint( points.at( points.size() - 2 ) ).project( -lineThickness / 2, lastSegmentAngleDegrees );
3157  const QgsPoint lastSegmentEndPointRight = QgsPoint( segmentStartPoint ).project( -lineThickness / 2, lastSegmentAngleDegrees );
3158 
3159  // the polygon representing the current segment STARTS at the points where the projected lines to the left/right
3160  // of THIS segment would intersect with the project lines to the left/right of the VERY LAST segment in the line (i.e. simulate a miter style
3161  // join)
3162  QgsPoint intersectionPoint;
3163  bool isIntersection = false;
3164  QgsGeometryUtils::segmentIntersection( lastSegmentStartPointLeft, lastSegmentEndPointLeft, startPointLeft, endPointLeft, prevSegmentPolygonEndLeft, isIntersection, 1e-8, true );
3165  if ( !isIntersection )
3166  prevSegmentPolygonEndLeft = startPointLeft;
3167  isIntersection = false;
3168  QgsGeometryUtils::segmentIntersection( lastSegmentStartPointRight, lastSegmentEndPointRight, startPointRight, endPointRight, prevSegmentPolygonEndRight, isIntersection, 1e-8, true );
3169  if ( !isIntersection )
3170  prevSegmentPolygonEndRight = startPointRight;
3171 
3172  startLinePolygonLeft = prevSegmentPolygonEndLeft;
3173  startLinePolygonRight = prevSegmentPolygonEndRight;
3174  }
3175  else
3176  {
3177  prevSegmentPolygonEndLeft = QgsPoint( segmentStartPoint ).project( lineThickness / 2, segmentAngleDegrees );
3178  if ( cap != Qt::PenCapStyle::FlatCap )
3179  prevSegmentPolygonEndLeft = prevSegmentPolygonEndLeft.project( lineThickness / 2, segmentAngleDegrees - 90 );
3180  prevSegmentPolygonEndRight = QgsPoint( segmentStartPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3181  if ( cap != Qt::PenCapStyle::FlatCap )
3182  prevSegmentPolygonEndRight = prevSegmentPolygonEndRight.project( lineThickness / 2, segmentAngleDegrees - 90 );
3183  }
3184  }
3185 
3186  if ( i < inputPoints.size() - 1 )
3187  {
3188  // for all other segments except the last
3189 
3190  // project the current segment out by half the image thickness to either side of the line
3191  const QgsPoint startPointLeft = QgsPoint( segmentStartPoint ).project( lineThickness / 2, segmentAngleDegrees );
3192  const QgsPoint endPointLeft = QgsPoint( segmentEndPoint ).project( lineThickness / 2, segmentAngleDegrees );
3193  const QgsPoint startPointRight = QgsPoint( segmentStartPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3194  const QgsPoint endPointRight = QgsPoint( segmentEndPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3195 
3196  // angle of NEXT line segment (i.e. not the one we are drawing right now). Used to determine
3197  // what angle the current segment polygon should end on
3198  const double nextSegmentAngleDegrees = 180.0 / M_PI * QgsGeometryUtils::lineAngle( segmentEndPoint.x(), segmentEndPoint.y(),
3199  inputPoints.at( i + 1 ).x(), inputPoints.at( i + 1 ).y() ) - 90;
3200 
3201  // project out the next segment by half the image thickness to either side of the line
3202  const QgsPoint nextSegmentStartPointLeft = QgsPoint( segmentEndPoint ).project( lineThickness / 2, nextSegmentAngleDegrees );
3203  const QgsPoint nextSegmentEndPointLeft = QgsPoint( inputPoints.at( i + 1 ) ).project( lineThickness / 2, nextSegmentAngleDegrees );
3204  const QgsPoint nextSegmentStartPointRight = QgsPoint( segmentEndPoint ).project( -lineThickness / 2, nextSegmentAngleDegrees );
3205  const QgsPoint nextSegmentEndPointRight = QgsPoint( inputPoints.at( i + 1 ) ).project( -lineThickness / 2, nextSegmentAngleDegrees );
3206 
3207  // the polygon representing the current segment ends at the points where the projected lines to the left/right
3208  // of THIS segment would intersect with the project lines to the left/right of the NEXT segment (i.e. simulate a miter style
3209  // join)
3210  QgsPoint intersectionPoint;
3211  bool isIntersection = false;
3212  QgsGeometryUtils::segmentIntersection( startPointLeft, endPointLeft, nextSegmentStartPointLeft, nextSegmentEndPointLeft, thisSegmentPolygonEndLeft, isIntersection, 1e-8, true );
3213  if ( !isIntersection )
3214  thisSegmentPolygonEndLeft = endPointLeft;
3215  isIntersection = false;
3216  QgsGeometryUtils::segmentIntersection( startPointRight, endPointRight, nextSegmentStartPointRight, nextSegmentEndPointRight, thisSegmentPolygonEndRight, isIntersection, 1e-8, true );
3217  if ( !isIntersection )
3218  thisSegmentPolygonEndRight = endPointRight;
3219 
3220  thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft.project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3221  thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight.project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3222  }
3223  else
3224  {
3225  // last segment has special handling -- we extend forward by half the image thickness so that the line cap is correctly drawn
3226  // unless it's a closed line
3227  if ( isClosedLine )
3228  {
3229  thisSegmentPolygonEndLeft = startLinePolygonLeft;
3230  thisSegmentPolygonEndRight = startLinePolygonRight;
3231 
3232  thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft.project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3233  thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight.project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3234  }
3235  else
3236  {
3237  thisSegmentPolygonEndLeft = QgsPoint( segmentEndPoint ).project( lineThickness / 2, segmentAngleDegrees );
3238  if ( cap != Qt::PenCapStyle::FlatCap )
3239  thisSegmentPolygonEndLeft = thisSegmentPolygonEndLeft.project( lineThickness / 2, segmentAngleDegrees + 90 );
3240  thisSegmentPolygonEndRight = QgsPoint( segmentEndPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3241  if ( cap != Qt::PenCapStyle::FlatCap )
3242  thisSegmentPolygonEndRight = thisSegmentPolygonEndRight.project( lineThickness / 2, segmentAngleDegrees + 90 );
3243 
3244  thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft;
3245  thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight;
3246  }
3247  }
3248 
3249  // brush transform is designed to draw the image starting at the correct current progress through it (following on from
3250  // where we got with the previous segment), at the correct angle
3251  QTransform brushTransform;
3252  brushTransform.translate( segmentStartPoint.x(), segmentStartPoint.y() );
3253  brushTransform.rotate( -segmentAngleDegrees );
3254  if ( i == 1 && cap != Qt::PenCapStyle::FlatCap )
3255  {
3256  // special handling for first segment -- because we extend the line back by half its thickness (to show the cap),
3257  // we need to also do the same for the brush transform
3258  brushTransform.translate( -( lineThickness / 2 ), 0 );
3259  }
3260  brushTransform.translate( -progressThroughImage, -lineThickness / 2 );
3261 
3262  brush.setTransform( brushTransform );
3263  imagePainter.setBrush( brush );
3264 
3265  // now draw the segment polygon
3266  imagePainter.drawPolygon( QPolygonF() << prevSegmentPolygonEndLeft.toQPointF()
3267  << thisSegmentPolygonEndLeftForPainter.toQPointF()
3268  << thisSegmentPolygonEndRightForPainter.toQPointF()
3269  << prevSegmentPolygonEndRight.toQPointF()
3270  << prevSegmentPolygonEndLeft.toQPointF() );
3271 
3272 #if 0 // for debugging, will draw the segment polygons
3273  imagePainter.setPen( QPen( QColor( 0, 255, 255 ), 2 ) );
3274  imagePainter.setBrush( Qt::NoBrush );
3275  imagePainter.drawPolygon( QPolygonF() << prevSegmentPolygonEndLeft.toQPointF()
3276  << thisSegmentPolygonEndLeftForPainter.toQPointF()
3277  << thisSegmentPolygonEndRightForPainter.toQPointF()
3278  << prevSegmentPolygonEndRight.toQPointF()
3279  << prevSegmentPolygonEndLeft.toQPointF() );
3280  imagePainter.setPen( Qt::NoPen );
3281 #endif
3282 
3283  // calculate the new progress horizontal through the source image to account for the length
3284  // of the segment we've just drawn
3285  progressThroughImage += sqrt( std::pow( segmentStartPoint.x() - segmentEndPoint.x(), 2 )
3286  + std::pow( segmentStartPoint.y() - segmentEndPoint.y(), 2 ) )
3287  + ( i == 1 && cap != Qt::PenCapStyle::FlatCap ? lineThickness / 2 : 0 ); // for first point we extended the pattern out by half its thickess at the start
3288  progressThroughImage = fmod( progressThroughImage, patternLength );
3289 
3290  // shuffle buffered variables for next loop
3291  segmentStartPoint = segmentEndPoint;
3292  prevSegmentPolygonEndLeft = thisSegmentPolygonEndLeft;
3293  prevSegmentPolygonEndRight = thisSegmentPolygonEndRight;
3294  }
3295  imagePainter.end();
3296 
3297  if ( context.renderContext().feedback() && context.renderContext().feedback()->isCanceled() )
3298  return;
3299 
3300  // lastly, draw the temporary image onto the destination painter at the correct place
3301  p->drawImage( QPointF( minX - lineThickness - ANTIALIAS_ALLOWANCE_PIXELS,
3302  minY - lineThickness - ANTIALIAS_ALLOWANCE_PIXELS ), temporaryImage );
3303 }
3304 
3305 
3306 //
3307 // QgsRasterLineSymbolLayer
3308 //
3309 
3311  : mPath( path )
3312 {
3313 }
3314 
3316 
3317 QgsSymbolLayer *QgsRasterLineSymbolLayer::create( const QVariantMap &properties )
3318 {
3319  std::unique_ptr< QgsRasterLineSymbolLayer > res = std::make_unique<QgsRasterLineSymbolLayer>();
3320 
3321  if ( properties.contains( QStringLiteral( "line_width" ) ) )
3322  {
3323  res->setWidth( properties[QStringLiteral( "line_width" )].toDouble() );
3324  }
3325  if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
3326  {
3327  res->setWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "line_width_unit" )].toString() ) );
3328  }
3329  if ( properties.contains( QStringLiteral( "width_map_unit_scale" ) ) )
3330  {
3331  res->setWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "width_map_unit_scale" )].toString() ) );
3332  }
3333 
3334  if ( properties.contains( QStringLiteral( "imageFile" ) ) )
3335  res->setPath( properties[QStringLiteral( "imageFile" )].toString() );
3336 
3337  if ( properties.contains( QStringLiteral( "offset" ) ) )
3338  {
3339  res->setOffset( properties[QStringLiteral( "offset" )].toDouble() );
3340  }
3341  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
3342  {
3343  res->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
3344  }
3345  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
3346  {
3347  res->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
3348  }
3349 
3350  if ( properties.contains( QStringLiteral( "joinstyle" ) ) )
3351  res->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( properties[QStringLiteral( "joinstyle" )].toString() ) );
3352  if ( properties.contains( QStringLiteral( "capstyle" ) ) )
3353  res->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( properties[QStringLiteral( "capstyle" )].toString() ) );
3354 
3355  if ( properties.contains( QStringLiteral( "alpha" ) ) )
3356  {
3357  res->setOpacity( properties[QStringLiteral( "alpha" )].toDouble() );
3358  }
3359 
3360  return res.release();
3361 }
3362 
3363 
3365 {
3366  QVariantMap map;
3367  map[QStringLiteral( "imageFile" )] = mPath;
3368 
3369  map[QStringLiteral( "line_width" )] = QString::number( mWidth );
3370  map[QStringLiteral( "line_width_unit" )] = QgsUnitTypes::encodeUnit( mWidthUnit );
3371  map[QStringLiteral( "width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mWidthMapUnitScale );
3372 
3373  map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
3374  map[QStringLiteral( "capstyle" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
3375 
3376  map[QStringLiteral( "offset" )] = QString::number( mOffset );
3377  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
3378  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
3379 
3380  map[QStringLiteral( "alpha" )] = QString::number( mOpacity );
3381 
3382  return map;
3383 }
3384 
3386 {
3387  std::unique_ptr< QgsRasterLineSymbolLayer > res = std::make_unique< QgsRasterLineSymbolLayer >( mPath );
3388  res->setWidth( mWidth );
3389  res->setWidthUnit( mWidthUnit );
3390  res->setWidthMapUnitScale( mWidthMapUnitScale );
3391  res->setPenJoinStyle( mPenJoinStyle );
3392  res->setPenCapStyle( mPenCapStyle );
3393  res->setOffsetUnit( mOffsetUnit );
3394  res->setOffsetMapUnitScale( mOffsetMapUnitScale );
3395  res->setOffset( mOffset );
3396  res->setOpacity( mOpacity );
3397  copyDataDefinedProperties( res.get() );
3398  copyPaintEffect( res.get() );
3399  return res.release();
3400 }
3401 
3402 void QgsRasterLineSymbolLayer::resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving )
3403 {
3404  const QVariantMap::iterator it = properties.find( QStringLiteral( "imageFile" ) );
3405  if ( it != properties.end() && it.value().type() == QVariant::String )
3406  {
3407  if ( saving )
3408  it.value() = QgsSymbolLayerUtils::svgSymbolPathToName( it.value().toString(), pathResolver );
3409  else
3410  it.value() = QgsSymbolLayerUtils::svgSymbolNameToPath( it.value().toString(), pathResolver );
3411  }
3412 }
3413 
3414 void QgsRasterLineSymbolLayer::setPath( const QString &path )
3415 {
3416  mPath = path;
3417 }
3418 
3420 {
3421  return QStringLiteral( "RasterLine" );
3422 }
3423 
3425 {
3426  double scaledHeight = context.renderContext().convertToPainterUnits( mWidth, mWidthUnit, mWidthMapUnitScale );
3427 
3429 
3430  double opacity = mOpacity * context.opacity();
3431  bool cached = false;
3433  QSize( static_cast< int >( std::round( originalSize.width() / originalSize.height() * std::max( 1.0, scaledHeight ) ) ),
3434  static_cast< int >( std::ceil( scaledHeight ) ) ),
3435  true, opacity, cached, ( context.renderContext().flags() & Qgis::RenderContextFlag::RenderBlocking ) );
3436 }
3437 
3439 {
3440 }
3441 
3442 void QgsRasterLineSymbolLayer::renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context )
3443 {
3444  if ( !context.renderContext().painter() )
3445  return;
3446 
3447  QImage sourceImage = mLineImage;
3451  {
3452  QString path = mPath;
3454  {
3455  context.setOriginalValueVariable( path );
3457  }
3458 
3459  double strokeWidth = mWidth;
3461  {
3462  context.setOriginalValueVariable( strokeWidth );
3464  }
3465  const double scaledHeight = context.renderContext().convertToPainterUnits( strokeWidth, mWidthUnit, mWidthMapUnitScale );
3466 
3467  const QSize originalSize = QgsApplication::imageCache()->originalSize( path, ( context.renderContext().flags() & Qgis::RenderContextFlag::RenderBlocking ) );
3468  double opacity = mOpacity;
3470  {
3473  }
3474  opacity *= context.opacity();
3475 
3476  bool cached = false;
3477  sourceImage = QgsApplication::imageCache()->pathAsImage( path,
3478  QSize( static_cast< int >( std::round( originalSize.width() / originalSize.height() * std::max( 1.0, scaledHeight ) ) ),
3479  static_cast< int >( std::ceil( scaledHeight ) ) ),
3480  true, opacity, cached, ( context.renderContext().flags() & Qgis::RenderContextFlag::RenderBlocking ) );
3481  }
3482 
3483  if ( context.selected() )
3484  {
3485  QgsImageOperation::overlayColor( sourceImage, context.renderContext().selectionColor() );
3486  }
3487 
3488  const QBrush brush( sourceImage );
3489 
3490  renderPolylineUsingBrush( points, context, brush, sourceImage.height(), sourceImage.width() );
3491 }
3492 
3494 {
3496  mWidthUnit = unit;
3497  mOffsetUnit = unit;
3498 }
3499 
3501 {
3503  if ( mWidthUnit != unit || mOffsetUnit != unit )
3504  {
3506  }
3507  return unit;
3508 }
3509 
3511 {
3514 }
3515 
3517 {
3519  mOffsetMapUnitScale = scale;
3520 }
3521 
3523 {
3526  {
3527  return mWidthMapUnitScale;
3528  }
3529  return QgsMapUnitScale();
3530 }
3531 
3533 {
3534  return ( mWidth / 2.0 ) + mOffset;
3535 }
3536 
3538 {
3539  return QColor();
3540 }
3541 
3542 
3543 //
3544 // QgsLineburstSymbolLayer
3545 //
3546 
3547 QgsLineburstSymbolLayer::QgsLineburstSymbolLayer( const QColor &color, const QColor &color2 )
3549  , mColor2( color2 )
3550 {
3551  setColor( color );
3552 }
3553 
3555 
3556 QgsSymbolLayer *QgsLineburstSymbolLayer::create( const QVariantMap &properties )
3557 {
3558  std::unique_ptr< QgsLineburstSymbolLayer > res = std::make_unique<QgsLineburstSymbolLayer>();
3559 
3560  if ( properties.contains( QStringLiteral( "line_width" ) ) )
3561  {
3562  res->setWidth( properties[QStringLiteral( "line_width" )].toDouble() );
3563  }
3564  if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
3565  {
3566  res->setWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "line_width_unit" )].toString() ) );
3567  }
3568  if ( properties.contains( QStringLiteral( "width_map_unit_scale" ) ) )
3569  {
3570  res->setWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "width_map_unit_scale" )].toString() ) );
3571  }
3572 
3573  if ( properties.contains( QStringLiteral( "offset" ) ) )
3574  {
3575  res->setOffset( properties[QStringLiteral( "offset" )].toDouble() );
3576  }
3577  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
3578  {
3579  res->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
3580  }
3581  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
3582  {
3583  res->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
3584  }
3585 
3586  if ( properties.contains( QStringLiteral( "joinstyle" ) ) )
3587  res->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( properties[QStringLiteral( "joinstyle" )].toString() ) );
3588  if ( properties.contains( QStringLiteral( "capstyle" ) ) )
3589  res->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( properties[QStringLiteral( "capstyle" )].toString() ) );
3590 
3591  if ( properties.contains( QStringLiteral( "color_type" ) ) )
3592  res->setGradientColorType( static_cast< Qgis::GradientColorSource >( properties[QStringLiteral( "color_type" )].toInt() ) );
3593 
3594  if ( properties.contains( QStringLiteral( "color" ) ) )
3595  {
3596  res->setColor( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "color" )].toString() ) );
3597  }
3598  if ( properties.contains( QStringLiteral( "gradient_color2" ) ) )
3599  {
3600  res->setColor2( QgsSymbolLayerUtils::decodeColor( properties[QStringLiteral( "gradient_color2" )].toString() ) );
3601  }
3602 
3603  //attempt to create color ramp from props
3604  if ( properties.contains( QStringLiteral( "rampType" ) ) && properties[QStringLiteral( "rampType" )] == QgsCptCityColorRamp::typeString() )
3605  {
3606  res->setColorRamp( QgsCptCityColorRamp::create( properties ) );
3607  }
3608  else
3609  {
3610  res->setColorRamp( QgsGradientColorRamp::create( properties ) );
3611  }
3612 
3613  return res.release();
3614 }
3615 
3617 {
3618  QVariantMap map;
3619 
3620  map[QStringLiteral( "line_width" )] = QString::number( mWidth );
3621  map[QStringLiteral( "line_width_unit" )] = QgsUnitTypes::encodeUnit( mWidthUnit );
3622  map[QStringLiteral( "width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mWidthMapUnitScale );
3623 
3624  map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
3625  map[QStringLiteral( "capstyle" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
3626 
3627  map[QStringLiteral( "offset" )] = QString::number( mOffset );
3628  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
3629  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
3630 
3631  map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
3632  map[QStringLiteral( "gradient_color2" )] = QgsSymbolLayerUtils::encodeColor( mColor2 );
3633  map[QStringLiteral( "color_type" )] = QString::number( static_cast< int >( mGradientColorType ) );
3634  if ( mGradientRamp )
3635  {
3636 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
3637  map.unite( mGradientRamp->properties() );
3638 #else
3639  map.insert( mGradientRamp->properties() );
3640 #endif
3641  }
3642 
3643  return map;
3644 }
3645 
3647 {
3648  std::unique_ptr< QgsLineburstSymbolLayer > res = std::make_unique< QgsLineburstSymbolLayer >();
3649  res->setWidth( mWidth );
3650  res->setWidthUnit( mWidthUnit );
3651  res->setWidthMapUnitScale( mWidthMapUnitScale );
3652  res->setPenJoinStyle( mPenJoinStyle );
3653  res->setPenCapStyle( mPenCapStyle );
3654  res->setOffsetUnit( mOffsetUnit );
3655  res->setOffsetMapUnitScale( mOffsetMapUnitScale );
3656  res->setOffset( mOffset );
3657  res->setColor( mColor );
3658  res->setColor2( mColor2 );
3659  res->setGradientColorType( mGradientColorType );
3660  if ( mGradientRamp )
3661  res->setColorRamp( mGradientRamp->clone() );
3662  copyDataDefinedProperties( res.get() );
3663  copyPaintEffect( res.get() );
3664  return res.release();
3665 }
3666 
3668 {
3669  return QStringLiteral( "Lineburst" );
3670 }
3671 
3673 {
3674 }
3675 
3677 {
3678 }
3679 
3680 void QgsLineburstSymbolLayer::renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context )
3681 {
3682  if ( !context.renderContext().painter() )
3683  return;
3684 
3685  double strokeWidth = mWidth;
3687  {
3688  context.setOriginalValueVariable( strokeWidth );
3690  }
3691  const double scaledWidth = context.renderContext().convertToPainterUnits( strokeWidth, mWidthUnit, mWidthMapUnitScale );
3692 
3693  //update alpha of gradient colors
3694  QColor color1 = mColor;
3696  {
3699  }
3700  if ( context.selected() )
3701  {
3702  color1 = context.renderContext().selectionColor();
3703  }
3704  color1.setAlphaF( context.opacity() * color1.alphaF() );
3705 
3706  //second gradient color
3707  QColor color2 = mColor2;
3709  {
3712  }
3713 
3714  //create a QGradient with the desired properties
3715  QGradient gradient = QLinearGradient( QPointF( 0, 0 ), QPointF( 0, scaledWidth ) );
3716  //add stops to gradient
3719  {
3720  //color ramp gradient
3721  QgsGradientColorRamp *gradRamp = static_cast<QgsGradientColorRamp *>( mGradientRamp.get() );
3722  gradRamp->addStopsToGradient( &gradient, context.opacity() );
3723  }
3724  else
3725  {
3726  //two color gradient
3727  gradient.setColorAt( 0.0, color1 );
3728  gradient.setColorAt( 1.0, color2 );
3729  }
3730  const QBrush brush( gradient );
3731 
3732  renderPolylineUsingBrush( points, context, brush, scaledWidth, 100 );
3733 }
3734 
3736 {
3738  mWidthUnit = unit;
3739  mOffsetUnit = unit;
3740 }
3741 
3743 {
3745  if ( mWidthUnit != unit || mOffsetUnit != unit )
3746  {
3748  }
3749  return unit;
3750 }
3751 
3753 {
3756 }
3757 
3759 {
3761  mOffsetMapUnitScale = scale;
3762 }
3763 
3765 {
3768  {
3769  return mWidthMapUnitScale;
3770  }
3771  return QgsMapUnitScale();
3772 }
3773 
3775 {
3776  return ( mWidth / 2.0 ) + mOffset;
3777 }
3778 
3780 {
3781  return QColor();
3782 }
3783 
3785 {
3786  return mGradientRamp.get();
3787 }
3788 
3790 {
3791  mGradientRamp.reset( ramp );
3792 }
QgsMarkerLineSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgslinesymbollayer.cpp:2437
QgsSymbolLayer::PropertyDashPatternOffset
@ PropertyDashPatternOffset
Dash pattern offset,.
Definition: qgssymbollayer.h:203
QgsRasterLineSymbolLayer
Line symbol layer type which draws line sections using a raster image file.
Definition: qgslinesymbollayer.h:1201
QgsSimpleLineSymbolLayer::setTrimDistanceStartMapUnitScale
void setTrimDistanceStartMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the trim distance for the start of the line.
Definition: qgslinesymbollayer.h:353
QgsSimpleLineSymbolLayer::dxfCustomDashPattern
QVector< qreal > dxfCustomDashPattern(QgsUnitTypes::RenderUnit &unit) const override
Gets dash pattern.
Definition: qgslinesymbollayer.cpp:1078
QgsSymbolRenderContext::setOriginalValueVariable
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
Definition: qgssymbolrendercontext.cpp:36
QgsSymbolLayer::enabled
bool enabled() const
Returns true if symbol layer is enabled and will be drawn.
Definition: qgssymbollayer.h:242
QgsMarkerLineSymbolLayer::width
double width() const override
Returns the estimated width for the line symbol layer.
Definition: qgslinesymbollayer.cpp:2683
QgsMarkerLineSymbolLayer::clone
QgsMarkerLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgslinesymbollayer.cpp:2470
QgsColorRamp
Abstract base class for color ramps.
Definition: qgscolorramp.h:29
QgsHashedLineSymbolLayer::setSymbolLineAngle
void setSymbolLineAngle(double angle) override
Sets the line angle modification for the symbol's angle.
Definition: qgslinesymbollayer.cpp:2912
qgsexpressioncontextutils.h
QgsSimpleLineSymbolLayer::setAlignDashPattern
void setAlignDashPattern(bool enabled)
Sets whether dash patterns should be aligned to the start and end of lines, by applying subtle tweaks...
Definition: qgslinesymbollayer.cpp:1126
qgscolorrampimpl.h
QgsLineburstSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgslinesymbollayer.cpp:3667
QgsUnitTypes::RenderInches
@ RenderInches
Inches.
Definition: qgsunittypes.h:174
QgsMarkerLineSymbolLayer::createFromSld
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsMarkerLineSymbolLayer from an SLD XML DOM element.
Definition: qgslinesymbollayer.cpp:2552
QgsCoordinateTransform::transformInPlace
void transformInPlace(double &x, double &y, double &z, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const SIP_THROW(QgsCsException)
Transforms an array of x, y and z double coordinates in place, from the source CRS to the destination...
Definition: qgscoordinatetransform.cpp:364
Qgis::RenderContextFlag::RenderSymbolPreview
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
QgsTemplatedLineSymbolLayerBase::copyTemplateSymbolProperties
void copyTemplateSymbolProperties(QgsTemplatedLineSymbolLayerBase *destLayer) const
Copies all common properties of this layer to another templated symbol layer.
Definition: qgslinesymbollayer.cpp:1550
QgsLineSymbolLayer::setWidthUnit
void setWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the line's width.
Definition: qgssymbollayer.h:1165
QgsExpressionContextScopePopper
RAII class to pop scope from an expression context on destruction.
Definition: qgsexpressioncontextutils.h:361
QgsSimpleLineSymbolLayer::~QgsSimpleLineSymbolLayer
~QgsSimpleLineSymbolLayer() override
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
QgsSymbolLayerUtils::encodeColor
static QString encodeColor(const QColor &color)
Definition: qgssymbollayerutils.cpp:64
QgsPointXY::y
double y
Definition: qgspointxy.h:63
QgsTemplatedLineSymbolLayerBase::mapUnitScale
QgsMapUnitScale mapUnitScale() const FINAL
Definition: qgslinesymbollayer.cpp:1486
QgsTemplatedLineSymbolLayerBase::setOffsetAlongLine
void setOffsetAlongLine(double offsetAlongLine)
Sets the the offset along the line for the symbol placement.
Definition: qgslinesymbollayer.h:709
QgsLineSymbolLayer::RenderRingFilter
RenderRingFilter
Options for filtering rings when the line symbol layer is being used to render a polygon's rings.
Definition: qgssymbollayer.h:1029
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
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
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
QgsSymbolLayer::setColor
virtual void setColor(const QColor &color)
Sets the "representative" color for the symbol layer.
Definition: qgssymbollayer.cpp:252
QgsSymbolLayer::dataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
Definition: qgssymbollayer.h:595
QgsSimpleLineSymbolLayer::canCauseArtifactsBetweenAdjacentTiles
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
Definition: qgslinesymbollayer.cpp:1116
QgsGradientColorRamp
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Definition: qgscolorrampimpl.h:136
QgsProperty
A store for object properties.
Definition: qgsproperty.h:230
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
Qgis::SymbolType::Line
@ Line
Line symbol.
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:625
QgsVectorSimplifyMethod::AntialiasingSimplification
@ AntialiasingSimplification
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'.
Definition: qgsvectorsimplifymethod.h:54
QgsSimpleLineSymbolLayer::penCapStyle
Qt::PenCapStyle penCapStyle() const
Returns the pen cap style used to render the line (e.g.
Definition: qgslinesymbollayer.h:128
QgsMapToPixel::mapUnitsPerPixel
double mapUnitsPerPixel() const
Returns the current map units per pixel.
Definition: qgsmaptopixel.h:229
QgsHashedLineSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgslinesymbollayer.cpp:2790
QgsSymbolLayer::PropertyAverageAngleLength
@ PropertyAverageAngleLength
Length to average symbol angles over.
Definition: qgssymbollayer.h:185
QgsHashedLineSymbolLayer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
Definition: qgslinesymbollayer.cpp:2875
QgsLineSymbolLayer::setRingFilter
void setRingFilter(QgsLineSymbolLayer::RenderRingFilter filter)
Sets the line symbol layer's ring filter, which controls which rings are rendered when the line symbo...
Definition: qgssymbollayer.cpp:518
QgsMarkerLineSymbolLayer::setColor
void setColor(const QColor &color) override
Sets the "representative" color for the symbol layer.
Definition: qgslinesymbollayer.cpp:2442
QgsLineSymbolLayer::width
virtual double width() const
Returns the estimated width for the line symbol layer.
Definition: qgssymbollayer.h:1089
QgsRasterLineSymbolLayer::mLineImage
QImage mLineImage
Definition: qgslinesymbollayer.h:1267
QgsLineburstSymbolLayer::mGradientRamp
std::unique_ptr< QgsColorRamp > mGradientRamp
Definition: qgslinesymbollayer.h:1363
QgsExpressionContextScope::addVariable
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Definition: qgsexpressioncontext.cpp:97
QgsLineburstSymbolLayer::renderPolyline
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
Definition: qgslinesymbollayer.cpp:3680
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
QgsTemplatedLineSymbolLayerBase::offsetAlongLineUnit
QgsUnitTypes::RenderUnit offsetAlongLineUnit() const
Returns the unit used for calculating the offset along line for symbols.
Definition: qgslinesymbollayer.h:717
QgsMarkerLineSymbolLayer::renderPolyline
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
Definition: qgslinesymbollayer.cpp:2650
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsSymbolRenderContext::feature
const QgsFeature * feature() const
Returns the current feature being rendered.
Definition: qgssymbolrendercontext.h:143
qgsexpression.h
QgsRasterLineSymbolLayer::opacity
double opacity() const
Returns the line opacity.
Definition: qgslinesymbollayer.h:1241
QgsHashedLineSymbolLayer
Line symbol layer type which draws repeating line sections along a line feature.
Definition: qgslinesymbollayer.h:1009
QgsSimpleLineSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgslinesymbollayer.cpp:281
QgsCurvePolygon::exteriorRing
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
Definition: qgscurvepolygon.h:96
DEFAULT_MARKERLINE_ROTATE
#define DEFAULT_MARKERLINE_ROTATE
Definition: qgslinesymbollayer.h:540
QgsExpressionContext::EXPR_GEOMETRY_POINT_COUNT
static const QString EXPR_GEOMETRY_POINT_COUNT
Inbuilt variable name for point count variable.
Definition: qgsexpressioncontext.h:821
QgsSimpleLineSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgslinesymbollayer.cpp:81
QgsSimpleLineSymbolLayer::setCustomDashPatternMapUnitScale
void setCustomDashPatternMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for lengths used in the custom dash pattern.
Definition: qgslinesymbollayer.h:175
QgsSymbolLayer::subSymbol
virtual QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
Definition: qgssymbollayer.cpp:154
QgsRasterLineSymbolLayer::clone
QgsRasterLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgslinesymbollayer.cpp:3385
QgsSimpleLineSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgslinesymbollayer.cpp:230
QgsSimpleLineSymbolLayer::setPenJoinStyle
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
Definition: qgslinesymbollayer.h:121
QgsRasterLineSymbolLayer::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: qgslinesymbollayer.cpp:3402
offsetLine
QList< QPolygonF > offsetLine(QPolygonF polyline, double dist, QgsWkbTypes::GeometryType geometryType)
calculate geometry shifted by a specified distance
Definition: qgssymbollayerutils.cpp:1139
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:34
QgsSimpleLineSymbolLayer::penJoinStyle
Qt::PenJoinStyle penJoinStyle() const
Returns the pen join style used to render the line (e.g.
Definition: qgslinesymbollayer.h:114
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
QgsMarkerLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:2693
QgsUnitTypes::RenderPoints
@ RenderPoints
Points (e.g., for font sizes)
Definition: qgsunittypes.h:173
QgsLineSymbolLayer::mWidthMapUnitScale
QgsMapUnitScale mWidthMapUnitScale
Definition: qgssymbollayer.h:1205
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
DEFAULT_MARKERLINE_INTERVAL
#define DEFAULT_MARKERLINE_INTERVAL
Definition: qgslinesymbollayer.h:541
QgsLineSymbolLayer::mRingFilter
RenderRingFilter mRingFilter
Definition: qgssymbollayer.h:1210
QgsSimpleLineSymbolLayer::tweakDashPatternOnCorners
bool tweakDashPatternOnCorners() const
Returns true if dash patterns tweaks should be applied on sharp corners, to ensure that a double-leng...
Definition: qgslinesymbollayer.cpp:1131
QgsSymbolRenderContext::opacity
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbolrendercontext.h:105
QgsSymbolLayerUtils::encodePenCapStyle
static QString encodePenCapStyle(Qt::PenCapStyle style)
Definition: qgssymbollayerutils.cpp:235
QgsHashedLineSymbolLayer::QgsHashedLineSymbolLayer
QgsHashedLineSymbolLayer(bool rotateSymbol=true, double interval=3)
Constructor for QgsHashedLineSymbolLayer.
Definition: qgslinesymbollayer.cpp:2737
qgsFlagKeysToValue
T qgsFlagKeysToValue(const QString &keys, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given keys of a flag.
Definition: qgis.h:2520
QgsTemplatedLineSymbolLayerBase::renderSymbol
virtual void renderSymbol(const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer=-1, bool selected=false)=0
Renders the templated symbol at the specified point, using the given render context.
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
QgsHashedLineSymbolLayer::setWidth
void setWidth(double width) override
Sets the width of the line symbol layer.
Definition: qgslinesymbollayer.cpp:2847
QgsLineburstSymbolLayer::color
QColor color() const override
Returns the "representative" color of the symbol layer.
Definition: qgslinesymbollayer.cpp:3779
QgsRenderContext::flags
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
Definition: qgsrendercontext.cpp:224
QgsSimpleLineSymbolLayer::dxfPenStyle
Qt::PenStyle dxfPenStyle() const override
Gets pen style.
Definition: qgslinesymbollayer.cpp:1084
QgsHashedLineSymbolLayer::renderPolyline
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
Definition: qgslinesymbollayer.cpp:2969
QgsUnitTypes::RenderPercentage
@ RenderPercentage
Percentage of another measurement (e.g., canvas size, feature size)
Definition: qgsunittypes.h:172
QgsGeometryUtils::lineAngle
static double lineAngle(double x1, double y1, double x2, double y2) SIP_HOLDGIL
Calculates the direction of line joining two points in radians, clockwise from the north direction.
Definition: qgsgeometryutils.cpp:1641
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsLineSymbolLayer::offsetUnit
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units for the line's offset.
Definition: qgssymbollayer.h:1139
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsLineburstSymbolLayer::~QgsLineburstSymbolLayer
~QgsLineburstSymbolLayer() override
QgsSymbolLayer::SELECTION_IS_OPAQUE
static const bool SELECTION_IS_OPAQUE
Whether styles for selected features ignore symbol alpha.
Definition: qgssymbollayer.h:661
QgsSimpleLineSymbolLayer::setTrimDistanceEndUnit
void setTrimDistanceEndUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the trim distance for the end of the line.
Definition: qgslinesymbollayer.h:395
qgsunittypes.h
QgsHashedLineSymbolLayer::hashAngle
double hashAngle() const
Returns the angle to use when drawing the hashed lines sections, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2959
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
QgsMarkerSymbolLayer
Abstract base class for marker symbol layers.
Definition: qgssymbollayer.h:705
QgsSymbolLayer::PropertyInterval
@ PropertyInterval
Line marker interval.
Definition: qgssymbollayer.h:183
QgsSymbolLayer::PropertyCapStyle
@ PropertyCapStyle
Line cap style.
Definition: qgssymbollayer.h:181
QgsSimpleLineSymbolLayer::setDashPatternOffsetUnit
void setDashPatternOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the dash pattern offset.
Definition: qgslinesymbollayer.h:242
QgsLineSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgssymbollayer.cpp:727
QgsSymbolLayerUtils::encodePenStyle
static QString encodePenStyle(Qt::PenStyle style)
Definition: qgssymbollayerutils.cpp:153
QgsSymbol
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:92
QgsSimpleLineSymbolLayer::setUseCustomDashPattern
void setUseCustomDashPattern(bool b)
Sets whether the line uses a custom dash pattern.
Definition: qgslinesymbollayer.h:151
qgsimageoperation.h
QgsHashedLineSymbolLayer::~QgsHashedLineSymbolLayer
~QgsHashedLineSymbolLayer() override
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
QgsRasterLineSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgslinesymbollayer.cpp:3516
QgsMarkerLineSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgslinesymbollayer.cpp:2395
QgsRenderContext::scaleFactor
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:266
QgsTemplatedLineSymbolLayerBase::setPlacement
Q_DECL_DEPRECATED void setPlacement(Qgis::MarkerLinePlacement placement)
Sets the placement of the symbols.
Definition: qgslinesymbollayer.cpp:1262
QgsSimpleLineSymbolLayer::createFromSld
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsSimpleLineSymbolLayer from an SLD XML DOM element.
Definition: qgslinesymbollayer.cpp:621
QgsSymbolLayer::PropertyStrokeColor
@ PropertyStrokeColor
Stroke color.
Definition: qgssymbollayer.h:148
QgsLineburstSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgslinesymbollayer.cpp:3758
QgsCoordinateTransform::isValid
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Definition: qgscoordinatetransform.cpp:900
QgsMarkerLineSymbolLayer::toSld
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
Definition: qgslinesymbollayer.cpp:2477
QgsSymbolLayerUtils::encodeRealVector
static QString encodeRealVector(const QVector< qreal > &v)
Definition: qgssymbollayerutils.cpp:764
QgsPointXY::project
QgsPointXY project(double distance, double bearing) const SIP_HOLDGIL
Returns a new point which corresponds to this point projected by a specified distance in a specified ...
Definition: qgspointxy.cpp:87
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:69
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
QgsSimpleLineSymbolLayer::customDashVector
QVector< qreal > customDashVector() const
Returns the custom dash vector, which is the pattern of alternating drawn/skipped lengths used while ...
Definition: qgslinesymbollayer.h:189
QgsLineSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgssymbollayer.cpp:737
QgsSimpleLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:54
QgsLineSymbolLayer::setOffset
void setOffset(double offset)
Sets the line's offset.
Definition: qgssymbollayer.h:1123
QgsLineSymbolLayer::setOffsetMapUnitScale
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the line's offset.
Definition: qgssymbollayer.h:1147
QgsPoint::project
QgsPoint project(double distance, double azimuth, double inclination=90.0) const SIP_HOLDGIL
Returns a new point which corresponds to this point projected by a specified distance with specified ...
Definition: qgspoint.cpp:735
QgsSymbolLayerUtils::createGeometryElement
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
Definition: qgssymbollayerutils.cpp:2923
qgsDoubleToString
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:2204
qgsgeometrysimplifier.h
QgsLineburstSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgslinesymbollayer.cpp:3752
QgsSimpleLineSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsSimpleLineSymbolLayer, using the settings serialized in the properties map (correspo...
Definition: qgslinesymbollayer.cpp:100
QgsSimpleLineSymbolLayer::setTrimDistanceEndMapUnitScale
void setTrimDistanceEndMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the trim distance for the end of the line.
Definition: qgslinesymbollayer.h:431
QgsMarkerLineSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgslinesymbollayer.cpp:2453
QgsHashedLineSymbolLayer::setSymbolAngle
void setSymbolAngle(double angle) override
Sets the symbol's angle, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2922
Qgis::GradientColorSource
GradientColorSource
Gradient color sources.
Definition: qgis.h:1433
QgsMarkerLineSymbolLayer::QgsMarkerLineSymbolLayer
QgsMarkerLineSymbolLayer(bool rotateMarker=DEFAULT_MARKERLINE_ROTATE, double interval=DEFAULT_MARKERLINE_INTERVAL)
Constructor for QgsMarkerLineSymbolLayer.
Definition: qgslinesymbollayer.cpp:2414
DEFAULT_SIMPLELINE_COLOR
#define DEFAULT_SIMPLELINE_COLOR
Definition: qgslinesymbollayer.h:32
QgsSimpleLineSymbolLayer::setCustomDashVector
void setCustomDashVector(const QVector< qreal > &vector)
Sets the custom dash vector, which is the pattern of alternating drawn/skipped lengths used while ren...
Definition: qgslinesymbollayer.h:203
QgsSymbolRenderContext::selected
bool selected() const
Returns true if symbols should be rendered using the selected symbol coloring and style.
Definition: qgssymbolrendercontext.h:118
QgsTemplatedLineSymbolLayerBase::setIntervalMapUnitScale
void setIntervalMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the interval between symbols.
Definition: qgslinesymbollayer.h:616
QgsSimpleLineSymbolLayer::penStyle
Qt::PenStyle penStyle() const
Returns the pen style used to render the line (e.g.
Definition: qgslinesymbollayer.h:100
QgsTemplatedLineSymbolLayerBase::setInterval
void setInterval(double interval)
Sets the interval between individual symbols.
Definition: qgslinesymbollayer.h:593
QgsHashedLineSymbolLayer::hasDataDefinedProperties
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
Definition: qgslinesymbollayer.cpp:2883
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
QgsSymbolRenderContext
Definition: qgssymbolrendercontext.h:35
QgsCptCityColorRamp::typeString
static QString typeString()
Returns the string identifier for QgsCptCityColorRamp.
Definition: qgscolorrampimpl.h:750
QgsSymbolRenderContext::originalGeometryType
QgsWkbTypes::GeometryType originalGeometryType() const
Returns the geometry type for the original feature geometry being rendered.
Definition: qgssymbolrendercontext.h:160
QgsHashedLineSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgslinesymbollayer.cpp:2834
QgsLineburstSymbolLayer::mGradientColorType
Qgis::GradientColorSource mGradientColorType
Definition: qgslinesymbollayer.h:1361
QgsSimpleLineSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgslinesymbollayer.cpp:89
QgsGradientColorRamp::typeString
static QString typeString()
Returns the string identifier for QgsGradientColorRamp.
Definition: qgscolorrampimpl.h:165
QgsLineSymbolLayer::mOffsetUnit
QgsUnitTypes::RenderUnit mOffsetUnit
Definition: qgssymbollayer.h:1207
QgsSymbol::setOpacity
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:502
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
QgsSymbolLayer::clone
virtual QgsSymbolLayer * clone() const =0
Shall be reimplemented by subclasses to create a deep copy of the instance.
QgsAbstractGeometry::vertexAngle
virtual double vertexAngle(QgsVertexId vertex) const =0
Returns approximate angle at a vertex.
Qgis::MarkerLinePlacement::LastVertex
@ LastVertex
Place symbols on the last vertex in the line.
qgsFlagValueToKeys
QString qgsFlagValueToKeys(const T &value, bool *returnOk=nullptr)
Returns the value for the given keys of a flag.
Definition: qgis.h:2498
QgsMarkerLineSymbolLayer::setSymbolLineAngle
void setSymbolLineAngle(double angle) override
Sets the line angle modification for the symbol's angle.
Definition: qgslinesymbollayer.cpp:2658
QgsRenderContext::coordinateTransform
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Definition: qgsrendercontext.h:178
QgsPoint::y
double y
Definition: qgspoint.h:70
QgsSymbol::opacity
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:495
QgsSimpleLineSymbolLayer::clone
QgsSimpleLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgslinesymbollayer.cpp:540
QgsSymbolLayer::PropertyOffset
@ PropertyOffset
Symbol offset.
Definition: qgssymbollayer.h:151
QgsLineburstSymbolLayer::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: qgslinesymbollayer.cpp:3774
QgsVertexId::type
Qgis::VertexType type
Vertex type.
Definition: qgsvertexid.h:98
QgsTemplatedLineSymbolLayerBase::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:1470
QgsMarkerLineSymbolLayer::setDataDefinedProperty
void setDataDefinedProperty(QgsSymbolLayer::Property key, const QgsProperty &property) override
Sets a data defined property for the layer.
Definition: qgslinesymbollayer.cpp:2641
QgsSymbolLayer
Definition: qgssymbollayer.h:54
QgsMarkerLineSymbolLayer::symbolAngle
double symbolAngle() const override
Returns the symbol's current angle, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2663
QgsDxfExport::mapUnits
QgsUnitTypes::DistanceUnit mapUnits() const
Retrieve map units.
Definition: qgsdxfexport.cpp:262
QgsSimpleLineSymbolLayer::toSld
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
Definition: qgslinesymbollayer.cpp:573
QgsRasterLineSymbolLayer::mPath
QString mPath
Definition: qgslinesymbollayer.h:1265
QgsLineburstSymbolLayer::mColor2
QColor mColor2
Definition: qgslinesymbollayer.h:1362
QgsUnitTypes::encodeUnit
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
Definition: qgsunittypes.cpp:122
Qgis::MarkerLinePlacement::InnerVertices
@ InnerVertices
Inner vertices (i.e. all vertices except the first and last vertex) (since QGIS 3....
QgsSimpleLineSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgslinesymbollayer.cpp:75
QgsLineburstSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgslinesymbollayer.cpp:3676
QgsRasterLineSymbolLayer::~QgsRasterLineSymbolLayer
virtual ~QgsRasterLineSymbolLayer()
Qgis::MarkerLinePlacement::FirstVertex
@ FirstVertex
Place symbols on the first vertex in the line.
QgsTemplatedLineSymbolLayerBase::setOffsetAlongLineUnit
void setOffsetAlongLineUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit used for calculating the offset along line for symbols.
Definition: qgslinesymbollayer.h:725
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
QgsMarkerLineSymbolLayer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
Definition: qgslinesymbollayer.cpp:2709
QgsRasterLineSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgslinesymbollayer.cpp:3522
QgsSymbolRenderContext::fields
QgsFields fields() const
Fields of the layer.
Definition: qgssymbolrendercontext.h:168
QgsPoint::toQPointF
QPointF toQPointF() const SIP_HOLDGIL
Returns the point as a QPointF.
Definition: qgspoint.h:348
QgsRasterLineSymbolLayer::QgsRasterLineSymbolLayer
QgsRasterLineSymbolLayer(const QString &path=QString())
Constructor for QgsRasterLineSymbolLayer, with the specified raster image path.
Definition: qgslinesymbollayer.cpp:3310
QgsSymbol::type
Qgis::SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:152
QgsSimpleLineSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgslinesymbollayer.cpp:507
QgsSimpleLineSymbolLayer::dxfColor
QColor dxfColor(QgsSymbolRenderContext &context) const override
Gets color.
Definition: qgslinesymbollayer.cpp:1106
QgsLineburstSymbolLayer::setColorRamp
void setColorRamp(QgsColorRamp *ramp)
Sets the color ramp used for the gradient line.
Definition: qgslinesymbollayer.cpp:3789
QgsSymbolLayerUtils::isSharpCorner
static bool isSharpCorner(QPointF p1, QPointF p2, QPointF p3)
Returns true if the angle formed by the line p1 - p2 - p3 forms a "sharp" corner.
Definition: qgssymbollayerutils.cpp:4533
QgsMarkerSymbol
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgsmarkersymbol.h:30
QgsRasterLineSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgslinesymbollayer.cpp:3419
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
QgsLineSymbolLayer::mOffset
double mOffset
Definition: qgssymbollayer.h:1206
QgsHashedLineSymbolLayer::setHashAngle
void setHashAngle(double angle)
Sets the angle to use when drawing the hashed lines sections, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2964
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
QgsLineSymbolLayer::setOffsetUnit
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the line's offset.
Definition: qgssymbollayer.h:1131
QgsTemplatedLineSymbolLayerBase::setAverageAngleMapUnitScale
void setAverageAngleMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the length over which the line's direction is averaged when calculating i...
Definition: qgslinesymbollayer.h:791
QgsMarkerLineSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgslinesymbollayer.cpp:2699
QgsSimpleLineSymbolLayer
A simple line symbol layer, which renders lines using a line in a variety of styles (e....
Definition: qgslinesymbollayer.h:43
QgsTemplatedLineSymbolLayerBase::intervalMapUnitScale
const QgsMapUnitScale & intervalMapUnitScale() const
Returns the map unit scale for the interval between symbols.
Definition: qgslinesymbollayer.h:624
QgsTemplatedLineSymbolLayerBase::canCauseArtifactsBetweenAdjacentTiles
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
Definition: qgslinesymbollayer.cpp:1521
QgsLineburstSymbolLayer
Line symbol layer type which draws a gradient pattern perpendicularly along a line.
Definition: qgslinesymbollayer.h:1283
QgsLineSymbolLayer::mWidthUnit
QgsUnitTypes::RenderUnit mWidthUnit
Definition: qgssymbollayer.h:1204
QgsSymbolLayerUtils::polylineLength
static double polylineLength(const QPolygonF &polyline)
Returns the total length of a polyline.
Definition: qgssymbollayerutils.cpp:4432
QgsSymbolLayer::copyPaintEffect
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
Definition: qgssymbollayer.cpp:491
Qgis::SymbolRenderHint::DynamicRotation
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
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
QgsApplication::imageCache
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
Definition: qgsapplication.cpp:2365
QgsSimpleLineSymbolLayer::ogrFeatureStyle
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
Definition: qgslinesymbollayer.cpp:606
Qgis::MarkerLinePlacement::Interval
@ Interval
Place symbols at regular intervals.
qgsrendercontext.h
QgsTemplatedLineSymbolLayerBase::interval
double interval() const
Returns the interval between individual symbols.
Definition: qgslinesymbollayer.h:585
QgsSimpleLineSymbolLayer::setPenCapStyle
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
Definition: qgslinesymbollayer.h:135
QgsTemplatedLineSymbolLayerBase::offsetAlongLine
double offsetAlongLine() const
Returns the offset along the line for the symbol placement.
Definition: qgslinesymbollayer.h:696
QgsLineSymbol
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:29
QgsRasterLineSymbolLayer::setPath
void setPath(const QString &path)
Set the raster image path.
Definition: qgslinesymbollayer.cpp:3414
QgsLineburstSymbolLayer::clone
QgsLineburstSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgslinesymbollayer.cpp:3646
QgsSimpleLineSymbolLayer::setDrawInsidePolygon
void setDrawInsidePolygon(bool drawInsidePolygon)
Sets whether the line should only be drawn inside polygons, and any portion of the line which falls o...
Definition: qgslinesymbollayer.h:453
QgsMarkerLineSymbolLayer::color
QColor color() const override
Returns the "representative" color of the symbol layer.
Definition: qgslinesymbollayer.cpp:2448
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
DEFAULT_SIMPLELINE_WIDTH
#define DEFAULT_SIMPLELINE_WIDTH
Definition: qgslinesymbollayer.h:33
QgsTemplatedLineSymbolLayerBase::offsetAlongLineMapUnitScale
const QgsMapUnitScale & offsetAlongLineMapUnitScale() const
Returns the map unit scale used for calculating the offset in map units along line for symbols.
Definition: qgslinesymbollayer.h:731
QgsLineSymbolLayer::mWidth
double mWidth
Definition: qgssymbollayer.h:1203
QgsRasterLineSymbolLayer::mOpacity
double mOpacity
Definition: qgslinesymbollayer.h:1266
QgsHashedLineSymbolLayer::symbolAngle
double symbolAngle() const override
Returns the symbol's current angle, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2917
QgsVectorSimplifyMethod::threshold
float threshold() const
Gets the simplification threshold of the vector layer managed.
Definition: qgsvectorsimplifymethod.h:89
QgsSimpleLineSymbolLayer::renderPolyline
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
Definition: qgslinesymbollayer.cpp:374
QgsSymbolLayer::PropertyTrimEnd
@ PropertyTrimEnd
Trim distance from end of line (since QGIS 3.20)
Definition: qgssymbollayer.h:205
QgsSymbolLayerUtils::createVendorOptionElement
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
Definition: qgssymbollayerutils.cpp:3115
QgsSymbolLayer::restoreOldDataDefinedProperties
void restoreOldDataDefinedProperties(const QVariantMap &stringMap)
Restores older data defined properties from string map.
Definition: qgssymbollayer.cpp:362
QgsAbstractBrushedLineSymbolLayer::renderPolylineUsingBrush
void renderPolylineUsingBrush(const QPolygonF &points, QgsSymbolRenderContext &context, const QBrush &brush, double patternThickness, double patternLength)
Renders a polyline of points using the specified brush.
Definition: qgslinesymbollayer.cpp:2981
QgsAbstractGeometry::nCoordinates
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
Definition: qgsabstractgeometry.cpp:150
QgsLineburstSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgslinesymbollayer.cpp:3616
DEFAULT_SIMPLELINE_PENSTYLE
#define DEFAULT_SIMPLELINE_PENSTYLE
Definition: qgslinesymbollayer.h:34
QgsMarkerLineSymbolLayer::setSymbolAngle
void setSymbolAngle(double angle) override
Sets the symbol's angle, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2668
QgsMapUnitScale
Struct for storing maximum and minimum scales for measurements in map units.
Definition: qgsmapunitscale.h:36
QgsHashedLineSymbolLayer::renderSymbol
void renderSymbol(const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer=-1, bool selected=false) override
Renders the templated symbol at the specified point, using the given render context.
Definition: qgslinesymbollayer.cpp:2927
Qgis::MarkerLinePlacement::SegmentCenter
@ SegmentCenter
Place symbols at the center of every line segment.
QgsAbstractGeometry::hasCurvedSegments
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
Definition: qgsabstractgeometry.cpp:385
QgsTemplatedLineSymbolLayerBase::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const FINAL
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:1460
QgsHashedLineSymbolLayer::clone
QgsHashedLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgslinesymbollayer.cpp:2807
QgsSimpleLineSymbolLayer::setTrimDistanceStart
void setTrimDistanceStart(double distance)
Sets the trim distance for the start of the line, which dictates a length from the start of the line ...
Definition: qgslinesymbollayer.h:305
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1336
QgsCurvePolygon::interiorRing
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
Definition: qgscurvepolygon.h:122
QgsGeometryUtils::segmentIntersection
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false) SIP_HOLDGIL
Compute the intersection between two segments.
Definition: qgsgeometryutils.cpp:277
QgsRasterLineSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:3500
QgsSimpleLineSymbolLayer::dxfWidth
double dxfWidth(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets line width.
Definition: qgslinesymbollayer.cpp:1089
QgsTemplatedLineSymbolLayerBase
Base class for templated line symbols, e.g. line symbols which draw markers or hash lines at interval...
Definition: qgslinesymbollayer.h:552
QgsMarkerLineSymbolLayer::subSymbol
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
Definition: qgslinesymbollayer.cpp:2390
QgsCptCityColorRamp::create
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates the symbol layer.
Definition: qgscolorrampimpl.cpp:944
QgsMarkerLineSymbolLayer::setWidth
void setWidth(double width) override
Sets the width of the line symbol layer.
Definition: qgslinesymbollayer.cpp:2636
QgsSymbolLayer::mDataDefinedProperties
QgsPropertyCollection mDataDefinedProperties
Definition: qgssymbollayer.h:651
QgsSymbolLayer::PropertyStrokeWidth
@ PropertyStrokeWidth
Stroke width.
Definition: qgssymbollayer.h:149
QgsHashedLineSymbolLayer::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: qgslinesymbollayer.cpp:2862
qgscurvepolygon.h
Qgis::MarkerLinePlacement::CentralPoint
@ CentralPoint
Place symbols at the mid point of the line.
QgsSimpleLineSymbolLayer::setDashPatternOffset
void setDashPatternOffset(double offset)
Sets the dash pattern offset, which dictates how far along the dash pattern the pattern should start ...
Definition: qgslinesymbollayer.h:231
QgsExpressionContext::EXPR_GEOMETRY_RING_NUM
static const QString EXPR_GEOMETRY_RING_NUM
Inbuilt variable name for geometry ring number variable.
Definition: qgsexpressioncontext.h:819
QgsSimpleLineSymbolLayer::renderPolygonStroke
void renderPolygonStroke(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the outline of polygon, using the given render context.
Definition: qgslinesymbollayer.cpp:286
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
QgsTemplatedLineSymbolLayerBase::placement
Q_DECL_DEPRECATED Qgis::MarkerLinePlacement placement() const
Returns the placement of the symbols.
Definition: qgslinesymbollayer.cpp:1238
QgsTemplatedLineSymbolLayerBase::setOffsetAlongLineMapUnitScale
void setOffsetAlongLineMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale used for calculating the offset in map units along line for symbols.
Definition: qgslinesymbollayer.h:737
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:113
QgsRasterLineSymbolLayer::path
QString path() const
Returns the raster image path.
Definition: qgslinesymbollayer.h:1228
QgsLineburstSymbolLayer::QgsLineburstSymbolLayer
QgsLineburstSymbolLayer(const QColor &color=DEFAULT_SIMPLELINE_COLOR, const QColor &color2=Qt::white)
Constructor for QgsLineburstSymbolLayer, with the specified start and end gradient colors.
Definition: qgslinesymbollayer.cpp:3547
QgsLineSymbolLayer::InteriorRingsOnly
@ InteriorRingsOnly
Render the interior rings only.
Definition: qgssymbollayer.h:1033
QgsRenderContext::vectorSimplifyMethod
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Returns the simplification settings to use when rendering vector layers.
Definition: qgsrendercontext.h:594
QgsTemplatedLineSymbolLayerBase::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) FINAL
Definition: qgslinesymbollayer.cpp:1478
QgsSymbolLayerUtils::appendPolyline
static void appendPolyline(QPolygonF &target, const QPolygonF &line)
Appends a polyline line to an existing target polyline.
Definition: qgssymbollayerutils.cpp:4542
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
QgsUnitTypes::RenderPixels
@ RenderPixels
Pixels.
Definition: qgsunittypes.h:171
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
QgsHashedLineSymbolLayer::setColor
void setColor(const QColor &color) override
Sets the "representative" color for the symbol layer.
Definition: qgslinesymbollayer.cpp:2818
QgsTemplatedLineSymbolLayerBase::setAverageAngleLength
void setAverageAngleLength(double length)
Sets the length of line over which the line's direction is averaged when calculating individual symbo...
Definition: qgslinesymbollayer.h:761
QgsSymbolLayer::PropertyOffsetAlongLine
@ PropertyOffsetAlongLine
Offset along line.
Definition: qgssymbollayer.h:184
qgsvectorlayer.h
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsHashedLineSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsHashedLineSymbolLayer, using the settings serialized in the properties map (correspo...
Definition: qgslinesymbollayer.cpp:2745
Qgis::MarkerLinePlacement::CurvePoint
@ CurvePoint
Place symbols at every virtual curve point in the line (used when rendering curved geometry types onl...
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
QgsLineburstSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgslinesymbollayer.cpp:3672
QgsSymbolLayerUtils::decodePenCapStyle
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:250
QgsHashedLineSymbolLayer::width
double width() const override
Returns the estimated width for the line symbol layer.
Definition: qgslinesymbollayer.cpp:2852
QgsHashedLineSymbolLayer::setDataDefinedProperty
void setDataDefinedProperty(QgsSymbolLayer::Property key, const QgsProperty &property) override
Sets a data defined property for the layer.
Definition: qgslinesymbollayer.cpp:2892
Qgis::GradientColorSource::ColorRamp
@ ColorRamp
Gradient color ramp.
QgsAbstractBrushedLineSymbolLayer::mPenCapStyle
Qt::PenCapStyle mPenCapStyle
Definition: qgslinesymbollayer.h:1185
QgsRenderContext::selectionColor
QColor selectionColor() const
Returns the color to use when rendering selected features.
Definition: qgsrendercontext.h:382
QgsHashedLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:2869
QgsMapToPixel::transformInPlace
void transformInPlace(double &x, double &y) const
Transforms device coordinates to map coordinates.
Definition: qgsmaptopixel.h:128
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:143
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
QgsLineburstSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgslinesymbollayer.cpp:3764
QgsRasterLineSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgslinesymbollayer.cpp:3510
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
QgsSimpleLineSymbolLayer::setDashPatternOffsetMapUnitScale
void setDashPatternOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the dash pattern offset.
Definition: qgslinesymbollayer.h:275
QgsGradientColorRamp::addStopsToGradient
void addStopsToGradient(QGradient *gradient, double opacity=1) const
Copy color ramp stops to a QGradient.
Definition: qgscolorrampimpl.cpp:540
qgslinesymbollayer.h
QgsRenderContext::geometry
const QgsAbstractGeometry * geometry() const
Returns pointer to the unsegmentized geometry.
Definition: qgsrendercontext.h:637
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
qgscurve.h
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
QgsMapToPixel
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:38
QgsTemplatedLineSymbolLayerBase::~QgsTemplatedLineSymbolLayerBase
~QgsTemplatedLineSymbolLayerBase() override
QgsLineburstSymbolLayer::colorRamp
QgsColorRamp * colorRamp()
Returns the color ramp used for the gradient line.
Definition: qgslinesymbollayer.cpp:3784
QgsSimpleLineSymbolLayer::setTrimDistanceEnd
void setTrimDistanceEnd(double distance)
Sets the trim distance for the end of the line, which dictates a length from the end of the line at w...
Definition: qgslinesymbollayer.h:383
QgsMarkerLineSymbolLayer::hasDataDefinedProperties
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
Definition: qgslinesymbollayer.cpp:2717
qgsimagecache.h
QgsMarkerLineSymbolLayer::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: qgslinesymbollayer.cpp:2726
QgsTemplatedLineSymbolLayerBase::renderPolygonStroke
void renderPolygonStroke(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) FINAL
Renders the line symbol layer along the outline of polygon, using the given render context.
Definition: qgslinesymbollayer.cpp:1400
QgsSymbolLayerUtils::getVendorOptionList
static QgsStringMap getVendorOptionList(QDomElement &element)
Definition: qgssymbollayerutils.cpp:3123
QgsSimpleLineSymbolLayer::alignDashPattern
bool alignDashPattern() const
Returns true if dash patterns should be aligned to the start and end of lines, by applying subtle twe...
Definition: qgslinesymbollayer.cpp:1121
QgsSymbolLayerList
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:27
QgsSymbolLayerUtils::svgSymbolNameToPath
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol's path from its name.
Definition: qgssymbollayerutils.cpp:4237
QgsLineSymbolLayer::mOffsetMapUnitScale
QgsMapUnitScale mOffsetMapUnitScale
Definition: qgssymbollayer.h:1208
qgsmarkersymbol.h
QgsHashedLineSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgslinesymbollayer.cpp:2795
QgsTemplatedLineSymbolLayerBase::startFeatureRender
void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called before the layer will be rendered for a particular feature.
Definition: qgslinesymbollayer.cpp:1529
QgsPointXY::x
double x
Definition: qgspointxy.h:62
QgsSymbolLayerUtils::polylineSubstring
static QPolygonF polylineSubstring(const QPolygonF &polyline, double startOffset, double endOffset)
Returns the substring of a polyline which starts at startOffset from the beginning of the line and en...
Definition: qgssymbollayerutils.cpp:4450
QgsSymbolLayer::PropertyFile
@ PropertyFile
Filename, eg for svg files.
Definition: qgssymbollayer.h:174
QgsVertexId
Utility class for identifying a unique vertex within a geometry.
Definition: qgsvertexid.h:30
QgsSymbolLayer::PropertyCustomDash
@ PropertyCustomDash
Custom dash pattern.
Definition: qgssymbollayer.h:180
QgsTemplatedLineSymbolLayerBase::setSymbolLineAngle
virtual void setSymbolLineAngle(double angle)=0
Sets the line angle modification for the symbol's angle.
QgsTemplatedLineSymbolLayerBase::rotateSymbols
bool rotateSymbols() const
Returns true if the repeating symbols be rotated to match their line segment orientation.
Definition: qgslinesymbollayer.h:572
QgsHashedLineSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgslinesymbollayer.cpp:2774
QgsSimpleLineSymbolLayer::setTweakDashPatternOnCorners
void setTweakDashPatternOnCorners(bool enabled)
Sets whether dash patterns tweaks should be applied on sharp corners, to ensure that a double-length ...
Definition: qgslinesymbollayer.cpp:1136
QgsUnitTypes::RenderMetersInMapUnits
@ RenderMetersInMapUnits
Meters value as Map units.
Definition: qgsunittypes.h:176
qgsproperty.h
QgsSimpleLineSymbolLayer::dxfOffset
double dxfOffset(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets offset.
Definition: qgslinesymbollayer.cpp:1141
QgsUnitTypes::RenderUnknownUnit
@ RenderUnknownUnit
Mixed or unknown units.
Definition: qgsunittypes.h:175
QgsLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgssymbollayer.cpp:721
QgsLineSymbolLayer::AllRings
@ AllRings
Render both exterior and interior rings.
Definition: qgssymbollayer.h:1031
QgsWkbTypes::UnknownGeometry
@ UnknownGeometry
Definition: qgswkbtypes.h:145
QgsMarkerLineSymbolLayer::~QgsMarkerLineSymbolLayer
~QgsMarkerLineSymbolLayer() override
QgsTemplatedLineSymbolLayerBase::renderPolyline
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
Definition: qgslinesymbollayer.cpp:1269
QgsTemplatedLineSymbolLayerBase::setCommonProperties
static void setCommonProperties(QgsTemplatedLineSymbolLayerBase *destLayer, const QVariantMap &properties)
Sets all common symbol properties in the destLayer, using the settings serialized in the properties m...
Definition: qgslinesymbollayer.cpp:1571
QgsTemplatedLineSymbolLayerBase::stopFeatureRender
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called after the layer has been rendered for a particular feature.
Definition: qgslinesymbollayer.cpp:1535
QgsMarkerLineSymbolLayer::renderSymbol
void renderSymbol(const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer=-1, bool selected=false) override
Renders the templated symbol at the specified point, using the given render context.
Definition: qgslinesymbollayer.cpp:2673
QgsSymbolLayerUtils::decodePenJoinStyle
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:200
QgsSymbolLayer::Property
Property
Data definable properties.
Definition: qgssymbollayer.h:142
QgsTemplatedLineSymbolLayerBase::setPlaceOnEveryPart
void setPlaceOnEveryPart(bool respect)
Sets whether the placement applies for every part of multi-part feature geometries.
Definition: qgslinesymbollayer.h:684
qgsdxfexport.h
QgsSimpleLineSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgslinesymbollayer.cpp:235
QgsTemplatedLineSymbolLayerBase::placements
Qgis::MarkerLinePlacements placements() const
Returns the placement of the symbols.
Definition: qgslinesymbollayer.h:645
QgsVectorSimplifyMethod::simplifyHints
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
Definition: qgsvectorsimplifymethod.h:64
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
QgsSymbolLayerUtils::encodePenJoinStyle
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
Definition: qgssymbollayerutils.cpp:185
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
segment
QLineF segment(int index, QRectF rect, double radius)
Definition: qgsshapegenerator.cpp:25
QgsMarkerLineSymbolLayer::mMarker
std::unique_ptr< QgsMarkerSymbol > mMarker
Definition: qgslinesymbollayer.h:984
QgsLineburstSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:3742
QgsSymbolLayer::PropertyOpacity
@ PropertyOpacity
Opacity.
Definition: qgssymbollayer.h:179
QgsRasterLineSymbolLayer::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: qgslinesymbollayer.cpp:3532
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
QgsRasterLineSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgslinesymbollayer.cpp:3364
QgsSymbolLayerUtils::decodeRealVector
static QVector< qreal > decodeRealVector(const QString &s)
Definition: qgssymbollayerutils.cpp:779
QgsRasterLineSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsRasterLineSymbolLayer, using the settings serialized in the properties map (correspo...
Definition: qgslinesymbollayer.cpp:3317
QgsLineSymbolLayer::setWidthMapUnitScale
void setWidthMapUnitScale(const QgsMapUnitScale &scale)
Definition: qgssymbollayer.h:1173
QgsLineburstSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsLineburstSymbolLayer, using the settings serialized in the properties map (correspon...
Definition: qgslinesymbollayer.cpp:3556
QgsRasterLineSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgslinesymbollayer.cpp:3424
QgsSimpleLineSymbolLayer::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: qgslinesymbollayer.cpp:1064
QgsLineSymbolLayer::offset
double offset() const
Returns the line's offset.
Definition: qgssymbollayer.h:1112
Qgis::MarkerLinePlacement::Vertex
@ Vertex
Place symbols on every vertex in the line.
QgsSymbolLayer::PropertyTrimStart
@ PropertyTrimStart
Trim distance from start of line (since QGIS 3.20)
Definition: qgssymbollayer.h:204
QgsDxfExport::clipValueToMapUnitScale
void clipValueToMapUnitScale(double &value, const QgsMapUnitScale &scale, double pixelToMMFactor) const
Clips value to scale minimum/maximum.
Definition: qgsdxfexport.cpp:1840
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
QgsMarkerLineSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsMarkerLineSymbolLayer, using the settings serialized in the properties map (correspo...
Definition: qgslinesymbollayer.cpp:2422
QgsTemplatedLineSymbolLayerBase::intervalUnit
QgsUnitTypes::RenderUnit intervalUnit() const
Returns the units for the interval between symbols.
Definition: qgslinesymbollayer.h:608
qgslogger.h
Qgis::RenderContextFlag::RenderingSubSymbol
@ RenderingSubSymbol
Set whenever a sub-symbol of a parent symbol is currently being rendered. Can be used during symbol a...
QgsLineSymbolLayer::widthUnit
QgsUnitTypes::RenderUnit widthUnit() const
Returns the units for the line's width.
Definition: qgssymbollayer.h:1171
QgsLineSymbolLayer::ExteriorRingOnly
@ ExteriorRingOnly
Render the exterior ring only.
Definition: qgssymbollayer.h:1032
QgsSimpleLineSymbolLayer::setCustomDashPatternUnit
void setCustomDashPatternUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for lengths used in the custom dash pattern.
Definition: qgslinesymbollayer.h:157
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:112
QgsRenderContext::setGeometry
void setGeometry(const QgsAbstractGeometry *geometry)
Sets pointer to original (unsegmentized) geometry.
Definition: qgsrendercontext.h:639
QgsHashedLineSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgslinesymbollayer.cpp:2779
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:120
QgsTemplatedLineSymbolLayerBase::QgsTemplatedLineSymbolLayerBase
QgsTemplatedLineSymbolLayerBase(bool rotateSymbol=true, double interval=3)
Constructor for QgsTemplatedLineSymbolLayerBase.
Definition: qgslinesymbollayer.cpp:1231
QgsSymbolLayerUtils::decodePenStyle
static Qt::PenStyle decodePenStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:174
QgsRasterLineSymbolLayer::color
QColor color() const override
Returns the "representative" color of the symbol layer.
Definition: qgslinesymbollayer.cpp:3537
QgsImageOperation::overlayColor
static void overlayColor(QImage &image, const QColor &color)
Overlays a color onto an image.
Definition: qgsimageoperation.cpp:371
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
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
QgsAbstractBrushedLineSymbolLayer
Base class for line symbol layer types which draws line sections using a QBrush.
Definition: qgslinesymbollayer.h:1144
QgsHashedLineSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgslinesymbollayer.cpp:2901
QgsSimpleLineSymbolLayer::QgsSimpleLineSymbolLayer
QgsSimpleLineSymbolLayer(const QColor &color=DEFAULT_SIMPLELINE_COLOR, double width=DEFAULT_SIMPLELINE_WIDTH, Qt::PenStyle penStyle=DEFAULT_SIMPLELINE_PENSTYLE)
Constructor for QgsSimpleLineSymbolLayer.
Definition: qgslinesymbollayer.cpp:44
qgsfeedback.h
QgsRasterLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:3493
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
QgsHashedLineSymbolLayer::subSymbol
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
Definition: qgslinesymbollayer.cpp:2829
QgsSymbolLayer::copyDataDefinedProperties
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
Definition: qgssymbollayer.cpp:483
QgsLineburstSymbolLayer::color2
QColor color2() const
Returns the color for endpoint of gradient, only used if the gradient color type is set to SimpleTwoC...
Definition: qgslinesymbollayer.h:1351
QgsSymbolLayer::PropertyPlacement
@ PropertyPlacement
Line marker placement.
Definition: qgssymbollayer.h:182
QgsSimpleLineSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:65
QgsSimpleLineSymbolLayer::setTrimDistanceStartUnit
void setTrimDistanceStartUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the trim distance for the start of the line.
Definition: qgslinesymbollayer.h:317
QgsAbstractGeometry::nextVertex
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
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
QgsUnitTypes::RenderMapUnits
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:170
QgsPoint::x
double x
Definition: qgspoint.h:69
QgsTemplatedLineSymbolLayerBase::setAverageAngleUnit
void setAverageAngleUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the length over which the line's direction is averaged when calculating individual ...
Definition: qgslinesymbollayer.h:771
QgsMarkerLineSymbolLayer::rotateMarker
Q_DECL_DEPRECATED bool rotateMarker() const
Shall the marker be rotated.
Definition: qgslinesymbollayer.h:972
QgsSymbolLayerUtils::decodeMapUnitScale
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Definition: qgssymbollayerutils.cpp:676
QgsLineSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgssymbollayer.cpp:732
QgsRasterLineSymbolLayer::renderPolyline
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
Definition: qgslinesymbollayer.cpp:3442
QgsSymbolLayer::PropertySecondaryColor
@ PropertySecondaryColor
Secondary color (eg for gradient fills)
Definition: qgssymbollayer.h:158
Qgis::SymbolType::Marker
@ Marker
Marker symbol.
QgsSymbolLayer::setDataDefinedProperty
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
Definition: qgssymbollayer.cpp:126
QgsAbstractGeometrySimplifier::isGeneralizableByDeviceBoundingBox
static bool isGeneralizableByDeviceBoundingBox(const QgsRectangle &envelope, float mapToPixelTol=1.0f)
Returns whether the device-envelope can be replaced by its BBOX when is applied the specified toleran...
Definition: qgsgeometrysimplifier.cpp:23
QgsHashedLineSymbolLayer::color
QColor color() const override
Returns the "representative" color of the symbol layer.
Definition: qgslinesymbollayer.cpp:2824
QgsMarkerLineSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgslinesymbollayer.cpp:2464
QgsRasterLineSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgslinesymbollayer.cpp:3438
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
QgsAbstractBrushedLineSymbolLayer::mPenJoinStyle
Qt::PenJoinStyle mPenJoinStyle
Definition: qgslinesymbollayer.h:1184
QgsTemplatedLineSymbolLayerBase::setPlacements
void setPlacements(Qgis::MarkerLinePlacements placements)
Sets the placement of the symbols.
Definition: qgslinesymbollayer.h:652
QgsLineburstSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:3735
QgsSymbolLayer::PropertyJoinStyle
@ PropertyJoinStyle
Line join style.
Definition: qgssymbollayer.h:157
QgsSymbolLayerUtils::createExpressionElement
static bool createExpressionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Creates a OGC Expression element based on the provided function expression.
Definition: qgssymbollayerutils.cpp:2966
qgslinesymbol.h
Qgis::MarkerLinePlacement
MarkerLinePlacement
Defines how/where the symbols should be placed on a line.
Definition: qgis.h:1411
QgsTemplatedLineSymbolLayerBase::averageAngleUnit
QgsUnitTypes::RenderUnit averageAngleUnit() const
Returns the unit for the length over which the line's direction is averaged when calculating individu...
Definition: qgslinesymbollayer.h:781
QgsTemplatedLineSymbolLayerBase::setIntervalUnit
void setIntervalUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the interval between symbols.
Definition: qgslinesymbollayer.h:601
QgsSymbolLayer::PropertyWidth
@ PropertyWidth
Symbol width.
Definition: qgssymbollayer.h:153
QgsTemplatedLineSymbolLayerBase::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgslinesymbollayer.cpp:1497