QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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 <QPainter>
31 #include <QDomDocument>
32 #include <QDomElement>
33 
34 #include <cmath>
35 
36 QgsSimpleLineSymbolLayer::QgsSimpleLineSymbolLayer( const QColor &color, double width, Qt::PenStyle penStyle )
37  : mPenStyle( penStyle )
38 {
39  mColor = color;
40  mWidth = width;
41  mCustomDashVector << 5 << 2;
42 }
43 
45 {
47  mWidthUnit = unit;
48  mOffsetUnit = unit;
49  mCustomDashPatternUnit = unit;
50 }
51 
53 {
55  if ( mWidthUnit != unit || mOffsetUnit != unit || mCustomDashPatternUnit != unit )
56  {
58  }
59  return unit;
60 }
61 
63 {
65  mWidthMapUnitScale = scale;
66  mOffsetMapUnitScale = scale;
67  mCustomDashPatternMapUnitScale = scale;
68 }
69 
71 {
74  mOffsetMapUnitScale == mCustomDashPatternMapUnitScale )
75  {
76  return mWidthMapUnitScale;
77  }
78  return QgsMapUnitScale();
79 }
80 
82 {
86 
87  if ( props.contains( QStringLiteral( "line_color" ) ) )
88  {
89  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "line_color" )] );
90  }
91  else if ( props.contains( QStringLiteral( "outline_color" ) ) )
92  {
93  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "outline_color" )] );
94  }
95  else if ( props.contains( QStringLiteral( "color" ) ) )
96  {
97  //pre 2.5 projects used "color"
98  color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color" )] );
99  }
100  if ( props.contains( QStringLiteral( "line_width" ) ) )
101  {
102  width = props[QStringLiteral( "line_width" )].toDouble();
103  }
104  else if ( props.contains( QStringLiteral( "outline_width" ) ) )
105  {
106  width = props[QStringLiteral( "outline_width" )].toDouble();
107  }
108  else if ( props.contains( QStringLiteral( "width" ) ) )
109  {
110  //pre 2.5 projects used "width"
111  width = props[QStringLiteral( "width" )].toDouble();
112  }
113  if ( props.contains( QStringLiteral( "line_style" ) ) )
114  {
115  penStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "line_style" )] );
116  }
117  else if ( props.contains( QStringLiteral( "outline_style" ) ) )
118  {
119  penStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "outline_style" )] );
120  }
121  else if ( props.contains( QStringLiteral( "penstyle" ) ) )
122  {
123  penStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "penstyle" )] );
124  }
125 
127  if ( props.contains( QStringLiteral( "line_width_unit" ) ) )
128  {
129  l->setWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "line_width_unit" )] ) );
130  }
131  else if ( props.contains( QStringLiteral( "outline_width_unit" ) ) )
132  {
133  l->setWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "outline_width_unit" )] ) );
134  }
135  else if ( props.contains( QStringLiteral( "width_unit" ) ) )
136  {
137  //pre 2.5 projects used "width_unit"
138  l->setWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "width_unit" )] ) );
139  }
140  if ( props.contains( QStringLiteral( "width_map_unit_scale" ) ) )
141  l->setWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "width_map_unit_scale" )] ) );
142  if ( props.contains( QStringLiteral( "offset" ) ) )
143  l->setOffset( props[QStringLiteral( "offset" )].toDouble() );
144  if ( props.contains( QStringLiteral( "offset_unit" ) ) )
145  l->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )] ) );
146  if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
147  l->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )] ) );
148  if ( props.contains( QStringLiteral( "joinstyle" ) ) )
149  l->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( props[QStringLiteral( "joinstyle" )] ) );
150  if ( props.contains( QStringLiteral( "capstyle" ) ) )
151  l->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( props[QStringLiteral( "capstyle" )] ) );
152 
153  if ( props.contains( QStringLiteral( "use_custom_dash" ) ) )
154  {
155  l->setUseCustomDashPattern( props[QStringLiteral( "use_custom_dash" )].toInt() );
156  }
157  if ( props.contains( QStringLiteral( "customdash" ) ) )
158  {
159  l->setCustomDashVector( QgsSymbolLayerUtils::decodeRealVector( props[QStringLiteral( "customdash" )] ) );
160  }
161  if ( props.contains( QStringLiteral( "customdash_unit" ) ) )
162  {
163  l->setCustomDashPatternUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "customdash_unit" )] ) );
164  }
165  if ( props.contains( QStringLiteral( "customdash_map_unit_scale" ) ) )
166  {
167  l->setCustomDashPatternMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "customdash_map_unit_scale" )] ) );
168  }
169 
170  if ( props.contains( QStringLiteral( "draw_inside_polygon" ) ) )
171  {
172  l->setDrawInsidePolygon( props[QStringLiteral( "draw_inside_polygon" )].toInt() );
173  }
174 
175  if ( props.contains( QStringLiteral( "ring_filter" ) ) )
176  {
177  l->setRingFilter( static_cast< RenderRingFilter>( props[QStringLiteral( "ring_filter" )].toInt() ) );
178  }
179 
181 
182  return l;
183 }
184 
185 
187 {
188  return QStringLiteral( "SimpleLine" );
189 }
190 
192 {
193  QColor penColor = mColor;
194  penColor.setAlphaF( mColor.alphaF() * context.opacity() );
195  mPen.setColor( penColor );
196  double scaledWidth = context.renderContext().convertToPainterUnits( mWidth, mWidthUnit, mWidthMapUnitScale );
197  mPen.setWidthF( scaledWidth );
198  if ( mUseCustomDashPattern )
199  {
200  mPen.setStyle( Qt::CustomDashLine );
201 
202  //scale pattern vector
203  double dashWidthDiv = qgsDoubleNear( scaledWidth, 0 ) ? 1.0 : scaledWidth;
204 
205  //fix dash pattern width in Qt 4.8
206  QStringList versionSplit = QString( qVersion() ).split( '.' );
207  if ( versionSplit.size() > 1
208  && versionSplit.at( 1 ).toInt() >= 8
209  && scaledWidth < 1.0 )
210  {
211  dashWidthDiv = 1.0;
212  }
213  QVector<qreal> scaledVector;
214  QVector<qreal>::const_iterator it = mCustomDashVector.constBegin();
215  for ( ; it != mCustomDashVector.constEnd(); ++it )
216  {
217  //the dash is specified in terms of pen widths, therefore the division
218  scaledVector << context.renderContext().convertToPainterUnits( ( *it ), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv;
219  }
220  mPen.setDashPattern( scaledVector );
221  }
222  else
223  {
224  mPen.setStyle( mPenStyle );
225  }
226  mPen.setJoinStyle( mPenJoinStyle );
227  mPen.setCapStyle( mPenCapStyle );
228 
229  mSelPen = mPen;
230  QColor selColor = context.renderContext().selectionColor();
231  if ( ! SELECTION_IS_OPAQUE )
232  selColor.setAlphaF( context.opacity() );
233  mSelPen.setColor( selColor );
234 }
235 
237 {
238  Q_UNUSED( context )
239 }
240 
241 void QgsSimpleLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
242 {
243  QPainter *p = context.renderContext().painter();
244  if ( !p )
245  {
246  return;
247  }
248 
249  if ( mDrawInsidePolygon )
250  p->save();
251 
252  switch ( mRingFilter )
253  {
254  case AllRings:
255  case ExteriorRingOnly:
256  {
257  if ( mDrawInsidePolygon )
258  {
259  //only drawing the line on the interior of the polygon, so set clip path for painter
260  QPainterPath clipPath;
261  clipPath.addPolygon( points );
262 
263  if ( rings )
264  {
265  //add polygon rings
266  for ( auto it = rings->constBegin(); it != rings->constEnd(); ++it )
267  {
268  QPolygonF ring = *it;
269  clipPath.addPolygon( ring );
270  }
271  }
272 
273  //use intersect mode, as a clip path may already exist (e.g., for composer maps)
274  p->setClipPath( clipPath, Qt::IntersectClip );
275  }
276 
277  renderPolyline( points, context );
278  }
279  break;
280 
281  case InteriorRingsOnly:
282  break;
283  }
284 
285  if ( rings )
286  {
287  switch ( mRingFilter )
288  {
289  case AllRings:
290  case InteriorRingsOnly:
291  {
292  mOffset = -mOffset; // invert the offset for rings!
293  for ( const QPolygonF &ring : qgis::as_const( *rings ) )
294  renderPolyline( ring, context );
295  mOffset = -mOffset;
296  }
297  break;
298  case ExteriorRingOnly:
299  break;
300  }
301  }
302 
303  if ( mDrawInsidePolygon )
304  {
305  //restore painter to reset clip path
306  p->restore();
307  }
308 
309 }
310 
311 void QgsSimpleLineSymbolLayer::renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context )
312 {
313  QPainter *p = context.renderContext().painter();
314  if ( !p )
315  {
316  return;
317  }
318 
319  double offset = mOffset;
320  applyDataDefinedSymbology( context, mPen, mSelPen, offset );
321 
322  p->setPen( context.selected() ? mSelPen : mPen );
323  p->setBrush( Qt::NoBrush );
324 
325  // Disable 'Antialiasing' if the geometry was generalized in the current RenderContext (We known that it must have least #2 points).
326  if ( points.size() <= 2 &&
329  ( p->renderHints() & QPainter::Antialiasing ) )
330  {
331  p->setRenderHint( QPainter::Antialiasing, false );
332 #if 0
333  p->drawPolyline( points );
334 #else
335  QPainterPath path;
336  path.addPolygon( points );
337  p->drawPath( path );
338 #endif
339  p->setRenderHint( QPainter::Antialiasing, true );
340  return;
341  }
342 
343  if ( qgsDoubleNear( offset, 0 ) )
344  {
345 #if 0
346  p->drawPolyline( points );
347 #else
348  QPainterPath path;
349  path.addPolygon( points );
350  p->drawPath( path );
351 #endif
352  }
353  else
354  {
355  double scaledOffset = context.renderContext().convertToPainterUnits( offset, mOffsetUnit, mOffsetMapUnitScale );
357  {
358  // rendering for symbol previews -- a size in meters in map units can't be calculated, so treat the size as millimeters
359  // and clamp it to a reasonable range. It's the best we can do in this situation!
360  scaledOffset = std::min( std::max( context.renderContext().convertToPainterUnits( offset, QgsUnitTypes::RenderMillimeters ), 3.0 ), 100.0 );
361  }
362 
363  QList<QPolygonF> mline = ::offsetLine( points, scaledOffset, context.originalGeometryType() != QgsWkbTypes::UnknownGeometry ? context.originalGeometryType() : QgsWkbTypes::LineGeometry );
364  for ( int part = 0; part < mline.count(); ++part )
365  {
366 #if 0
367  p->drawPolyline( mline );
368 #else
369  QPainterPath path;
370  path.addPolygon( mline[ part ] );
371  p->drawPath( path );
372 #endif
373  }
374  }
375 }
376 
378 {
379  QgsStringMap map;
380  map[QStringLiteral( "line_color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
381  map[QStringLiteral( "line_width" )] = QString::number( mWidth );
382  map[QStringLiteral( "line_width_unit" )] = QgsUnitTypes::encodeUnit( mWidthUnit );
383  map[QStringLiteral( "width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mWidthMapUnitScale );
384  map[QStringLiteral( "line_style" )] = QgsSymbolLayerUtils::encodePenStyle( mPenStyle );
385  map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
386  map[QStringLiteral( "capstyle" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
387  map[QStringLiteral( "offset" )] = QString::number( mOffset );
388  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
389  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
390  map[QStringLiteral( "use_custom_dash" )] = ( mUseCustomDashPattern ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
391  map[QStringLiteral( "customdash" )] = QgsSymbolLayerUtils::encodeRealVector( mCustomDashVector );
392  map[QStringLiteral( "customdash_unit" )] = QgsUnitTypes::encodeUnit( mCustomDashPatternUnit );
393  map[QStringLiteral( "customdash_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mCustomDashPatternMapUnitScale );
394  map[QStringLiteral( "draw_inside_polygon" )] = ( mDrawInsidePolygon ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
395  map[QStringLiteral( "ring_filter" )] = QString::number( static_cast< int >( mRingFilter ) );
396  return map;
397 }
398 
400 {
402  l->setWidthUnit( mWidthUnit );
406  l->setCustomDashPatternUnit( mCustomDashPatternUnit );
407  l->setCustomDashPatternMapUnitScale( mCustomDashPatternMapUnitScale );
408  l->setOffset( mOffset );
409  l->setPenJoinStyle( mPenJoinStyle );
410  l->setPenCapStyle( mPenCapStyle );
411  l->setUseCustomDashPattern( mUseCustomDashPattern );
412  l->setCustomDashVector( mCustomDashVector );
413  l->setDrawInsidePolygon( mDrawInsidePolygon );
416  copyPaintEffect( l );
417  return l;
418 }
419 
420 void QgsSimpleLineSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
421 {
422  if ( mPenStyle == Qt::NoPen )
423  return;
424 
425  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:LineSymbolizer" ) );
426  if ( !props.value( QStringLiteral( "uom" ), QString() ).isEmpty() )
427  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ) );
428  element.appendChild( symbolizerElem );
429 
430  // <Geometry>
431  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ) );
432 
433  // <Stroke>
434  QDomElement strokeElem = doc.createElement( QStringLiteral( "se:Stroke" ) );
435  symbolizerElem.appendChild( strokeElem );
436 
437  Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
439  QVector<qreal> customDashVector = QgsSymbolLayerUtils::rescaleUom( mCustomDashVector, mCustomDashPatternUnit, props );
441  &mPenJoinStyle, &mPenCapStyle, &customDashVector );
442 
443  // <se:PerpendicularOffset>
444  if ( !qgsDoubleNear( mOffset, 0.0 ) )
445  {
446  QDomElement perpOffsetElem = doc.createElement( QStringLiteral( "se:PerpendicularOffset" ) );
448  perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
449  symbolizerElem.appendChild( perpOffsetElem );
450  }
451 }
452 
453 QString QgsSimpleLineSymbolLayer::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
454 {
455  if ( mUseCustomDashPattern )
456  {
457  return QgsSymbolLayerUtils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor,
458  mPen.color(), mPenJoinStyle,
459  mPenCapStyle, mOffset, &mCustomDashVector );
460  }
461  else
462  {
463  return QgsSymbolLayerUtils::ogrFeatureStylePen( mWidth, mmScaleFactor, mapUnitScaleFactor, mPen.color(), mPenJoinStyle,
464  mPenCapStyle, mOffset );
465  }
466 }
467 
469 {
470  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
471 
472  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
473  if ( strokeElem.isNull() )
474  return nullptr;
475 
476  Qt::PenStyle penStyle;
477  QColor color;
478  double width;
479  Qt::PenJoinStyle penJoinStyle;
480  Qt::PenCapStyle penCapStyle;
481  QVector<qreal> customDashVector;
482 
483  if ( !QgsSymbolLayerUtils::lineFromSld( strokeElem, penStyle,
484  color, width,
486  &customDashVector ) )
487  return nullptr;
488 
489  double offset = 0.0;
490  QDomElement perpOffsetElem = element.firstChildElement( QStringLiteral( "PerpendicularOffset" ) );
491  if ( !perpOffsetElem.isNull() )
492  {
493  bool ok;
494  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
495  if ( ok )
496  offset = d;
497  }
498 
499  QString uom = element.attribute( QStringLiteral( "uom" ) );
502 
504  l->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
505  l->setOffset( offset );
508  l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
510  return l;
511 }
512 
513 void QgsSimpleLineSymbolLayer::applyDataDefinedSymbology( QgsSymbolRenderContext &context, QPen &pen, QPen &selPen, double &offset )
514 {
515  if ( !dataDefinedProperties().hasActiveProperties() )
516  return; // shortcut
517 
518  //data defined properties
519  bool hasStrokeWidthExpression = false;
521  {
522  context.setOriginalValueVariable( mWidth );
523  double scaledWidth = context.renderContext().convertToPainterUnits(
526  pen.setWidthF( scaledWidth );
527  selPen.setWidthF( scaledWidth );
528  hasStrokeWidthExpression = true;
529  }
530 
531  //color
533  {
536  }
537 
538  //offset
540  {
543  }
544 
545  //dash dot vector
547  {
548  double scaledWidth = context.renderContext().convertToPainterUnits( mWidth, mWidthUnit, mWidthMapUnitScale );
549  double dashWidthDiv = mPen.widthF();
550 
551  if ( hasStrokeWidthExpression )
552  {
553  dashWidthDiv = pen.widthF();
554  scaledWidth = pen.widthF();
555  }
556 
557  //fix dash pattern width in Qt 4.8
558  QStringList versionSplit = QString( qVersion() ).split( '.' );
559  if ( versionSplit.size() > 1
560  && versionSplit.at( 1 ).toInt() >= 8
561  && scaledWidth < 1.0 )
562  {
563  dashWidthDiv = 1.0;
564  }
565 
566  QVector<qreal> dashVector;
568  if ( exprVal.isValid() )
569  {
570  QStringList dashList = exprVal.toString().split( ';' );
571  QStringList::const_iterator dashIt = dashList.constBegin();
572  for ( ; dashIt != dashList.constEnd(); ++dashIt )
573  {
574  dashVector.push_back( context.renderContext().convertToPainterUnits( dashIt->toDouble(), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv );
575  }
576  pen.setDashPattern( dashVector );
577  }
578  }
579 
580  //line style
582  {
585  if ( exprVal.isValid() )
586  pen.setStyle( QgsSymbolLayerUtils::decodePenStyle( exprVal.toString() ) );
587  }
588 
589  //join style
591  {
594  if ( exprVal.isValid() )
595  pen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( exprVal.toString() ) );
596  }
597 
598  //cap style
600  {
603  if ( exprVal.isValid() )
604  pen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( exprVal.toString() ) );
605  }
606 }
607 
609 {
610  if ( mDrawInsidePolygon )
611  {
612  //set to clip line to the interior of polygon, so we expect no bleed
613  return 0;
614  }
615  else
616  {
617  return context.convertToPainterUnits( ( mWidth / 2.0 ), mWidthUnit, mWidthMapUnitScale ) +
619  }
620 }
621 
623 {
624  unit = mCustomDashPatternUnit;
625  return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>();
626 }
627 
629 {
630  return mPenStyle;
631 }
632 
634 {
635  double width = mWidth;
637  {
638  context.setOriginalValueVariable( mWidth );
640  }
641 
644  {
646  }
647  return width;
648 }
649 
651 {
653  {
656  }
657  return mColor;
658 }
659 
661 {
662  Q_UNUSED( e )
663  double offset = mOffset;
664 
666  {
669  }
670 
673  {
675  }
676  return -offset; //direction seems to be inverse to symbology offset
677 }
678 
680 
682 
683 class MyLine
684 {
685  public:
686  MyLine( QPointF p1, QPointF p2 )
687  : mVertical( false )
688  , mIncreasing( false )
689  , mT( 0.0 )
690  , mLength( 0.0 )
691  {
692  if ( p1 == p2 )
693  return; // invalid
694 
695  // tangent and direction
696  if ( qgsDoubleNear( p1.x(), p2.x() ) )
697  {
698  // vertical line - tangent undefined
699  mVertical = true;
700  mIncreasing = ( p2.y() > p1.y() );
701  }
702  else
703  {
704  mVertical = false;
705  mT = ( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
706  mIncreasing = ( p2.x() > p1.x() );
707  }
708 
709  // length
710  double x = ( p2.x() - p1.x() );
711  double y = ( p2.y() - p1.y() );
712  mLength = std::sqrt( x * x + y * y );
713  }
714 
715  // return angle in radians
716  double angle()
717  {
718  double a = ( mVertical ? M_PI_2 : std::atan( mT ) );
719 
720  if ( !mIncreasing )
721  a += M_PI;
722  return a;
723  }
724 
725  // return difference for x,y when going along the line with specified interval
726  QPointF diffForInterval( double interval )
727  {
728  if ( mVertical )
729  return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
730 
731  double alpha = std::atan( mT );
732  double dx = std::cos( alpha ) * interval;
733  double dy = std::sin( alpha ) * interval;
734  return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
735  }
736 
737  double length() { return mLength; }
738 
739  protected:
740  bool mVertical;
741  bool mIncreasing;
742  double mT;
743  double mLength;
744 };
745 
747 
748 //
749 // QgsTemplatedLineSymbolLayerBase
750 //
752  : mRotateSymbols( rotateSymbol )
753  , mInterval( interval )
754 {
755 
756 }
757 
759 {
760  double offset = mOffset;
761 
763  {
766  }
767 
769 
771  {
773  if ( exprVal.isValid() )
774  {
775  QString placementString = exprVal.toString();
776  if ( placementString.compare( QLatin1String( "interval" ), Qt::CaseInsensitive ) == 0 )
777  {
779  }
780  else if ( placementString.compare( QLatin1String( "vertex" ), Qt::CaseInsensitive ) == 0 )
781  {
783  }
784  else if ( placementString.compare( QLatin1String( "lastvertex" ), Qt::CaseInsensitive ) == 0 )
785  {
787  }
788  else if ( placementString.compare( QLatin1String( "firstvertex" ), Qt::CaseInsensitive ) == 0 )
789  {
791  }
792  else if ( placementString.compare( QLatin1String( "centerpoint" ), Qt::CaseInsensitive ) == 0 )
793  {
795  }
796  else if ( placementString.compare( QLatin1String( "curvepoint" ), Qt::CaseInsensitive ) == 0 )
797  {
799  }
800  else if ( placementString.compare( QLatin1String( "segmentcenter" ), Qt::CaseInsensitive ) == 0 )
801  {
803  }
804  else
805  {
807  }
808  }
809  }
810 
811 
812  context.renderContext().painter()->save();
813 
814  double averageOver = mAverageAngleLength;
816  {
817  context.setOriginalValueVariable( mAverageAngleLength );
819  }
820  averageOver = context.renderContext().convertToPainterUnits( averageOver, mAverageAngleLengthUnit, mAverageAngleLengthMapUnitScale ) / 2.0;
821 
822  if ( qgsDoubleNear( offset, 0.0 ) )
823  {
824  switch ( placement )
825  {
826  case Interval:
827  renderPolylineInterval( points, context, averageOver );
828  break;
829 
830  case CentralPoint:
831  renderPolylineCentral( points, context, averageOver );
832  break;
833 
834  case Vertex:
835  case LastVertex:
836  case FirstVertex:
837  case CurvePoint:
838  case SegmentCenter:
839  renderPolylineVertex( points, context, placement );
840  break;
841  }
842  }
843  else
844  {
845  context.renderContext().setGeometry( nullptr ); //always use segmented geometry with offset
847 
848  for ( int part = 0; part < mline.count(); ++part )
849  {
850  const QPolygonF &points2 = mline[ part ];
851 
852  switch ( placement )
853  {
854  case Interval:
855  renderPolylineInterval( points2, context, averageOver );
856  break;
857 
858  case CentralPoint:
859  renderPolylineCentral( points2, context, averageOver );
860  break;
861 
862  case Vertex:
863  case LastVertex:
864  case FirstVertex:
865  case CurvePoint:
866  case SegmentCenter:
867  renderPolylineVertex( points2, context, placement );
868  break;
869  }
870  }
871  }
872 
873  context.renderContext().painter()->restore();
874 }
875 
876 void QgsTemplatedLineSymbolLayerBase::renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
877 {
878  const QgsCurvePolygon *curvePolygon = dynamic_cast<const QgsCurvePolygon *>( context.renderContext().geometry() );
879 
880  if ( curvePolygon )
881  {
882  context.renderContext().setGeometry( curvePolygon->exteriorRing() );
883  }
884 
885  switch ( mRingFilter )
886  {
887  case AllRings:
888  case ExteriorRingOnly:
889  renderPolyline( points, context );
890  break;
891  case InteriorRingsOnly:
892  break;
893  }
894 
895  if ( rings )
896  {
897  switch ( mRingFilter )
898  {
899  case AllRings:
900  case InteriorRingsOnly:
901  {
902  mOffset = -mOffset; // invert the offset for rings!
903  for ( int i = 0; i < rings->size(); ++i )
904  {
905  if ( curvePolygon )
906  {
907  context.renderContext().setGeometry( curvePolygon->interiorRing( i ) );
908  }
909  renderPolyline( rings->at( i ), context );
910  }
911  mOffset = -mOffset;
912  }
913  break;
914  case ExteriorRingOnly:
915  break;
916  }
917  }
918 }
919 
921 {
923  if ( intervalUnit() != unit || mOffsetUnit != unit || offsetAlongLineUnit() != unit )
924  {
926  }
927  return unit;
928 }
929 
931 {
933  setIntervalMapUnitScale( scale );
934  mOffsetMapUnitScale = scale;
936 }
937 
939 {
943  {
944  return mOffsetMapUnitScale;
945  }
946  return QgsMapUnitScale();
947 }
948 
950 {
951  QgsStringMap map;
952  map[QStringLiteral( "rotate" )] = ( rotateSymbols() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
953  map[QStringLiteral( "interval" )] = QString::number( interval() );
954  map[QStringLiteral( "offset" )] = QString::number( mOffset );
955  map[QStringLiteral( "offset_along_line" )] = QString::number( offsetAlongLine() );
956  map[QStringLiteral( "offset_along_line_unit" )] = QgsUnitTypes::encodeUnit( offsetAlongLineUnit() );
957  map[QStringLiteral( "offset_along_line_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( offsetAlongLineMapUnitScale() );
958  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
959  map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
960  map[QStringLiteral( "interval_unit" )] = QgsUnitTypes::encodeUnit( intervalUnit() );
961  map[QStringLiteral( "interval_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( intervalMapUnitScale() );
962  map[QStringLiteral( "average_angle_length" )] = QString::number( mAverageAngleLength );
963  map[QStringLiteral( "average_angle_unit" )] = QgsUnitTypes::encodeUnit( mAverageAngleLengthUnit );
964  map[QStringLiteral( "average_angle_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mAverageAngleLengthMapUnitScale );
965 
966  switch ( mPlacement )
967  {
968  case Vertex:
969  map[QStringLiteral( "placement" )] = QStringLiteral( "vertex" );
970  break;
971  case LastVertex:
972  map[QStringLiteral( "placement" )] = QStringLiteral( "lastvertex" );
973  break;
974  case FirstVertex:
975  map[QStringLiteral( "placement" )] = QStringLiteral( "firstvertex" );
976  break;
977  case CentralPoint:
978  map[QStringLiteral( "placement" )] = QStringLiteral( "centralpoint" );
979  break;
980  case CurvePoint:
981  map[QStringLiteral( "placement" )] = QStringLiteral( "curvepoint" );
982  break;
983  case Interval:
984  map[QStringLiteral( "placement" )] = QStringLiteral( "interval" );
985  break;
986  case SegmentCenter:
987  map[QStringLiteral( "placement" )] = QStringLiteral( "segmentcenter" );
988  break;
989  }
990 
991  map[QStringLiteral( "ring_filter" )] = QString::number( static_cast< int >( mRingFilter ) );
992  return map;
993 }
994 
996 {
997  destLayer->setSubSymbol( const_cast< QgsTemplatedLineSymbolLayerBase * >( this )->subSymbol()->clone() );
998  destLayer->setOffset( mOffset );
999  destLayer->setPlacement( placement() );
1000  destLayer->setOffsetUnit( mOffsetUnit );
1002  destLayer->setIntervalUnit( intervalUnit() );
1004  destLayer->setOffsetAlongLine( offsetAlongLine() );
1007  destLayer->setAverageAngleLength( mAverageAngleLength );
1008  destLayer->setAverageAngleUnit( mAverageAngleLengthUnit );
1009  destLayer->setAverageAngleMapUnitScale( mAverageAngleLengthMapUnitScale );
1010  destLayer->setRingFilter( mRingFilter );
1011  copyDataDefinedProperties( destLayer );
1012  copyPaintEffect( destLayer );
1013 }
1014 
1016 {
1017  if ( properties.contains( QStringLiteral( "offset" ) ) )
1018  {
1019  destLayer->setOffset( properties[QStringLiteral( "offset" )].toDouble() );
1020  }
1021  if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
1022  {
1023  destLayer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )] ) );
1024  }
1025  if ( properties.contains( QStringLiteral( "interval_unit" ) ) )
1026  {
1027  destLayer->setIntervalUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "interval_unit" )] ) );
1028  }
1029  if ( properties.contains( QStringLiteral( "offset_along_line" ) ) )
1030  {
1031  destLayer->setOffsetAlongLine( properties[QStringLiteral( "offset_along_line" )].toDouble() );
1032  }
1033  if ( properties.contains( QStringLiteral( "offset_along_line_unit" ) ) )
1034  {
1035  destLayer->setOffsetAlongLineUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_along_line_unit" )] ) );
1036  }
1037  if ( properties.contains( ( QStringLiteral( "offset_along_line_map_unit_scale" ) ) ) )
1038  {
1039  destLayer->setOffsetAlongLineMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_along_line_map_unit_scale" )] ) );
1040  }
1041 
1042  if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
1043  {
1044  destLayer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )] ) );
1045  }
1046  if ( properties.contains( QStringLiteral( "interval_map_unit_scale" ) ) )
1047  {
1048  destLayer->setIntervalMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "interval_map_unit_scale" )] ) );
1049  }
1050 
1051  if ( properties.contains( QStringLiteral( "average_angle_length" ) ) )
1052  {
1053  destLayer->setAverageAngleLength( properties[QStringLiteral( "average_angle_length" )].toDouble() );
1054  }
1055  if ( properties.contains( QStringLiteral( "average_angle_unit" ) ) )
1056  {
1057  destLayer->setAverageAngleUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "average_angle_unit" )] ) );
1058  }
1059  if ( properties.contains( ( QStringLiteral( "average_angle_map_unit_scale" ) ) ) )
1060  {
1061  destLayer->setAverageAngleMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "average_angle_map_unit_scale" )] ) );
1062  }
1063 
1064  if ( properties.contains( QStringLiteral( "placement" ) ) )
1065  {
1066  if ( properties[QStringLiteral( "placement" )] == QLatin1String( "vertex" ) )
1068  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "lastvertex" ) )
1070  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "firstvertex" ) )
1072  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "centralpoint" ) )
1074  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "curvepoint" ) )
1076  else if ( properties[QStringLiteral( "placement" )] == QLatin1String( "segmentcenter" ) )
1078  else
1080  }
1081 
1082  if ( properties.contains( QStringLiteral( "ring_filter" ) ) )
1083  {
1084  destLayer->setRingFilter( static_cast< RenderRingFilter>( properties[QStringLiteral( "ring_filter" )].toInt() ) );
1085  }
1086 
1088 }
1089 
1090 void QgsTemplatedLineSymbolLayerBase::renderPolylineInterval( const QPolygonF &points, QgsSymbolRenderContext &context, double averageOver )
1091 {
1092  if ( points.isEmpty() )
1093  return;
1094 
1095  double lengthLeft = 0; // how much is left until next marker
1096 
1097  QgsRenderContext &rc = context.renderContext();
1098  double interval = mInterval;
1099 
1101  QgsExpressionContextScopePopper scopePopper( context.renderContext().expressionContext(), scope );
1102 
1104  {
1105  context.setOriginalValueVariable( mInterval );
1107  }
1108  if ( interval <= 0 )
1109  {
1110  interval = 0.1;
1111  }
1112  double offsetAlongLine = mOffsetAlongLine;
1114  {
1115  context.setOriginalValueVariable( mOffsetAlongLine );
1117  }
1118 
1119  double painterUnitInterval = rc.convertToPainterUnits( interval, intervalUnit(), intervalMapUnitScale() );
1121  {
1122  // rendering for symbol previews -- an interval in meters in map units can't be calculated, so treat the size as millimeters
1123  // and clamp it to a reasonable range. It's the best we can do in this situation!
1124  painterUnitInterval = std::min( std::max( rc.convertToPainterUnits( interval, QgsUnitTypes::RenderMillimeters ), 10.0 ), 100.0 );
1125  }
1126 
1127  if ( painterUnitInterval < 0 )
1128  return;
1129 
1130  double painterUnitOffsetAlongLine = rc.convertToPainterUnits( offsetAlongLine, offsetAlongLineUnit(), offsetAlongLineMapUnitScale() );
1132  {
1133  // rendering for symbol previews -- an offset in meters in map units can't be calculated, so treat the size as millimeters
1134  // and clamp it to a reasonable range. It's the best we can do in this situation!
1135  painterUnitOffsetAlongLine = std::min( std::max( rc.convertToPainterUnits( offsetAlongLine, QgsUnitTypes::RenderMillimeters ), 3.0 ), 100.0 );
1136  }
1137 
1138  lengthLeft = painterUnitInterval - painterUnitOffsetAlongLine;
1139 
1140  if ( averageOver > 0 && !qgsDoubleNear( averageOver, 0.0 ) )
1141  {
1142  QVector< QPointF > angleStartPoints;
1143  QVector< QPointF > symbolPoints;
1144  QVector< QPointF > angleEndPoints;
1145 
1146  // we collect 3 arrays of points. These correspond to
1147  // 1. the actual point at which to render the symbol
1148  // 2. the start point of a line averaging the angle over the desired distance (i.e. -averageOver distance from the points in array 1)
1149  // 3. the end point of a line averaging the angle over the desired distance (i.e. +averageOver distance from the points in array 2)
1150  // it gets quite tricky, because for closed rings we need to trace backwards from the initial point to calculate this
1151  // (or trace past the final point)
1152  collectOffsetPoints( points, symbolPoints, painterUnitInterval, lengthLeft );
1153 
1154  if ( symbolPoints.empty() )
1155  {
1156  // no symbols to draw, shortcut out early
1157  return;
1158  }
1159 
1160  if ( symbolPoints.count() > 1 && symbolPoints.constFirst() == symbolPoints.constLast() )
1161  {
1162  // avoid duplicate points at start and end of closed rings
1163  symbolPoints.pop_back();
1164  }
1165 
1166  angleEndPoints.reserve( symbolPoints.size() );
1167  angleStartPoints.reserve( symbolPoints.size() );
1168  if ( averageOver <= painterUnitOffsetAlongLine )
1169  {
1170  collectOffsetPoints( points, angleStartPoints, painterUnitInterval, lengthLeft + averageOver, 0, symbolPoints.size() );
1171  }
1172  else
1173  {
1174  collectOffsetPoints( points, angleStartPoints, painterUnitInterval, 0, averageOver - painterUnitOffsetAlongLine, symbolPoints.size() );
1175  }
1176  collectOffsetPoints( points, angleEndPoints, painterUnitInterval, lengthLeft - averageOver, 0, symbolPoints.size() );
1177 
1178  int pointNum = 0;
1179  for ( int i = 0; i < symbolPoints.size(); ++ i )
1180  {
1181  if ( context.renderContext().renderingStopped() )
1182  break;
1183 
1184  const QPointF pt = symbolPoints[i];
1185  const QPointF startPt = angleStartPoints[i];
1186  const QPointF endPt = angleEndPoints[i];
1187 
1188  MyLine l( startPt, endPt );
1189  // rotate marker (if desired)
1190  if ( rotateSymbols() )
1191  {
1192  setSymbolLineAngle( l.angle() * 180 / M_PI );
1193  }
1194 
1196  renderSymbol( pt, context.feature(), rc, -1, context.selected() );
1197  }
1198  }
1199  else
1200  {
1201  // not averaging line angle -- always use exact section angle
1202  int pointNum = 0;
1203  QPointF lastPt = points[0];
1204  for ( int i = 1; i < points.count(); ++i )
1205  {
1206  if ( context.renderContext().renderingStopped() )
1207  break;
1208 
1209  const QPointF &pt = points[i];
1210 
1211  if ( lastPt == pt ) // must not be equal!
1212  continue;
1213 
1214  // for each line, find out dx and dy, and length
1215  MyLine l( lastPt, pt );
1216  QPointF diff = l.diffForInterval( painterUnitInterval );
1217 
1218  // if there's some length left from previous line
1219  // use only the rest for the first point in new line segment
1220  double c = 1 - lengthLeft / painterUnitInterval;
1221 
1222  lengthLeft += l.length();
1223 
1224  // rotate marker (if desired)
1225  if ( rotateSymbols() )
1226  {
1227  setSymbolLineAngle( l.angle() * 180 / M_PI );
1228  }
1229 
1230  // while we're not at the end of line segment, draw!
1231  while ( lengthLeft > painterUnitInterval )
1232  {
1233  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
1234  lastPt += c * diff;
1235  lengthLeft -= painterUnitInterval;
1237  renderSymbol( lastPt, context.feature(), rc, -1, context.selected() );
1238  c = 1; // reset c (if wasn't 1 already)
1239  }
1240 
1241  lastPt = pt;
1242  }
1243 
1244  }
1245 }
1246 
1247 static double _averageAngle( QPointF prevPt, QPointF pt, QPointF nextPt )
1248 {
1249  // calc average angle between the previous and next point
1250  double a1 = MyLine( prevPt, pt ).angle();
1251  double a2 = MyLine( pt, nextPt ).angle();
1252  double unitX = std::cos( a1 ) + std::cos( a2 ), unitY = std::sin( a1 ) + std::sin( a2 );
1253 
1254  return std::atan2( unitY, unitX );
1255 }
1256 
1257 void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex( const QPolygonF &points, QgsSymbolRenderContext &context, QgsTemplatedLineSymbolLayerBase::Placement placement )
1258 {
1259  if ( points.isEmpty() )
1260  return;
1261 
1262  QgsRenderContext &rc = context.renderContext();
1263 
1264  double origAngle = symbolAngle();
1265  int i = -1, maxCount = 0;
1266  bool isRing = false;
1267 
1269  QgsExpressionContextScopePopper scopePopper( context.renderContext().expressionContext(), scope );
1271 
1272  double offsetAlongLine = mOffsetAlongLine;
1274  {
1275  context.setOriginalValueVariable( mOffsetAlongLine );
1277  }
1278  if ( !qgsDoubleNear( offsetAlongLine, 0.0 ) )
1279  {
1280  //scale offset along line
1282  }
1283 
1284  if ( qgsDoubleNear( offsetAlongLine, 0.0 ) && context.renderContext().geometry()
1286  {
1288  const QgsMapToPixel &mtp = context.renderContext().mapToPixel();
1289 
1290  QgsVertexId vId;
1291  QgsPoint vPoint;
1292  double x, y, z;
1293  QPointF mapPoint;
1294  int pointNum = 0;
1295  while ( context.renderContext().geometry()->nextVertex( vId, vPoint ) )
1296  {
1297  if ( context.renderContext().renderingStopped() )
1298  break;
1299 
1301 
1304  {
1305  //transform
1306  x = vPoint.x();
1307  y = vPoint.y();
1308  z = 0.0;
1309  if ( ct.isValid() )
1310  {
1311  ct.transformInPlace( x, y, z );
1312  }
1313  mapPoint.setX( x );
1314  mapPoint.setY( y );
1315  mtp.transformInPlace( mapPoint.rx(), mapPoint.ry() );
1316  if ( rotateSymbols() )
1317  {
1318  double angle = context.renderContext().geometry()->vertexAngle( vId );
1319  setSymbolAngle( angle * 180 / M_PI );
1320  }
1321  renderSymbol( mapPoint, context.feature(), rc, -1, context.selected() );
1322  }
1323  }
1324 
1325  return;
1326  }
1327 
1328  switch ( placement )
1329  {
1330  case FirstVertex:
1331  {
1332  i = 0;
1333  maxCount = 1;
1334  break;
1335  }
1336 
1337  case LastVertex:
1338  {
1339  i = points.count() - 1;
1340  maxCount = points.count();
1341  break;
1342  }
1343 
1344  case Vertex:
1345  case SegmentCenter:
1346  {
1347  i = placement == Vertex ? 0 : 1;
1348  maxCount = points.count();
1349  if ( points.first() == points.last() )
1350  isRing = true;
1351  break;
1352  }
1353 
1354  case Interval:
1355  case CentralPoint:
1356  case CurvePoint:
1357  {
1358  return;
1359  }
1360  }
1361 
1363  {
1364  double distance;
1366  renderOffsetVertexAlongLine( points, i, distance, context );
1367  // restore original rotation
1368  setSymbolAngle( origAngle );
1369 
1370  return;
1371  }
1372 
1373  int pointNum = 0;
1374  QPointF prevPoint;
1375  if ( placement == SegmentCenter && !points.empty() )
1376  prevPoint = points.at( 0 );
1377 
1378  QPointF symbolPoint;
1379  for ( ; i < maxCount; ++i )
1380  {
1382 
1383  if ( isRing && placement == QgsTemplatedLineSymbolLayerBase::Vertex && i == points.count() - 1 )
1384  {
1385  continue; // don't draw the last marker - it has been drawn already
1386  }
1387 
1388  if ( placement == SegmentCenter )
1389  {
1390  QPointF currentPoint = points.at( i );
1391  symbolPoint = QPointF( 0.5 * ( currentPoint.x() + prevPoint.x() ),
1392  0.5 * ( currentPoint.y() + prevPoint.y() ) );
1393  if ( rotateSymbols() )
1394  {
1395  double angle = std::atan2( currentPoint.y() - prevPoint.y(),
1396  currentPoint.x() - prevPoint.x() );
1397  setSymbolAngle( origAngle + angle * 180 / M_PI );
1398  }
1399  prevPoint = currentPoint;
1400  }
1401  else
1402  {
1403  symbolPoint = points.at( i );
1404  // rotate marker (if desired)
1405  if ( rotateSymbols() )
1406  {
1407  double angle = markerAngle( points, isRing, i );
1408  setSymbolAngle( origAngle + angle * 180 / M_PI );
1409  }
1410  }
1411 
1412  renderSymbol( symbolPoint, context.feature(), rc, -1, context.selected() );
1413  }
1414 
1415  // restore original rotation
1416  setSymbolAngle( origAngle );
1417 }
1418 
1419 double QgsTemplatedLineSymbolLayerBase::markerAngle( const QPolygonF &points, bool isRing, int vertex )
1420 {
1421  double angle = 0;
1422  const QPointF &pt = points[vertex];
1423 
1424  if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
1425  {
1426  int prevIndex = vertex - 1;
1427  int nextIndex = vertex + 1;
1428 
1429  if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
1430  {
1431  prevIndex = points.count() - 2;
1432  nextIndex = 1;
1433  }
1434 
1435  QPointF prevPoint, nextPoint;
1436  while ( prevIndex >= 0 )
1437  {
1438  prevPoint = points[ prevIndex ];
1439  if ( prevPoint != pt )
1440  {
1441  break;
1442  }
1443  --prevIndex;
1444  }
1445 
1446  while ( nextIndex < points.count() )
1447  {
1448  nextPoint = points[ nextIndex ];
1449  if ( nextPoint != pt )
1450  {
1451  break;
1452  }
1453  ++nextIndex;
1454  }
1455 
1456  if ( prevIndex >= 0 && nextIndex < points.count() )
1457  {
1458  angle = _averageAngle( prevPoint, pt, nextPoint );
1459  }
1460  }
1461  else //no ring and vertex is at start / at end
1462  {
1463  if ( vertex == 0 )
1464  {
1465  while ( vertex < points.size() - 1 )
1466  {
1467  const QPointF &nextPt = points[vertex + 1];
1468  if ( pt != nextPt )
1469  {
1470  angle = MyLine( pt, nextPt ).angle();
1471  return angle;
1472  }
1473  ++vertex;
1474  }
1475  }
1476  else
1477  {
1478  // use last segment's angle
1479  while ( vertex >= 1 ) //in case of duplicated vertices, take the next suitable one
1480  {
1481  const QPointF &prevPt = points[vertex - 1];
1482  if ( pt != prevPt )
1483  {
1484  angle = MyLine( prevPt, pt ).angle();
1485  return angle;
1486  }
1487  --vertex;
1488  }
1489  }
1490  }
1491  return angle;
1492 }
1493 
1494 void QgsTemplatedLineSymbolLayerBase::renderOffsetVertexAlongLine( const QPolygonF &points, int vertex, double distance, QgsSymbolRenderContext &context )
1495 {
1496  if ( points.isEmpty() )
1497  return;
1498 
1499  QgsRenderContext &rc = context.renderContext();
1500  double origAngle = symbolAngle();
1501  if ( qgsDoubleNear( distance, 0.0 ) )
1502  {
1503  // rotate marker (if desired)
1504  if ( rotateSymbols() )
1505  {
1506  bool isRing = false;
1507  if ( points.first() == points.last() )
1508  isRing = true;
1509  double angle = markerAngle( points, isRing, vertex );
1510  setSymbolAngle( origAngle + angle * 180 / M_PI );
1511  }
1512  renderSymbol( points[vertex], context.feature(), rc, -1, context.selected() );
1513  return;
1514  }
1515 
1516  int pointIncrement = distance > 0 ? 1 : -1;
1517  QPointF previousPoint = points[vertex];
1518  int startPoint = distance > 0 ? std::min( vertex + 1, points.count() - 1 ) : std::max( vertex - 1, 0 );
1519  int endPoint = distance > 0 ? points.count() - 1 : 0;
1520  double distanceLeft = std::fabs( distance );
1521 
1522  for ( int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
1523  {
1524  const QPointF &pt = points[i];
1525 
1526  if ( previousPoint == pt ) // must not be equal!
1527  continue;
1528 
1529  // create line segment
1530  MyLine l( previousPoint, pt );
1531 
1532  if ( distanceLeft < l.length() )
1533  {
1534  //destination point is in current segment
1535  QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
1536  // rotate marker (if desired)
1537  if ( rotateSymbols() )
1538  {
1539  setSymbolAngle( origAngle + ( l.angle() * 180 / M_PI ) );
1540  }
1541  renderSymbol( markerPoint, context.feature(), rc, -1, context.selected() );
1542  return;
1543  }
1544 
1545  distanceLeft -= l.length();
1546  previousPoint = pt;
1547  }
1548 
1549  //didn't find point
1550 }
1551 
1552 void QgsTemplatedLineSymbolLayerBase::collectOffsetPoints( const QVector<QPointF> &p, QVector<QPointF> &dest, double intervalPainterUnits, double initialOffset, double initialLag, int numberPointsRequired )
1553 {
1554  if ( p.empty() )
1555  return;
1556 
1557  QVector< QPointF > points = p;
1558  const bool closedRing = points.first() == points.last();
1559 
1560  double lengthLeft = initialOffset;
1561 
1562  double initialLagLeft = initialLag > 0 ? -initialLag : 1; // an initialLagLeft of > 0 signifies end of lagging start points
1563  if ( initialLagLeft < 0 && closedRing )
1564  {
1565  // tracking back around the ring from the first point, insert pseudo vertices before the first vertex
1566  QPointF lastPt = points.constLast();
1567  QVector< QPointF > pseudoPoints;
1568  for ( int i = points.count() - 2; i > 0; --i )
1569  {
1570  if ( initialLagLeft >= 0 )
1571  {
1572  break;
1573  }
1574 
1575  const QPointF &pt = points[i];
1576 
1577  if ( lastPt == pt ) // must not be equal!
1578  continue;
1579 
1580  MyLine l( lastPt, pt );
1581  initialLagLeft += l.length();
1582  lastPt = pt;
1583 
1584  pseudoPoints << pt;
1585  }
1586  std::reverse( pseudoPoints.begin(), pseudoPoints.end() );
1587 
1588  points = pseudoPoints;
1589  points.append( p );
1590  }
1591  else
1592  {
1593  while ( initialLagLeft < 0 )
1594  {
1595  dest << points.constFirst();
1596  initialLagLeft += intervalPainterUnits;
1597  }
1598  }
1599  if ( initialLag > 0 )
1600  {
1601  lengthLeft += intervalPainterUnits - initialLagLeft;
1602  }
1603 
1604  QPointF lastPt = points[0];
1605  for ( int i = 1; i < points.count(); ++i )
1606  {
1607  const QPointF &pt = points[i];
1608 
1609  if ( lastPt == pt ) // must not be equal!
1610  {
1611  if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
1612  {
1613  lastPt = points[0];
1614  i = 0;
1615  }
1616  continue;
1617  }
1618 
1619  // for each line, find out dx and dy, and length
1620  MyLine l( lastPt, pt );
1621  QPointF diff = l.diffForInterval( intervalPainterUnits );
1622 
1623  // if there's some length left from previous line
1624  // use only the rest for the first point in new line segment
1625  double c = 1 - lengthLeft / intervalPainterUnits;
1626 
1627  lengthLeft += l.length();
1628 
1629 
1630  while ( lengthLeft > intervalPainterUnits || qgsDoubleNear( lengthLeft, intervalPainterUnits, 0.000000001 ) )
1631  {
1632  // "c" is 1 for regular point or in interval (0,1] for begin of line segment
1633  lastPt += c * diff;
1634  lengthLeft -= intervalPainterUnits;
1635  dest << lastPt;
1636  c = 1; // reset c (if wasn't 1 already)
1637  if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
1638  break;
1639  }
1640  lastPt = pt;
1641 
1642  if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
1643  break;
1644 
1645  // if a closed ring, we keep looping around the ring until we hit the required number of points
1646  if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
1647  {
1648  lastPt = points[0];
1649  i = 0;
1650  }
1651  }
1652 
1653  if ( !closedRing && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
1654  {
1655  // pad with repeating last point to match desired size
1656  while ( dest.size() < numberPointsRequired )
1657  dest << points.constLast();
1658  }
1659 }
1660 
1661 void QgsTemplatedLineSymbolLayerBase::renderPolylineCentral( const QPolygonF &points, QgsSymbolRenderContext &context, double averageAngleOver )
1662 {
1663  if ( !points.isEmpty() )
1664  {
1665  // calc length
1666  qreal length = 0;
1667  QPolygonF::const_iterator it = points.constBegin();
1668  QPointF last = *it;
1669  for ( ++it; it != points.constEnd(); ++it )
1670  {
1671  length += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
1672  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1673  last = *it;
1674  }
1675  if ( qgsDoubleNear( length, 0.0 ) )
1676  return;
1677 
1678  const double midPoint = length / 2;
1679 
1680  QPointF pt;
1681  double thisSymbolAngle = 0;
1682 
1683  if ( averageAngleOver > 0 && !qgsDoubleNear( averageAngleOver, 0.0 ) )
1684  {
1685  QVector< QPointF > angleStartPoints;
1686  QVector< QPointF > symbolPoints;
1687  QVector< QPointF > angleEndPoints;
1688  // collectOffsetPoints will have the first point in the line as the first result -- we don't want this, we need the second
1689  collectOffsetPoints( points, symbolPoints, midPoint, midPoint, 0.0, 2 );
1690  collectOffsetPoints( points, angleStartPoints, midPoint, 0, averageAngleOver, 2 );
1691  collectOffsetPoints( points, angleEndPoints, midPoint, midPoint - averageAngleOver, 0, 2 );
1692 
1693  pt = symbolPoints.at( 1 );
1694  MyLine l( angleStartPoints.at( 1 ), angleEndPoints.at( 1 ) );
1695  thisSymbolAngle = l.angle();
1696  }
1697  else
1698  {
1699  // find the segment where the central point lies
1700  it = points.constBegin();
1701  last = *it;
1702  qreal last_at = 0, next_at = 0;
1703  QPointF next;
1704  int segment = 0;
1705  for ( ++it; it != points.constEnd(); ++it )
1706  {
1707  next = *it;
1708  next_at += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
1709  ( last.y() - it->y() ) * ( last.y() - it->y() ) );
1710  if ( next_at >= midPoint )
1711  break; // we have reached the center
1712  last = *it;
1713  last_at = next_at;
1714  segment++;
1715  }
1716 
1717  // find out the central point on segment
1718  MyLine l( last, next ); // for line angle
1719  qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
1720  pt = last + ( next - last ) * k;
1721  thisSymbolAngle = l.angle();
1722  }
1723 
1724  // draw the marker
1725  double origAngle = symbolAngle();
1726  if ( rotateSymbols() )
1727  setSymbolAngle( origAngle + thisSymbolAngle * 180 / M_PI );
1728  renderSymbol( pt, context.feature(), context.renderContext(), -1, context.selected() );
1729  if ( rotateSymbols() )
1730  setSymbolAngle( origAngle );
1731  }
1732 }
1733 
1735 {
1736  return mMarker.get();
1737 }
1738 
1740 {
1741  if ( !symbol || symbol->type() != QgsSymbol::Marker )
1742  {
1743  delete symbol;
1744  return false;
1745  }
1746 
1747  mMarker.reset( static_cast<QgsMarkerSymbol *>( symbol ) );
1748  mColor = mMarker->color();
1749  return true;
1750 }
1751 
1752 
1753 
1754 //
1755 // QgsMarkerLineSymbolLayer
1756 //
1757 
1758 QgsMarkerLineSymbolLayer::QgsMarkerLineSymbolLayer( bool rotateMarker, double interval )
1759  : QgsTemplatedLineSymbolLayerBase( rotateMarker, interval )
1760 {
1761  setSubSymbol( new QgsMarkerSymbol() );
1762 }
1763 
1765 {
1766  bool rotate = DEFAULT_MARKERLINE_ROTATE;
1768 
1769  if ( props.contains( QStringLiteral( "interval" ) ) )
1770  interval = props[QStringLiteral( "interval" )].toDouble();
1771  if ( props.contains( QStringLiteral( "rotate" ) ) )
1772  rotate = ( props[QStringLiteral( "rotate" )] == QLatin1String( "1" ) );
1773 
1774  std::unique_ptr< QgsMarkerLineSymbolLayer > x = qgis::make_unique< QgsMarkerLineSymbolLayer >( rotate, interval );
1775  setCommonProperties( x.get(), props );
1776  return x.release();
1777 }
1778 
1780 {
1781  return QStringLiteral( "MarkerLine" );
1782 }
1783 
1784 void QgsMarkerLineSymbolLayer::setColor( const QColor &color )
1785 {
1786  mMarker->setColor( color );
1787  mColor = color;
1788 }
1789 
1791 {
1792  return mMarker ? mMarker->color() : mColor;
1793 }
1794 
1796 {
1797  mMarker->setOpacity( context.opacity() );
1798 
1799  // if being rotated, it gets initialized with every line segment
1800  QgsSymbol::RenderHints hints = nullptr;
1801  if ( rotateSymbols() )
1802  hints |= QgsSymbol::DynamicRotation;
1803  mMarker->setRenderHints( hints );
1804 
1805  mMarker->startRender( context.renderContext(), context.fields() );
1806 }
1807 
1809 {
1810  mMarker->stopRender( context.renderContext() );
1811 }
1812 
1813 
1815 {
1816  std::unique_ptr< QgsMarkerLineSymbolLayer > x = qgis::make_unique< QgsMarkerLineSymbolLayer >( rotateSymbols(), interval() );
1817  copyTemplateSymbolProperties( x.get() );
1818  return x.release();
1819 }
1820 
1821 void QgsMarkerLineSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
1822 {
1823  for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
1824  {
1825  QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:LineSymbolizer" ) );
1826  if ( !props.value( QStringLiteral( "uom" ), QString() ).isEmpty() )
1827  symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ) );
1828  element.appendChild( symbolizerElem );
1829 
1830  // <Geometry>
1831  QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ) );
1832 
1833  QString gap;
1834  switch ( placement() )
1835  {
1837  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "firstPoint" ) ) );
1838  break;
1840  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "lastPoint" ) ) );
1841  break;
1843  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "centralPoint" ) ) );
1844  break;
1846  // no way to get line/polygon's vertices, use a VendorOption
1847  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "placement" ), QStringLiteral( "points" ) ) );
1848  break;
1849  default:
1851  gap = qgsDoubleToString( interval );
1852  break;
1853  }
1854 
1855  if ( !rotateSymbols() )
1856  {
1857  // markers in LineSymbolizer must be drawn following the line orientation,
1858  // use a VendorOption when no marker rotation
1859  symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "rotateMarker" ), QStringLiteral( "0" ) ) );
1860  }
1861 
1862  // <Stroke>
1863  QDomElement strokeElem = doc.createElement( QStringLiteral( "se:Stroke" ) );
1864  symbolizerElem.appendChild( strokeElem );
1865 
1866  // <GraphicStroke>
1867  QDomElement graphicStrokeElem = doc.createElement( QStringLiteral( "se:GraphicStroke" ) );
1868  strokeElem.appendChild( graphicStrokeElem );
1869 
1870  QgsSymbolLayer *layer = mMarker->symbolLayer( i );
1871  QgsMarkerSymbolLayer *markerLayer = static_cast<QgsMarkerSymbolLayer *>( layer );
1872  if ( !markerLayer )
1873  {
1874  graphicStrokeElem.appendChild( doc.createComment( QStringLiteral( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() ) ) );
1875  }
1876  else
1877  {
1878  markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
1879  }
1880 
1881  if ( !gap.isEmpty() )
1882  {
1883  QDomElement gapElem = doc.createElement( QStringLiteral( "se:Gap" ) );
1884  QgsSymbolLayerUtils::createExpressionElement( doc, gapElem, gap );
1885  graphicStrokeElem.appendChild( gapElem );
1886  }
1887 
1888  if ( !qgsDoubleNear( mOffset, 0.0 ) )
1889  {
1890  QDomElement perpOffsetElem = doc.createElement( QStringLiteral( "se:PerpendicularOffset" ) );
1892  perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
1893  symbolizerElem.appendChild( perpOffsetElem );
1894  }
1895  }
1896 }
1897 
1899 {
1900  QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
1901 
1902  QDomElement strokeElem = element.firstChildElement( QStringLiteral( "Stroke" ) );
1903  if ( strokeElem.isNull() )
1904  return nullptr;
1905 
1906  QDomElement graphicStrokeElem = strokeElem.firstChildElement( QStringLiteral( "GraphicStroke" ) );
1907  if ( graphicStrokeElem.isNull() )
1908  return nullptr;
1909 
1910  // retrieve vendor options
1911  bool rotateMarker = true;
1913 
1914  QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( element );
1915  for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
1916  {
1917  if ( it.key() == QLatin1String( "placement" ) )
1918  {
1919  if ( it.value() == QLatin1String( "points" ) )
1921  else if ( it.value() == QLatin1String( "firstPoint" ) )
1923  else if ( it.value() == QLatin1String( "lastPoint" ) )
1925  else if ( it.value() == QLatin1String( "centralPoint" ) )
1927  }
1928  else if ( it.value() == QLatin1String( "rotateMarker" ) )
1929  {
1930  rotateMarker = it.value() == QLatin1String( "0" );
1931  }
1932  }
1933 
1934  std::unique_ptr< QgsMarkerSymbol > marker;
1935 
1937  if ( l )
1938  {
1939  QgsSymbolLayerList layers;
1940  layers.append( l );
1941  marker.reset( new QgsMarkerSymbol( layers ) );
1942  }
1943 
1944  if ( !marker )
1945  return nullptr;
1946 
1947  double interval = 0.0;
1948  QDomElement gapElem = graphicStrokeElem.firstChildElement( QStringLiteral( "Gap" ) );
1949  if ( !gapElem.isNull() )
1950  {
1951  bool ok;
1952  double d = gapElem.firstChild().nodeValue().toDouble( &ok );
1953  if ( ok )
1954  interval = d;
1955  }
1956 
1957  double offset = 0.0;
1958  QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( QStringLiteral( "PerpendicularOffset" ) );
1959  if ( !perpOffsetElem.isNull() )
1960  {
1961  bool ok;
1962  double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
1963  if ( ok )
1964  offset = d;
1965  }
1966 
1967  QString uom = element.attribute( QStringLiteral( "uom" ) );
1970 
1972  x->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
1973  x->setPlacement( placement );
1974  x->setInterval( interval );
1975  x->setSubSymbol( marker.release() );
1976  x->setOffset( offset );
1977  return x;
1978 }
1979 
1981 {
1982  mMarker->setSize( width );
1983 }
1984 
1986 {
1987  if ( key == QgsSymbolLayer::PropertyWidth && mMarker && property )
1988  {
1989  mMarker->setDataDefinedSize( property );
1990  }
1992 }
1993 
1995 {
1996  mMarker->setLineAngle( angle );
1997 }
1998 
2000 {
2001  return mMarker->angle();
2002 }
2003 
2005 {
2006  mMarker->setAngle( angle );
2007 }
2008 
2009 void QgsMarkerLineSymbolLayer::renderSymbol( const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer, bool selected )
2010 {
2011  mMarker->renderPoint( point, feature, context, layer, selected );
2012 }
2013 
2015 {
2016  return mMarker->size();
2017 }
2018 
2020 {
2021  return mMarker->size( context );
2022 }
2023 
2025 {
2027  mMarker->setOutputUnit( unit );
2028  setIntervalUnit( unit );
2029  mOffsetUnit = unit;
2030  setOffsetAlongLineUnit( unit );
2031 }
2032 
2033 
2034 QSet<QString> QgsMarkerLineSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
2035 {
2036  QSet<QString> attr = QgsLineSymbolLayer::usedAttributes( context );
2037  if ( mMarker )
2038  attr.unite( mMarker->usedAttributes( context ) );
2039  return attr;
2040 }
2041 
2043 {
2045  return true;
2046  if ( mMarker && mMarker->hasDataDefinedProperties() )
2047  return true;
2048  return false;
2049 }
2050 
2052 {
2053  return ( mMarker->size( context ) / 2.0 ) +
2055 }
2056 
2057 
2058 //
2059 // QgsHashedLineSymbolLayer
2060 //
2061 
2062 QgsHashedLineSymbolLayer::QgsHashedLineSymbolLayer( bool rotateSymbol, double interval )
2063  : QgsTemplatedLineSymbolLayerBase( rotateSymbol, interval )
2064 {
2065  setSubSymbol( new QgsLineSymbol() );
2066 }
2067 
2069 {
2070  bool rotate = DEFAULT_MARKERLINE_ROTATE;
2072 
2073  if ( props.contains( QStringLiteral( "interval" ) ) )
2074  interval = props[QStringLiteral( "interval" )].toDouble();
2075  if ( props.contains( QStringLiteral( "rotate" ) ) )
2076  rotate = ( props[QStringLiteral( "rotate" )] == QLatin1String( "1" ) );
2077 
2078  std::unique_ptr< QgsHashedLineSymbolLayer > x = qgis::make_unique< QgsHashedLineSymbolLayer >( rotate, interval );
2079  setCommonProperties( x.get(), props );
2080  if ( props.contains( QStringLiteral( "hash_angle" ) ) )
2081  {
2082  x->setHashAngle( props[QStringLiteral( "hash_angle" )].toDouble() );
2083  }
2084 
2085  if ( props.contains( QStringLiteral( "hash_length" ) ) )
2086  x->setHashLength( props[QStringLiteral( "hash_length" )].toDouble() );
2087 
2088  if ( props.contains( QStringLiteral( "hash_length_unit" ) ) )
2089  x->setHashLengthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "hash_length_unit" )] ) );
2090 
2091  if ( props.contains( QStringLiteral( "hash_length_map_unit_scale" ) ) )
2092  x->setHashLengthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "hash_length_map_unit_scale" )] ) );
2093 
2094  return x.release();
2095 }
2096 
2098 {
2099  return QStringLiteral( "HashLine" );
2100 }
2101 
2103 {
2104  mHashSymbol->setOpacity( context.opacity() );
2105 
2106  // if being rotated, it gets initialized with every line segment
2107  QgsSymbol::RenderHints hints = nullptr;
2108  if ( rotateSymbols() )
2109  hints |= QgsSymbol::DynamicRotation;
2110  mHashSymbol->setRenderHints( hints );
2111 
2112  mHashSymbol->startRender( context.renderContext(), context.fields() );
2113 }
2114 
2116 {
2117  mHashSymbol->stopRender( context.renderContext() );
2118 }
2119 
2121 {
2123  map[ QStringLiteral( "hash_angle" ) ] = QString::number( mHashAngle );
2124 
2125  map[QStringLiteral( "hash_length" )] = QString::number( mHashLength );
2126  map[QStringLiteral( "hash_length_unit" )] = QgsUnitTypes::encodeUnit( mHashLengthUnit );
2127  map[QStringLiteral( "hash_length_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mHashLengthMapUnitScale );
2128 
2129  return map;
2130 }
2131 
2133 {
2134  std::unique_ptr< QgsHashedLineSymbolLayer > x = qgis::make_unique< QgsHashedLineSymbolLayer >( rotateSymbols(), interval() );
2135  copyTemplateSymbolProperties( x.get() );
2136  x->setHashAngle( mHashAngle );
2137  x->setHashLength( mHashLength );
2138  x->setHashLengthUnit( mHashLengthUnit );
2139  x->setHashLengthMapUnitScale( mHashLengthMapUnitScale );
2140  return x.release();
2141 }
2142 
2143 void QgsHashedLineSymbolLayer::setColor( const QColor &color )
2144 {
2145  mHashSymbol->setColor( color );
2146  mColor = color;
2147 }
2148 
2150 {
2151  return mHashSymbol ? mHashSymbol->color() : mColor;
2152 }
2153 
2155 {
2156  return mHashSymbol.get();
2157 }
2158 
2160 {
2161  if ( !symbol || symbol->type() != QgsSymbol::Line )
2162  {
2163  delete symbol;
2164  return false;
2165  }
2166 
2167  mHashSymbol.reset( static_cast<QgsLineSymbol *>( symbol ) );
2168  mColor = mHashSymbol->color();
2169  return true;
2170 }
2171 
2172 void QgsHashedLineSymbolLayer::setWidth( const double width )
2173 {
2174  mHashLength = width;
2175 }
2176 
2178 {
2179  return mHashLength;
2180 }
2181 
2183 {
2184  return context.convertToPainterUnits( mHashLength, mHashLengthUnit, mHashLengthMapUnitScale );
2185 }
2186 
2188 {
2189  return ( mHashSymbol->width( context ) / 2.0 )
2190  + context.convertToPainterUnits( mHashLength, mHashLengthUnit, mHashLengthMapUnitScale )
2191  + context.convertToPainterUnits( std::fabs( mOffset ), mOffsetUnit, mOffsetMapUnitScale );
2192 }
2193 
2195 {
2197  mHashSymbol->setOutputUnit( unit );
2198  setIntervalUnit( unit );
2199  mOffsetUnit = unit;
2200  setOffsetAlongLineUnit( unit );
2201 }
2202 
2203 QSet<QString> QgsHashedLineSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
2204 {
2205  QSet<QString> attr = QgsLineSymbolLayer::usedAttributes( context );
2206  if ( mHashSymbol )
2207  attr.unite( mHashSymbol->usedAttributes( context ) );
2208  return attr;
2209 }
2210 
2212 {
2214  return true;
2215  if ( mHashSymbol && mHashSymbol->hasDataDefinedProperties() )
2216  return true;
2217  return false;
2218 }
2219 
2221 {
2222  if ( key == QgsSymbolLayer::PropertyWidth && mHashSymbol && property )
2223  {
2224  mHashSymbol->setDataDefinedWidth( property );
2225  }
2227 }
2228 
2230 {
2231  mSymbolLineAngle = angle;
2232 }
2233 
2235 {
2236  return mSymbolAngle;
2237 }
2238 
2240 {
2241  mSymbolAngle = angle;
2242 }
2243 
2244 void QgsHashedLineSymbolLayer::renderSymbol( const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer, bool selected )
2245 {
2246  double lineLength = mHashLength;
2248  {
2249  context.expressionContext().setOriginalValueVariable( mHashLength );
2251  }
2252  const double w = context.convertToPainterUnits( lineLength, mHashLengthUnit, mHashLengthMapUnitScale ) / 2.0;
2253 
2254  double hashAngle = mHashAngle;
2256  {
2257  context.expressionContext().setOriginalValueVariable( mHashAngle );
2259  }
2260 
2261  QgsPointXY center( point );
2262  QgsPointXY start = center.project( w, 180 - ( mSymbolAngle + mSymbolLineAngle + hashAngle ) );
2263  QgsPointXY end = center.project( -w, 180 - ( mSymbolAngle + mSymbolLineAngle + hashAngle ) );
2264 
2265  QPolygonF points;
2266  points << QPointF( start.x(), start.y() ) << QPointF( end.x(), end.y() );
2267 
2268  mHashSymbol->renderPolyline( points, feature, context, layer, selected );
2269 }
2270 
2272 {
2273  return mHashAngle;
2274 }
2275 
2277 {
2278  mHashAngle = angle;
2279 }
2280 
2281 
QgsMarkerLineSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgslinesymbollayer.cpp:1779
QgsSimpleLineSymbolLayer::dxfCustomDashPattern
QVector< qreal > dxfCustomDashPattern(QgsUnitTypes::RenderUnit &unit) const override
Gets dash pattern.
Definition: qgslinesymbollayer.cpp:622
QgsSymbolRenderContext::setOriginalValueVariable
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
Definition: qgssymbol.cpp:1370
QgsMarkerLineSymbolLayer::width
double width() const override
Returns the estimated width for the line symbol layer.
Definition: qgslinesymbollayer.cpp:2014
QgsMarkerLineSymbolLayer::clone
QgsMarkerLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgslinesymbollayer.cpp:1814
QgsHashedLineSymbolLayer::setSymbolLineAngle
void setSymbolLineAngle(double angle) override
Sets the line angle modification for the symbol's angle.
Definition: qgslinesymbollayer.cpp:2229
qgsexpressioncontextutils.h
QgsMarkerLineSymbolLayer::createFromSld
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsMarkerLineSymbolLayer from an SLD XML DOM element.
Definition: qgslinesymbollayer.cpp:1898
QgsSymbolLayer::setSubSymbol
virtual bool setSubSymbol(QgsSymbol *symbol)
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgssymbollayer.h:351
QgsTemplatedLineSymbolLayerBase::copyTemplateSymbolProperties
void copyTemplateSymbolProperties(QgsTemplatedLineSymbolLayerBase *destLayer) const
Copies all common properties of this layer to another templated symbol layer.
Definition: qgslinesymbollayer.cpp:995
QgsLineSymbolLayer::setWidthUnit
void setWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the line's width.
Definition: qgssymbollayer.h:1035
QgsExpressionContextScopePopper
Definition: qgsexpressioncontextutils.h:354
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:938
QgsTemplatedLineSymbolLayerBase::setOffsetAlongLine
void setOffsetAlongLine(double offsetAlongLine)
Sets the the offset along the line for the symbol placement.
Definition: qgslinesymbollayer.h:375
QgsLineSymbolLayer::RenderRingFilter
RenderRingFilter
Options for filtering rings when the line symbol layer is being used to render a polygon's rings.
Definition: qgssymbollayer.h:899
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:287
QgsSymbolLayer::mColor
QColor mColor
Definition: qgssymbollayer.h:521
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:309
QgsSymbolLayer::dataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
Definition: qgssymbollayer.h:480
QgsProperty
A store for object properties.
Definition: qgsproperty.h:231
QgsUnitTypes::RenderUnit
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:166
QgsDxfExport
Definition: qgsdxfexport.h:62
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:580
QgsVectorSimplifyMethod::AntialiasingSimplification
@ AntialiasingSimplification
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'.
Definition: qgsvectorsimplifymethod.h:54
QgsSimpleLineSymbolLayer::penCapStyle
Qt::PenCapStyle penCapStyle() const
Returns the pen cap style used to render the line (e.g.
Definition: qgslinesymbollayer.h: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:2115
QgsVertexId::SegmentVertex
@ SegmentVertex
Definition: qgsabstractgeometry.h:1037
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:2203
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:433
QgsMarkerLineSymbolLayer::setColor
void setColor(const QColor &color) override
The fill color.
Definition: qgslinesymbollayer.cpp:1784
QgsLineSymbolLayer::width
virtual double width() const
Returns the estimated width for the line symbol layer.
Definition: qgssymbollayer.h:959
QgsPointXY::project
QgsPointXY project(double distance, double bearing) const
Returns a new point which corresponds to this point projected by a specified distance in a specified ...
Definition: qgspointxy.cpp:87
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:37
QgsTemplatedLineSymbolLayerBase::offsetAlongLineUnit
QgsUnitTypes::RenderUnit offsetAlongLineUnit() const
Returns the unit used for calculating the offset along line for symbols.
Definition: qgslinesymbollayer.h:383
QgsTemplatedLineSymbolLayerBase::properties
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgslinesymbollayer.cpp:949
QgsSymbolLayerUtils::sizeInPixelsFromSldUom
static double sizeInPixelsFromSldUom(const QString &uom, double size)
Returns the size scaled in pixels according to the uom attribute.
Definition: qgssymbollayerutils.cpp:4397
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsSymbolRenderContext::feature
const QgsFeature * feature() const
Returns the current feature being rendered.
Definition: qgssymbol.h:789
qgsexpression.h
QgsHashedLineSymbolLayer
Definition: qgslinesymbollayer.h:656
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:81
QgsSimpleLineSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgslinesymbollayer.cpp:236
DEFAULT_MARKERLINE_ROTATE
#define DEFAULT_MARKERLINE_ROTATE
Definition: qgslinesymbollayer.h:242
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:62
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:1764
QgsSimpleLineSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgslinesymbollayer.cpp:186
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:966
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:34
QgsHashedLineSymbolLayer::properties
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgslinesymbollayer.cpp:2120
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:226
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:1999
QgsMarkerLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:2024
QgsLineSymbolLayer::mWidthMapUnitScale
QgsMapUnitScale mWidthMapUnitScale
Definition: qgssymbollayer.h:1075
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:243
QgsLineSymbolLayer::mRingFilter
RenderRingFilter mRingFilter
Definition: qgssymbollayer.h:1080
QgsMarkerLineSymbolLayer::toSld
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props) const override
Definition: qgslinesymbollayer.cpp:1821
QgsSymbolRenderContext::opacity
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:751
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:2062
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:1428
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:215
QgsHashedLineSymbolLayer::setWidth
void setWidth(double width) override
Sets the width of the line symbol layer.
Definition: qgslinesymbollayer.cpp:2172
QgsSimpleLineSymbolLayer::dxfPenStyle
Qt::PenStyle dxfPenStyle() const override
Gets pen style.
Definition: qgslinesymbollayer.cpp:628
QgsCurvePolygon::exteriorRing
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
Definition: qgscurvepolygon.h:86
QgsLineSymbolLayer::offsetUnit
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units for the line's offset.
Definition: qgssymbollayer.h:1009
QgsTemplatedLineSymbolLayerBase::Vertex
@ Vertex
Place symbols on every vertex in the line.
Definition: qgslinesymbollayer.h:264
QgsRenderContext
Definition: qgsrendercontext.h:57
QgsSymbolLayer::SELECTION_IS_OPAQUE
static const bool SELECTION_IS_OPAQUE
Whether styles for selected features ignore symbol alpha.
Definition: qgssymbollayer.h:531
qgsunittypes.h
QgsHashedLineSymbolLayer::hashAngle
double hashAngle() const
Returns the angle to use when drawing the hashed lines sections, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2271
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:168
QgsMarkerSymbolLayer
Abstract base class for marker symbol layers.
Definition: qgssymbollayer.h:575
QgsSymbolLayer::PropertyInterval
@ PropertyInterval
Line marker interval.
Definition: qgssymbollayer.h:171
QgsTemplatedLineSymbolLayerBase::placement
Placement placement() const
Returns the placement of the symbols.
Definition: qgslinesymbollayer.h:344
QgsSymbolLayer::PropertyCapStyle
@ PropertyCapStyle
Line cap style.
Definition: qgssymbollayer.h:169
QgsLineSymbolLayer::outputUnit
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Definition: qgssymbollayer.cpp:641
QgsSymbolLayerUtils::encodePenStyle
static QString encodePenStyle(Qt::PenStyle style)
Definition: qgssymbollayerutils.cpp:141
QgsSymbol
Definition: qgssymbol.h:63
QgsSimpleLineSymbolLayer::setUseCustomDashPattern
void setUseCustomDashPattern(bool b)
Sets whether the line uses a custom dash pattern.
Definition: qgslinesymbollayer.h:143
QgsMarkerLineSymbolLayer
Definition: qgslinesymbollayer.h:567
QgsMarkerLineSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgslinesymbollayer.cpp:1739
QgsRenderContext::scaleFactor
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:317
QgsSimpleLineSymbolLayer::createFromSld
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsSimpleLineSymbolLayer from an SLD XML DOM element.
Definition: qgslinesymbollayer.cpp:468
QgsTemplatedLineSymbolLayerBase::CurvePoint
@ CurvePoint
Place symbols at every virtual curve point in the line (used when rendering curved geometry types onl...
Definition: qgslinesymbollayer.h:268
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:876
QgsSymbolLayerUtils::encodeRealVector
static QString encodeRealVector(const QVector< qreal > &v)
Definition: qgssymbollayerutils.cpp:655
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:651
QgsSimpleLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:44
QgsLineSymbolLayer::setOffset
void setOffset(double offset)
Sets the line's offset.
Definition: qgssymbollayer.h:993
QgsTemplatedLineSymbolLayerBase::setPlacement
void setPlacement(Placement placement)
Sets the placement of the symbols.
Definition: qgslinesymbollayer.h:350
QgsSimpleLineSymbolLayer::properties
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgslinesymbollayer.cpp:377
QgsCurvePolygon::interiorRing
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
Definition: qgscurvepolygon.h:99
QgsLineSymbolLayer::setOffsetMapUnitScale
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the line's offset.
Definition: qgssymbollayer.h:1017
QgsSymbolLayerUtils::createGeometryElement
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
Definition: qgssymbollayerutils.cpp:2695
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:261
QgsMarkerLineSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgslinesymbollayer.cpp:1795
QgsHashedLineSymbolLayer::setSymbolAngle
void setSymbolAngle(double angle) override
Sets the symbol's angle, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2239
QgsMarkerLineSymbolLayer::QgsMarkerLineSymbolLayer
QgsMarkerLineSymbolLayer(bool rotateMarker=DEFAULT_MARKERLINE_ROTATE, double interval=DEFAULT_MARKERLINE_INTERVAL)
Constructor for QgsMarkerLineSymbolLayer.
Definition: qgslinesymbollayer.cpp:1758
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:764
QgsTemplatedLineSymbolLayerBase::setIntervalMapUnitScale
void setIntervalMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the interval between symbols.
Definition: qgslinesymbollayer.h:330
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:307
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:2211
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:681
QgsSymbolRenderContext::originalGeometryType
QgsWkbTypes::GeometryType originalGeometryType() const
Returns the geometry type for the original feature geometry being rendered.
Definition: qgssymbol.h:806
QgsHashedLineSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgslinesymbollayer.cpp:2159
QgsSimpleLineSymbolLayer::mapUnitScale
QgsMapUnitScale mapUnitScale() const override
Definition: qgslinesymbollayer.cpp:70
QgsLineSymbolLayer::mOffsetUnit
QgsUnitTypes::RenderUnit mOffsetUnit
Definition: qgssymbollayer.h:1077
QgsRenderContext::renderingStopped
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Definition: qgsrendercontext.h:325
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:1994
QgsRenderContext::coordinateTransform
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Definition: qgsrendercontext.h:229
QgsPoint::y
double y
Definition: qgspoint.h:59
QgsSimpleLineSymbolLayer::clone
QgsSimpleLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgslinesymbollayer.cpp:399
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:1985
QgsSymbolLayer
Definition: qgssymbollayer.h:52
QgsMarkerLineSymbolLayer::symbolAngle
double symbolAngle() const override
Returns the symbol's current angle, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:1999
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:269
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:391
QgsMarkerLineSymbolLayer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
Definition: qgslinesymbollayer.cpp:2034
QgsSymbolRenderContext::fields
QgsFields fields() const
Fields of the layer.
Definition: qgssymbol.h:814
QgsSimpleLineSymbolLayer::dxfColor
QColor dxfColor(QgsSymbolRenderContext &context) const override
Gets color.
Definition: qgslinesymbollayer.cpp:650
QgsMarkerSymbol
Definition: qgssymbol.h:917
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:1076
QgsHashedLineSymbolLayer::setHashAngle
void setHashAngle(double angle)
Sets the angle to use when drawing the hashed lines sections, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2276
QgsLineSymbolLayer::setOffsetUnit
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the line's offset.
Definition: qgssymbollayer.h:1001
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:457
QgsSimpleLineSymbolLayer
Definition: qgslinesymbollayer.h:39
QgsTemplatedLineSymbolLayerBase::intervalMapUnitScale
const QgsMapUnitScale & intervalMapUnitScale() const
Returns the map unit scale for the interval between symbols.
Definition: qgslinesymbollayer.h:338
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:4262
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:1015
QgsLineSymbolLayer::mWidthUnit
QgsUnitTypes::RenderUnit mWidthUnit
Definition: qgssymbollayer.h:1074
QgsSymbolLayer::copyPaintEffect
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
Definition: qgssymbollayer.cpp:406
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:453
qgsrendercontext.h
QgsTemplatedLineSymbolLayerBase::interval
double interval() const
Returns the interval between individual symbols.
Definition: qgslinesymbollayer.h:299
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:362
QgsLineSymbol
Definition: qgssymbol.h:1117
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:217
QgsMarkerLineSymbolLayer::color
QColor color() const override
The fill color.
Definition: qgslinesymbollayer.cpp:1790
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:758
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:397
QgsLineSymbolLayer::mWidth
double mWidth
Definition: qgssymbollayer.h:1073
QgsTemplatedLineSymbolLayerBase::Interval
@ Interval
Place symbols at regular intervals.
Definition: qgslinesymbollayer.h:263
QgsHashedLineSymbolLayer::symbolAngle
double symbolAngle() const override
Returns the symbol's current angle, in degrees clockwise.
Definition: qgslinesymbollayer.cpp:2234
QgsVectorSimplifyMethod::threshold
float threshold() const
Gets the simplification threshold of the vector layer managed.
Definition: qgsvectorsimplifymethod.h:89
QgsSimpleLineSymbolLayer::renderPolyline
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
Definition: qgslinesymbollayer.cpp:311
QgsSymbolLayerUtils::createVendorOptionElement
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
Definition: qgssymbollayerutils.cpp:2887
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:2004
QgsMapUnitScale
Struct for storing maximum and minimum scales for measurements in map units.
Definition: qgsmapunitscale.h:37
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:2244
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:920
QgsHashedLineSymbolLayer::clone
QgsHashedLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgslinesymbollayer.cpp:2132
QgsSimpleLineSymbolLayer::dxfWidth
double dxfWidth(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets line width.
Definition: qgslinesymbollayer.cpp:633
QgsTemplatedLineSymbolLayerBase
Definition: qgslinesymbollayer.h:254
QgsMarkerLineSymbolLayer::subSymbol
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
Definition: qgslinesymbollayer.cpp:1734
QgsMarkerLineSymbolLayer::setWidth
void setWidth(double width) override
Sets the width of the line symbol layer.
Definition: qgslinesymbollayer.cpp:1980
QgsSymbolLayer::mDataDefinedProperties
QgsPropertyCollection mDataDefinedProperties
Definition: qgssymbollayer.h:524
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:2187
qgscurvepolygon.h
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:241
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:2611
QgsSymbolLayer::subSymbol
virtual QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
Definition: qgssymbollayer.h:348
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:403
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:111
QgsVertexId::type
VertexType type
Definition: qgsabstractgeometry.h:1083
QgsLineSymbolLayer::InteriorRingsOnly
@ InteriorRingsOnly
Render the interior rings only.
Definition: qgssymbollayer.h:903
QgsRenderContext::vectorSimplifyMethod
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Returns the simplification settings to use when rendering vector layers.
Definition: qgsrendercontext.h:549
QgsTemplatedLineSymbolLayerBase::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) FINAL
Definition: qgslinesymbollayer.cpp:930
QgsSymbolLayer::usedAttributes
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the set of attributes referenced by the layer.
Definition: qgssymbollayer.cpp:246
QgsHashedLineSymbolLayer::setColor
void setColor(const QColor &color) override
The fill color.
Definition: qgslinesymbollayer.cpp:2143
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:427
QgsSymbolLayer::PropertyOffsetAlongLine
@ PropertyOffsetAlongLine
Offset along line.
Definition: qgssymbollayer.h:172
qgsvectorlayer.h
QgsPointXY
Definition: qgspointxy.h:43
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:2177
QgsHashedLineSymbolLayer::setDataDefinedProperty
void setDataDefinedProperty(QgsSymbolLayer::Property key, const QgsProperty &property) override
Sets a data defined property for the layer.
Definition: qgslinesymbollayer.cpp:2220
QgsRenderContext::selectionColor
QColor selectionColor() const
Returns the color to use when rendering selected features.
Definition: qgsrendercontext.h:374
QgsHashedLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgslinesymbollayer.cpp:2194
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:420
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:142
QgsStringMap
QMap< QString, QString > QgsStringMap
Definition: qgis.h:714
qgslinesymbollayer.h
QgsRenderContext::geometry
const QgsAbstractGeometry * geometry() const
Returns pointer to the unsegmentized geometry.
Definition: qgsrendercontext.h:592
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:218
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
Definition: qgsmaptopixel.h:37
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:2042
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:2051
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:876
QgsSymbolLayerUtils::getVendorOptionList
static QgsStringMap getVendorOptionList(QDomElement &element)
Definition: qgssymbollayerutils.cpp:2895
QgsSymbolLayerList
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:53
QgsLineSymbolLayer::mOffsetMapUnitScale
QgsMapUnitScale mOffsetMapUnitScale
Definition: qgssymbollayer.h:1078
QgsPointXY::x
double x
Definition: qgspointxy.h:47
QgsTemplatedLineSymbolLayerBase::LastVertex
@ LastVertex
Place symbols on the last vertex in the line.
Definition: qgslinesymbollayer.h:265
QgsVertexId
Utility class for identifying a unique vertex within a geometry.
Definition: qgsabstractgeometry.h:1033
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:286
QgsHashedLineSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgslinesymbollayer.cpp:2097
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:660
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:636
QgsLineSymbolLayer::AllRings
@ AllRings
Render both exterior and interior rings.
Definition: qgssymbollayer.h:901
QgsWkbTypes::UnknownGeometry
@ UnknownGeometry
Definition: qgswkbtypes.h:144
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:2068
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:799
QgsSymbolLayer::restoreOldDataDefinedProperties
void restoreOldDataDefinedProperties(const QgsStringMap &stringMap)
Restores older data defined properties from string map.
Definition: qgssymbollayer.cpp:277
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:2009
QgsSymbolLayerUtils::decodePenJoinStyle
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:188
QgsSymbolLayer::Property
Property
Data definable properties.
Definition: qgssymbollayer.h:130
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:191
QgsVectorSimplifyMethod::simplifyHints
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
Definition: qgsvectorsimplifymethod.h:64
QgsSymbolLayer::layerType
virtual QString layerType() const =0
Returns a string that represents this layer type.
QgsRenderContext::RenderSymbolPreview
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
Definition: qgsrendercontext.h:82
QgsSymbolLayerUtils::encodePenJoinStyle
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
Definition: qgssymbollayerutils.cpp:173
QgsFeature
Definition: qgsfeature.h:55
QgsMarkerLineSymbolLayer::mMarker
std::unique_ptr< QgsMarkerSymbol > mMarker
Definition: qgslinesymbollayer.h:631
QgsSymbolRenderContext::renderContext
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgssymbol.h:708
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:1043
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:608
QgsLineSymbolLayer::offset
double offset() const
Returns the line's offset.
Definition: qgssymbollayer.h:982
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:266
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:2083
QgsTemplatedLineSymbolLayerBase::intervalUnit
QgsUnitTypes::RenderUnit intervalUnit() const
Returns the units for the interval between symbols.
Definition: qgslinesymbollayer.h:322
qgslogger.h
QgsLineSymbolLayer::widthUnit
QgsUnitTypes::RenderUnit widthUnit() const
Returns the units for the line's width.
Definition: qgssymbollayer.h:1041
QgsLineSymbolLayer::ExteriorRingOnly
@ ExteriorRingOnly
Render the exterior ring only.
Definition: qgssymbollayer.h:902
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:174
QgsRenderContext::setGeometry
void setGeometry(const QgsAbstractGeometry *geometry)
Sets pointer to original (unsegmentized) geometry.
Definition: qgsrendercontext.h:594
QgsHashedLineSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgslinesymbollayer.cpp:2102
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:118
QgsTemplatedLineSymbolLayerBase::QgsTemplatedLineSymbolLayerBase
QgsTemplatedLineSymbolLayerBase(bool rotateSymbol=true, double interval=3)
Constructor for QgsTemplatedLineSymbolLayerBase.
Definition: qgslinesymbollayer.cpp:751
QgsSymbolLayerUtils::decodePenStyle
static Qt::PenStyle decodePenStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:162
QgsVertexId::CurveVertex
@ CurveVertex
Definition: qgsabstractgeometry.h:1038
QgsPropertyCollection::isActive
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
Definition: qgspropertycollection.cpp:258
QgsCoordinateTransform
Definition: qgscoordinatetransform.h:52
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:36
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:2154
QgsSymbolLayer::copyDataDefinedProperties
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
Definition: qgssymbollayer.cpp:398
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:52
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:267
QgsPoint::x
double x
Definition: qgspoint.h:58
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:437
QgsMarkerLineSymbolLayer::rotateMarker
Q_DECL_DEPRECATED bool rotateMarker() const
Shall the marker be rotated.
Definition: qgslinesymbollayer.h:621
QgsSymbolLayerUtils::decodeMapUnitScale
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Definition: qgssymbollayerutils.cpp:568
QgsLineSymbolLayer::setMapUnitScale
void setMapUnitScale(const QgsMapUnitScale &scale) override
Definition: qgssymbollayer.cpp:646
QgsSymbolLayer::setDataDefinedProperty
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
Definition: qgssymbollayer.cpp:112
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:2149
QgsMarkerLineSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgslinesymbollayer.cpp:1808
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:2738
QgsRenderContext::flags
Flags flags() const
Returns combination of flags used for rendering.
Definition: qgsrendercontext.cpp:160
QgsTemplatedLineSymbolLayerBase::setIntervalUnit
void setIntervalUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the interval between symbols.
Definition: qgslinesymbollayer.h:315
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