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