1 /***************************************************************************
2  qgslinesymbollayer.h
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 #ifndef QGSLINESYMBOLLAYER_H
17 #define QGSLINESYMBOLLAYER_H
18 
19 #include "qgis_core.h"
20 #include "qgis.h"
21 #include "qgssymbollayer.h"
22 
23 #include <QPen>
24 #include <QVector>
25 
26 class QgsExpression;
27 class QgsMarkerSymbol;
28 class QgsLineSymbol;
29 
30 #define DEFAULT_SIMPLELINE_COLOR     QColor(35,35,35)
31 #define DEFAULT_SIMPLELINE_WIDTH     DEFAULT_LINE_WIDTH
32 #define DEFAULT_SIMPLELINE_PENSTYLE  Qt::SolidLine
33 #define DEFAULT_SIMPLELINE_JOINSTYLE Qt::BevelJoin
34 #define DEFAULT_SIMPLELINE_CAPSTYLE  Qt::SquareCap
35 
36 /**
37  * \ingroup core
38  * \class QgsSimpleLineSymbolLayer
39  * \brief A simple line symbol layer, which renders lines using a line in a variety of styles (e.g. solid, dotted, dashed).
40  */
41 class CORE_EXPORT QgsSimpleLineSymbolLayer : public QgsLineSymbolLayer
42 {
43   public:
44 
45     /**
46      * Constructor for QgsSimpleLineSymbolLayer. Creates a simple line
47      * symbol in the specified \a color, \a width (in millimeters)
48      * and \a penStyle.
49      */
50     QgsSimpleLineSymbolLayer( const QColor &color = DEFAULT_SIMPLELINE_COLOR,
51                               double width = DEFAULT_SIMPLELINE_WIDTH,
52                               Qt::PenStyle penStyle = DEFAULT_SIMPLELINE_PENSTYLE );
53 
54     ~QgsSimpleLineSymbolLayer() override;
55 
56     // static stuff
57 
58     /**
59      * Creates a new QgsSimpleLineSymbolLayer, using the settings
60      * serialized in the \a properties map (corresponding to the output from
61      * QgsSimpleLineSymbolLayer::properties() ).
62      */
63     static QgsSymbolLayer *create( const QVariantMap &properties = QVariantMap() ) SIP_FACTORY;
64 
65     /**
66      * Creates a new QgsSimpleLineSymbolLayer from an SLD XML DOM \a element.
67      */
68     static QgsSymbolLayer *createFromSld( QDomElement &element ) SIP_FACTORY;
69 
70     QString layerType() const override;
71     void startRender( QgsSymbolRenderContext &context ) override;
72     void stopRender( QgsSymbolRenderContext &context ) override;
73     void renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context ) override;
74     //overridden so that clip path can be set when using draw inside polygon option
75     void renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
76     QVariantMap properties() const override;
77     QgsSimpleLineSymbolLayer *clone() const override SIP_FACTORY;
78     void toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const override;
79     QString ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const override;
80     void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override;
81     QgsUnitTypes::RenderUnit outputUnit() const override;
82     bool usesMapUnits() const override;
83     void setMapUnitScale( const QgsMapUnitScale &scale ) override;
84     QgsMapUnitScale mapUnitScale() const override;
85     double estimateMaxBleed( const QgsRenderContext &context ) const override;
86     QVector<qreal> dxfCustomDashPattern( QgsUnitTypes::RenderUnit &unit ) const override;
87     Qt::PenStyle dxfPenStyle() const override;
88     double dxfWidth( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const override;
89     double dxfOffset( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const override;
90     QColor dxfColor( QgsSymbolRenderContext &context ) const override;
91     bool canCauseArtifactsBetweenAdjacentTiles() const override;
92 
93     /**
94      * Returns the pen style used to render the line (e.g. solid, dashed, etc).
95      *
96      * \see setPenStyle()
97      */
penStyle()98     Qt::PenStyle penStyle() const { return mPenStyle; }
99 
100     /**
101      * Sets the pen \a style used to render the line (e.g. solid, dashed, etc).
102      *
103      * \see penStyle()
104      */
setPenStyle(Qt::PenStyle style)105     void setPenStyle( Qt::PenStyle style ) { mPenStyle = style; }
106 
107     /**
108      * Returns the pen join style used to render the line (e.g. miter, bevel, round, etc).
109      *
110      * \see setPenJoinStyle()
111      */
penJoinStyle()112     Qt::PenJoinStyle penJoinStyle() const { return mPenJoinStyle; }
113 
114     /**
115      * Sets the pen join \a style used to render the line (e.g. miter, bevel, round, etc).
116      *
117      * \see penJoinStyle()
118      */
setPenJoinStyle(Qt::PenJoinStyle style)119     void setPenJoinStyle( Qt::PenJoinStyle style ) { mPenJoinStyle = style; }
120 
121     /**
122      * Returns the pen cap style used to render the line (e.g. flat, square, round, etc).
123      *
124      * \see setPenCapStyle()
125      */
penCapStyle()126     Qt::PenCapStyle penCapStyle() const { return mPenCapStyle; }
127 
128     /**
129      * Sets the pen cap \a style used to render the line (e.g. flat, square, round, etc).
130      *
131      * \see penCapStyle()
132      */
setPenCapStyle(Qt::PenCapStyle style)133     void setPenCapStyle( Qt::PenCapStyle style ) { mPenCapStyle = style; }
134 
135     /**
136      * Returns TRUE if the line uses a custom dash pattern.
137      * \see setUseCustomDashPattern()
138      * \see customDashPatternUnit()
139      * \see customDashVector()
140      */
useCustomDashPattern()141     bool useCustomDashPattern() const { return mUseCustomDashPattern; }
142 
143     /**
144      * Sets whether the line uses a custom dash pattern.
145      * \see useCustomDashPattern()
146      * \see setCustomDashPatternUnit()
147      * \see setCustomDashVector()
148      */
setUseCustomDashPattern(bool b)149     void setUseCustomDashPattern( bool b ) { mUseCustomDashPattern = b; }
150 
151     /**
152      * Sets the \a unit for lengths used in the custom dash pattern.
153      * \see customDashPatternUnit()
154     */
setCustomDashPatternUnit(QgsUnitTypes::RenderUnit unit)155     void setCustomDashPatternUnit( QgsUnitTypes::RenderUnit unit ) { mCustomDashPatternUnit = unit; }
156 
157     /**
158      * Returns the units for lengths used in the custom dash pattern.
159      * \see setCustomDashPatternUnit()
160     */
customDashPatternUnit()161     QgsUnitTypes::RenderUnit customDashPatternUnit() const { return mCustomDashPatternUnit; }
162 
163     /**
164      * Returns the map unit scale for lengths used in the custom dash pattern.
165      * \see setCustomDashPatternMapUnitScale()
166     */
customDashPatternMapUnitScale()167     const QgsMapUnitScale &customDashPatternMapUnitScale() const { return mCustomDashPatternMapUnitScale; }
168 
169     /**
170      * Sets the map unit \a scale for lengths used in the custom dash pattern.
171      * \see customDashPatternMapUnitScale()
172     */
setCustomDashPatternMapUnitScale(const QgsMapUnitScale & scale)173     void setCustomDashPatternMapUnitScale( const QgsMapUnitScale &scale ) { mCustomDashPatternMapUnitScale = scale; }
174 
175     /**
176      * Returns the custom dash vector, which is the pattern of alternating drawn/skipped lengths
177      * used while rendering a custom dash pattern.
178      *
179      * Units for the vector are specified by customDashPatternUnit()
180      *
181      * This setting is only used when useCustomDashPattern() returns TRUE.
182      *
183      * \see setCustomDashVector()
184      * \see customDashPatternUnit()
185      * \see useCustomDashPattern()
186      */
customDashVector()187     QVector<qreal> customDashVector() const { return mCustomDashVector; }
188 
189     /**
190      * Sets the custom dash \a vector, which is the pattern of alternating drawn/skipped lengths
191      * used while rendering a custom dash pattern.
192      *
193      * Units for the vector are specified by customDashPatternUnit()
194      *
195      * This setting is only used when useCustomDashPattern() returns TRUE.
196      *
197      * \see customDashVector()
198      * \see setCustomDashPatternUnit()
199      * \see setUseCustomDashPattern()
200      */
setCustomDashVector(const QVector<qreal> & vector)201     void setCustomDashVector( const QVector<qreal> &vector ) { mCustomDashVector = vector; }
202 
203     /**
204      * Returns the dash pattern offset, which dictates how far along the dash pattern
205      * the pattern should start rendering at.
206      *
207      * Offset units can be retrieved by calling dashPatternOffsetUnit().
208      *
209      * \see setDashPatternOffset()
210      * \see dashPatternOffsetUnit()
211      * \see dashPatternOffsetMapUnitScale()
212      *
213      * \since QGIS 3.16
214      */
dashPatternOffset()215     double dashPatternOffset() const { return mDashPatternOffset; }
216 
217     /**
218      * Sets the dash pattern \a offset, which dictates how far along the dash pattern
219      * the pattern should start rendering at.
220      *
221      * Offset units are set via setDashPatternOffsetUnit().
222      *
223      * \see dashPatternOffset()
224      * \see setDashPatternOffsetUnit()
225      * \see setDashPatternOffsetMapUnitScale()
226      *
227      * \since QGIS 3.16
228      */
setDashPatternOffset(double offset)229     void setDashPatternOffset( double offset ) { mDashPatternOffset = offset; }
230 
231     /**
232      * Sets the \a unit for the dash pattern offset.
233      *
234      * \see dashPatternOffsetUnit()
235      * \see setDashPatternOffset()
236      * \see setDashPatternOffsetMapUnitScale()
237      *
238      * \since QGIS 3.16
239     */
setDashPatternOffsetUnit(QgsUnitTypes::RenderUnit unit)240     void setDashPatternOffsetUnit( QgsUnitTypes::RenderUnit unit ) { mDashPatternOffsetUnit = unit; }
241 
242     /**
243      * Returns the units for the dash pattern offset.
244      *
245      * \see setDashPatternOffsetUnit()
246      * \see dashPatternOffset()
247      * \see dashPatternOffsetMapUnitScale()
248      *
249      * \since QGIS 3.16
250     */
dashPatternOffsetUnit()251     QgsUnitTypes::RenderUnit dashPatternOffsetUnit() const { return mDashPatternOffsetUnit; }
252 
253     /**
254      * Returns the map unit scale for the dash pattern offset value.
255      *
256      * \see setDashPatternOffsetMapUnitScale()
257      * \see dashPatternOffsetUnit()
258      * \see dashPatternOffset()
259      *
260      * \since QGIS 3.16
261     */
dashPatternOffsetMapUnitScale()262     const QgsMapUnitScale &dashPatternOffsetMapUnitScale() const { return mDashPatternOffsetMapUnitScale; }
263 
264     /**
265      * Sets the map unit \a scale for the dash pattern offset.
266      *
267      * \see dashPatternOffsetMapUnitScale()
268      * \see setDashPatternOffset()
269      * \see setDashPatternOffsetUnit()
270      *
271      * \since QGIS 3.16
272     */
setDashPatternOffsetMapUnitScale(const QgsMapUnitScale & scale)273     void setDashPatternOffsetMapUnitScale( const QgsMapUnitScale &scale ) { mDashPatternOffsetMapUnitScale = scale; }
274 
275     /**
276      * Returns the trim distance for the start of the line, which dictates a length
277      * from the start of the line at which the actual rendering should start.
278      *
279      * Trim units can be retrieved by calling trimDistanceStartUnit().
280      *
281      * \see setTrimDistanceStart()
282      * \see trimDistanceEnd()
283      * \see trimDistanceStartUnit()
284      * \see trimDistanceStartMapUnitScale()
285      *
286      * \since QGIS 3.20
287      */
trimDistanceStart()288     double trimDistanceStart() const { return mTrimDistanceStart; }
289 
290     /**
291      * Sets the trim \a distance for the start of the line, which dictates a length
292      * from the start of the line at which the actual rendering should start.
293      *
294      * Trim units can be set by calling setTrimDistanceStartUnit().
295      *
296      * \see trimDistanceStart()
297      * \see setTrimDistanceEnd()
298      * \see setTrimDistanceStartUnit()
299      * \see setTrimDistanceStartMapUnitScale()
300      *
301      * \since QGIS 3.20
302      */
setTrimDistanceStart(double distance)303     void setTrimDistanceStart( double distance ) { mTrimDistanceStart = distance; }
304 
305     /**
306      * Sets the \a unit for the trim distance for the start of the line.
307      *
308      * \see trimDistanceStartUnit()
309      * \see setTrimDistanceEndUnit()
310      * \see setTrimDistanceStart()
311      * \see setTrimDistanceStartMapUnitScale()
312      *
313      * \since QGIS 3.20
314     */
setTrimDistanceStartUnit(QgsUnitTypes::RenderUnit unit)315     void setTrimDistanceStartUnit( QgsUnitTypes::RenderUnit unit ) { mTrimDistanceStartUnit = unit; }
316 
317     /**
318      * Returns the unit for the trim distance for the start of the line.
319      *
320      * \see setTrimDistanceStartUnit()
321      * \see trimDistanceEndUnit()
322      * \see trimDistanceStart()
323      * \see trimDistanceStartMapUnitScale()
324      *
325      * \since QGIS 3.20
326     */
trimDistanceStartUnit()327     QgsUnitTypes::RenderUnit trimDistanceStartUnit() const { return mTrimDistanceStartUnit; }
328 
329     /**
330      * Returns the map unit scale for the trim distance for the start of the line.
331      *
332      * \see setTrimDistanceStartMapUnitScale()
333      * \see trimDistanceEndMapUnitScale()
334      * \see trimDistanceStart()
335      * \see trimDistanceStartUnit()
336      *
337      * \since QGIS 3.20
338     */
trimDistanceStartMapUnitScale()339     const QgsMapUnitScale &trimDistanceStartMapUnitScale() const { return mTrimDistanceStartMapUnitScale; }
340 
341     /**
342      * Sets the map unit \a scale for the trim distance for the start of the line.
343      *
344      * \see trimDistanceStartMapUnitScale()
345      * \see setTrimDistanceEndMapUnitScale()
346      * \see setTrimDistanceStart()
347      * \see setTrimDistanceStartUnit()
348      *
349      * \since QGIS 3.20
350     */
setTrimDistanceStartMapUnitScale(const QgsMapUnitScale & scale)351     void setTrimDistanceStartMapUnitScale( const QgsMapUnitScale &scale ) { mTrimDistanceStartMapUnitScale = scale; }
352 
353     /**
354      * Returns the trim distance for the end of the line, which dictates a length
355      * from the end of the line at which the actual rendering should end.
356      *
357      * Trim units can be retrieved by calling trimDistanceEndUnit().
358      *
359      * \see setTrimDistanceEnd()
360      * \see trimDistanceStart()
361      * \see trimDistanceEndUnit()
362      * \see trimDistanceEndMapUnitScale()
363      *
364      * \since QGIS 3.20
365      */
trimDistanceEnd()366     double trimDistanceEnd() const { return mTrimDistanceEnd; }
367 
368     /**
369      * Sets the trim \a distance for the end of the line, which dictates a length
370      * from the end of the line at which the actual rendering should end.
371      *
372      * Trim units can be set by calling setTrimDistanceEndUnit().
373      *
374      * \see trimDistanceEnd()
375      * \see setTrimDistanceStart()
376      * \see setTrimDistanceEndUnit()
377      * \see setTrimDistanceEndMapUnitScale()
378      *
379      * \since QGIS 3.20
380      */
setTrimDistanceEnd(double distance)381     void setTrimDistanceEnd( double distance ) { mTrimDistanceEnd = distance; }
382 
383     /**
384      * Sets the \a unit for the trim distance for the end of the line.
385      *
386      * \see trimDistanceEndUnit()
387      * \see setTrimDistanceStartUnit()
388      * \see setTrimDistanceEnd()
389      * \see setTrimDistanceEndMapUnitScale()
390      *
391      * \since QGIS 3.20
392     */
setTrimDistanceEndUnit(QgsUnitTypes::RenderUnit unit)393     void setTrimDistanceEndUnit( QgsUnitTypes::RenderUnit unit ) { mTrimDistanceEndUnit = unit; }
394 
395     /**
396      * Returns the unit for the trim distance for the end of the line.
397      *
398      * \see setTrimDistanceEndUnit()
399      * \see trimDistanceStartUnit()
400      * \see trimDistanceEnd()
401      * \see trimDistanceEndMapUnitScale()
402      *
403      * \since QGIS 3.20
404     */
trimDistanceEndUnit()405     QgsUnitTypes::RenderUnit trimDistanceEndUnit() const { return mTrimDistanceEndUnit; }
406 
407     /**
408      * Returns the map unit scale for the trim distance for the end of the line.
409      *
410      * \see setTrimDistanceEndMapUnitScale()
411      * \see trimDistanceStartMapUnitScale()
412      * \see trimDistanceEnd()
413      * \see trimDistanceEndUnit()
414      *
415      * \since QGIS 3.20
416     */
trimDistanceEndMapUnitScale()417     const QgsMapUnitScale &trimDistanceEndMapUnitScale() const { return mTrimDistanceEndMapUnitScale; }
418 
419     /**
420      * Sets the map unit \a scale for the trim distance for the end of the line.
421      *
422      * \see trimDistanceEndMapUnitScale()
423      * \see setTrimDistanceStartMapUnitScale()
424      * \see setTrimDistanceEnd()
425      * \see setTrimDistanceEndUnit()
426      *
427      * \since QGIS 3.20
428     */
setTrimDistanceEndMapUnitScale(const QgsMapUnitScale & scale)429     void setTrimDistanceEndMapUnitScale( const QgsMapUnitScale &scale ) { mTrimDistanceEndMapUnitScale = scale; }
430 
431     /**
432      * Returns TRUE if the line should only be drawn inside polygons, and any portion
433      * of the line which falls outside the polygon should be clipped away.
434      *
435      * This setting only has an effect when the line symbol is being
436      * used to render polygon rings.
437      *
438      * \see setDrawInsidePolygon()
439      */
drawInsidePolygon()440     bool drawInsidePolygon() const { return mDrawInsidePolygon; }
441 
442     /**
443      * Sets whether the line should only be drawn inside polygons, and any portion
444      * of the line which falls outside the polygon should be clipped away.
445      *
446      * This setting only has an effect when the line symbol is being
447      * used to render polygon rings.
448      *
449      * \see drawInsidePolygon()
450      */
setDrawInsidePolygon(bool drawInsidePolygon)451     void setDrawInsidePolygon( bool drawInsidePolygon ) { mDrawInsidePolygon = drawInsidePolygon; }
452 
453     /**
454      * Returns TRUE if dash patterns should be aligned to the start and end of lines, by
455      * applying subtle tweaks to the pattern sizing in order to ensure that the end of
456      * a line is represented by a complete dash element.
457      *
458      * \see setAlignDashPattern()
459      * \see tweakDashPatternOnCorners()
460      * \since QGIS 3.16
461      */
462     bool alignDashPattern() const;
463 
464     /**
465      * Sets whether dash patterns should be aligned to the start and end of lines, by
466      * applying subtle tweaks to the pattern sizing in order to ensure that the end of
467      * a line is represented by a complete dash element.
468      *
469      * \see alignDashPattern()
470      * \see setTweakDashPatternOnCorners()
471      * \since QGIS 3.16
472      */
473     void setAlignDashPattern( bool enabled );
474 
475     /**
476      * Returns TRUE if dash patterns tweaks should be applied on sharp corners, to ensure
477      * that a double-length dash is drawn running into and out of the corner.
478      *
479      * \note This setting is only applied if alignDashPattern() is TRUE.
480      *
481      * \see setTweakDashPatternOnCorners()
482      * \see alignDashPattern()
483      * \since QGIS 3.16
484      */
485     bool tweakDashPatternOnCorners() const;
486 
487     /**
488      * Sets whether dash patterns tweaks should be applied on sharp corners, to ensure
489      * that a double-length dash is drawn running into and out of the corner.
490      *
491      * \note This setting is only applied if alignDashPattern() is TRUE.
492      *
493      * \see tweakDashPatternOnCorners()
494      * \see setAlignDashPattern()
495      * \since QGIS 3.16
496      */
497     void setTweakDashPatternOnCorners( bool enabled );
498 
499   private:
500 
501     Qt::PenStyle mPenStyle = Qt::SolidLine;
502     Qt::PenJoinStyle mPenJoinStyle = DEFAULT_SIMPLELINE_JOINSTYLE;
503     Qt::PenCapStyle mPenCapStyle = DEFAULT_SIMPLELINE_CAPSTYLE;
504     QPen mPen;
505     QPen mSelPen;
506 
507     bool mUseCustomDashPattern = false;
508     QgsUnitTypes::RenderUnit mCustomDashPatternUnit = QgsUnitTypes::RenderMillimeters;
509     QgsMapUnitScale mCustomDashPatternMapUnitScale;
510 
511     double mDashPatternOffset = 0;
512     QgsUnitTypes::RenderUnit mDashPatternOffsetUnit = QgsUnitTypes::RenderMillimeters;
513     QgsMapUnitScale mDashPatternOffsetMapUnitScale;
514 
515     double mTrimDistanceStart = 0;
516     QgsUnitTypes::RenderUnit mTrimDistanceStartUnit = QgsUnitTypes::RenderMillimeters;
517     QgsMapUnitScale mTrimDistanceStartMapUnitScale;
518 
519     double mTrimDistanceEnd = 0;
520     QgsUnitTypes::RenderUnit mTrimDistanceEndUnit = QgsUnitTypes::RenderMillimeters;
521     QgsMapUnitScale mTrimDistanceEndMapUnitScale;
522 
523     //! Vector with an even number of entries for the
524     QVector<qreal> mCustomDashVector;
525 
526     bool mAlignDashPattern = false;
527     bool mPatternCartographicTweakOnSharpCorners = false;
528 
529     bool mDrawInsidePolygon = false;
530 
531     //helper functions for data defined symbology
532     void applyDataDefinedSymbology( QgsSymbolRenderContext &context, QPen &pen, QPen &selPen, double &offset );
533     void drawPathWithDashPatternTweaks( QPainter *painter, const QPolygonF &points, QPen pen ) const;
534 };
535 
536 /////////
537 
538 #define DEFAULT_MARKERLINE_ROTATE     true
539 #define DEFAULT_MARKERLINE_INTERVAL   3
540 
541 /**
542  * \ingroup core
543  * \class QgsTemplatedLineSymbolLayerBase
544  *
545  * \brief Base class for templated line symbols, e.g. line symbols which draw markers or hash
546  * lines at intervals along the line feature.
547  *
548  * \since QGIS 3.8
549  */
550 class CORE_EXPORT QgsTemplatedLineSymbolLayerBase : public QgsLineSymbolLayer
551 {
552   public:
553 
554     /**
555      * Defines how/where the templated symbol should be placed on the line.
556      */
557     enum Placement
558     {
559       Interval, //!< Place symbols at regular intervals
560       Vertex, //!< Place symbols on every vertex in the line
561       LastVertex, //!< Place symbols on the last vertex in the line
562       FirstVertex, //!< Place symbols on the first vertex in the line
563       CentralPoint, //!< Place symbols at the mid point of the line
564       CurvePoint, //!< Place symbols at every virtual curve point in the line (used when rendering curved geometry types only)
565       SegmentCenter, //!< Place symbols at the center of every line segment
566     };
567 
568     /**
569      * Constructor for QgsTemplatedLineSymbolLayerBase. Creates a template
570      * line placed at the specified \a interval (in millimeters).
571      *
572      * The \a rotateSymbol argument specifies whether individual symbols
573      * should be rotated to match the line segment alignment.
574      */
575     QgsTemplatedLineSymbolLayerBase( bool rotateSymbol = true,
576                                      double interval = 3 );
577 
578     ~QgsTemplatedLineSymbolLayerBase() override;
579 
580     /**
581      * Returns TRUE if the repeating symbols be rotated to match their line segment orientation.
582      * \see setRotateSymbols()
583      */
rotateSymbols()584     bool rotateSymbols() const { return mRotateSymbols; }
585 
586     /**
587      * Sets whether the repeating symbols should be rotated to match their line segment orientation.
588      * \see rotateSymbols()
589      */
setRotateSymbols(bool rotate)590     void setRotateSymbols( bool rotate ) { mRotateSymbols = rotate; }
591 
592     /**
593      * Returns the interval between individual symbols. Units are specified through intervalUnits().
594      * \see setInterval()
595      * \see intervalUnit()
596      */
interval()597     double interval() const { return mInterval; }
598 
599     /**
600      * Sets the interval between individual symbols.
601      * \param interval interval size. Units are specified through setIntervalUnit()
602      * \see interval()
603      * \see setIntervalUnit()
604      */
setInterval(double interval)605     void setInterval( double interval ) { mInterval = interval; }
606 
607     /**
608      * Sets the units for the interval between symbols.
609      * \param unit interval units
610      * \see intervalUnit()
611      * \see setInterval()
612     */
setIntervalUnit(QgsUnitTypes::RenderUnit unit)613     void setIntervalUnit( QgsUnitTypes::RenderUnit unit ) { mIntervalUnit = unit; }
614 
615     /**
616      * Returns the units for the interval between symbols.
617      * \see setIntervalUnit()
618      * \see interval()
619     */
intervalUnit()620     QgsUnitTypes::RenderUnit intervalUnit() const { return mIntervalUnit; }
621 
622     /**
623      * Sets the map unit \a scale for the interval between symbols.
624      * \see intervalMapUnitScale()
625      * \see setIntervalUnit()
626      * \see setInterval()
627      */
setIntervalMapUnitScale(const QgsMapUnitScale & scale)628     void setIntervalMapUnitScale( const QgsMapUnitScale &scale ) { mIntervalMapUnitScale = scale; }
629 
630     /**
631      * Returns the map unit scale for the interval between symbols.
632      * \see setIntervalMapUnitScale()
633      * \see intervalUnit()
634      * \see interval()
635      */
intervalMapUnitScale()636     const QgsMapUnitScale &intervalMapUnitScale() const { return mIntervalMapUnitScale; }
637 
638     /**
639      * Returns the placement of the symbols.
640      * \see setPlacement()
641      */
placement()642     Placement placement() const { return mPlacement; }
643 
644     /**
645      * Sets the \a placement of the symbols.
646      * \see placement()
647      */
setPlacement(Placement placement)648     void setPlacement( Placement placement ) { mPlacement = placement; }
649 
650     /**
651      * Returns the offset along the line for the symbol placement. For Interval placements, this is the distance
652      * between the start of the line and the first symbol. For FirstVertex and LastVertex placements, this is the
653      * distance between the symbol and the start of the line or the end of the line respectively.
654      * This setting has no effect for Vertex or CentralPoint placements.
655      * \returns The offset along the line. The unit for the offset is retrievable via offsetAlongLineUnit.
656      * \see setOffsetAlongLine()
657      * \see offsetAlongLineUnit()
658      * \see placement()
659      */
offsetAlongLine()660     double offsetAlongLine() const { return mOffsetAlongLine; }
661 
662     /**
663      * Sets the the offset along the line for the symbol placement. For Interval placements, this is the distance
664      * between the start of the line and the first symbol. For FirstVertex and LastVertex placements, this is the
665      * distance between the symbol and the start of the line or the end of the line respectively.
666      * This setting has no effect for Vertex or CentralPoint placements.
667      * \param offsetAlongLine Distance to offset markers along the line. The offset
668      * unit is set via setOffsetAlongLineUnit.
669      * \see offsetAlongLine()
670      * \see setOffsetAlongLineUnit()
671      * \see setPlacement()
672      */
setOffsetAlongLine(double offsetAlongLine)673     void setOffsetAlongLine( double offsetAlongLine ) { mOffsetAlongLine = offsetAlongLine; }
674 
675     /**
676      * Returns the unit used for calculating the offset along line for symbols.
677      * \returns Offset along line unit type.
678      * \see setOffsetAlongLineUnit()
679      * \see offsetAlongLine()
680      */
offsetAlongLineUnit()681     QgsUnitTypes::RenderUnit offsetAlongLineUnit() const { return mOffsetAlongLineUnit; }
682 
683     /**
684      * Sets the unit used for calculating the offset along line for symbols.
685      * \param unit Offset along line unit type.
686      * \see offsetAlongLineUnit()
687      * \see setOffsetAlongLine()
688      */
setOffsetAlongLineUnit(QgsUnitTypes::RenderUnit unit)689     void setOffsetAlongLineUnit( QgsUnitTypes::RenderUnit unit ) { mOffsetAlongLineUnit = unit; }
690 
691     /**
692      * Returns the map unit scale used for calculating the offset in map units along line for symbols.
693      * \see setOffsetAlongLineMapUnitScale()
694      */
offsetAlongLineMapUnitScale()695     const QgsMapUnitScale &offsetAlongLineMapUnitScale() const { return mOffsetAlongLineMapUnitScale; }
696 
697     /**
698      * Sets the map unit \a scale used for calculating the offset in map units along line for symbols.
699      * \see offsetAlongLineMapUnitScale()
700      */
setOffsetAlongLineMapUnitScale(const QgsMapUnitScale & scale)701     void setOffsetAlongLineMapUnitScale( const QgsMapUnitScale &scale ) { mOffsetAlongLineMapUnitScale = scale; }
702 
703     /**
704      * Returns the length of line over which the line's direction is averaged when
705      * calculating individual symbol angles. Longer lengths smooth out angles from jagged lines to a greater extent.
706      *
707      * Units are retrieved through averageAngleUnit()
708      *
709      * \see setAverageAngleLength()
710      * \see averageAngleUnit()
711      * \see averageAngleMapUnitScale()
712      */
averageAngleLength()713     double averageAngleLength() const { return mAverageAngleLength; }
714 
715     /**
716      * Sets the \a length of line over which the line's direction is averaged when
717      * calculating individual symbol angles. Longer lengths smooth out angles from jagged lines to a greater extent.
718      *
719      * Units are set through setAverageAngleUnit()
720      *
721      * \see averageAngleLength()
722      * \see setAverageAngleUnit()
723      * \see setAverageAngleMapUnitScale()
724      */
setAverageAngleLength(double length)725     void setAverageAngleLength( double length ) { mAverageAngleLength = length; }
726 
727     /**
728      * Sets the \a unit for the length over which the line's direction is averaged when
729      * calculating individual symbol angles.
730      *
731      * \see averageAngleUnit()
732      * \see setAverageAngleLength()
733      * \see setAverageAngleMapUnitScale()
734     */
setAverageAngleUnit(QgsUnitTypes::RenderUnit unit)735     void setAverageAngleUnit( QgsUnitTypes::RenderUnit unit ) { mAverageAngleLengthUnit = unit; }
736 
737     /**
738      * Returns the unit for the length over which the line's direction is averaged when
739      * calculating individual symbol angles.
740      *
741      * \see setAverageAngleUnit()
742      * \see averageAngleLength()
743      * \see averageAngleMapUnitScale()
744     */
averageAngleUnit()745     QgsUnitTypes::RenderUnit averageAngleUnit() const { return mAverageAngleLengthUnit; }
746 
747     /**
748      * Sets the map unit \a scale for the length over which the line's direction is averaged when
749      * calculating individual symbol angles.
750      *
751      * \see averageAngleMapUnitScale()
752      * \see setAverageAngleLength()
753      * \see setAverageAngleUnit()
754     */
setAverageAngleMapUnitScale(const QgsMapUnitScale & scale)755     void setAverageAngleMapUnitScale( const QgsMapUnitScale &scale ) { mAverageAngleLengthMapUnitScale = scale; }
756 
757     /**
758      * Returns the map unit scale for the length over which the line's direction is averaged when
759      * calculating individual symbol angles.
760      *
761      * \see setAverageAngleMapUnitScale()
762      * \see averageAngleLength()
763      * \see averageAngleUnit()
764     */
averageAngleMapUnitScale()765     const QgsMapUnitScale &averageAngleMapUnitScale() const { return mAverageAngleLengthMapUnitScale; }
766 
767     void renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context ) override;
768     void renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) FINAL;
769     QgsUnitTypes::RenderUnit outputUnit() const FINAL;
770     void setMapUnitScale( const QgsMapUnitScale &scale ) FINAL;
771     QgsMapUnitScale mapUnitScale() const FINAL;
772     QVariantMap properties() const override;
773     bool canCauseArtifactsBetweenAdjacentTiles() const override;
774 
775   protected:
776 
777     /**
778      * Sets the line \a angle modification for the symbol's angle. This angle is added to
779      * the symbol's rotation and data defined rotation before rendering the symbol, and
780      * is used for orienting symbols to match the line's angle.
781      * \param angle Angle in degrees, valid values are between 0 and 360
782      */
783     virtual void setSymbolLineAngle( double angle ) = 0;
784 
785     /**
786      * Returns the symbol's current angle, in degrees clockwise.
787      */
788     virtual double symbolAngle() const = 0;
789 
790     /**
791      * Sets the symbol's \a angle, in degrees clockwise.
792      */
793     virtual void setSymbolAngle( double angle ) = 0;
794 
795     /**
796      * Renders the templated symbol at the specified \a point, using the given render \a context.
797      *
798      * The \a feature argument is used to pass the feature currently being rendered (when available).
799      *
800      * If only a single symbol layer from the symbol should be rendered, it should be specified
801      * in the \a layer argument. A \a layer of -1 indicates that all symbol layers should be
802      * rendered.
803      *
804      * If \a selected is TRUE then the symbol will be drawn using the "selected feature"
805      * style and colors instead of the symbol's normal style.
806      */
807     virtual void renderSymbol( const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer = -1, bool selected = false ) = 0;
808 
809     /**
810      * Copies all common properties of this layer to another templated symbol layer.
811      */
812     void copyTemplateSymbolProperties( QgsTemplatedLineSymbolLayerBase *destLayer ) const;
813 
814     /**
815      * Sets all common symbol properties in the \a destLayer, using the settings
816      * serialized in the \a properties map.
817      */
818     static void setCommonProperties( QgsTemplatedLineSymbolLayerBase *destLayer, const QVariantMap &properties );
819 
820   private:
821 
822     void renderPolylineInterval( const QPolygonF &points, QgsSymbolRenderContext &context, double averageAngleOver );
823     void renderPolylineVertex( const QPolygonF &points, QgsSymbolRenderContext &context, QgsTemplatedLineSymbolLayerBase::Placement placement = QgsTemplatedLineSymbolLayerBase::Vertex );
824     void renderPolylineCentral( const QPolygonF &points, QgsSymbolRenderContext &context, double averageAngleOver );
825     double markerAngle( const QPolygonF &points, bool isRing, int vertex );
826 
827     /**
828      * Renders a symbol by offsetting a vertex along the line by a specified distance.
829      * \param points vertices making up the line
830      * \param vertex vertex number to begin offset at
831      * \param distance distance to offset from vertex. If distance is positive, offset is calculated
832      * moving forward along the line. If distance is negative, offset is calculated moving backward
833      * along the line's vertices.
834      * \param context render context
835      * \see setoffsetAlongLine
836      * \see setOffsetAlongLineUnit
837      */
838     void renderOffsetVertexAlongLine( const QPolygonF &points, int vertex, double distance, QgsSymbolRenderContext &context );
839 
840 
841     static void collectOffsetPoints( const QVector< QPointF> &points,
842                                      QVector< QPointF> &dest, double intervalPainterUnits, double initialOffset, double initialLag = 0,
843                                      int numberPointsRequired = -1 );
844 
845     bool mRotateSymbols = true;
846     double mInterval = 3;
847     QgsUnitTypes::RenderUnit mIntervalUnit = QgsUnitTypes::RenderMillimeters;
848     QgsMapUnitScale mIntervalMapUnitScale;
849     Placement mPlacement = Interval;
850     double mOffsetAlongLine = 0; //distance to offset along line before marker is drawn
851     QgsUnitTypes::RenderUnit mOffsetAlongLineUnit = QgsUnitTypes::RenderMillimeters; //unit for offset along line
852     QgsMapUnitScale mOffsetAlongLineMapUnitScale;
853     double mAverageAngleLength = 4;
854     QgsUnitTypes::RenderUnit mAverageAngleLengthUnit = QgsUnitTypes::RenderMillimeters;
855     QgsMapUnitScale mAverageAngleLengthMapUnitScale;
856 
857     friend class TestQgsMarkerLineSymbol;
858 
859 };
860 
861 /**
862  * \ingroup core
863  * \class QgsMarkerLineSymbolLayer
864  * \brief Line symbol layer type which draws repeating marker symbols along a line feature.
865  */
866 class CORE_EXPORT QgsMarkerLineSymbolLayer : public QgsTemplatedLineSymbolLayerBase
867 {
868   public:
869 
870     /**
871      * Constructor for QgsMarkerLineSymbolLayer. Creates a marker line
872      * with a default marker symbol, placed at the specified \a interval (in millimeters).
873      *
874      * The \a rotateMarker argument specifies whether individual marker symbols
875      * should be rotated to match the line segment alignment.
876      */
877     QgsMarkerLineSymbolLayer( bool rotateMarker = DEFAULT_MARKERLINE_ROTATE,
878                               double interval = DEFAULT_MARKERLINE_INTERVAL );
879 
880     ~QgsMarkerLineSymbolLayer() override;
881 
882     // static stuff
883 
884     /**
885      * Creates a new QgsMarkerLineSymbolLayer, using the settings
886      * serialized in the \a properties map (corresponding to the output from
887      * QgsMarkerLineSymbolLayer::properties() ).
888      */
889     static QgsSymbolLayer *create( const QVariantMap &properties = QVariantMap() ) SIP_FACTORY;
890 
891     /**
892      * Creates a new QgsMarkerLineSymbolLayer from an SLD XML DOM \a element.
893      */
894     static QgsSymbolLayer *createFromSld( QDomElement &element ) SIP_FACTORY;
895 
896     // implemented from base classes
897 
898     QString layerType() const override;
899     void startRender( QgsSymbolRenderContext &context ) override;
900     void stopRender( QgsSymbolRenderContext &context ) override;
901     QgsMarkerLineSymbolLayer *clone() const override SIP_FACTORY;
902     void toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const override;
903     void setColor( const QColor &color ) override;
904     QColor color() const override;
905     QgsSymbol *subSymbol() override;
906     bool setSubSymbol( QgsSymbol *symbol SIP_TRANSFER ) override;
907     void setWidth( double width ) override;
908     double width() const override;
909     double width( const QgsRenderContext &context ) const override;
910     double estimateMaxBleed( const QgsRenderContext &context ) const override;
911     void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override;
912     bool usesMapUnits() const override;
913     QSet<QString> usedAttributes( const QgsRenderContext &context ) const override;
914     bool hasDataDefinedProperties() const override;
915     void setDataDefinedProperty( QgsSymbolLayer::Property key, const QgsProperty &property ) override;
916 
917     /**
918      * Shall the marker be rotated.
919      *
920      * \returns TRUE if the marker should be rotated.
921      * \deprecated Use rotateSymbols() instead.
922      */
rotateMarker()923     Q_DECL_DEPRECATED bool rotateMarker() const SIP_DEPRECATED { return rotateSymbols(); }
924 
925     /**
926      * Shall the marker be rotated.
927      * \deprecated Use setRotateSymbols() instead.
928      */
setRotateMarker(bool rotate)929     Q_DECL_DEPRECATED void setRotateMarker( bool rotate ) SIP_DEPRECATED { setRotateSymbols( rotate ); }
930 
931     void renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context ) override;
932 
933   protected:
934 
935     std::unique_ptr< QgsMarkerSymbol > mMarker;
936 
937     void setSymbolLineAngle( double angle ) override;
938     double symbolAngle() const override;
939     void setSymbolAngle( double angle ) override;
940     void renderSymbol( const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer = -1, bool selected = false ) override;
941 
942   private:
943 
944 #ifdef SIP_RUN
945     QgsMarkerLineSymbolLayer( const QgsMarkerLineSymbolLayer &other );
946 #endif
947 
948 
949 };
950 
951 
952 /**
953  * \ingroup core
954  * \class QgsHashedLineSymbolLayer
955  *
956  * \brief Line symbol layer type which draws repeating line sections along a line feature.
957  *
958  * \since QGIS 3.8
959  */
960 class CORE_EXPORT QgsHashedLineSymbolLayer : public QgsTemplatedLineSymbolLayerBase
961 {
962   public:
963 
964     /**
965      * Constructor for QgsHashedLineSymbolLayer. Creates a line
966      * with a default hash symbol, placed at the specified \a interval (in millimeters).
967      *
968      * The \a rotateSymbol argument specifies whether individual hash symbols
969      * should be rotated to match the line segment alignment.
970      */
971     QgsHashedLineSymbolLayer( bool rotateSymbol = true,
972                               double interval = 3 );
973 
974     ~QgsHashedLineSymbolLayer() override;
975 
976     /**
977      * Creates a new QgsHashedLineSymbolLayer, using the settings
978      * serialized in the \a properties map (corresponding to the output from
979      * QgsHashedLineSymbolLayer::properties() ).
980      */
981     static QgsSymbolLayer *create( const QVariantMap &properties = QVariantMap() ) SIP_FACTORY;
982 
983     QString layerType() const override;
984     void startRender( QgsSymbolRenderContext &context ) override;
985     void stopRender( QgsSymbolRenderContext &context ) override;
986     QVariantMap properties() const override;
987     QgsHashedLineSymbolLayer *clone() const override SIP_FACTORY;
988     void setColor( const QColor &color ) override;
989     QColor color() const override;
990     QgsSymbol *subSymbol() override;
991     bool setSubSymbol( QgsSymbol *symbol SIP_TRANSFER ) override;
992     void setWidth( double width ) override;
993     double width() const override;
994     double width( const QgsRenderContext &context ) const override;
995     double estimateMaxBleed( const QgsRenderContext &context ) const override;
996     void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override;
997     QSet<QString> usedAttributes( const QgsRenderContext &context ) const override;
998     bool hasDataDefinedProperties() const override;
999     void setDataDefinedProperty( QgsSymbolLayer::Property key, const QgsProperty &property ) override;
1000     bool usesMapUnits() const override;
1001 
1002     /**
1003      * Returns the angle to use when drawing the hashed lines sections, in degrees clockwise.
1004      *
1005      * \see setHashAngle()
1006      */
1007     double hashAngle() const;
1008 
1009     /**
1010      * Sets the \a angle to use when drawing the hashed lines sections, in degrees clockwise.
1011      *
1012      * \see hashAngle()
1013      */
1014     void setHashAngle( double angle );
1015 
1016     /**
1017      * Returns the length of hash symbols. Units are specified through hashLengthUnits().
1018      * \see setHashLength()
1019      * \see hashLengthUnit()
1020      */
hashLength()1021     double hashLength() const { return mHashLength; }
1022 
1023     /**
1024      * Sets the \a length of hash symbols. Units are specified through setHashLengthUnit()
1025      * \see hashLength()
1026      * \see setHashLengthUnit()
1027      */
setHashLength(double length)1028     void setHashLength( double length ) { mHashLength = length; }
1029 
1030     /**
1031      * Sets the \a unit for the length of hash symbols.
1032      * \see hashLengthUnit()
1033      * \see setHashLength()
1034     */
setHashLengthUnit(QgsUnitTypes::RenderUnit unit)1035     void setHashLengthUnit( QgsUnitTypes::RenderUnit unit ) { mHashLengthUnit = unit; }
1036 
1037     /**
1038      * Returns the units for the length of hash symbols.
1039      * \see setHashLengthUnit()
1040      * \see hashLength()
1041     */
hashLengthUnit()1042     QgsUnitTypes::RenderUnit hashLengthUnit() const { return mHashLengthUnit; }
1043 
1044     /**
1045      * Sets the map unit \a scale for the hash length.
1046      * \see hashLengthMapUnitScale()
1047      * \see setHashLengthUnit()
1048      * \see setHashLength()
1049      */
setHashLengthMapUnitScale(const QgsMapUnitScale & scale)1050     void setHashLengthMapUnitScale( const QgsMapUnitScale &scale ) { mHashLengthMapUnitScale = scale; }
1051 
1052     /**
1053      * Returns the map unit scale for the hash length.
1054      * \see setHashLengthMapUnitScale()
1055      * \see hashLengthUnit()
1056      * \see hashLength()
1057      */
hashLengthMapUnitScale()1058     const QgsMapUnitScale &hashLengthMapUnitScale() const { return mHashLengthMapUnitScale; }
1059 
1060     void renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context ) override;
1061 
1062   protected:
1063 
1064     void setSymbolLineAngle( double angle ) override;
1065     double symbolAngle() const override;
1066     void setSymbolAngle( double angle ) override;
1067     void renderSymbol( const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer = -1, bool selected = false ) override;
1068 
1069   private:
1070 #ifdef SIP_RUN
1071     QgsHashedLineSymbolLayer( const QgsHashedLineSymbolLayer &other );
1072 #endif
1073 
1074     std::unique_ptr< QgsLineSymbol > mHashSymbol;
1075 
1076     double mSymbolLineAngle = 0;
1077     double mSymbolAngle = 0;
1078 
1079     double mHashAngle = 0;
1080     double mHashLength = 3;
1081     QgsUnitTypes::RenderUnit mHashLengthUnit = QgsUnitTypes::RenderMillimeters;
1082     QgsMapUnitScale mHashLengthMapUnitScale;
1083 
1084 };
1085 
1086 #endif
1087 
1088 
1089