QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 
30 #include <algorithm>
31 #include <QPainter>
32 #include <QDomDocument>
33 #include <QDomElement>
34 
35 #include <cmath>
36 
37 QgsSimpleLineSymbolLayer::QgsSimpleLineSymbolLayer( const QColor &color, double width, Qt::PenStyle penStyle )
38  : mPenStyle( penStyle )
39 {
40  mColor = color;
41  mWidth = width;
42  mCustomDashVector << 5 << 2;
43 }
44 
46 {
48  mWidthUnit = unit;
49  mOffsetUnit = unit;
50  mCustomDashPatternUnit = unit;
51 }
52 
54 {
56  if ( mWidthUnit != unit || mOffsetUnit != unit || mCustomDashPatternUnit != unit )
57  {
59  }
60  return unit;
61 }
62 
64 {
66  mWidthMapUnitScale = scale;
67  mOffsetMapUnitScale = scale;
68  mCustomDashPatternMapUnitScale = scale;
69 }
70 
72 {
75  mOffsetMapUnitScale == mCustomDashPatternMapUnitScale )
76  {
77  return mWidthMapUnitScale;
78  }
79  return QgsMapUnitScale();
80 }
81 
83 {
87 
88  if ( props.contains( QStringLiteral( "line_color" ) ) )
89  {
90  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "line_color" )] );
91  }
92  else if ( props.contains( QStringLiteral( "outline_color" ) ) )
93  {
94  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "outline_color" )] );
95  }
96  else if ( props.contains( QStringLiteral( "color" ) ) )
97  {
98  //pre 2.5 projects used "color"
99  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color" )] );
100  }
101  if ( props.contains( QStringLiteral( "line_width" ) ) )
102  {
103  width = props[QStringLiteral( "line_width" )].toDouble();
104  }
105  else if ( props.contains( QStringLiteral( "outline_width" ) ) )
106  {
107  width = props[QStringLiteral( "outline_width" )].toDouble();
108  }
109  else if ( props.contains( QStringLiteral( "width" ) ) )
110  {
111  //pre 2.5 projects used "width"
112  width = props[QStringLiteral( "width" )].toDouble();
113  }
114  if ( props.contains( QStringLiteral( "line_style" ) ) )
115  {
116  penStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "line_style" )] );
117  }
118  else if ( props.contains( QStringLiteral( "outline_style" ) ) )
119  {
120  penStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "outline_style" )] );
121  }
122  else if ( props.contains( QStringLiteral( "penstyle" ) ) )
123  {
124  penStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "penstyle" )] );
125  }
126 
128  if ( props.contains( QStringLiteral( "line_width_unit" ) ) )
129  {
130  l->setWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "line_width_unit" )] ) );
131  }
132  else if ( props.contains( QStringLiteral( "outline_width_unit" ) ) )
133  {
134  l->setWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "outline_width_unit" )] ) );
135  }
136  else if ( props.contains( QStringLiteral( "width_unit" ) ) )
137  {
138  //pre 2.5 projects used "width_unit"
139  l->setWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "width_unit" )] ) );
140  }
141  if ( props.contains( QStringLiteral( "width_map_unit_scale" ) ) )
142  l->setWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "width_map_unit_scale" )] ) );
143  if ( props.contains( QStringLiteral( "offset" ) ) )
144  l->setOffset( props[QStringLiteral( "offset" )].toDouble() );
145  if ( props.contains( QStringLiteral( "offset_unit" ) ) )
146  l->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )] ) );
147  if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
148  l->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )] ) );
149  if ( props.contains( QStringLiteral( "joinstyle" ) ) )
150  l->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( props[QStringLiteral( "joinstyle" )] ) );
151  if ( props.contains( QStringLiteral( "capstyle" ) ) )
152  l->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( props[QStringLiteral( "capstyle" )] ) );
153 
154  if ( props.contains( QStringLiteral( "use_custom_dash" ) ) )
155  {
156  l->setUseCustomDashPattern( props[QStringLiteral( "use_custom_dash" )].toInt() );
157  }
158  if ( props.contains( QStringLiteral( "customdash" ) ) )
159  {
160  l->setCustomDashVector( QgsSymbolLayerUtils::decodeRealVector( props[QStringLiteral( "customdash" )] ) );
161  }
162  if ( props.contains( QStringLiteral( "customdash_unit" ) ) )
163  {
164  l->setCustomDashPatternUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "customdash_unit" )] ) );
165  }
166  if ( props.contains( QStringLiteral( "customdash_map_unit_scale" ) ) )
167  {
168  l->setCustomDashPatternMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "customdash_map_unit_scale" )] ) );
169  }
170 
171  if ( props.contains( QStringLiteral( "draw_inside_polygon" ) ) )
172  {
173  l->setDrawInsidePolygon( props[QStringLiteral( "draw_inside_polygon" )].toInt() );
174  }
175 
176  if ( props.contains( QStringLiteral( "ring_filter" ) ) )
177  {
178  l->setRingFilter( static_cast< RenderRingFilter>( props[QStringLiteral( "ring_filter" )].toInt() ) );
179  }
180 
181  if ( props.contains( QStringLiteral( "dash_pattern_offset" ) ) )
182  l->setDashPatternOffset( props[QStringLiteral( "dash_pattern_offset" )].toDouble() );
183  if ( props.contains( QStringLiteral( "dash_pattern_offset_unit" ) ) )
184  l->setDashPatternOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "dash_pattern_offset_unit" )] ) );
185  if ( props.contains( QStringLiteral( "dash_pattern_offset_map_unit_scale" ) ) )
186  l->setDashPatternOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "dash_pattern_offset_map_unit_scale" )] ) );
187 
188  if ( props.contains( QStringLiteral( "align_dash_pattern" ) ) )
189  l->setAlignDashPattern( props[ QStringLiteral( "align_dash_pattern" )].toInt() );
190 
191  if ( props.contains( QStringLiteral( "tweak_dash_pattern_on_corners" ) ) )
192  l->setTweakDashPatternOnCorners( props[ QStringLiteral( "tweak_dash_pattern_on_corners" )].toInt() );
193 
195 
196  return l;
197 }
198 
199 
201 {
202  return QStringLiteral( "SimpleLine" );
203 }
204 
206 {
207  QColor penColor = mColor;
208  penColor.setAlphaF( mColor.alphaF() * context.opacity() );
209  mPen.setColor( penColor );
210  double scaledWidth = context.renderContext().convertToPainterUnits( mWidth, mWidthUnit, mWidthMapUnitScale );
211  mPen.setWidthF( scaledWidth );
212 
213  //note that Qt seems to have issues with scaling dash patterns with very small pen widths.
214  //treating the pen as having no less than a 1 pixel size avoids the worst of these issues
215  const double dashWidthDiv = std::max( 1.0, scaledWidth );
216  if ( mUseCustomDashPattern )
217  {
218  mPen.setStyle( Qt::CustomDashLine );
219 
220  //scale pattern vector
221 
222  QVector<qreal> scaledVector;
223  QVector<qreal>::const_iterator it = mCustomDashVector.constBegin();
224  for ( ; it != mCustomDashVector.constEnd(); ++it )
225  {
226  //the dash is specified in terms of pen widths, therefore the division
227  scaledVector << context.renderContext().convertToPainterUnits( ( *it ), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv;
228  }
229  mPen.setDashPattern( scaledVector );
230  }
231  else
232  {
233  mPen.setStyle( mPenStyle );
234  }
235 
236  if ( mDashPatternOffset && mPen.style() != Qt::SolidLine )
237  {
238  mPen.setDashOffset( context.renderContext().convertToPainterUnits( mDashPatternOffset, mDashPatternOffsetUnit, mDashPatternOffsetMapUnitScale ) / dashWidthDiv ) ;
239  }
240 
241  mPen.setJoinStyle( mPenJoinStyle );
242  mPen.setCapStyle( mPenCapStyle );
243 
244  mSelPen = mPen;
245  QColor selColor = context.renderContext().selectionColor();
246  if ( ! SELECTION_IS_OPAQUE )
247  selColor.setAlphaF( context.opacity() );
248  mSelPen.setColor( selColor );
249 }
250 
252 {
253  Q_UNUSED( context )
254 }
255 
256 void QgsSimpleLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
257 {
258  QPainter *p = context.renderContext().painter();
259  if ( !p )
260  {
261  return;
262  }
263 
264  if ( mDrawInsidePolygon )
265  p->save();
266 
267  switch ( mRingFilter )
268  {
269  case AllRings:
270  case ExteriorRingOnly:
271  {
272  if ( mDrawInsidePolygon )
273  {
274  //only drawing the line on the interior of the polygon, so set clip path for painter
275  QPainterPath clipPath;
276  clipPath.addPolygon( points );
277 
278  if ( rings )
279  {
280  //add polygon rings
281  for ( auto it = rings->constBegin(); it != rings->constEnd(); ++it )
282  {
283  QPolygonF ring = *it;
284  clipPath.addPolygon( ring );
285  }
286  }
287 
288  //use intersect mode, as a clip path may already exist (e.g., for composer maps)
289  p->setClipPath( clipPath, Qt::IntersectClip );
290  }
291 
292  renderPolyline( points, context );
293  }
294  break;
295 
296  case InteriorRingsOnly:
297  break;
298  }
299 
300  if ( rings )
301  {
302  switch ( mRingFilter )
303  {
304  case AllRings:
305  case InteriorRingsOnly:
306  {
307  mOffset = -mOffset; // invert the offset for rings!
308  for ( const QPolygonF &ring : qgis::as_const( *rings ) )
309  renderPolyline( ring, context );
310  mOffset = -mOffset;
311  }
312  break;
313  case ExteriorRingOnly:
314  break;
315  }
316  }
317 
318  if ( mDrawInsidePolygon )
319  {
320  //restore painter to reset clip path
321  p->restore();
322  }
323 
324 }
325 
326 void QgsSimpleLineSymbolLayer::renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context )
327 {
328  QPainter *p = context.renderContext().painter();
329  if ( !p )
330  {
331  return;
332  }
333 
334  double offset = mOffset;
335  applyDataDefinedSymbology( context, mPen, mSelPen, offset );
336 
337  const QPen pen = context.selected() ? mSelPen : mPen;
338  p->setBrush( Qt::NoBrush );
339 
340  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #2 points).
341  std::unique_ptr< QgsScopedQPainterState > painterState;
342  if ( points.size() <= 2 &&
345  ( p->renderHints() & QPainter::Antialiasing ) )
346  {
347  painterState = qgis::make_unique< QgsScopedQPainterState >( p );
348  p->setRenderHint( QPainter::Antialiasing, false );
349  }
350 
351  const bool applyPatternTweaks = mAlignDashPattern
352  && ( pen.style() != Qt::SolidLine || !pen.dashPattern().empty() )
353  && pen.dashOffset() == 0;
354 
355  if ( qgsDoubleNear( offset, 0 ) )
356  {
357  if ( applyPatternTweaks )
358  {
359  drawPathWithDashPatternTweaks( p, points, pen );
360  }
361  else
362  {
363  p->setPen( pen );
364  QPainterPath path;
365  path.addPolygon( points );
366  p->drawPath( path );
367  }
368  }
369  else
370  {
371  double scaledOffset = context.renderContext().convertToPainterUnits( offset, mOffsetUnit, mOffsetMapUnitScale );
373  {
374  // rendering for symbol previews -- a size in meters in map units can't be calculated, so treat the size as millimeters
375  // and clamp it to a reasonable range. It's the best we can do in this situation!
376  scaledOffset = std::min( std::max( context.renderContext().convertToPainterUnits( offset, QgsUnitTypes::RenderMillimeters ), 3.0 ), 100.0 );
377  }
378 
379  QList<QPolygonF> mline = ::offsetLine( points, scaledOffset, context.originalGeometryType() != QgsWkbTypes::UnknownGeometry ? context.originalGeometryType() : QgsWkbTypes::LineGeometry );
380  for ( const QPolygonF &part : mline )
381  {
382  if ( applyPatternTweaks )
383  {
384  drawPathWithDashPatternTweaks( p, part, pen );
385  }
386  else
387  {
388  p->setPen( pen );
389  QPainterPath path;
390  path.addPolygon( part );
391  p->drawPath( path );
392  }
393  }
394  }
395 }
396 
398 {
399  QgsStringMap map;
400  map[QStringLiteral( "line_color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
401  map[QStringLiteral( "line_width" )] = QString::number( mWidth );
402  map[QStringLiteral( "line_width_unit" )] = QgsUnitTypes::encodeUnit( mWidthUnit );
403  map[QStringLiteral( "width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mWidthMapUnitScale );
404  map[QStringLiteral( "line_style" )] = QgsSymbolLayerUtils::encodePenStyle( mPenStyle );
405  map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
406  map[QStringLiteral( "capstyle" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
407  map[QStringLiteral( "offset" )] = QString::number( mOffset );
408  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
409  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
410  map[QStringLiteral( "use_custom_dash" )] = ( mUseCustomDashPattern ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
411  map[QStringLiteral( "customdash" )] = QgsSymbolLayerUtils::encodeRealVector( mCustomDashVector );
412  map[QStringLiteral( "customdash_unit" )] = QgsUnitTypes::encodeUnit( mCustomDashPatternUnit );
413  map[QStringLiteral( "customdash_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mCustomDashPatternMapUnitScale );
414  map[QStringLiteral( "dash_pattern_offset" )] = QString::number( mDashPatternOffset );
415  map[QStringLiteral( "dash_pattern_offset_unit" )] = QgsUnitTypes::encodeUnit( mDashPatternOffsetUnit );
416  map[QStringLiteral( "dash_pattern_offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mDashPatternOffsetMapUnitScale );
417  map[QStringLiteral( "draw_inside_polygon" )] = ( mDrawInsidePolygon ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
418  map[QStringLiteral( "ring_filter" )] = QString::number( static_cast< int >( mRingFilter ) );
419  map[QStringLiteral( "align_dash_pattern" )] = mAlignDashPattern ? QStringLiteral( "1" ) : QStringLiteral( "0" );
420  map[QStringLiteral( "tweak_dash_pattern_on_corners" )] = mPatternCartographicTweakOnSharpCorners ? QStringLiteral( "1" ) : QStringLiteral( "0" );
421  return map;
422 }
423 
425 {
427  l->setWidthUnit( mWidthUnit );
431  l->setCustomDashPatternUnit( mCustomDashPatternUnit );
432  l->setCustomDashPatternMapUnitScale( mCustomDashPatternMapUnitScale );
433  l->setOffset( mOffset );
434  l->setPenJoinStyle( mPenJoinStyle );
435  l->setPenCapStyle( mPenCapStyle );
436  l->setUseCustomDashPattern( mUseCustomDashPattern );
437  l->setCustomDashVector( mCustomDashVector );
438  l->setDrawInsidePolygon( mDrawInsidePolygon );
440  l->setDashPatternOffset( mDashPatternOffset );
441  l->setDashPatternOffsetUnit( mDashPatternOffsetUnit );
442  l->setDashPatternOffsetMapUnitScale( mDashPatternOffsetMapUnitScale );
443  l->setAlignDashPattern( mAlignDashPattern );
444  l->setTweakDashPatternOnCorners( mPatternCartographicTweakOnSharpCorners );
445 
447  copyPaintEffect( l );
448  return l;
449 }
450 
451 void QgsSimpleLineSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
452 {
453  if ( mPenStyle == Qt::NoPen )
454  return;
455 
456  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:LineSymbolizer" ) );
457  if ( !props.value( QStringLiteral( "uom" ), QString() ).isEmpty() )
458  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ) );
459  element.appendChild( symbolizerElem );
460 
461  // <Geometry>
462  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ) );
463 
464  // <Stroke>
465  QDomElement strokeElem = doc.createElement( QStringLiteral( "se:Stroke" ) );
466  symbolizerElem.appendChild( strokeElem );
467 
468  Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
470  QVector<qreal> customDashVector = QgsSymbolLayerUtils::rescaleUom( mCustomDashVector, mCustomDashPatternUnit, props );
472  &mPenJoinStyle, &mPenCapStyle, &customDashVector );
473 
474  // <se:PerpendicularOffset>
475  if ( !qgsDoubleNear( mOffset, 0.0 ) )
476  {
477  QDomElement perpOffsetElem = doc.createElement( QStringLiteral( "se:PerpendicularOffset" ) );
479  perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
480  symbolizerElem.appendChild( perpOffsetElem );
481  }
482 }
483 
484 QString QgsSimpleLineSymbolLayer::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
485 {
486  if ( mUseCustomDashPattern )
487  {
488  return QgsSymbolLayerUtils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor,
489  mPen.color(), mPenJoinStyle,
490  mPenCapStyle, mOffset, &mCustomDashVector );
491  }
492  else
493  {
494  return QgsSymbolLayerUtils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor, mPen.color(), mPenJoinStyle,
495  mPenCapStyle, mOffset );
496  }
497 }
498 
500 {
501  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
502 
503  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
504  if ( strokeElem.isNull() )
505  return nullptr;
506 
507  Qt::PenStyle penStyle;
508  QColor color;
509  double width;
510  Qt::PenJoinStyle penJoinStyle;
511  Qt::PenCapStyle penCapStyle;
512  QVector<qreal> customDashVector;
513 
514  if ( !QgsSymbolLayerUtils::lineFromSld( strokeElem, penStyle,
515  color, width,
517  &customDashVector ) )
518  return nullptr;
519 
520  double offset = 0.0;
521  QDomElement perpOffsetElem = element.firstChildElement( QStringLiteral( "PerpendicularOffset" ) );
522  if ( !perpOffsetElem.isNull() )
523  {
524  bool ok;
525  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
526  if ( ok )
527  offset = d;
528  }
529 
530  QString uom = element.attribute( QStringLiteral( "uom" ) );
533 
535  l->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
536  l->setOffset( offset );
539  l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
541  return l;
542 }
543 
544 void QgsSimpleLineSymbolLayer::applyDataDefinedSymbology( QgsSymbolRenderContext &context, QPen &pen, QPen &selPen, double &offset )
545 {
546  if ( !dataDefinedProperties().hasActiveProperties() )
547  return; // shortcut
548 
549  //data defined properties
550  bool hasStrokeWidthExpression = false;
552  {
553  context.setOriginalValueVariable( mWidth );
554  double scaledWidth = context.renderContext().convertToPainterUnits(
557  pen.setWidthF( scaledWidth );
558  selPen.setWidthF( scaledWidth );
559  hasStrokeWidthExpression = true;
560  }
561 
562  //color
564  {
567  }
568 
569  //offset
571  {
574  }
575 
576  //dash dot vector
577 
578  //note that Qt seems to have issues with scaling dash patterns with very small pen widths.
579  //treating the pen as having no less than a 1 pixel size avoids the worst of these issues
580  const double dashWidthDiv = std::max( hasStrokeWidthExpression ? pen.widthF() : mPen.widthF(), 1.0 );
581 
583  {
584  QVector<qreal> dashVector;
586  if ( exprVal.isValid() )
587  {
588  QStringList dashList = exprVal.toString().split( ';' );
589  QStringList::const_iterator dashIt = dashList.constBegin();
590  for ( ; dashIt != dashList.constEnd(); ++dashIt )
591  {
592  dashVector.push_back( context.renderContext().convertToPainterUnits( dashIt->toDouble(), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv );
593  }
594  pen.setDashPattern( dashVector );
595  }
596  }
597  else if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyStrokeWidth ) && mUseCustomDashPattern )
598  {
599  //re-scale pattern vector after data defined pen width was applied
600 
601  QVector<qreal> scaledVector;
602  for ( double v : mCustomDashVector )
603  {
604  //the dash is specified in terms of pen widths, therefore the division
605  scaledVector << context.renderContext().convertToPainterUnits( v, mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv;
606  }
607  mPen.setDashPattern( scaledVector );
608  }
609 
610  // dash pattern offset
611  double patternOffset = mDashPatternOffset;
612  if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyDashPatternOffset ) && pen.style() != Qt::SolidLine )
613  {
614  context.setOriginalValueVariable( mDashPatternOffset );
616  pen.setDashOffset( context.renderContext().convertToPainterUnits( patternOffset, mDashPatternOffsetUnit, mDashPatternOffsetMapUnitScale ) / dashWidthDiv );
617  }
618 
619  //line style
621  {
624  if ( exprVal.isValid() )
625  pen.setStyle( QgsSymbolLayerUtils::decodePenStyle( exprVal.toString() ) );
626  }
627 
628  //join style
630  {
633  if ( exprVal.isValid() )
634  pen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( exprVal.toString() ) );
635  }
636 
637  //cap style
639  {
642  if ( exprVal.isValid() )
643  pen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( exprVal.toString() ) );
644  }
645 }
646 
647 void QgsSimpleLineSymbolLayer::drawPathWithDashPatternTweaks( QPainter *painter, const QPolygonF &points, QPen pen ) const
648 {
649  if ( pen.dashPattern().empty() || points.size() < 2 )
650  return;
651 
652  QVector< qreal > sourcePattern = pen.dashPattern();
653  const double dashWidthDiv = std::max( 1.0001, pen.widthF() );
654  // back to painter units
655  for ( int i = 0; i < sourcePattern.size(); ++ i )
656  sourcePattern[i] *= pen.widthF();
657 
658  if ( pen.widthF() <= 1.0 )
659  pen.setWidthF( 1.0001 );
660 
661  QVector< qreal > buffer;
662  QPolygonF bufferedPoints;
663  QPolygonF previousSegmentBuffer;
664  // we iterate through the line points, building a custom dash pattern and adding it to the buffer
665  // as soon as we hit a sharp bend, we scale the buffered pattern in order to nicely place a dash component over the bend
666  // and then append the buffer to the output pattern.
667 
668  auto ptIt = points.constBegin();
669  double totalBufferLength = 0;
670  int patternIndex = 0;
671  double currentRemainingDashLength = 0;
672  double currentRemainingGapLength = 0;
673 
674  auto compressPattern = []( const QVector< qreal > &buffer ) -> QVector< qreal >
675  {
676  QVector< qreal > result;
677  result.reserve( buffer.size() );
678  for ( auto it = buffer.begin(); it != buffer.end(); )
679  {
680  qreal dash = *it++;
681  qreal gap = *it++;
682  while ( dash == 0 && !result.empty() )
683  {
684  result.last() += gap;
685 
686  if ( it == buffer.end() )
687  return result;
688  dash = *it++;
689  gap = *it++;
690  }
691  while ( gap == 0 && it != buffer.end() )
692  {
693  dash += *it++;
694  gap = *it++;
695  }
696  result << dash << gap;
697  }
698  return result;
699  };
700 
701  double currentBufferLineLength = 0;
702  auto flushBuffer = [pen, painter, &buffer, &bufferedPoints, &previousSegmentBuffer, &currentRemainingDashLength, &currentRemainingGapLength, &currentBufferLineLength, &totalBufferLength,
703  dashWidthDiv, &compressPattern]( QPointF * nextPoint )
704  {
705  if ( buffer.empty() || bufferedPoints.size() < 2 )
706  {
707  return;
708  }
709 
710  if ( currentRemainingDashLength )
711  {
712  // ended midway through a dash -- we want to finish this off
713  buffer << currentRemainingDashLength << 0.0;
714  totalBufferLength += currentRemainingDashLength;
715  }
716  QVector< qreal > compressed = compressPattern( buffer );
717  if ( !currentRemainingDashLength )
718  {
719  // ended midway through a gap -- we don't want this, we want to end at previous dash
720  totalBufferLength -= compressed.last();
721  compressed.last() = 0;
722  }
723 
724  // rescale buffer for final bit of line -- we want to end at the end of a dash, not a gap
725  const double scaleFactor = currentBufferLineLength / totalBufferLength;
726 
727  bool shouldFlushPreviousSegmentBuffer = false;
728 
729  if ( !previousSegmentBuffer.empty() )
730  {
731  // add first dash from current buffer
732  QPolygonF firstDashSubstring = QgsSymbolLayerUtils::polylineSubstring( bufferedPoints, 0, compressed.first() * scaleFactor );
733  if ( !firstDashSubstring.empty() )
734  QgsSymbolLayerUtils::appendPolyline( previousSegmentBuffer, firstDashSubstring );
735 
736  // then we skip over the first dash and gap for this segment
737  bufferedPoints = QgsSymbolLayerUtils::polylineSubstring( bufferedPoints, ( compressed.first() + compressed.at( 1 ) ) * scaleFactor, 0 );
738 
739  compressed = compressed.mid( 2 );
740  shouldFlushPreviousSegmentBuffer = !compressed.empty();
741  }
742 
743  if ( !previousSegmentBuffer.empty() && ( shouldFlushPreviousSegmentBuffer || !nextPoint ) )
744  {
745  QPen adjustedPen = pen;
746  adjustedPen.setStyle( Qt::SolidLine );
747  painter->setPen( adjustedPen );
748  QPainterPath path;
749  path.addPolygon( previousSegmentBuffer );
750  painter->drawPath( path );
751  previousSegmentBuffer.clear();
752  }
753 
754  double finalDash = 0;
755  if ( nextPoint )
756  {
757  // sharp bend:
758  // 1. rewind buffered points line by final dash and gap length
759  // (later) 2. draw the bend with a solid line of length 2 * final dash size
760 
761  if ( !compressed.empty() )
762  {
763  finalDash = compressed.at( compressed.size() - 2 );
764  const double finalGap = compressed.size() > 2 ? compressed.at( compressed.size() - 3 ) : 0;
765 
766  const QPolygonF thisPoints = bufferedPoints;
767  bufferedPoints = QgsSymbolLayerUtils::polylineSubstring( thisPoints, 0, -( finalDash + finalGap ) * scaleFactor );
768  previousSegmentBuffer = QgsSymbolLayerUtils::polylineSubstring( thisPoints, - finalDash * scaleFactor, 0 );
769  }
770  else
771  {
772  previousSegmentBuffer << bufferedPoints;
773  }
774  }
775 
776  currentBufferLineLength = 0;
777  currentRemainingDashLength = 0;
778  currentRemainingGapLength = 0;
779  totalBufferLength = 0;
780  buffer.clear();
781 
782  if ( !bufferedPoints.empty() && ( !compressed.empty() || !nextPoint ) )
783  {
784  QPen adjustedPen = pen;
785  if ( !compressed.empty() )
786  {
787  // maximum size of dash pattern is 32 elements
788  compressed = compressed.mid( 0, 32 );
789  std::for_each( compressed.begin(), compressed.end(), [scaleFactor, dashWidthDiv]( qreal & element ) { element *= scaleFactor / dashWidthDiv; } );
790  adjustedPen.setDashPattern( compressed );
791  }
792  else
793  {
794  adjustedPen.setStyle( Qt::SolidLine );
795  }
796 
797  painter->setPen( adjustedPen );
798  QPainterPath path;
799  path.addPolygon( bufferedPoints );
800  painter->drawPath( path );
801  }
802 
803  bufferedPoints.clear();
804  };
805 
806  QPointF p1;
807  QPointF p2 = *ptIt;
808  ptIt++;
809  bufferedPoints << p2;
810  for ( ; ptIt != points.constEnd(); ++ptIt )
811  {
812  p1 = *ptIt;
813  if ( qgsDoubleNear( p1.y(), p2.y() ) && qgsDoubleNear( p1.x(), p2.x() ) )
814  {
815  continue;
816  }
817 
818  double remainingSegmentDistance = std::sqrt( std::pow( p2.x() - p1.x(), 2.0 ) + std::pow( p2.y() - p1.y(), 2.0 ) );
819  currentBufferLineLength += remainingSegmentDistance;
820  while ( true )
821  {
822  // handle currentRemainingDashLength/currentRemainingGapLength
823  if ( currentRemainingDashLength > 0 )
824  {
825  // bit more of dash to insert
826  if ( remainingSegmentDistance >= currentRemainingDashLength )
827  {
828  // all of dash fits in
829  buffer << currentRemainingDashLength << 0.0;
830  totalBufferLength += currentRemainingDashLength;
831  remainingSegmentDistance -= currentRemainingDashLength;
832  patternIndex++;
833  currentRemainingDashLength = 0.0;
834  currentRemainingGapLength = sourcePattern.at( patternIndex );
835  }
836  else
837  {
838  // only part of remaining dash fits in
839  buffer << remainingSegmentDistance << 0.0;
840  totalBufferLength += remainingSegmentDistance;
841  currentRemainingDashLength -= remainingSegmentDistance;
842  break;
843  }
844  }
845  if ( currentRemainingGapLength > 0 )
846  {
847  // bit more of gap to insert
848  if ( remainingSegmentDistance >= currentRemainingGapLength )
849  {
850  // all of gap fits in
851  buffer << 0.0 << currentRemainingGapLength;
852  totalBufferLength += currentRemainingGapLength;
853  remainingSegmentDistance -= currentRemainingGapLength;
854  currentRemainingGapLength = 0.0;
855  patternIndex++;
856  }
857  else
858  {
859  // only part of remaining gap fits in
860  buffer << 0.0 << remainingSegmentDistance;
861  totalBufferLength += remainingSegmentDistance;
862  currentRemainingGapLength -= remainingSegmentDistance;
863  break;
864  }
865  }
866 
867  if ( patternIndex >= sourcePattern.size() )
868  patternIndex = 0;
869 
870  const double nextPatternDashLength = sourcePattern.at( patternIndex );
871  const double nextPatternGapLength = sourcePattern.at( patternIndex + 1 );
872  if ( nextPatternDashLength + nextPatternGapLength <= remainingSegmentDistance )
873  {
874  buffer << nextPatternDashLength << nextPatternGapLength;
875  remainingSegmentDistance -= nextPatternDashLength + nextPatternGapLength;
876  totalBufferLength += nextPatternDashLength + nextPatternGapLength;
877  patternIndex += 2;
878  }
879  else if ( nextPatternDashLength <= remainingSegmentDistance )
880  {
881  // can fit in "dash", but not "gap"
882  buffer << nextPatternDashLength << remainingSegmentDistance - nextPatternDashLength;
883  totalBufferLength += remainingSegmentDistance;
884  currentRemainingGapLength = nextPatternGapLength - ( remainingSegmentDistance - nextPatternDashLength );
885  currentRemainingDashLength = 0;
886  patternIndex++;
887  break;
888  }
889  else
890  {
891  // can't fit in "dash"
892  buffer << remainingSegmentDistance << 0.0;
893  totalBufferLength += remainingSegmentDistance;
894  currentRemainingGapLength = 0;
895  currentRemainingDashLength = nextPatternDashLength - remainingSegmentDistance;
896  break;
897  }
898  }
899 
900  bufferedPoints << p1;
901  if ( mPatternCartographicTweakOnSharpCorners && ptIt + 1 != points.constEnd() )
902  {
903  QPointF nextPoint = *( ptIt + 1 );
904 
905  // extreme angles form more than 45 degree angle at a node
906  if ( QgsSymbolLayerUtils::isSharpCorner( p2, p1, nextPoint ) )
907  {
908  // extreme angle. Rescale buffer and flush
909  flushBuffer( &nextPoint );
910  bufferedPoints << p1;
911  // restart the line with the full length of the most recent dash element -- see
912  // "Cartographic Generalization" (Swiss Society of Cartography) p33, example #8
913  if ( patternIndex % 2 == 1 )
914  {
915  patternIndex--;
916  }
917  currentRemainingDashLength = sourcePattern.at( patternIndex );
918  }
919  }
920 
921  p2 = p1;
922  }
923 
924  flushBuffer( nullptr );
925  if ( !previousSegmentBuffer.empty() )
926  {
927  QPen adjustedPen = pen;
928  adjustedPen.setStyle( Qt::SolidLine );
929  painter->setPen( adjustedPen );
930  QPainterPath path;
931  path.addPolygon( previousSegmentBuffer );
932  painter->drawPath( path );
933  previousSegmentBuffer.clear();
934  }
935 }
936 
938 {
939  if ( mDrawInsidePolygon )
940  {
941  //set to clip line to the interior of polygon, so we expect no bleed
942  return 0;
943  }
944  else
945  {
946  return context.convertToPainterUnits( ( mWidth / 2.0 ), mWidthUnit, mWidthMapUnitScale ) +
948  }
949 }
950 
952 {
953  unit = mCustomDashPatternUnit;
954  return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>();
955 }
956 
958 {
959  return mPenStyle;
960 }
961 
963 {
964  double width = mWidth;
966  {
967  context.setOriginalValueVariable( mWidth );
969  }
970 
973  {
975  }
976  return width;
977 }
978 
980 {
982  {
985  }
986  return mColor;
987 }
988 
990 {
991  return mAlignDashPattern;
992 }
993 
995 {
996  mAlignDashPattern = enabled;
997 }
998 
1000 {
1001  return mPatternCartographicTweakOnSharpCorners;
1002 }
1003 
1005 {
1006  mPatternCartographicTweakOnSharpCorners = enabled;
1007 }
1008 
1010 {
1011  Q_UNUSED( e )
1012  double offset = mOffset;
1013 
1015  {
1016  context.setOriginalValueVariable( mOffset );
1018  }
1019 
1022  {
1024  }
1025  return -offset; //direction seems to be inverse to symbology offset
1026 }
1027 
1029 
1031 
1032 class MyLine
1033 {
1034  public:
1035  MyLine( QPointF p1, QPointF p2 )
1036  : mVertical( false )
1037  , mIncreasing( false )
1038  , mT( 0.0 )
1039  , mLength( 0.0 )
1040  {
1041  if ( p1 == p2 )
1042  return; // invalid
1043 
1044  // tangent and direction
1045  if ( qgsDoubleNear( p1.x(), p2.x() ) )
1046  {
1047  // vertical line - tangent undefined
1048  mVertical = true;
1049  mIncreasing = ( p2.y() > p1.y() );
1050  }
1051  else
1052  {
1053  mVertical = false;
1054  mT = ( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
1055  mIncreasing = ( p2.x() > p1.x() );
1056  }
1057 
1058  // length
1059  double x = ( p2.x() - p1.x() );
1060  double y = ( p2.y() - p1.y() );
1061  mLength = std::sqrt( x * x + y * y );
1062  }
1063 
1064  // return angle in radians
1065  double angle()
1066  {
1067  double a = ( mVertical ? M_PI_2 : std::atan( mT ) );
1068 
1069  if ( !mIncreasing )
1070  a += M_PI;
1071  return a;
1072  }
1073 
1074  // return difference for x,y when going along the line with specified interval
1075  QPointF diffForInterval( double interval )
1076  {
1077  if ( mVertical )
1078  return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
1079 
1080  double alpha = std::atan( mT );
1081  double dx = std::cos( alpha ) * interval;
1082  double dy = std::sin( alpha ) * interval;
1083  return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
1084  }
1085 
1086  double length() { return mLength; }
1087 
1088  protected:
1089  bool mVertical;
1090  bool mIncreasing;
1091  double mT;
1092  double mLength;
1093 };
1094 
1096 
1097 //
1098 // QgsTemplatedLineSymbolLayerBase
1099 //
1101  : mRotateSymbols( rotateSymbol )
1102  , mInterval( interval )
1103 {
1104 
1105 }
1106 
1108 {
1109  double offset = mOffset;
1110 
1112  {
1113  context.setOriginalValueVariable( mOffset );
1115  }
1116 
1118 
1120  {
1122  if ( exprVal.isValid() )
1123  {
1124  QString placementString = exprVal.toString();
1125  if ( placementString.compare( QLatin1String( "interval" ), Qt::CaseInsensitive ) == 0 )
1126  {
1128  }
1129  else if ( placementString.compare( QLatin1String( "vertex" ), Qt::CaseInsensitive ) == 0 )
1130  {
1132  }
1133  else if ( placementString.compare( QLatin1String( "lastvertex" ), Qt::CaseInsensitive ) == 0 )
1134  {
1136  }
1137  else if ( placementString.compare( QLatin1String( "firstvertex" ), Qt::CaseInsensitive ) == 0 )
1138  {
1140  }
1141  else if ( placementString.compare( QLatin1String( "centerpoint" ), Qt::CaseInsensitive ) == 0 )
1142  {
1144  }
1145  else if ( placementString.compare( QLatin1String( "curvepoint" ), Qt::CaseInsensitive ) == 0 )
1146  {
1148  }
1149  else if ( placementString.compare( QLatin1String( "segmentcenter" ), Qt::CaseInsensitive ) == 0 )
1150  {
1152  }
1153  else
1154  {
1156  }
1157  }
1158  }
1159 
1160  QgsScopedQPainterState painterState( context.renderContext().painter() );
1161 
1162  double averageOver = mAverageAngleLength;
1164  {
1165  context.setOriginalValueVariable( mAverageAngleLength );
1167  }
1168  averageOver = context.renderContext().convertToPainterUnits( averageOver, mAverageAngleLengthUnit, mAverageAngleLengthMapUnitScale ) / 2.0;
1169 
1170  if ( qgsDoubleNear( offset, 0.0 ) )
1171  {
1172  switch ( placement )
1173  {
1174  case Interval:
1175  renderPolylineInterval( points, context, averageOver );
1176  break;
1177 
1178  case CentralPoint:
1179  renderPolylineCentral( points, context, averageOver );
1180  break;
1181 
1182  case Vertex:
1183  case LastVertex:
1184  case FirstVertex:
1185  case CurvePoint:
1186  case SegmentCenter:
1187  renderPolylineVertex( points, context, placement );
1188  break;
1189  }
1190  }
1191  else
1192  {
1193  context.renderContext().setGeometry( nullptr ); //always use segmented geometry with offset
1195 
1196  for ( int part = 0; part < mline.count(); ++part )
1197  {
1198  const QPolygonF &points2 = mline[ part ];
1199 
1200  switch ( placement )
1201  {
1202  case Interval:
1203  renderPolylineInterval( points2, context, averageOver );
1204  break;
1205 
1206  case CentralPoint:
1207  renderPolylineCentral( points2, context, averageOver );
1208  break;
1209 
1210  case Vertex:
1211  case LastVertex:
1212  case FirstVertex:
1213  case CurvePoint:
1214  case SegmentCenter:
1215  renderPolylineVertex( points2, context, placement );
1216  break;
1217  }
1218  }
1219  }
1220 }
1221 
1222 void QgsTemplatedLineSymbolLayerBase::renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
1223 {
1224  const QgsCurvePolygon *curvePolygon = dynamic_cast<const QgsCurvePolygon *>( context.renderContext().geometry() );
1225 
1226  if ( curvePolygon )
1227  {
1228  context.renderContext().setGeometry( curvePolygon->exteriorRing() );
1229  }
1230 
1231  switch ( mRingFilter )
1232  {
1233  case AllRings:
1234  case ExteriorRingOnly:
1235  renderPolyline( points, context );
1236  break;
1237  case InteriorRingsOnly:
1238  break;
1239  }
1240 
1241  if ( rings )
1242  {
1243  switch ( mRingFilter )
1244  {
1245  case AllRings:
1246  case InteriorRingsOnly:
1247  {
1248  mOffset = -mOffset; // invert the offset for rings!
1249  for ( int i = 0; i < rings->size(); ++i )
1250  {
1251  if ( curvePolygon )
1252  {
1253  context.renderContext().setGeometry( curvePolygon->interiorRing( i ) );
1254  }
1255  renderPolyline( rings->at( i ), context );
1256  }
1257  mOffset = -mOffset;
1258  }
1259  break;
1260  case ExteriorRingOnly:
1261  break;
1262  }
1263  }
1264 }
1265 
1267 {
1269  if ( intervalUnit() != unit || mOffsetUnit != unit || offsetAlongLineUnit() != unit )
1270  {
1272  }
1273  return unit;
1274 }
1275 
1277 {
1279  setIntervalMapUnitScale( scale );
1280  mOffsetMapUnitScale = scale;
1282 }
1283 
1285 {
1289  {
1290  return mOffsetMapUnitScale;
1291  }
1292  return QgsMapUnitScale();
1293 }
1294 
1296 {
1297  QgsStringMap map;
1298  map[QStringLiteral( "rotate" )] = ( rotateSymbols() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1299  map[QStringLiteral( "interval" )] = QString::number( interval() );
1300  map[QStringLiteral( "offset" )] = QString::number( mOffset );
1301  map[QStringLiteral( "offset_along_line" )] = QString::number( offsetAlongLine() );
1302  map[QStringLiteral( "offset_along_line_unit" )] = QgsUnitTypes::encodeUnit( offsetAlongLineUnit() );
1303  map[QStringLiteral( "offset_along_line_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( offsetAlongLineMapUnitScale() );
1304  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
1305  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
1306  map[QStringLiteral( "interval_unit" )] = QgsUnitTypes::encodeUnit( intervalUnit() );
1307  map[QStringLiteral( "interval_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( intervalMapUnitScale() );
1308  map[QStringLiteral( "average_angle_length" )] = QString::number( mAverageAngleLength );
1309  map[QStringLiteral( "average_angle_unit" )] = QgsUnitTypes::encodeUnit( mAverageAngleLengthUnit );
1310  map[QStringLiteral( "average_angle_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mAverageAngleLengthMapUnitScale );
1311 
1312  switch ( mPlacement )
1313  {
1314  case Vertex:
1315  map[QStringLiteral( "placement" )] = QStringLiteral( "vertex" );
1316  break;
1317  case LastVertex:
1318  map[QStringLiteral( "placement" )] = QStringLiteral( "lastvertex" );
1319  break;
1320  case FirstVertex:
1321  map[QStringLiteral( "placement" )] = QStringLiteral( "firstvertex" );
1322  break;
1323  case CentralPoint:
1324  map[QStringLiteral( "placement" )] = QStringLiteral( "centralpoint" );
1325  break;
1326  case CurvePoint:
1327  map[QStringLiteral( "placement" )] = QStringLiteral( "curvepoint" );
1328  break;
1329  case Interval:
1330  map[QStringLiteral( "placement" )] = QStringLiteral( "interval" );
1331  break;
1332  case SegmentCenter:
1333  map[QStringLiteral( "placement" )] = QStringLiteral( "segmentcenter" );
1334  break;
1335  }
1336 
1337  map[QStringLiteral( "ring_filter" )] = QString::number( static_cast< int >( mRingFilter ) );
1338  return map;
1339 }
1340 
1342 {
1343  destLayer->setSubSymbol( const_cast< QgsTemplatedLineSymbolLayerBase * >( this )->subSymbol()->clone() );
1344  destLayer->setOffset( mOffset );
1345  destLayer->setPlacement( placement() );
1346  destLayer->setOffsetUnit( mOffsetUnit );
1348  destLayer->setIntervalUnit( intervalUnit() );
1350  destLayer->setOffsetAlongLine( offsetAlongLine() );
1353  destLayer->setAverageAngleLength( mAverageAngleLength );
1354  destLayer->setAverageAngleUnit( mAverageAngleLengthUnit );
1355  destLayer->setAverageAngleMapUnitScale( mAverageAngleLengthMapUnitScale );
1356  destLayer->setRingFilter( mRingFilter );
1357  copyDataDefinedProperties( destLayer );
1358  copyPaintEffect( destLayer );
1359 }
1360 
1362 {
1363  if ( properties.contains( QStringLiteral( "offset" ) ) )
1364  {
1365  destLayer->setOffset( properties[QStringLiteral( "offset" )].toDouble() );
1366  }
1367  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
1368  {
1369  destLayer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )] ) );
1370  }
1371  if ( properties.contains( QStringLiteral( "interval_unit" ) ) )
1372  {
1373  destLayer->setIntervalUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "interval_unit" )] ) );
1374  }
1375  if ( properties.contains( QStringLiteral( "offset_along_line" ) ) )
1376  {
1377  destLayer->setOffsetAlongLine( properties[QStringLiteral( "offset_along_line" )].toDouble() );
1378  }
1379  if ( properties.contains( QStringLiteral( "offset_along_line_unit" ) ) )
1380  {
1381  destLayer->setOffsetAlongLineUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_along_line_unit" )] ) );
1382  }
1383  if ( properties.contains( ( QStringLiteral( "offset_along_line_map_unit_scale" ) ) ) )
1384  {
1385  destLayer->setOffsetAlongLineMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_along_line_map_unit_scale" )] ) );
1386  }
1387 
1388  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
1389  {
1390  destLayer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )] ) );
1391  }
1392  if ( properties.contains( QStringLiteral( "interval_map_unit_scale" ) ) )
1393  {
1394  destLayer->setIntervalMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "interval_map_unit_scale" )] ) );
1395  }
1396 
1397  if ( properties.contains( QStringLiteral( "average_angle_length" ) ) )
1398  {
1399  destLayer->setAverageAngleLength( properties[QStringLiteral( "average_angle_length" )].toDouble() );
1400  }
1401  if ( properties.contains( QStringLiteral( "average_angle_unit" ) ) )
1402  {
1403  destLayer->setAverageAngleUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "average_angle_unit" )] ) );
1404  }
1405  if ( properties.contains( ( QStringLiteral( "average_angle_map_unit_scale" ) ) ) )
1406  {
1407  destLayer->setAverageAngleMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "average_angle_map_unit_scale" )] ) );
1408  }
1409 
1410  if ( properties.contains( QStringLiteral( "placement" ) ) )
1411  {
1412  if ( properties[QStringLiteral( "placement" )] == QLatin1String( "vertex" ) )
1414  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "lastvertex" ) )
1416  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "firstvertex" ) )
1418  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "centralpoint" ) )
1420  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "curvepoint" ) )
1422  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "segmentcenter" ) )
1424  else
1426  }
1427 
1428  if ( properties.contains( QStringLiteral( "ring_filter" ) ) )
1429  {
1430  destLayer->setRingFilter( static_cast< RenderRingFilter>( properties[QStringLiteral( "ring_filter" )].toInt() ) );
1431  }
1432 
1434 }
1435 
1436 void QgsTemplatedLineSymbolLayerBase::renderPolylineInterval( const QPolygonF &points, QgsSymbolRenderContext &context, double averageOver )
1437 {
1438  if ( points.isEmpty() )
1439  return;
1440 
1441  double lengthLeft = 0; // how much is left until next marker
1442 
1443  QgsRenderContext &rc = context.renderContext();
1444  double interval = mInterval;
1445 
1447  QgsExpressionContextScopePopper scopePopper( context.renderContext().expressionContext(), scope );
1448 
1450  {
1451  context.setOriginalValueVariable( mInterval );
1453  }
1454  if ( interval <= 0 )
1455  {
1456  interval = 0.1;
1457  }
1458  double offsetAlongLine = mOffsetAlongLine;
1460  {
1461  context.setOriginalValueVariable( mOffsetAlongLine );
1463  }
1464 
1465  double painterUnitInterval = rc.convertToPainterUnits( interval, intervalUnit(), intervalMapUnitScale() );
1467  {
1468  // rendering for symbol previews -- an interval in meters in map units can't be calculated, so treat the size as millimeters
1469  // and clamp it to a reasonable range. It's the best we can do in this situation!
1470  painterUnitInterval = std::min( std::max( rc.convertToPainterUnits( interval, QgsUnitTypes::RenderMillimeters ), 10.0 ), 100.0 );
1471  }
1472 
1473  if ( painterUnitInterval < 0 )
1474  return;
1475 
1476  double painterUnitOffsetAlongLine = rc.convertToPainterUnits( offsetAlongLine, offsetAlongLineUnit(), offsetAlongLineMapUnitScale() );
1478  {
1479  // rendering for symbol previews -- an offset in meters in map units can't be calculated, so treat the size as millimeters
1480  // and clamp it to a reasonable range. It's the best we can do in this situation!
1481  painterUnitOffsetAlongLine = std::min( std::max( rc.convertToPainterUnits( offsetAlongLine, QgsUnitTypes::RenderMillimeters ), 3.0 ), 100.0 );
1482  }
1483 
1484  lengthLeft = painterUnitInterval - painterUnitOffsetAlongLine;
1485 
1486  if ( averageOver > 0 && !qgsDoubleNear( averageOver, 0.0 ) )
1487  {
1488  QVector< QPointF > angleStartPoints;
1489  QVector< QPointF > symbolPoints;
1490  QVector< QPointF > angleEndPoints;
1491 
1492  // we collect 3 arrays of points. These correspond to
1493  // 1. the actual point at which to render the symbol
1494  // 2. the start point of a line averaging the angle over the desired distance (i.e. -averageOver distance from the points in array 1)
1495  // 3. the end point of a line averaging the angle over the desired distance (i.e. +averageOver distance from the points in array 2)
1496  // it gets quite tricky, because for closed rings we need to trace backwards from the initial point to calculate this
1497  // (or trace past the final point)
1498  collectOffsetPoints( points, symbolPoints, painterUnitInterval, lengthLeft );
1499 
1500  if ( symbolPoints.empty() )
1501  {
1502  // no symbols to draw, shortcut out early
1503  return;
1504  }
1505 
1506  if ( symbolPoints.count() > 1 && symbolPoints.constFirst() == symbolPoints.constLast() )
1507  {
1508  // avoid duplicate points at start and end of closed rings
1509  symbolPoints.pop_back();
1510  }
1511 
1512  angleEndPoints.reserve( symbolPoints.size() );
1513  angleStartPoints.reserve( symbolPoints.size() );
1514  if ( averageOver <= painterUnitOffsetAlongLine )
1515  {
1516  collectOffsetPoints( points, angleStartPoints, painterUnitInterval, lengthLeft + averageOver, 0, symbolPoints.size() );
1517  }
1518  else
1519  {
1520  collectOffsetPoints( points, angleStartPoints, painterUnitInterval, 0, averageOver - painterUnitOffsetAlongLine, symbolPoints.size() );
1521  }
1522  collectOffsetPoints( points, angleEndPoints, painterUnitInterval, lengthLeft - averageOver, 0, symbolPoints.size() );
1523 
1524  int pointNum = 0;
1525  for ( int i = 0; i < symbolPoints.size(); ++ i )
1526  {
1527  if ( context.renderContext().renderingStopped() )
1528  break;
1529 
1530  const QPointF pt = symbolPoints[i];
1531  const QPointF startPt = angleStartPoints[i];
1532  const QPointF endPt = angleEndPoints[i];
1533 
1534  MyLine l( startPt, endPt );
1535  // rotate marker (if desired)
1536  if ( rotateSymbols() )
1537  {
1538  setSymbolLineAngle( l.angle() * 180 / M_PI );
1539  }
1540 
1542  renderSymbol( pt, context.feature(), rc, -1, context.selected() );
1543  }
1544  }
1545  else
1546  {
1547  // not averaging line angle -- always use exact section angle
1548  int pointNum = 0;
1549  QPointF lastPt = points[0];
1550  for ( int i = 1; i < points.count(); ++i )
1551  {
1552  if ( context.renderContext().renderingStopped() )
1553  break;
1554 
1555  const QPointF &pt = points[i];
1556 
1557  if ( lastPt == pt ) // must not be equal!
1558  continue;
1559 
1560  // for each line, find out dx and dy, and length
1561  MyLine l( lastPt, pt );
1562  QPointF diff = l.diffForInterval( painterUnitInterval );
1563 
1564  // if there's some length left from previous line
1565  // use only the rest for the first point in new line segment
1566  double c = 1 - lengthLeft / painterUnitInterval;
1567 
1568  lengthLeft += l.length();
1569 
1570  // rotate marker (if desired)
1571  if ( rotateSymbols() )
1572  {
1573  setSymbolLineAngle( l.angle() * 180 / M_PI );
1574  }
1575 
1576  // while we're not at the end of line segment, draw!
1577  while ( lengthLeft > painterUnitInterval )
1578  {
1579  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
1580  lastPt += c * diff;
1581  lengthLeft -= painterUnitInterval;
1583  renderSymbol( lastPt, context.feature(), rc, -1, context.selected() );
1584  c = 1; // reset c (if wasn't 1 already)
1585  }
1586 
1587  lastPt = pt;
1588  }
1589 
1590  }
1591 }
1592 
1593 static double _averageAngle( QPointF prevPt, QPointF pt, QPointF nextPt )
1594 {
1595  // calc average angle between the previous and next point
1596  double a1 = MyLine( prevPt, pt ).angle();
1597  double a2 = MyLine( pt, nextPt ).angle();
1598  double unitX = std::cos( a1 ) + std::cos( a2 ), unitY = std::sin( a1 ) + std::sin( a2 );
1599 
1600  return std::atan2( unitY, unitX );
1601 }
1602 
1603 void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex( const QPolygonF &points, QgsSymbolRenderContext &context, QgsTemplatedLineSymbolLayerBase::Placement placement )
1604 {
1605  if ( points.isEmpty() )
1606  return;
1607 
1608  QgsRenderContext &rc = context.renderContext();
1609 
1610  double origAngle = symbolAngle();
1611  int i = -1, maxCount = 0;
1612  bool isRing = false;
1613 
1615  QgsExpressionContextScopePopper scopePopper( context.renderContext().expressionContext(), scope );
1617 
1618  double offsetAlongLine = mOffsetAlongLine;
1620  {
1621  context.setOriginalValueVariable( mOffsetAlongLine );
1623  }
1624  if ( !qgsDoubleNear( offsetAlongLine, 0.0 ) )
1625  {
1626  //scale offset along line
1628  }
1629 
1630  if ( qgsDoubleNear( offsetAlongLine, 0.0 ) && context.renderContext().geometry()
1632  {
1634  const QgsMapToPixel &mtp = context.renderContext().mapToPixel();
1635 
1636  QgsVertexId vId;
1637  QgsPoint vPoint;
1638  double x, y, z;
1639  QPointF mapPoint;
1640  int pointNum = 0;
1641  while ( context.renderContext().geometry()->nextVertex( vId, vPoint ) )
1642  {
1643  if ( context.renderContext().renderingStopped() )
1644  break;
1645 
1647 
1650  {
1651  //transform
1652  x = vPoint.x();
1653  y = vPoint.y();
1654  z = 0.0;
1655  if ( ct.isValid() )
1656  {
1657  ct.transformInPlace( x, y, z );
1658  }
1659  mapPoint.setX( x );
1660  mapPoint.setY( y );
1661  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1662  if ( rotateSymbols() )
1663  {
1664  double angle = context.renderContext().geometry()->vertexAngle( vId );
1665  setSymbolAngle( angle * 180 / M_PI );
1666  }
1667  renderSymbol( mapPoint, context.feature(), rc, -1, context.selected() );
1668  }
1669  }
1670 
1671  return;
1672  }
1673 
1674  switch ( placement )
1675  {
1676  case FirstVertex:
1677  {
1678  i = 0;
1679  maxCount = 1;
1680  break;
1681  }
1682 
1683  case LastVertex:
1684  {
1685  i = points.count() - 1;
1686  maxCount = points.count();
1687  break;
1688  }
1689 
1690  case Vertex:
1691  case SegmentCenter:
1692  {
1693  i = placement == Vertex ? 0 : 1;
1694  maxCount = points.count();
1695  if ( points.first() == points.last() )
1696  isRing = true;
1697  break;
1698  }
1699 
1700  case Interval:
1701  case CentralPoint:
1702  case CurvePoint:
1703  {
1704  return;
1705  }
1706  }
1707 
1709  {
1710  double distance;
1712  renderOffsetVertexAlongLine( points, i, distance, context );
1713  // restore original rotation
1714  setSymbolAngle( origAngle );
1715 
1716  return;
1717  }
1718 
1719  int pointNum = 0;
1720  QPointF prevPoint;
1721  if ( placement == SegmentCenter && !points.empty() )
1722  prevPoint = points.at( 0 );
1723 
1724  QPointF symbolPoint;
1725  for ( ; i < maxCount; ++i )
1726  {
1728 
1729  if ( isRing && placement == QgsTemplatedLineSymbolLayerBase::Vertex && i == points.count() - 1 )
1730  {
1731  continue; // don't draw the last marker - it has been drawn already
1732  }
1733 
1734  if ( placement == SegmentCenter )
1735  {
1736  QPointF currentPoint = points.at( i );
1737  symbolPoint = QPointF( 0.5 * ( currentPoint.x() + prevPoint.x() ),
1738  0.5 * ( currentPoint.y() + prevPoint.y() ) );
1739  if ( rotateSymbols() )
1740  {
1741  double angle = std::atan2( currentPoint.y() - prevPoint.y(),
1742  currentPoint.x() - prevPoint.x() );
1743  setSymbolAngle( origAngle + angle * 180 / M_PI );
1744  }
1745  prevPoint = currentPoint;
1746  }
1747  else
1748  {
1749  symbolPoint = points.at( i );
1750  // rotate marker (if desired)
1751  if ( rotateSymbols() )
1752  {
1753  double angle = markerAngle( points, isRing, i );
1754  setSymbolAngle( origAngle + angle * 180 / M_PI );
1755  }
1756  }
1757 
1758  renderSymbol( symbolPoint, context.feature(), rc, -1, context.selected() );
1759  }
1760 
1761  // restore original rotation
1762  setSymbolAngle( origAngle );
1763 }
1764 
1765 double QgsTemplatedLineSymbolLayerBase::markerAngle( const QPolygonF &points, bool isRing, int vertex )
1766 {
1767  double angle = 0;
1768  const QPointF &pt = points[vertex];
1769 
1770  if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
1771  {
1772  int prevIndex = vertex - 1;
1773  int nextIndex = vertex + 1;
1774 
1775  if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
1776  {
1777  prevIndex = points.count() - 2;
1778  nextIndex = 1;
1779  }
1780 
1781  QPointF prevPoint, nextPoint;
1782  while ( prevIndex >= 0 )
1783  {
1784  prevPoint = points[ prevIndex ];
1785  if ( prevPoint != pt )
1786  {
1787  break;
1788  }
1789  --prevIndex;
1790  }
1791 
1792  while ( nextIndex < points.count() )
1793  {
1794  nextPoint = points[ nextIndex ];
1795  if ( nextPoint != pt )
1796  {
1797  break;
1798  }
1799  ++nextIndex;
1800  }
1801 
1802  if ( prevIndex >= 0 && nextIndex < points.count() )
1803  {
1804  angle = _averageAngle( prevPoint, pt, nextPoint );
1805  }
1806  }
1807  else //no ring and vertex is at start / at end
1808  {
1809  if ( vertex == 0 )
1810  {
1811  while ( vertex < points.size() - 1 )
1812  {
1813  const QPointF &nextPt = points[vertex + 1];
1814  if ( pt != nextPt )
1815  {
1816  angle = MyLine( pt, nextPt ).angle();
1817  return angle;
1818  }
1819  ++vertex;
1820  }
1821  }
1822  else
1823  {
1824  // use last segment's angle
1825  while ( vertex >= 1 ) //in case of duplicated vertices, take the next suitable one
1826  {
1827  const QPointF &prevPt = points[vertex - 1];
1828  if ( pt != prevPt )
1829  {
1830  angle = MyLine( prevPt, pt ).angle();
1831  return angle;
1832  }
1833  --vertex;
1834  }
1835  }
1836  }
1837  return angle;
1838 }
1839 
1840 void QgsTemplatedLineSymbolLayerBase::renderOffsetVertexAlongLine( const QPolygonF &points, int vertex, double distance, QgsSymbolRenderContext &context )
1841 {
1842  if ( points.isEmpty() )
1843  return;
1844 
1845  QgsRenderContext &rc = context.renderContext();
1846  double origAngle = symbolAngle();
1847  if ( qgsDoubleNear( distance, 0.0 ) )
1848  {
1849  // rotate marker (if desired)
1850  if ( rotateSymbols() )
1851  {
1852  bool isRing = false;
1853  if ( points.first() == points.last() )
1854  isRing = true;
1855  double angle = markerAngle( points, isRing, vertex );
1856  setSymbolAngle( origAngle + angle * 180 / M_PI );
1857  }
1858  renderSymbol( points[vertex], context.feature(), rc, -1, context.selected() );
1859  return;
1860  }
1861 
1862  int pointIncrement = distance > 0 ? 1 : -1;
1863  QPointF previousPoint = points[vertex];
1864  int startPoint = distance > 0 ? std::min( vertex + 1, points.count() - 1 ) : std::max( vertex - 1, 0 );
1865  int endPoint = distance > 0 ? points.count() - 1 : 0;
1866  double distanceLeft = std::fabs( distance );
1867 
1868  for ( int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
1869  {
1870  const QPointF &pt = points[i];
1871 
1872  if ( previousPoint == pt ) // must not be equal!
1873  continue;
1874 
1875  // create line segment
1876  MyLine l( previousPoint, pt );
1877 
1878  if ( distanceLeft < l.length() )
1879  {
1880  //destination point is in current segment
1881  QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
1882  // rotate marker (if desired)
1883  if ( rotateSymbols() )
1884  {
1885  setSymbolAngle( origAngle + ( l.angle() * 180 / M_PI ) );
1886  }
1887  renderSymbol( markerPoint, context.feature(), rc, -1, context.selected() );
1888  return;
1889  }
1890 
1891  distanceLeft -= l.length();
1892  previousPoint = pt;
1893  }
1894 
1895  //didn't find point
1896 }
1897 
1898 void QgsTemplatedLineSymbolLayerBase::collectOffsetPoints( const QVector<QPointF> &p, QVector<QPointF> &dest, double intervalPainterUnits, double initialOffset, double initialLag, int numberPointsRequired )
1899 {
1900  if ( p.empty() )
1901  return;
1902 
1903  QVector< QPointF > points = p;
1904  const bool closedRing = points.first() == points.last();
1905 
1906  double lengthLeft = initialOffset;
1907 
1908  double initialLagLeft = initialLag > 0 ? -initialLag : 1; // an initialLagLeft of > 0 signifies end of lagging start points
1909  if ( initialLagLeft < 0 && closedRing )
1910  {
1911  // tracking back around the ring from the first point, insert pseudo vertices before the first vertex
1912  QPointF lastPt = points.constLast();
1913  QVector< QPointF > pseudoPoints;
1914  for ( int i = points.count() - 2; i > 0; --i )
1915  {
1916  if ( initialLagLeft >= 0 )
1917  {
1918  break;
1919  }
1920 
1921  const QPointF &pt = points[i];
1922 
1923  if ( lastPt == pt ) // must not be equal!
1924  continue;
1925 
1926  MyLine l( lastPt, pt );
1927  initialLagLeft += l.length();
1928  lastPt = pt;
1929 
1930  pseudoPoints << pt;
1931  }
1932  std::reverse( pseudoPoints.begin(), pseudoPoints.end() );
1933 
1934  points = pseudoPoints;
1935  points.append( p );
1936  }
1937  else
1938  {
1939  while ( initialLagLeft < 0 )
1940  {
1941  dest << points.constFirst();
1942  initialLagLeft += intervalPainterUnits;
1943  }
1944  }
1945  if ( initialLag > 0 )
1946  {
1947  lengthLeft += intervalPainterUnits - initialLagLeft;
1948  }
1949 
1950  QPointF lastPt = points[0];
1951  for ( int i = 1; i < points.count(); ++i )
1952  {
1953  const QPointF &pt = points[i];
1954 
1955  if ( lastPt == pt ) // must not be equal!
1956  {
1957  if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
1958  {
1959  lastPt = points[0];
1960  i = 0;
1961  }
1962  continue;
1963  }
1964 
1965  // for each line, find out dx and dy, and length
1966  MyLine l( lastPt, pt );
1967  QPointF diff = l.diffForInterval( intervalPainterUnits );
1968 
1969  // if there's some length left from previous line
1970  // use only the rest for the first point in new line segment
1971  double c = 1 - lengthLeft / intervalPainterUnits;
1972 
1973  lengthLeft += l.length();
1974 
1975 
1976  while ( lengthLeft > intervalPainterUnits || qgsDoubleNear( lengthLeft, intervalPainterUnits, 0.000000001 ) )
1977  {
1978  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
1979  lastPt += c * diff;
1980  lengthLeft -= intervalPainterUnits;
1981  dest << lastPt;
1982  c = 1; // reset c (if wasn't 1 already)
1983  if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
1984  break;
1985  }
1986  lastPt = pt;
1987 
1988  if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
1989  break;
1990 
1991  // if a closed ring, we keep looping around the ring until we hit the required number of points
1992  if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
1993  {
1994  lastPt = points[0];
1995  i = 0;
1996  }
1997  }
1998 
1999  if ( !closedRing && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2000  {
2001  // pad with repeating last point to match desired size
2002  while ( dest.size() < numberPointsRequired )
2003  dest << points.constLast();
2004  }
2005 }
2006 
2007 void QgsTemplatedLineSymbolLayerBase::renderPolylineCentral( const QPolygonF &points, QgsSymbolRenderContext &context, double averageAngleOver )
2008 {
2009  if ( !points.isEmpty() )
2010  {
2011  // calc length
2012  qreal length = 0;
2013  QPolygonF::const_iterator it = points.constBegin();
2014  QPointF last = *it;
2015  for ( ++it; it != points.constEnd(); ++it )
2016  {
2017  length += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2018  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2019  last = *it;
2020  }
2021  if ( qgsDoubleNear( length, 0.0 ) )
2022  return;
2023 
2024  const double midPoint = length / 2;
2025 
2026  QPointF pt;
2027  double thisSymbolAngle = 0;
2028 
2029  if ( averageAngleOver > 0 && !qgsDoubleNear( averageAngleOver, 0.0 ) )
2030  {
2031  QVector< QPointF > angleStartPoints;
2032  QVector< QPointF > symbolPoints;
2033  QVector< QPointF > angleEndPoints;
2034  // collectOffsetPoints will have the first point in the line as the first result -- we don't want this, we need the second
2035  collectOffsetPoints( points, symbolPoints, midPoint, midPoint, 0.0, 2 );
2036  collectOffsetPoints( points, angleStartPoints, midPoint, 0, averageAngleOver, 2 );
2037  collectOffsetPoints( points, angleEndPoints, midPoint, midPoint - averageAngleOver, 0, 2 );
2038 
2039  pt = symbolPoints.at( 1 );
2040  MyLine l( angleStartPoints.at( 1 ), angleEndPoints.at( 1 ) );
2041  thisSymbolAngle = l.angle();
2042  }
2043  else
2044  {
2045  // find the segment where the central point lies
2046  it = points.constBegin();
2047  last = *it;
2048  qreal last_at = 0, next_at = 0;
2049  QPointF next;
2050  int segment = 0;
2051  for ( ++it; it != points.constEnd(); ++it )
2052  {
2053  next = *it;
2054  next_at += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2055  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2056  if ( next_at >= midPoint )
2057  break; // we have reached the center
2058  last = *it;
2059  last_at = next_at;
2060  segment++;
2061  }
2062 
2063  // find out the central point on segment
2064  MyLine l( last, next ); // for line angle
2065  qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
2066  pt = last + ( next - last ) * k;
2067  thisSymbolAngle = l.angle();
2068  }
2069 
2070  // draw the marker
2071  // rotate marker (if desired)
2072  if ( rotateSymbols() )
2073  {
2074  setSymbolLineAngle( thisSymbolAngle * 180 / M_PI );
2075  }
2076 
2077  renderSymbol( pt, context.feature(), context.renderContext(), -1, context.selected() );
2078 
2079  }
2080 }
2081 
2083 {
2084  return mMarker.get();
2085 }
2086 
2088 {
2089  if ( !symbol || symbol->type() != QgsSymbol::Marker )
2090  {
2091  delete symbol;
2092  return false;
2093  }
2094 
2095  mMarker.reset( static_cast<QgsMarkerSymbol *>( symbol ) );
2096  mColor = mMarker->color();
2097  return true;
2098 }
2099 
2100 
2101 
2102 //
2103 // QgsMarkerLineSymbolLayer
2104 //
2105 
2106 QgsMarkerLineSymbolLayer::QgsMarkerLineSymbolLayer( bool rotateMarker, double interval )
2107  : QgsTemplatedLineSymbolLayerBase( rotateMarker, interval )
2108 {
2109  setSubSymbol( new QgsMarkerSymbol() );
2110 }
2111 
2113 {
2114  bool rotate = DEFAULT_MARKERLINE_ROTATE;
2116 
2117  if ( props.contains( QStringLiteral( "interval" ) ) )
2118  interval = props[QStringLiteral( "interval" )].toDouble();
2119  if ( props.contains( QStringLiteral( "rotate" ) ) )
2120  rotate = ( props[QStringLiteral( "rotate" )] == QLatin1String( "1" ) );
2121 
2122  std::unique_ptr< QgsMarkerLineSymbolLayer > x = qgis::make_unique< QgsMarkerLineSymbolLayer >( rotate, interval );
2123  setCommonProperties( x.get(), props );
2124  return x.release();
2125 }
2126 
2128 {
2129  return QStringLiteral( "MarkerLine" );
2130 }
2131 
2132 void QgsMarkerLineSymbolLayer::setColor( const QColor &color )
2133 {
2134  mMarker->setColor( color );
2135  mColor = color;
2136 }
2137 
2139 {
2140  return mMarker ? mMarker->color() : mColor;
2141 }
2142 
2144 {
2145  mMarker->setOpacity( context.opacity() );
2146 
2147  // if being rotated, it gets initialized with every line segment
2148  QgsSymbol::RenderHints hints = QgsSymbol::RenderHints();
2149  if ( rotateSymbols() )
2150  hints |= QgsSymbol::DynamicRotation;
2151  mMarker->setRenderHints( hints );
2152 
2153  mMarker->startRender( context.renderContext(), context.fields() );
2154 }
2155 
2157 {
2158  mMarker->stopRender( context.renderContext() );
2159 }
2160 
2161 
2163 {
2164  std::unique_ptr< QgsMarkerLineSymbolLayer > x = qgis::make_unique< QgsMarkerLineSymbolLayer >( rotateSymbols(), interval() );
2165  copyTemplateSymbolProperties( x.get() );
2166  return x.release();
2167 }
2168 
2169 void QgsMarkerLineSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
2170 {
2171  for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
2172  {
2173  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:LineSymbolizer" ) );
2174  if ( !props.value( QStringLiteral( "uom" ), QString() ).isEmpty() )
2175  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ) );
2176  element.appendChild( symbolizerElem );
2177 
2178  // <Geometry>
2179  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ) );
2180 
2181  QString gap;
2182  switch ( placement() )
2183  {
2185  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "firstPoint" ) ) );
2186  break;
2188  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "lastPoint" ) ) );
2189  break;
2191  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "centralPoint" ) ) );
2192  break;
2194  // no way to get line/polygon's vertices, use a VendorOption
2195  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "points" ) ) );
2196  break;
2197  default:
2199  gap = qgsDoubleToString( interval );
2200  break;
2201  }
2202 
2203  if ( !rotateSymbols() )
2204  {
2205  // markers in LineSymbolizer must be drawn following the line orientation,
2206  // use a VendorOption when no marker rotation
2207  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "rotateMarker" ), QStringLiteral( "0" ) ) );
2208  }
2209 
2210  // <Stroke>
2211  QDomElement strokeElem = doc.createElement( QStringLiteral( "se:Stroke" ) );
2212  symbolizerElem.appendChild( strokeElem );
2213 
2214  // <GraphicStroke>
2215  QDomElement graphicStrokeElem = doc.createElement( QStringLiteral( "se:GraphicStroke" ) );
2216  strokeElem.appendChild( graphicStrokeElem );
2217 
2218  QgsSymbolLayer *layer = mMarker->symbolLayer( i );
2219  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
2220  if ( !markerLayer )
2221  {
2222  graphicStrokeElem.appendChild( doc.createComment( QStringLiteral( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() ) ) );
2223  }
2224  else
2225  {
2226  markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
2227  }
2228 
2229  if ( !gap.isEmpty() )
2230  {
2231  QDomElement gapElem = doc.createElement( QStringLiteral( "se:Gap" ) );
2232  QgsSymbolLayerUtils::createExpressionElement( doc, gapElem, gap );
2233  graphicStrokeElem.appendChild( gapElem );
2234  }
2235 
2236  if ( !qgsDoubleNear( mOffset, 0.0 ) )
2237  {
2238  QDomElement perpOffsetElem = doc.createElement( QStringLiteral( "se:PerpendicularOffset" ) );
2240  perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
2241  symbolizerElem.appendChild( perpOffsetElem );
2242  }
2243  }
2244 }
2245 
2247 {
2248  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
2249 
2250  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
2251  if ( strokeElem.isNull() )
2252  return nullptr;
2253 
2254  QDomElement graphicStrokeElem = strokeElem.firstChildElement( QStringLiteral( "GraphicStroke" ) );
2255  if ( graphicStrokeElem.isNull() )
2256  return nullptr;
2257 
2258  // retrieve vendor options
2259  bool rotateMarker = true;
2261 
2262  QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( element );
2263  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
2264  {
2265  if ( it.key() == QLatin1String( "placement" ) )
2266  {
2267  if ( it.value() == QLatin1String( "points" ) )
2269  else if ( it.value() == QLatin1String( "firstPoint" ) )
2271  else if ( it.value() == QLatin1String( "lastPoint" ) )
2273  else if ( it.value() == QLatin1String( "centralPoint" ) )
2275  }
2276  else if ( it.value() == QLatin1String( "rotateMarker" ) )
2277  {
2278  rotateMarker = it.value() == QLatin1String( "0" );
2279  }
2280  }
2281 
2282  std::unique_ptr< QgsMarkerSymbol > marker;
2283 
2285  if ( l )
2286  {
2287  QgsSymbolLayerList layers;
2288  layers.append( l );
2289  marker.reset( new QgsMarkerSymbol( layers ) );
2290  }
2291 
2292  if ( !marker )
2293  return nullptr;
2294 
2295  double interval = 0.0;
2296  QDomElement gapElem = graphicStrokeElem.firstChildElement( QStringLiteral( "Gap" ) );
2297  if ( !gapElem.isNull() )
2298  {
2299  bool ok;
2300  double d = gapElem.firstChild().nodeValue().toDouble( &ok );
2301  if ( ok )
2302  interval = d;
2303  }
2304 
2305  double offset = 0.0;
2306  QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( QStringLiteral( "PerpendicularOffset" ) );
2307  if ( !perpOffsetElem.isNull() )
2308  {
2309  bool ok;
2310  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
2311  if ( ok )
2312  offset = d;
2313  }
2314 
2315  QString uom = element.attribute( QStringLiteral( "uom" ) );
2318 
2320  x->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
2321  x->setPlacement( placement );
2322  x->setInterval( interval );
2323  x->setSubSymbol( marker.release() );
2324  x->setOffset( offset );
2325  return x;
2326 }
2327 
2329 {
2330  mMarker->setSize( width );
2331 }
2332 
2334 {
2335  if ( key == QgsSymbolLayer::PropertyWidth && mMarker && property )
2336  {
2337  mMarker->setDataDefinedSize( property );
2338  }
2340 }
2341 
2343 {
2344  mMarker->setLineAngle( angle );
2345 }
2346 
2348 {
2349  return mMarker->angle();
2350 }
2351 
2353 {
2354  mMarker->setAngle( angle );
2355 }
2356 
2357 void QgsMarkerLineSymbolLayer::renderSymbol( const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer, bool selected )
2358 {
2359  mMarker->renderPoint( point, feature, context, layer, selected );
2360 }
2361 
2363 {
2364  return mMarker->size();
2365 }
2366 
2368 {
2369  return mMarker->size( context );
2370 }
2371 
2373 {
2375  mMarker->setOutputUnit( unit );
2376  setIntervalUnit( unit );
2377  mOffsetUnit = unit;
2378  setOffsetAlongLineUnit( unit );
2379 }
2380 
2381 
2382 QSet<QString> QgsMarkerLineSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
2383 {
2384  QSet<QString> attr = QgsLineSymbolLayer::usedAttributes( context );
2385  if ( mMarker )
2386  attr.unite( mMarker->usedAttributes( context ) );
2387  return attr;
2388 }
2389 
2391 {
2393  return true;
2394  if ( mMarker && mMarker->hasDataDefinedProperties() )
2395  return true;
2396  return false;
2397 }
2398 
2400 {
2401  return ( mMarker->size( context ) / 2.0 ) +
2403 }
2404 
2405 
2406 //
2407 // QgsHashedLineSymbolLayer
2408 //
2409 
2410 QgsHashedLineSymbolLayer::QgsHashedLineSymbolLayer( bool rotateSymbol, double interval )
2411  : QgsTemplatedLineSymbolLayerBase( rotateSymbol, interval )
2412 {
2413  setSubSymbol( new QgsLineSymbol() );
2414 }
2415 
2417 {
2418  bool rotate = DEFAULT_MARKERLINE_ROTATE;
2420 
2421  if ( props.contains( QStringLiteral( "interval" ) ) )
2422  interval = props[QStringLiteral( "interval" )].toDouble();
2423  if ( props.contains( QStringLiteral( "rotate" ) ) )
2424  rotate = ( props[QStringLiteral( "rotate" )] == QLatin1String( "1" ) );
2425 
2426  std::unique_ptr< QgsHashedLineSymbolLayer > x = qgis::make_unique< QgsHashedLineSymbolLayer >( rotate, interval );
2427  setCommonProperties( x.get(), props );
2428  if ( props.contains( QStringLiteral( "hash_angle" ) ) )
2429  {
2430  x->setHashAngle( props[QStringLiteral( "hash_angle" )].toDouble() );
2431  }
2432 
2433  if ( props.contains( QStringLiteral( "hash_length" ) ) )
2434  x->setHashLength( props[QStringLiteral( "hash_length" )].toDouble() );
2435 
2436  if ( props.contains( QStringLiteral( "hash_length_unit" ) ) )
2437  x->setHashLengthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "hash_length_unit" )] ) );
2438 
2439  if ( props.contains( QStringLiteral( "hash_length_map_unit_scale" ) ) )
2440  x->setHashLengthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "hash_length_map_unit_scale" )] ) );
2441 
2442  return x.release();
2443 }
2444 
2446 {
2447  return QStringLiteral( "HashLine" );
2448 }
2449 
2451 {
2452  mHashSymbol->setOpacity( context.opacity() );
2453 
2454  // if being rotated, it gets initialized with every line segment
2455  QgsSymbol::RenderHints hints = QgsSymbol::RenderHints();
2456  if ( rotateSymbols() )
2457  hints |= QgsSymbol::DynamicRotation;
2458  mHashSymbol->setRenderHints( hints );
2459 
2460  mHashSymbol->startRender( context.renderContext(), context.fields() );
2461 }
2462 
2464 {
2465  mHashSymbol->stopRender( context.renderContext() );
2466 }
2467 
2469 {
2471  map[ QStringLiteral( "hash_angle" ) ] = QString::number( mHashAngle );
2472 
2473  map[QStringLiteral( "hash_length" )] = QString::number( mHashLength );
2474  map[QStringLiteral( "hash_length_unit" )] = QgsUnitTypes::encodeUnit( mHashLengthUnit );
2475  map[QStringLiteral( "hash_length_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mHashLengthMapUnitScale );
2476 
2477  return map;
2478 }
2479 
2481 {
2482  std::unique_ptr< QgsHashedLineSymbolLayer > x = qgis::make_unique< QgsHashedLineSymbolLayer >( rotateSymbols(), interval() );
2483  copyTemplateSymbolProperties( x.get() );
2484  x->setHashAngle( mHashAngle );
2485  x->setHashLength( mHashLength );
2486  x->setHashLengthUnit( mHashLengthUnit );
2487  x->setHashLengthMapUnitScale( mHashLengthMapUnitScale );
2488  return x.release();
2489 }
2490 
2491 void QgsHashedLineSymbolLayer::setColor( const QColor &color )
2492 {
2493  mHashSymbol->setColor( color );
2494  mColor = color;
2495 }
2496 
2498 {
2499  return mHashSymbol ? mHashSymbol->color() : mColor;
2500 }
2501 
2503 {
2504  return mHashSymbol.get();
2505 }
2506 
2508 {
2509  if ( !symbol || symbol->type() != QgsSymbol::Line )
2510  {
2511  delete symbol;
2512  return false;
2513  }
2514 
2515  mHashSymbol.reset( static_cast<QgsLineSymbol *>( symbol ) );
2516  mColor = mHashSymbol->color();
2517  return true;
2518 }
2519 
2520 void QgsHashedLineSymbolLayer::setWidth( const double width )
2521 {
2522  mHashLength = width;
2523 }
2524 
2526 {
2527  return mHashLength;
2528 }
2529 
2531 {
2532  return context.convertToPainterUnits( mHashLength, mHashLengthUnit, mHashLengthMapUnitScale );
2533 }
2534 
2536 {
2537  return ( mHashSymbol->width( context ) / 2.0 )
2538  + context.convertToPainterUnits( mHashLength, mHashLengthUnit, mHashLengthMapUnitScale )
2539  + context.convertToPainterUnits( std::fabs( mOffset ), mOffsetUnit, mOffsetMapUnitScale );
2540 }
2541 
2543 {
2545  mHashSymbol->setOutputUnit( unit );
2546  setIntervalUnit( unit );
2547  mOffsetUnit = unit;
2548  setOffsetAlongLineUnit( unit );
2549 }
2550 
2551 QSet<QString> QgsHashedLineSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
2552 {
2553  QSet<QString> attr = QgsLineSymbolLayer::usedAttributes( context );
2554  if ( mHashSymbol )
2555  attr.unite( mHashSymbol->usedAttributes( context ) );
2556  return attr;
2557 }
2558 
2560 {
2562  return true;
2563  if ( mHashSymbol && mHashSymbol->hasDataDefinedProperties() )
2564  return true;
2565  return false;
2566 }
2567 
2569 {
2570  if ( key == QgsSymbolLayer::PropertyWidth && mHashSymbol && property )
2571  {
2572  mHashSymbol->setDataDefinedWidth( property );
2573  }
2575 }
2576 
2578 {
2579  mSymbolLineAngle = angle;
2580 }
2581 
2583 {
2584  return mSymbolAngle;
2585 }
2586 
2588 {
2589  mSymbolAngle = angle;
2590 }
2591 
2592 void QgsHashedLineSymbolLayer::renderSymbol( const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer, bool selected )
2593 {
2594  double lineLength = mHashLength;
2596  {
2597  context.expressionContext().setOriginalValueVariable( mHashLength );
2599  }
2600  const double w = context.convertToPainterUnits( lineLength, mHashLengthUnit, mHashLengthMapUnitScale ) / 2.0;
2601 
2602  double hashAngle = mHashAngle;
2604  {
2605  context.expressionContext().setOriginalValueVariable( mHashAngle );
2607  }
2608 
2609  QgsPointXY center( point );
2610  QgsPointXY start = center.project( w, 180 - ( mSymbolAngle + mSymbolLineAngle + hashAngle ) );
2611  QgsPointXY end = center.project( -w, 180 - ( mSymbolAngle + mSymbolLineAngle + hashAngle ) );
2612 
2613  QPolygonF points;
2614  points << QPointF( start.x(), start.y() ) << QPointF( end.x(), end.y() );
2615 
2616  mHashSymbol->renderPolyline( points, feature, context, layer, selected );
2617 }
2618 
2620 {
2621  return mHashAngle;
2622 }
2623 
2625 {
2626  mHashAngle = angle;
2627 }
2628 
2629 
QgsMarkerLineSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgslinesymbollayer.cpp:2127
QgsSymbolLayer::PropertyDashPatternOffset
@ PropertyDashPatternOffset
Dash pattern offset.
Definition: qgssymbollayer.h:191
QgsSimpleLineSymbolLayer::dxfCustomDashPattern
QVector< qreal > dxfCustomDashPattern(QgsUnitTypes::RenderUnit &unit) const override
Gets dash pattern.
Definition: qgslinesymbollayer.cpp:951
QgsSymbolRenderContext::setOriginalValueVariable
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
Definition: qgssymbol.cpp:1411
QgsSymbolLayer::enabled
bool enabled() const
Returns true if symbol layer is enabled and will be drawn.
Definition: qgssymbollayer.h:213
QgsMarkerLineSymbolLayer::width
double width() const override
Returns the estimated width for the line symbol layer.
Definition: qgslinesymbollayer.cpp:2362
QgsMarkerLineSymbolLayer::clone
QgsMarkerLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgslinesymbollayer.cpp:2162
QgsHashedLineSymbolLayer::setSymbolLineAngle
void setSymbolLineAngle(double angle) override
Sets the line angle modification for the symbol's angle.
Definition: qgslinesymbollayer.cpp:2577
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:994
QgsMarkerLineSymbolLayer::createFromSld
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsMarkerLineSymbolLayer from an SLD XML DOM element.
Definition: qgslinesymbollayer.cpp:2246
QgsSymbolLayer::setSubSymbol
virtual bool setSubSymbol(QgsSymbol *symbol)
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgssymbollayer.h:356
QgsTemplatedLineSymbolLayerBase::copyTemplateSymbolProperties
void copyTemplateSymbolProperties(QgsTemplatedLineSymbolLayerBase *destLayer) const
Copies all common properties of this layer to another templated symbol layer.
Definition: qgslinesymbollayer.cpp:1341
QgsLineSymbolLayer::setWidthUnit
void setWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the line's width.
Definition: qgssymbollayer.h:1041
QgsExpressionContextScopePopper
RAII class to pop scope from an expression context on destruction.
Definition: qgsexpressioncontextutils.h:355
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:52
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsTemplatedLineSymbolLayerBase::mapUnitScale
QgsMapUnitScale mapUnitScale() const FINAL
Definition: qgslinesymbollayer.cpp:1284
QgsTemplatedLineSymbolLayerBase::setOffsetAlongLine
void setOffsetAlongLine(double offsetAlongLine)
Sets the the offset along the line for the symbol placement.
Definition: qgslinesymbollayer.h:501
QgsLineSymbolLayer::RenderRingFilter
RenderRingFilter
Options for filtering rings when the line symbol layer is being used to render a polygon's rings.
Definition: qgssymbollayer.h:906
QgsSymbolLayer::PropertyLineDistance
@ PropertyLineDistance
Distance between lines, or length of lines for hash line symbols.
Definition: qgssymbollayer.h:148
QgsRenderContext::convertToPainterUnits
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
Definition: qgsrendercontext.cpp:318
QgsSymbolLayer::mColor
QColor mColor
Definition: qgssymbollayer.h:527
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:325
QgsSymbolLayer::dataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
Definition: qgssymbollayer.h:486
QgsProperty
A store for object properties.
Definition: qgsproperty.h:232
QgsUnitTypes::RenderUnit
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:167
QgsDxfExport
Definition: qgsdxfexport.h:63
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:596
QgsVectorSimplifyMethod::AntialiasingSimplification
@ AntialiasingSimplification
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'.
Definition: qgsvectorsimplifymethod.h:41
QgsSimpleLineSymbolLayer::penCapStyle
Qt::PenCapStyle penCapStyle() const
Returns the pen cap style used to render the line (e.g.
Definition: qgslinesymbollayer.h:120
QgsMapToPixel::mapUnitsPerPixel
double mapUnitsPerPixel() const
Returns current map units per pixel.
Definition: qgsmaptopixel.cpp:128
QgsHashedLineSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgslinesymbollayer.cpp:2463
QgsVertexId::SegmentVertex
@ SegmentVertex
The actual start or end point of a segment.
Definition: qgsabstractgeometry.h:1066
QgsSymbolLayer::PropertyAverageAngleLength
@ PropertyAverageAngleLength
Length to average symbol angles over.
Definition: qgssymbollayer.h:173
QgsHashedLineSymbolLayer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
Definition: qgslinesymbollayer.cpp:2551
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:437
QgsMarkerLineSymbolLayer::setColor
void setColor(const QColor &color) override
The fill color.
Definition: qgslinesymbollayer.cpp:2132
QgsLineSymbolLayer::width
virtual double width() const
Returns the estimated width for the line symbol layer.
Definition: qgssymbollayer.h:965
QgsExpressionContextScope::addVariable
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Definition: qgsexpressioncontext.cpp:93
QgsSymbolLayerUtils::encodeMapUnitScale
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
Definition: qgssymbollayerutils.cpp:558
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:38
QgsTemplatedLineSymbolLayerBase::offsetAlongLineUnit
QgsUnitTypes::RenderUnit offsetAlongLineUnit() const
Returns the unit used for calculating the offset along line for symbols.
Definition: qgslinesymbollayer.h:509
QgsTemplatedLineSymbolLayerBase::properties
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgslinesymbollayer.cpp:1295
QgsSymbolLayerUtils::sizeInPixelsFromSldUom
static double sizeInPixelsFromSldUom(const QString &uom, double size)
Returns the size scaled in pixels according to the uom attribute.
Definition: qgssymbollayerutils.cpp:4563
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsSymbolRenderContext::feature
const QgsFeature * feature() const
Returns the current feature being rendered.
Definition: qgssymbol.h:802
qgsexpression.h
QgsHashedLineSymbolLayer
Line symbol layer type which draws repeating line sections along a line feature.
Definition: qgslinesymbollayer.h:783
QgsSimpleLineSymbolLayer::create
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsSimpleLineSymbolLayer, using the settings serialized in the properties map (correspo...
Definition: qgslinesymbollayer.cpp:82
QgsSimpleLineSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgslinesymbollayer.cpp:251
QgsCurvePolygon::exteriorRing
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
Definition: qgscurvepolygon.h:87
DEFAULT_MARKERLINE_ROTATE
#define DEFAULT_MARKERLINE_ROTATE
Definition: qgslinesymbollayer.h:368
QgsExpressionContext::EXPR_GEOMETRY_POINT_COUNT
static const QString EXPR_GEOMETRY_POINT_COUNT
Inbuilt variable name for point count variable.
Definition: qgsexpressioncontext.h:731
QgsSimpleLineSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgslinesymbollayer.cpp:63
QgsPointXY::x
Q_GADGET double x
Definition: qgspointxy.h:47
QgsSimpleLineSymbolLayer::setCustomDashPatternMapUnitScale
void setCustomDashPatternMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for lengths used in the custom dash pattern.
Definition: qgslinesymbollayer.h:167
QgsMarkerLineSymbolLayer::create
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsMarkerLineSymbolLayer, using the settings serialized in the properties map (correspo...
Definition: qgslinesymbollayer.cpp:2112
QgsSimpleLineSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgslinesymbollayer.cpp:200
QgsSimpleLineSymbolLayer::setPenJoinStyle
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
Definition: qgslinesymbollayer.h:113
offsetLine
QList< QPolygonF > offsetLine(QPolygonF polyline, double dist, QgsWkbTypes::GeometryType geometryType)
calculate geometry shifted by a specified distance
Definition: qgssymbollayerutils.cpp:968
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:35
QgsHashedLineSymbolLayer::properties
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgslinesymbollayer.cpp:2468
QgsSimpleLineSymbolLayer::penJoinStyle
Qt::PenJoinStyle penJoinStyle() const
Returns the pen join style used to render the line (e.g.
Definition: qgslinesymbollayer.h:106
QgsSymbolLayer::color
virtual QColor color() const
The fill color.
Definition: qgssymbollayer.h:227
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:2001
QgsMarkerLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:2372
QgsLineSymbolLayer::mWidthMapUnitScale
QgsMapUnitScale mWidthMapUnitScale
Definition: qgssymbollayer.h:1081
QgsExpressionContext::EXPR_GEOMETRY_POINT_NUM
static const QString EXPR_GEOMETRY_POINT_NUM
Inbuilt variable name for point number variable.
Definition: qgsexpressioncontext.h:733
QgsExpressionContext::setOriginalValueVariable
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
Definition: qgsexpressioncontext.cpp:566
qgssymbollayerutils.h
DEFAULT_MARKERLINE_INTERVAL
#define DEFAULT_MARKERLINE_INTERVAL
Definition: qgslinesymbollayer.h:369
QgsLineSymbolLayer::mRingFilter
RenderRingFilter mRingFilter
Definition: qgssymbollayer.h:1086
QgsMarkerLineSymbolLayer::toSld
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Definition: qgslinesymbollayer.cpp:2169
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:999
QgsSymbolRenderContext::opacity
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:764
QgsSymbolLayerUtils::encodePenCapStyle
static QString encodePenCapStyle(Qt::PenCapStyle style)
Definition: qgssymbollayerutils.cpp:223
QgsHashedLineSymbolLayer::QgsHashedLineSymbolLayer
QgsHashedLineSymbolLayer(bool rotateSymbol=true, double interval=3)
Constructor for QgsHashedLineSymbolLayer.
Definition: qgslinesymbollayer.cpp:2410
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:1430
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:216
QgsHashedLineSymbolLayer::setWidth
void setWidth(double width) override
Sets the width of the line symbol layer.
Definition: qgslinesymbollayer.cpp:2520
QgsSimpleLineSymbolLayer::dxfPenStyle
Qt::PenStyle dxfPenStyle() const override
Gets pen style.
Definition: qgslinesymbollayer.cpp:957
QgsLineSymbolLayer::offsetUnit
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units for the line's offset.
Definition: qgssymbollayer.h:1015
QgsTemplatedLineSymbolLayerBase::Vertex
@ Vertex
Place symbols on every vertex in the line.
Definition: qgslinesymbollayer.h:390
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:58
QgsSymbolLayer::SELECTION_IS_OPAQUE
static const bool SELECTION_IS_OPAQUE
Whether styles for selected features ignore symbol alpha.
Definition: qgssymbollayer.h:537
qgsunittypes.h
QgsHashedLineSymbolLayer::hashAngle
double hashAngle() const
Returns the angle to use when drawing the hashed lines sections, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2619
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:168
QgsMarkerSymbolLayer
Abstract base class for marker symbol layers.
Definition: qgssymbollayer.h:582
QgsSymbolLayer::PropertyInterval
@ PropertyInterval
Line marker interval.
Definition: qgssymbollayer.h:171
QgsTemplatedLineSymbolLayerBase::placement
Placement placement() const
Returns the placement of the symbols.
Definition: qgslinesymbollayer.h:470
QgsSymbolLayer::PropertyCapStyle
@ PropertyCapStyle
Line cap style.
Definition: qgssymbollayer.h:169
QgsSimpleLineSymbolLayer::setDashPatternOffsetUnit
void setDashPatternOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the dash pattern offset.
Definition: qgslinesymbollayer.h:234
QgsLineSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgssymbollayer.cpp:645
QgsSymbolLayerUtils::encodePenStyle
static QString encodePenStyle(Qt::PenStyle style)
Definition: qgssymbollayerutils.cpp:141
QgsSymbol
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:64
QgsSimpleLineSymbolLayer::setUseCustomDashPattern
void setUseCustomDashPattern(bool b)
Sets whether the line uses a custom dash pattern.
Definition: qgslinesymbollayer.h:143
QgsMarkerLineSymbolLayer
Line symbol layer type which draws repeating marker symbols along a line feature.
Definition: qgslinesymbollayer.h:694
QgsMarkerLineSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgslinesymbollayer.cpp:2087
QgsRenderContext::scaleFactor
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:333
QgsSimpleLineSymbolLayer::createFromSld
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsSimpleLineSymbolLayer from an SLD XML DOM element.
Definition: qgslinesymbollayer.cpp:499
QgsTemplatedLineSymbolLayerBase::CurvePoint
@ CurvePoint
Place symbols at every virtual curve point in the line (used when rendering curved geometry types onl...
Definition: qgslinesymbollayer.h:394
QgsSymbolLayer::PropertyStrokeColor
@ PropertyStrokeColor
Stroke color.
Definition: qgssymbollayer.h:136
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:892
QgsSymbolLayerUtils::encodeRealVector
static QString encodeRealVector(const QVector< qreal > &v)
Definition: qgssymbollayerutils.cpp:655
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:57
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:1819
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:181
QgsLineSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgssymbollayer.cpp:655
QgsSimpleLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:45
QgsLineSymbolLayer::setOffset
void setOffset(double offset)
Sets the line's offset.
Definition: qgssymbollayer.h:999
QgsTemplatedLineSymbolLayerBase::setPlacement
void setPlacement(Placement placement)
Sets the placement of the symbols.
Definition: qgslinesymbollayer.h:476
QgsSimpleLineSymbolLayer::properties
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgslinesymbollayer.cpp:397
QgsLineSymbolLayer::setOffsetMapUnitScale
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the line's offset.
Definition: qgssymbollayer.h:1023
QgsSymbolLayerUtils::createGeometryElement
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
Definition: qgssymbollayerutils.cpp:2697
qgsDoubleToString
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:275
qgsgeometrysimplifier.h
QgsTemplatedLineSymbolLayerBase::Placement
Placement
Defines how/where the templated symbol should be placed on the line.
Definition: qgslinesymbollayer.h:388
QgsMarkerLineSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgslinesymbollayer.cpp:2143
QgsHashedLineSymbolLayer::setSymbolAngle
void setSymbolAngle(double angle) override
Sets the symbol's angle, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2587
QgsMarkerLineSymbolLayer::QgsMarkerLineSymbolLayer
QgsMarkerLineSymbolLayer(bool rotateMarker=DEFAULT_MARKERLINE_ROTATE, double interval=DEFAULT_MARKERLINE_INTERVAL)
Constructor for QgsMarkerLineSymbolLayer.
Definition: qgslinesymbollayer.cpp:2106
DEFAULT_SIMPLELINE_COLOR
#define DEFAULT_SIMPLELINE_COLOR
Definition: qgslinesymbollayer.h:28
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:195
QgsSymbolRenderContext::selected
bool selected() const
Returns true if symbols should be rendered using the selected symbol coloring and style.
Definition: qgssymbol.h:777
QgsTemplatedLineSymbolLayerBase::setIntervalMapUnitScale
void setIntervalMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the interval between symbols.
Definition: qgslinesymbollayer.h:456
QgsSimpleLineSymbolLayer::penStyle
Qt::PenStyle penStyle() const
Returns the pen style used to render the line (e.g.
Definition: qgslinesymbollayer.h:92
QgsTemplatedLineSymbolLayerBase::setInterval
void setInterval(double interval)
Sets the interval between individual symbols.
Definition: qgslinesymbollayer.h:433
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:2559
QgsUnitTypes::decodeRenderUnit
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
Definition: qgsunittypes.cpp:2900
QgsSymbolRenderContext
Definition: qgssymbol.h:695
QgsSymbolRenderContext::originalGeometryType
QgsWkbTypes::GeometryType originalGeometryType() const
Returns the geometry type for the original feature geometry being rendered.
Definition: qgssymbol.h:819
QgsHashedLineSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgslinesymbollayer.cpp:2507
QgsSimpleLineSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgslinesymbollayer.cpp:71
QgsLineSymbolLayer::mOffsetUnit
QgsUnitTypes::RenderUnit mOffsetUnit
Definition: qgssymbollayer.h:1083
QgsRenderContext::renderingStopped
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Definition: qgsrendercontext.h:341
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.
QgsMarkerLineSymbolLayer::setSymbolLineAngle
void setSymbolLineAngle(double angle) override
Sets the line angle modification for the symbol's angle.
Definition: qgslinesymbollayer.cpp:2342
QgsRenderContext::coordinateTransform
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Definition: qgsrendercontext.h:245
QgsPoint::y
double y
Definition: qgspoint.h:42
QgsSimpleLineSymbolLayer::clone
QgsSimpleLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgslinesymbollayer.cpp:424
QgsSymbolLayer::PropertyOffset
@ PropertyOffset
Symbol offset.
Definition: qgssymbollayer.h:139
QgsMarkerLineSymbolLayer::setDataDefinedProperty
void setDataDefinedProperty(QgsSymbolLayer::Property key, const QgsProperty &property) override
Sets a data defined property for the layer.
Definition: qgslinesymbollayer.cpp:2333
QgsSymbolLayer
Definition: qgssymbollayer.h:53
QgsMarkerLineSymbolLayer::symbolAngle
double symbolAngle() const override
Returns the symbol's current angle, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2347
QgsDxfExport::mapUnits
QgsUnitTypes::DistanceUnit mapUnits() const
Retrieve map units.
Definition: qgsdxfexport.cpp:245
QgsTemplatedLineSymbolLayerBase::SegmentCenter
@ SegmentCenter
Place symbols at the center of every line segment.
Definition: qgslinesymbollayer.h:395
QgsUnitTypes::encodeUnit
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
Definition: qgsunittypes.cpp:122
QgsTemplatedLineSymbolLayerBase::setOffsetAlongLineUnit
void setOffsetAlongLineUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit used for calculating the offset along line for symbols.
Definition: qgslinesymbollayer.h:517
QgsMarkerLineSymbolLayer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
Definition: qgslinesymbollayer.cpp:2382
QgsSymbolRenderContext::fields
QgsFields fields() const
Fields of the layer.
Definition: qgssymbol.h:827
QgsSimpleLineSymbolLayer::dxfColor
QColor dxfColor(QgsSymbolRenderContext &context) const override
Gets color.
Definition: qgslinesymbollayer.cpp:979
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:4219
QgsMarkerSymbol
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:931
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:315
QgsLineSymbolLayer::mOffset
double mOffset
Definition: qgssymbollayer.h:1082
QgsHashedLineSymbolLayer::setHashAngle
void setHashAngle(double angle)
Sets the angle to use when drawing the hashed lines sections, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2624
QgsLineSymbolLayer::setOffsetUnit
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the line's offset.
Definition: qgssymbollayer.h:1007
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:583
QgsSimpleLineSymbolLayer
A simple line symbol layer, which renders lines using a line in a variety of styles (e....
Definition: qgslinesymbollayer.h:40
QgsTemplatedLineSymbolLayerBase::intervalMapUnitScale
const QgsMapUnitScale & intervalMapUnitScale() const
Returns the map unit scale for the interval between symbols.
Definition: qgslinesymbollayer.h:464
QgsSymbolLayerUtils::rescaleUom
static double rescaleUom(double size, QgsUnitTypes::RenderUnit unit, const QgsStringMap &props)
Rescales the given size based on the uomScale found in the props, if any is found,...
Definition: qgssymbollayerutils.cpp:4428
QgsTemplatedLineSymbolLayerBase::setCommonProperties
static void setCommonProperties(QgsTemplatedLineSymbolLayerBase *destLayer, const QgsStringMap &properties)
Sets all common symbol properties in the destLayer, using the settings serialized in the properties m...
Definition: qgslinesymbollayer.cpp:1361
QgsLineSymbolLayer::mWidthUnit
QgsUnitTypes::RenderUnit mWidthUnit
Definition: qgssymbollayer.h:1080
QgsSymbolLayer::copyPaintEffect
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
Definition: qgssymbollayer.cpp:410
QgsSymbolLayer::PropertyStrokeStyle
@ PropertyStrokeStyle
Stroke style (eg solid, dashed)
Definition: qgssymbollayer.h:138
QgsSimpleLineSymbolLayer::ogrFeatureStyle
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
Definition: qgslinesymbollayer.cpp:484
qgsrendercontext.h
QgsTemplatedLineSymbolLayerBase::interval
double interval() const
Returns the interval between individual symbols.
Definition: qgslinesymbollayer.h:425
QgsSimpleLineSymbolLayer::setPenCapStyle
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
Definition: qgslinesymbollayer.h:127
QgsTemplatedLineSymbolLayerBase::offsetAlongLine
double offsetAlongLine() const
Returns the offset along the line for the symbol placement.
Definition: qgslinesymbollayer.h:488
QgsLineSymbol
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1131
QgsTemplatedLineSymbolLayerBase::setSymbolAngle
virtual void setSymbolAngle(double angle)=0
Sets the symbol's angle, in degrees clockwise.
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:289
QgsPoint::x
Q_GADGET double x
Definition: qgspoint.h:41
QgsMarkerLineSymbolLayer::color
QColor color() const override
The fill color.
Definition: qgslinesymbollayer.cpp:2138
QgsTemplatedLineSymbolLayerBase::renderPolyline
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) FINAL
Renders the line symbol layer along the line joining points, using the given render context.
Definition: qgslinesymbollayer.cpp:1107
DEFAULT_SIMPLELINE_WIDTH
#define DEFAULT_SIMPLELINE_WIDTH
Definition: qgslinesymbollayer.h:29
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:523
QgsLineSymbolLayer::mWidth
double mWidth
Definition: qgssymbollayer.h:1079
QgsTemplatedLineSymbolLayerBase::Interval
@ Interval
Place symbols at regular intervals.
Definition: qgslinesymbollayer.h:389
QgsHashedLineSymbolLayer::symbolAngle
double symbolAngle() const override
Returns the symbol's current angle, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2582
QgsVectorSimplifyMethod::threshold
float threshold() const
Gets the simplification threshold of the vector layer managed.
Definition: qgsvectorsimplifymethod.h:76
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:326
QgsSymbolLayerUtils::createVendorOptionElement
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
Definition: qgssymbollayerutils.cpp:2889
DEFAULT_SIMPLELINE_PENSTYLE
#define DEFAULT_SIMPLELINE_PENSTYLE
Definition: qgslinesymbollayer.h:30
QgsMarkerLineSymbolLayer::setSymbolAngle
void setSymbolAngle(double angle) override
Sets the symbol's angle, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2352
QgsMapUnitScale
Struct for storing maximum and minimum scales for measurements in map units.
Definition: qgsmapunitscale.h:38
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:2592
QgsAbstractGeometry::hasCurvedSegments
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
Definition: qgsabstractgeometry.cpp:305
QgsTemplatedLineSymbolLayerBase::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const FINAL
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:1266
QgsHashedLineSymbolLayer::clone
QgsHashedLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgslinesymbollayer.cpp:2480
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1120
QgsCurvePolygon::interiorRing
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
Definition: qgscurvepolygon.h:100
QgsSimpleLineSymbolLayer::dxfWidth
double dxfWidth(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets line width.
Definition: qgslinesymbollayer.cpp:962
QgsTemplatedLineSymbolLayerBase
Base class for templated line symbols, e.g.
Definition: qgslinesymbollayer.h:381
QgsMarkerLineSymbolLayer::subSymbol
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
Definition: qgslinesymbollayer.cpp:2082
QgsMarkerLineSymbolLayer::setWidth
void setWidth(double width) override
Sets the width of the line symbol layer.
Definition: qgslinesymbollayer.cpp:2328
QgsSymbolLayer::mDataDefinedProperties
QgsPropertyCollection mDataDefinedProperties
Definition: qgssymbollayer.h:530
QgsSymbolLayer::PropertyStrokeWidth
@ PropertyStrokeWidth
Stroke width.
Definition: qgssymbollayer.h:137
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:2535
qgscurvepolygon.h
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:223
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:256
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:2613
QgsSymbolLayer::subSymbol
virtual QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
Definition: qgssymbollayer.h:353
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:529
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext.
Definition: qgsexpressioncontext.h:112
QgsVertexId::type
VertexType type
Vertex type.
Definition: qgsabstractgeometry.h:1140
QgsLineSymbolLayer::InteriorRingsOnly
@ InteriorRingsOnly
Render the interior rings only.
Definition: qgssymbollayer.h:909
QgsRenderContext::vectorSimplifyMethod
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Returns the simplification settings to use when rendering vector layers.
Definition: qgsrendercontext.h:565
QgsTemplatedLineSymbolLayerBase::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) FINAL
Definition: qgslinesymbollayer.cpp:1276
QgsSymbolLayerUtils::appendPolyline
static void appendPolyline(QPolygonF &target, const QPolygonF &line)
Appends a polyline line to an existing target polyline.
Definition: qgssymbollayerutils.cpp:4228
QgsSymbolLayer::usedAttributes
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the set of attributes referenced by the layer.
Definition: qgssymbollayer.cpp:247
QgsHashedLineSymbolLayer::setColor
void setColor(const QColor &color) override
The fill color.
Definition: qgslinesymbollayer.cpp:2491
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:553
QgsSymbolLayer::PropertyOffsetAlongLine
@ PropertyOffsetAlongLine
Offset along line.
Definition: qgssymbollayer.h:172
qgsvectorlayer.h
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsSymbolLayerUtils::decodePenCapStyle
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:238
QgsHashedLineSymbolLayer::width
double width() const override
Returns the estimated width for the line symbol layer.
Definition: qgslinesymbollayer.cpp:2525
QgsHashedLineSymbolLayer::setDataDefinedProperty
void setDataDefinedProperty(QgsSymbolLayer::Property key, const QgsProperty &property) override
Sets a data defined property for the layer.
Definition: qgslinesymbollayer.cpp:2568
QgsRenderContext::selectionColor
QColor selectionColor() const
Returns the color to use when rendering selected features.
Definition: qgsrendercontext.h:390
QgsHashedLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:2542
QgsMapToPixel::transformInPlace
void transformInPlace(double &x, double &y) const
Transform device coordinates to map coordinates.
Definition: qgsmaptopixel.cpp:233
QgsSimpleLineSymbolLayer::toSld
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Definition: qgslinesymbollayer.cpp:451
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:143
QgsStringMap
QMap< QString, QString > QgsStringMap
Definition: qgis.h:758
QgsSimpleLineSymbolLayer::setDashPatternOffsetMapUnitScale
void setDashPatternOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the dash pattern offset.
Definition: qgslinesymbollayer.h:267
qgslinesymbollayer.h
QgsRenderContext::geometry
const QgsAbstractGeometry * geometry() const
Returns pointer to the unsegmentized geometry.
Definition: qgsrendercontext.h:608
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
QgsSymbol::DynamicRotation
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
Definition: qgssymbol.h:106
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:2390
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:2399
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:1222
QgsSymbolLayerUtils::getVendorOptionList
static QgsStringMap getVendorOptionList(QDomElement &element)
Definition: qgssymbollayerutils.cpp:2897
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:989
QgsSymbolLayerList
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:53
QgsLineSymbolLayer::mOffsetMapUnitScale
QgsMapUnitScale mOffsetMapUnitScale
Definition: qgssymbollayer.h:1084
QgsTemplatedLineSymbolLayerBase::LastVertex
@ LastVertex
Place symbols on the last vertex in the line.
Definition: qgslinesymbollayer.h:391
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:4136
QgsVertexId
Utility class for identifying a unique vertex within a geometry.
Definition: qgsabstractgeometry.h:1059
QgsSymbolLayer::PropertyCustomDash
@ PropertyCustomDash
Custom dash pattern.
Definition: qgssymbollayer.h:168
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:412
QgsHashedLineSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgslinesymbollayer.cpp:2445
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:1004
QgsUnitTypes::RenderMetersInMapUnits
@ RenderMetersInMapUnits
Meters value as Map units.
Definition: qgsunittypes.h:175
qgsproperty.h
QgsSimpleLineSymbolLayer::dxfOffset
double dxfOffset(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets offset.
Definition: qgslinesymbollayer.cpp:1009
QgsSymbol::Line
@ Line
Line symbol.
Definition: qgssymbol.h:88
QgsUnitTypes::RenderUnknownUnit
@ RenderUnknownUnit
Mixed or unknown units.
Definition: qgsunittypes.h:174
QgsLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgssymbollayer.cpp:640
QgsLineSymbolLayer::AllRings
@ AllRings
Render both exterior and interior rings.
Definition: qgssymbollayer.h:907
QgsWkbTypes::UnknownGeometry
@ UnknownGeometry
Definition: qgswkbtypes.h:145
QgsHashedLineSymbolLayer::create
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
Creates a new QgsHashedLineSymbolLayer, using the settings serialized in the properties map (correspo...
Definition: qgslinesymbollayer.cpp:2416
QgsSymbol::type
SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:122
QgsSymbol::Marker
@ Marker
Marker symbol.
Definition: qgssymbol.h:87
QgsMarkerSymbolLayer::writeSldMarker
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const
Writes the symbol layer definition as a SLD XML element.
Definition: qgssymbollayer.h:805
QgsSymbolLayer::restoreOldDataDefinedProperties
void restoreOldDataDefinedProperties(const QgsStringMap &stringMap)
Restores older data defined properties from string map.
Definition: qgssymbollayer.cpp:281
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:2357
QgsSymbolLayerUtils::decodePenJoinStyle
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:188
QgsSymbolLayer::Property
Property
Data definable properties.
Definition: qgssymbollayer.h:131
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:205
QgsVectorSimplifyMethod::simplifyHints
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
Definition: qgsvectorsimplifymethod.h:51
QgsSymbolLayer::layerType
virtual QString layerType() const =0
Returns a string that represents this layer type.
QgsRenderContext::RenderSymbolPreview
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
Definition: qgsrendercontext.h:83
QgsSymbolLayerUtils::encodePenJoinStyle
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
Definition: qgssymbollayerutils.cpp:173
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsMarkerLineSymbolLayer::mMarker
std::unique_ptr< QgsMarkerSymbol > mMarker
Definition: qgslinesymbollayer.h:757
QgsSymbolRenderContext::renderContext
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgssymbol.h:721
QgsDxfExport::symbologyScale
double symbologyScale() const
Returns the reference scale for output.
Definition: qgsdxfexport.h:227
QgsSymbolLayerUtils::decodeRealVector
static QVector< qreal > decodeRealVector(const QString &s)
Definition: qgssymbollayerutils.cpp:670
QgsLineSymbolLayer::setWidthMapUnitScale
void setWidthMapUnitScale(const QgsMapUnitScale &scale)
Definition: qgssymbollayer.h:1049
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:937
QgsLineSymbolLayer::offset
double offset() const
Returns the line's offset.
Definition: qgssymbollayer.h:988
QgsDxfExport::clipValueToMapUnitScale
void clipValueToMapUnitScale(double &value, const QgsMapUnitScale &scale, double pixelToMMFactor) const
Clips value to scale minimum/maximum.
Definition: qgsdxfexport.cpp:1836
QgsTemplatedLineSymbolLayerBase::FirstVertex
@ FirstVertex
Place symbols on the first vertex in the line.
Definition: qgslinesymbollayer.h:392
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:2085
QgsTemplatedLineSymbolLayerBase::intervalUnit
QgsUnitTypes::RenderUnit intervalUnit() const
Returns the units for the interval between symbols.
Definition: qgslinesymbollayer.h:448
qgslogger.h
QgsLineSymbolLayer::widthUnit
QgsUnitTypes::RenderUnit widthUnit() const
Returns the units for the line's width.
Definition: qgssymbollayer.h:1047
QgsLineSymbolLayer::ExteriorRingOnly
@ ExteriorRingOnly
Render the exterior ring only.
Definition: qgssymbollayer.h:908
QgsSimpleLineSymbolLayer::setCustomDashPatternUnit
void setCustomDashPatternUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for lengths used in the custom dash pattern.
Definition: qgslinesymbollayer.h:149
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:179
QgsRenderContext::setGeometry
void setGeometry(const QgsAbstractGeometry *geometry)
Sets pointer to original (unsegmentized) geometry.
Definition: qgsrendercontext.h:610
QgsHashedLineSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgslinesymbollayer.cpp:2450
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:119
QgsTemplatedLineSymbolLayerBase::QgsTemplatedLineSymbolLayerBase
QgsTemplatedLineSymbolLayerBase(bool rotateSymbol=true, double interval=3)
Constructor for QgsTemplatedLineSymbolLayerBase.
Definition: qgslinesymbollayer.cpp:1100
QgsSymbolLayerUtils::decodePenStyle
static Qt::PenStyle decodePenStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:162
QgsVertexId::CurveVertex
@ CurveVertex
An intermediate point on a segment defining the curvature of the segment.
Definition: qgsabstractgeometry.h:1067
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:53
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:37
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:2502
QgsSymbolLayer::copyDataDefinedProperties
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
Definition: qgssymbollayer.cpp:402
QgsTemplatedLineSymbolLayerBase::symbolAngle
virtual double symbolAngle() const =0
Returns the symbol's current angle, in degrees clockwise.
QgsSymbolLayer::PropertyPlacement
@ PropertyPlacement
Line marker placement.
Definition: qgssymbollayer.h:170
QgsSimpleLineSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:53
QgsAbstractGeometry::nextVertex
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
QgsSymbolLayer::PropertyLineAngle
@ PropertyLineAngle
Line angle, or angle of hash lines for hash line symbols.
Definition: qgssymbollayer.h:147
QgsUnitTypes::RenderMapUnits
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:169
QgsTemplatedLineSymbolLayerBase::CentralPoint
@ CentralPoint
Place symbols at the mid point of the line.
Definition: qgslinesymbollayer.h:393
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:563
QgsMarkerLineSymbolLayer::rotateMarker
Q_DECL_DEPRECATED bool rotateMarker() const
Shall the marker be rotated.
Definition: qgslinesymbollayer.h:747
QgsSymbolLayerUtils::decodeMapUnitScale
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Definition: qgssymbollayerutils.cpp:568
QgsLineSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgssymbollayer.cpp:650
QgsSymbolLayer::setDataDefinedProperty
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
Definition: qgssymbollayer.cpp:113
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:22
QgsHashedLineSymbolLayer::color
QColor color() const override
The fill color.
Definition: qgslinesymbollayer.cpp:2497
QgsMarkerLineSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgslinesymbollayer.cpp:2156
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
QgsSymbolLayer::PropertyJoinStyle
@ PropertyJoinStyle
Line join style.
Definition: qgssymbollayer.h:145
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:2740
QgsRenderContext::flags
Flags flags() const
Returns combination of flags used for rendering.
Definition: qgsrendercontext.cpp:187
QgsTemplatedLineSymbolLayerBase::setIntervalUnit
void setIntervalUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the interval between symbols.
Definition: qgslinesymbollayer.h:441
QgsSymbolLayer::PropertyWidth
@ PropertyWidth
Symbol width.
Definition: qgssymbollayer.h:141
QgsCoordinateTransform::transformInPlace
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) 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:313