1 /***************************************************************************
2  qgsmarkersymbollayer.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 QGSMARKERSYMBOLLAYER_H
17 #define QGSMARKERSYMBOLLAYER_H
18 
19 #include "qgis_core.h"
20 #include "qgis_sip.h"
21 #include "qgssymbollayer.h"
22 
23 #define DEFAULT_SIMPLEMARKER_NAME         "circle"
24 #define DEFAULT_SIMPLEMARKER_COLOR        QColor(255,0,0)
25 #define DEFAULT_SIMPLEMARKER_BORDERCOLOR  QColor( 35, 35, 35 )
26 #define DEFAULT_SIMPLEMARKER_JOINSTYLE    Qt::BevelJoin
27 #define DEFAULT_SIMPLEMARKER_SIZE         DEFAULT_POINT_SIZE
28 #define DEFAULT_SIMPLEMARKER_ANGLE        0
29 
30 #include <QPen>
31 #include <QBrush>
32 #include <QPicture>
33 #include <QPolygonF>
34 #include <QFont>
35 
36 /**
37  * \ingroup core
38  * \class QgsSimpleMarkerSymbolLayerBase
39  * \brief Abstract base class for simple marker symbol layers. Handles creation of the symbol shapes but
40  * leaves the actual drawing of the symbols to subclasses.
41  * \since QGIS 2.16
42  */
43 class CORE_EXPORT QgsSimpleMarkerSymbolLayerBase : public QgsMarkerSymbolLayer
44 {
45 
46   public:
47 
48     //! Marker symbol shapes
49     enum Shape
50     {
51       Square, //!< Square
52       Diamond, //!< Diamond
53       Pentagon, //!< Pentagon
54       Hexagon, //!< Hexagon
55       Triangle, //!< Triangle
56       EquilateralTriangle, //!< Equilateral triangle
57       Star, //!< Star
58       Arrow, //!< Arrow
59       Circle, //!< Circle
60       Cross, //!< Cross (lines only)
61       CrossFill, //!< Solid filled cross
62       Cross2, //!< Rotated cross (lines only), "x" shape
63       Line, //!< Vertical line
64       ArrowHead, //!< Right facing arrow head (unfilled, lines only)
65       ArrowHeadFilled, //!< Right facing filled arrow head
66       SemiCircle, //!< Semi circle (top half)
67       ThirdCircle, //!< One third circle (top left third)
68       QuarterCircle, //!< Quarter circle (top left quarter)
69       QuarterSquare, //!< Quarter square (top left quarter)
70       HalfSquare, //!< Half square (left half)
71       DiagonalHalfSquare, //!< Diagonal half square (bottom left half)
72       RightHalfTriangle, //!< Right half of triangle
73       LeftHalfTriangle, //!< Left half of triangle
74       Octagon, //!< Octagon (since QGIS 3.18)
75       SquareWithCorners, //!< A square with diagonal corners (since QGIS 3.18)
76       AsteriskFill, //!< A filled asterisk shape (since QGIS 3.18)
77     };
78 
79     //! Returns a list of all available shape types.
80     static QList< QgsSimpleMarkerSymbolLayerBase::Shape > availableShapes();
81 
82     /**
83      * Returns TRUE if a symbol shape has a fill.
84      * \param shape shape to test
85      * \returns TRUE if shape uses a fill, or FALSE if shape uses lines only
86      */
87     static bool shapeIsFilled( QgsSimpleMarkerSymbolLayerBase::Shape shape );
88 
89     /**
90      * Constructor for QgsSimpleMarkerSymbolLayerBase.
91     * \param shape symbol shape for markers
92     * \param size symbol size (in mm)
93     * \param angle symbol rotation angle
94     * \param scaleMethod scaling method for data defined scaling
95     */
96     QgsSimpleMarkerSymbolLayerBase( QgsSimpleMarkerSymbolLayerBase::Shape shape = Circle,
97                                     double size = DEFAULT_SIMPLEMARKER_SIZE,
98                                     double angle = DEFAULT_SIMPLEMARKER_ANGLE,
99                                     QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD );
100 
101     /**
102      * Returns the shape for the rendered marker symbol.
103      * \see setShape()
104      */
shape()105     QgsSimpleMarkerSymbolLayerBase::Shape shape() const { return mShape; }
106 
107     /**
108      * Sets the rendered marker shape.
109      * \param shape new marker shape
110      * \see shape()
111      */
setShape(QgsSimpleMarkerSymbolLayerBase::Shape shape)112     void setShape( QgsSimpleMarkerSymbolLayerBase::Shape shape ) { mShape = shape; }
113 
114     /**
115      * Attempts to decode a string representation of a shape name to the corresponding
116      * shape.
117      * \param name encoded shape name
118      * \param ok if specified, will be set to TRUE if shape was successfully decoded
119      * \returns decoded name
120      * \see encodeShape()
121      */
122     static QgsSimpleMarkerSymbolLayerBase::Shape decodeShape( const QString &name, bool *ok = nullptr );
123 
124     /**
125      * Encodes a shape to its string representation.
126      * \param shape shape to encode
127      * \returns encoded string
128      * \see decodeShape()
129      */
130     static QString encodeShape( QgsSimpleMarkerSymbolLayerBase::Shape shape );
131 
132     void startRender( QgsSymbolRenderContext &context ) override;
133     void stopRender( QgsSymbolRenderContext &context ) override;
134     void renderPoint( QPointF point, QgsSymbolRenderContext &context ) override;
135     QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override;
136 
137   protected:
138 
139     /**
140      * Prepares the layer for drawing the specified shape (QPolygonF version)
141      */
142     bool prepareMarkerShape( Shape shape );
143 
144     /**
145      * Prepares the layer for drawing the specified shape (QPainterPath version)
146      */
147     bool prepareMarkerPath( Shape symbol );
148 
149     /**
150      * Creates a polygon representing the specified shape.
151      * \param shape shape to create
152      * \param polygon destination polygon for shape
153      * \returns TRUE if shape was successfully stored in polygon
154      */
155     bool shapeToPolygon( Shape shape, QPolygonF &polygon ) const;
156 
157     /**
158      * Calculates the desired size of the marker, considering data defined size overrides.
159      * \param context symbol render context
160      * \param hasDataDefinedSize will be set to TRUE if marker uses data defined sizes
161      * \returns marker size, in original size units
162      */
163     double calculateSize( QgsSymbolRenderContext &context, bool &hasDataDefinedSize ) const;
164 
165     /**
166      * Calculates the marker offset and rotation.
167      * \param context symbol render context
168      * \param scaledSize size of symbol to render
169      * \param hasDataDefinedRotation will be set to TRUE if marker has data defined rotation
170      * \param offset will be set to calculated marker offset (in painter units)
171      * \param angle will be set to calculated marker angle
172      */
173     void calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedRotation, QPointF &offset, double &angle ) const;
174 
175     //! Polygon of points in shape. If polygon is empty then shape is using mPath.
176     QPolygonF mPolygon;
177 
178     //! Painter path representing shape. If mPolygon is empty then the shape is stored in mPath.
179     QPainterPath mPath;
180 
181     //! Symbol shape
182     Shape mShape;
183 
184   private:
185 
186     /**
187      * Derived classes must implement draw() to handle drawing the generated shape onto the painter surface.
188      * \param context symbol render context
189      * \param shape shape to draw
190      * \param polygon polygon representing transformed marker shape. May be empty, in which case the shape will be specified
191      * in the path argument.
192      * \param path transformed painter path representing shape to draw
193      */
194     virtual void draw( QgsSymbolRenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path ) = 0 SIP_FORCE;
195 };
196 
197 /**
198  * \ingroup core
199  * \class QgsSimpleMarkerSymbolLayer
200  * \brief Simple marker symbol layer, consisting of a rendered shape with solid fill color and an stroke.
201  */
202 class CORE_EXPORT QgsSimpleMarkerSymbolLayer : public QgsSimpleMarkerSymbolLayerBase
203 {
204   public:
205 
206     /**
207      * Constructor for QgsSimpleMarkerSymbolLayer.
208     * \param shape symbol shape
209     * \param size symbol size (in mm)
210     * \param angle symbol rotation angle
211     * \param scaleMethod scaling method for data defined scaling
212     * \param color fill color for symbol
213     * \param strokeColor stroke color for symbol
214     * \param penJoinStyle join style for stroke pen
215     */
216     QgsSimpleMarkerSymbolLayer( QgsSimpleMarkerSymbolLayerBase::Shape shape = Circle,
217                                 double size = DEFAULT_SIMPLEMARKER_SIZE,
218                                 double angle = DEFAULT_SIMPLEMARKER_ANGLE,
219                                 QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD,
220                                 const QColor &color = DEFAULT_SIMPLEMARKER_COLOR,
221                                 const QColor &strokeColor = DEFAULT_SIMPLEMARKER_BORDERCOLOR,
222                                 Qt::PenJoinStyle penJoinStyle = DEFAULT_SIMPLEMARKER_JOINSTYLE );
223 
224     // static methods
225 
226     /**
227      * Creates a new QgsSimpleMarkerSymbolLayer.
228      * \param properties a property map containing symbol properties (see properties())
229      * \returns new QgsSimpleMarkerSymbolLayer
230      */
231     static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) SIP_FACTORY;
232 
233     /**
234      * Creates a new QgsSimpleMarkerSymbolLayer from an SLD XML element.
235      * \param element XML element containing SLD definition of symbol
236      * \returns new QgsSimpleMarkerSymbolLayer
237      */
238     static QgsSymbolLayer *createFromSld( QDomElement &element ) SIP_FACTORY;
239 
240     // reimplemented from base classes
241 
242     QString layerType() const override;
243     void startRender( QgsSymbolRenderContext &context ) override;
244     void renderPoint( QPointF point, QgsSymbolRenderContext &context ) override;
245     QgsStringMap properties() const override;
246     QgsSimpleMarkerSymbolLayer *clone() const override SIP_FACTORY;
247     void writeSldMarker( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const override;
248     QString ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const override;
249     bool writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift = QPointF( 0.0, 0.0 ) ) const override;
250     void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override;
251     QgsUnitTypes::RenderUnit outputUnit() const override;
252     void setMapUnitScale( const QgsMapUnitScale &scale ) override;
253     QgsMapUnitScale mapUnitScale() const override;
254     bool usesMapUnits() const override;
255     QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override;
fillColor()256     QColor fillColor() const override { return mColor; }
setFillColor(const QColor & color)257     void setFillColor( const QColor &color ) override { mColor = color; }
258     void setColor( const QColor &color ) override;
259     QColor color() const override;
260 
261     // new methods
262 
263     /**
264      * Returns the marker's stroke color.
265      * \see setStrokeColor()
266      * \see strokeStyle()
267      * \see penJoinStyle()
268      */
strokeColor()269     QColor strokeColor() const override { return mStrokeColor; }
270 
271     /**
272      * Sets the marker's stroke color.
273      * \param color stroke color
274      * \see strokeColor()
275      * \see setStrokeStyle()
276      * \see setPenJoinStyle()
277      */
setStrokeColor(const QColor & color)278     void setStrokeColor( const QColor &color ) override { mStrokeColor = color; }
279 
280     /**
281      * Returns the marker's stroke style (e.g., solid, dashed, etc)
282      * \see setStrokeStyle()
283      * \see strokeColor()
284      * \see penJoinStyle()
285      * \since QGIS 2.4
286     */
strokeStyle()287     Qt::PenStyle strokeStyle() const { return mStrokeStyle; }
288 
289     /**
290      * Sets the marker's stroke style (e.g., solid, dashed, etc)
291      * \param strokeStyle style
292      * \see strokeStyle()
293      * \see setStrokeColor()
294      * \see setPenJoinStyle()
295      * \since QGIS 2.4
296     */
setStrokeStyle(Qt::PenStyle strokeStyle)297     void setStrokeStyle( Qt::PenStyle strokeStyle ) { mStrokeStyle = strokeStyle; }
298 
299     /**
300      * Returns the marker's stroke join style (e.g., miter, bevel, etc).
301      * \see setPenJoinStyle()
302      * \see strokeColor()
303      * \see strokeStyle()
304      * \since QGIS 2.16
305     */
penJoinStyle()306     Qt::PenJoinStyle penJoinStyle() const { return mPenJoinStyle; }
307 
308     /**
309      * Sets the marker's stroke join style (e.g., miter, bevel, etc).
310      * \param style join style
311      * \see penJoinStyle()
312      * \see setStrokeColor()
313      * \see setStrokeStyle()
314      * \since QGIS 2.16
315     */
setPenJoinStyle(Qt::PenJoinStyle style)316     void setPenJoinStyle( Qt::PenJoinStyle style ) { mPenJoinStyle = style; }
317 
318     /**
319      * Returns the width of the marker's stroke.
320      * \see setStrokeWidth()
321      * \see strokeWidthUnit()
322      * \see strokeWidthMapUnitScale()
323      */
strokeWidth()324     double strokeWidth() const { return mStrokeWidth; }
325 
326     /**
327      * Sets the width of the marker's stroke.
328      * \param w stroke width. See strokeWidthUnit() for units.
329      * \see strokeWidth()
330      * \see setStrokeWidthUnit()
331      * \see setStrokeWidthMapUnitScale()
332      */
setStrokeWidth(double w)333     void setStrokeWidth( double w ) { mStrokeWidth = w; }
334 
335     /**
336      * Sets the unit for the width of the marker's stroke.
337      * \param u stroke width unit
338      * \see strokeWidthUnit()
339      * \see setStrokeWidth()
340      * \see setStrokeWidthMapUnitScale()
341      */
setStrokeWidthUnit(QgsUnitTypes::RenderUnit u)342     void setStrokeWidthUnit( QgsUnitTypes::RenderUnit u ) { mStrokeWidthUnit = u; }
343 
344     /**
345      * Returns the unit for the width of the marker's stroke.
346      * \see setStrokeWidthUnit()
347      * \see strokeWidth()
348      * \see strokeWidthMapUnitScale()
349      */
strokeWidthUnit()350     QgsUnitTypes::RenderUnit strokeWidthUnit() const { return mStrokeWidthUnit; }
351 
352     /**
353      * Sets the map scale for the width of the marker's stroke.
354      * \param scale stroke width map unit scale
355      * \see strokeWidthMapUnitScale()
356      * \see setStrokeWidth()
357      * \see setStrokeWidthUnit()
358      */
setStrokeWidthMapUnitScale(const QgsMapUnitScale & scale)359     void setStrokeWidthMapUnitScale( const QgsMapUnitScale &scale ) { mStrokeWidthMapUnitScale = scale; }
360 
361     /**
362      * Returns the map scale for the width of the marker's stroke.
363      * \see setStrokeWidthMapUnitScale()
364      * \see strokeWidth()
365      * \see strokeWidthUnit()
366      */
strokeWidthMapUnitScale()367     const QgsMapUnitScale &strokeWidthMapUnitScale() const { return mStrokeWidthMapUnitScale; }
368 
369   protected:
370 
371     /**
372      * Draws the marker shape in the specified painter.
373      * \param p destination QPainter
374      * \param context symbol context
375      * \note this method does not handle setting the painter pen or brush to match the symbol's fill or stroke
376      */
377     void drawMarker( QPainter *p, QgsSymbolRenderContext &context );
378 
379     /**
380      * Prepares cache image
381      * \returns TRUE in case of success, FALSE if cache image size too large
382     */
383     bool prepareCache( QgsSymbolRenderContext &context );
384 
385     //! Stroke color
386     QColor mStrokeColor;
387     //! Stroke style
388     Qt::PenStyle mStrokeStyle = Qt::SolidLine;
389     //! Stroke width
390     double mStrokeWidth = 0;
391     //! Stroke width units
392     QgsUnitTypes::RenderUnit mStrokeWidthUnit = QgsUnitTypes::RenderMillimeters;
393     //! Stroke width map unit scale
394     QgsMapUnitScale mStrokeWidthMapUnitScale;
395     //! Stroke pen join style
396     Qt::PenJoinStyle mPenJoinStyle;
397     //! QPen corresponding to marker's stroke style
398     QPen mPen;
399     //! QBrush corresponding to marker's fill style
400     QBrush mBrush;
401 
402     //! Cached image of marker, if using cached version
403     QImage mCache;
404     //! QPen to use as stroke of selected symbols
405     QPen mSelPen;
406     //! QBrush to use as fill of selected symbols
407     QBrush mSelBrush;
408     //! Cached image of selected marker, if using cached version
409     QImage mSelCache;
410 
411     /**
412      * TRUE if using cached images of markers for drawing. This is faster, but cannot
413      * be used when data defined properties are present
414      */
415     bool mUsingCache = false;
416 
417     //! Maximum width/height of cache image
418     static const int MAXIMUM_CACHE_WIDTH = 3000;
419 
420   private:
421 
422     void draw( QgsSymbolRenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path ) override SIP_FORCE;
423 
424     double mCachedOpacity = 1.0;
425 
426 };
427 
428 /**
429  * \ingroup core
430  * \class QgsFilledMarkerSymbolLayer
431  * \brief Filled marker symbol layer, consisting of a shape which is rendered using a QgsFillSymbol. This allows
432  * the symbol to support advanced styling of the interior and stroke of the shape.
433  * \since QGIS 2.16
434  */
435 class CORE_EXPORT QgsFilledMarkerSymbolLayer : public QgsSimpleMarkerSymbolLayerBase
436 {
437   public:
438 
439     /**
440      * Constructor for QgsFilledMarkerSymbolLayer.
441     * \param shape symbol shape
442     * \param size symbol size (in mm)
443     * \param angle symbol rotation angle
444     * \param scaleMethod size scaling method
445     */
446     QgsFilledMarkerSymbolLayer( QgsSimpleMarkerSymbolLayerBase::Shape shape = Circle,
447                                 double size = DEFAULT_SIMPLEMARKER_SIZE,
448                                 double angle = DEFAULT_SIMPLEMARKER_ANGLE,
449                                 QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD );
450 
451     /**
452      * Creates a new QgsFilledMarkerSymbolLayer.
453      * \param properties a property map containing symbol properties (see properties())
454      * \returns new QgsFilledMarkerSymbolLayer
455      */
456     static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) SIP_FACTORY;
457 
458     QString layerType() const override;
459     void startRender( QgsSymbolRenderContext &context ) override;
460     void stopRender( QgsSymbolRenderContext &context ) override;
461     QgsStringMap properties() const override;
462     QgsFilledMarkerSymbolLayer *clone() const override SIP_FACTORY;
463     QgsSymbol *subSymbol() override;
464     bool setSubSymbol( QgsSymbol *symbol SIP_TRANSFER ) override;
465     double estimateMaxBleed( const QgsRenderContext &context ) const override;
466     QSet<QString> usedAttributes( const QgsRenderContext &context ) const override;
467     bool hasDataDefinedProperties() const override;
468     void setColor( const QColor &c ) override;
469     QColor color() const override;
470     bool usesMapUnits() const override;
471 
472   private:
473 #ifdef SIP_RUN
474     QgsFilledMarkerSymbolLayer( const QgsFilledMarkerSymbolLayer & );
475 #endif
476 
477     void draw( QgsSymbolRenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path ) override SIP_FORCE;
478 
479     //! Fill subsymbol
480     std::unique_ptr< QgsFillSymbol > mFill;
481 };
482 
483 //////////
484 
485 #define DEFAULT_SVGMARKER_SIZE         2*DEFAULT_POINT_SIZE
486 #define DEFAULT_SVGMARKER_ANGLE        0
487 
488 /**
489  * \ingroup core
490  * \class QgsSvgMarkerSymbolLayer
491  */
492 class CORE_EXPORT QgsSvgMarkerSymbolLayer : public QgsMarkerSymbolLayer
493 {
494   public:
495     //! Constructs SVG marker symbol layer with picture from given absolute path to a SVG file
496     QgsSvgMarkerSymbolLayer( const QString &path,
497                              double size = DEFAULT_SVGMARKER_SIZE,
498                              double angle = DEFAULT_SVGMARKER_ANGLE,
499                              QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD );
500 
501     // static stuff
502 
503     static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) SIP_FACTORY;
504     static QgsSymbolLayer *createFromSld( QDomElement &element ) SIP_FACTORY;
505 
506     /**
507      * Turns relative paths in properties map to absolute when reading and vice versa when writing.
508      * Used internally when reading/writing symbols.
509      * \since QGIS 3.0
510      */
511     static void resolvePaths( QgsStringMap &properties, const QgsPathResolver &pathResolver, bool saving );
512 
513     // implemented from base classes
514 
515     QString layerType() const override;
516 
517     void startRender( QgsSymbolRenderContext &context ) override;
518 
519     void stopRender( QgsSymbolRenderContext &context ) override;
520 
521     void renderPoint( QPointF point, QgsSymbolRenderContext &context ) override;
522 
523     QgsStringMap properties() const override;
524     bool usesMapUnits() const override;
525 
526     QgsSvgMarkerSymbolLayer *clone() const override SIP_FACTORY;
527 
528     void writeSldMarker( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const override;
529 
530     /**
531      * Returns the marker SVG path.
532      * \see setPath()
533      */
path()534     QString path() const { return mPath; }
535 
536     /**
537      * Set the marker SVG path.
538      * \param path SVG path
539      * \see path()
540      */
541     void setPath( const QString &path );
542 
543     /**
544      * Returns the default marker aspect ratio between width and height, 0 if not yet calculated.
545      * \see updateDefaultAspectRatio()
546      */
defaultAspectRatio()547     double defaultAspectRatio() const { return mDefaultAspectRatio; }
548 
549     /**
550      * Calculates the default marker aspect ratio between width and height.
551      * \returns the default aspect ratio value
552      * \see defaultAspectRatio()
553      */
554     double updateDefaultAspectRatio();
555 
556     /**
557      * Returns the preserved aspect ratio value, TRUE if fixed aspect ratio has been lower or equal to 0.
558      * \see setPreservedAspectRatio()
559      */
preservedAspectRatio()560     bool preservedAspectRatio() const { return mFixedAspectRatio <= 0.0; }
561 
562     /**
563      * Set preserved the marker aspect ratio between width and height.
564      * \param par Preserved Aspect Ratio
565      * \returns the preserved aspect ratio value, TRUE if fixed aspect ratio has been lower or equal to 0
566      * \see preservedAspectRatio()
567      */
568     bool setPreservedAspectRatio( bool par );
569 
570     /**
571      * Returns the marker aspect ratio between width and height to be used in rendering,
572      * if the value set is lower or equal to 0 the aspect ratio will be preserved in rendering
573      * \see setFixedAspectRatio() QgsSvgCache
574      */
fixedAspectRatio()575     double fixedAspectRatio() const { return mFixedAspectRatio; }
576 
577     /**
578      * Set the marker aspect ratio between width and height to be used in rendering,
579      * if the value set is lower or equal to 0 the aspect ratio will be preserved in rendering
580      * \param ratio Fixed Aspect Ratio
581      * \see fixedAspectRatio() QgsSvgCache
582      */
setFixedAspectRatio(double ratio)583     void setFixedAspectRatio( double ratio ) { mFixedAspectRatio = ratio; }
584 
fillColor()585     QColor fillColor() const override { return color(); }
setFillColor(const QColor & color)586     void setFillColor( const QColor &color ) override { setColor( color ); }
587 
strokeColor()588     QColor strokeColor() const override { return mStrokeColor; }
setStrokeColor(const QColor & c)589     void setStrokeColor( const QColor &c ) override { mStrokeColor = c; }
590 
strokeWidth()591     double strokeWidth() const { return mStrokeWidth; }
setStrokeWidth(double w)592     void setStrokeWidth( double w ) { mStrokeWidth = w; }
593 
594     /**
595      * Sets the units for the stroke width.
596      * \param unit width units
597      * \see strokeWidthUnit()
598     */
setStrokeWidthUnit(QgsUnitTypes::RenderUnit unit)599     void setStrokeWidthUnit( QgsUnitTypes::RenderUnit unit ) { mStrokeWidthUnit = unit; }
600 
601     /**
602      * Returns the units for the stroke width.
603      * \see strokeWidthUnit()
604     */
strokeWidthUnit()605     QgsUnitTypes::RenderUnit strokeWidthUnit() const { return mStrokeWidthUnit; }
606 
setStrokeWidthMapUnitScale(const QgsMapUnitScale & scale)607     void setStrokeWidthMapUnitScale( const QgsMapUnitScale &scale ) { mStrokeWidthMapUnitScale = scale; }
strokeWidthMapUnitScale()608     const QgsMapUnitScale &strokeWidthMapUnitScale() const { return mStrokeWidthMapUnitScale; }
609 
610     void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override;
611     QgsUnitTypes::RenderUnit outputUnit() const override;
612 
613     void setMapUnitScale( const QgsMapUnitScale &scale ) override;
614     QgsMapUnitScale mapUnitScale() const override;
615 
616     bool writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift = QPointF( 0.0, 0.0 ) ) const override;
617 
618     QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override;
619 
620   protected:
621 
622     /**
623      * Calculates the marker aspect ratio between width and height.
624      * \param context symbol render context
625      * \param scaledSize size of symbol to render
626      * \param hasDataDefinedAspectRatio will be set to TRUE if marker has data defined aspectRatio
627      */
628     double calculateAspectRatio( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedAspectRatio ) const;
629 
630     QString mPath;
631 
632     //! The marker default aspect ratio
633     double mDefaultAspectRatio = 0.0;
634     //! The marker fixed aspect ratio
635     double mFixedAspectRatio = 0.0;
636     //param(fill), param(stroke), param(stroke-width) are going
637     //to be replaced in memory
638     bool mHasFillParam = false;
639     QColor mStrokeColor;
640     double mStrokeWidth;
641 
642     QgsUnitTypes::RenderUnit mStrokeWidthUnit;
643     QgsMapUnitScale mStrokeWidthMapUnitScale;
644 
645   private:
646     double calculateSize( QgsSymbolRenderContext &context, bool &hasDataDefinedSize ) const;
647     void calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledWidth, double scaledHeight, QPointF &offset, double &angle ) const;
648 
649 };
650 
651 
652 //////////
653 
654 #define DEFAULT_RASTERMARKER_SIZE         2*DEFAULT_POINT_SIZE
655 #define DEFAULT_RASTERMARKER_ANGLE        0
656 
657 /**
658  * \ingroup core
659  * \class QgsRasterMarkerSymbolLayer
660  * \brief Raster marker symbol layer class.
661  * \since QGIS 3.6
662  */
663 class CORE_EXPORT QgsRasterMarkerSymbolLayer : public QgsMarkerSymbolLayer
664 {
665   public:
666     //! Constructs raster marker symbol layer with picture from given absolute path to a raster image file
667     QgsRasterMarkerSymbolLayer( const QString &path = QString(),
668                                 double size = DEFAULT_SVGMARKER_SIZE,
669                                 double angle = DEFAULT_SVGMARKER_ANGLE,
670                                 QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD );
671 
672     // static stuff
673 
674     /**
675      * Creates a raster marker symbol layer from a string map of properties.
676      * \param properties QgsStringMap properties object
677      */
678     static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) SIP_FACTORY;
679 
680     /**
681      * Turns relative paths in properties map to absolute when reading and vice versa when writing.
682      * Used internally when reading/writing symbols.
683      * \since QGIS 3.0
684      */
685     static void resolvePaths( QgsStringMap &properties, const QgsPathResolver &pathResolver, bool saving );
686 
687     // implemented from base classes
688 
689     QString layerType() const override;
690 
691     void renderPoint( QPointF point, QgsSymbolRenderContext &context ) override;
692 
693     QgsStringMap properties() const override;
694 
695     QgsRasterMarkerSymbolLayer *clone() const override SIP_FACTORY;
696     bool usesMapUnits() const override;
697 
698     /**
699      * Calculates the marker aspect ratio between width and height.
700      * \param context symbol render context
701      * \param scaledSize size of symbol to render
702      * \param hasDataDefinedAspectRatio will be set to TRUE if marker has data defined aspectRatio
703      */
704     double calculateAspectRatio( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedAspectRatio ) const;
705 
706     /**
707      * Returns the marker raster image path.
708      * \see setPath()
709      */
path()710     QString path() const { return mPath; }
711 
712     /**
713      * Set the marker raster image path.
714      * \param path raster image path
715      * \see path()
716      */
717     void setPath( const QString &path );
718 
719     /**
720      * Returns the marker opacity.
721      * \returns opacity value between 0 (fully transparent) and 1 (fully opaque)
722      * \see setOpacity()
723      */
opacity()724     double opacity() const { return mOpacity; }
725 
726     /**
727      * Set the marker opacity.
728      * \param opacity opacity value between 0 (fully transparent) and 1 (fully opaque)
729      * \see opacity()
730      */
setOpacity(double opacity)731     void setOpacity( double opacity ) { mOpacity = opacity; }
732 
733     /**
734      * Returns the default marker aspect ratio between width and height, 0 if not yet calculated.
735      * \see updateDefaultAspectRatio()
736      */
defaultAspectRatio()737     double defaultAspectRatio() const { return mDefaultAspectRatio; }
738 
739     /**
740      * Calculates the default marker aspect ratio between width and height.
741      * \returns the default aspect ratio value
742      * \see defaultAspectRatio()
743      */
744     double updateDefaultAspectRatio();
745 
746     /**
747      * Returns the preserved aspect ratio value, TRUE if fixed aspect ratio has been lower or equal to 0.
748      * \see setPreservedAspectRatio()
749      */
preservedAspectRatio()750     bool preservedAspectRatio() const { return mFixedAspectRatio <= 0.0; }
751 
752     /**
753      * Set preserved the marker aspect ratio between width and height.
754      * \param par Preserved Aspect Ratio
755      * \returns the preserved aspect ratio value, TRUE if fixed aspect ratio has been lower or equal to 0
756      * \see preservedAspectRatio()
757      */
758     bool setPreservedAspectRatio( bool par );
759 
760     /**
761      * Returns the marker aspect ratio between width and height to be used in rendering,
762      * if the value set is lower or equal to 0 the aspect ratio will be preserved in rendering
763      * \see setFixedAspectRatio() QgsSvgCache
764      */
fixedAspectRatio()765     double fixedAspectRatio() const { return mFixedAspectRatio; }
766 
767     /**
768      * Set the marker aspect ratio between width and height to be used in rendering,
769      * if the value set is lower or equal to 0 the aspect ratio will be preserved in rendering
770      * \param ratio Fixed Aspect Ratio
771      * \see fixedAspectRatio() QgsSvgCache
772      */
setFixedAspectRatio(double ratio)773     void setFixedAspectRatio( double ratio ) { mFixedAspectRatio = ratio; }
774 
775     void setMapUnitScale( const QgsMapUnitScale &scale ) override;
776     QgsMapUnitScale mapUnitScale() const override;
777 
778     QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override;
779 
780   protected:
781 
782     QString mPath;
783     //! The marker default opacity
784     double mOpacity = 1.0;
785     //! The marker default aspect ratio
786     double mDefaultAspectRatio = 0.0;
787     //! The marker fixed aspect ratio
788     double mFixedAspectRatio = 0.0;
789 
790   private:
791     double calculateSize( QgsSymbolRenderContext &context, bool &hasDataDefinedSize ) const;
792     void calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledWidth, double scaledHeight, QPointF &offset, double &angle ) const;
793 
794 };
795 
796 
797 //////////
798 
799 #define POINT2MM(x) ( (x) * 25.4 / 72 ) // point is 1/72 of inch
800 #define MM2POINT(x) ( (x) * 72 / 25.4 )
801 
802 #define DEFAULT_FONTMARKER_FONT   "Dingbats"
803 #define DEFAULT_FONTMARKER_CHR    QChar('A')
804 #define DEFAULT_FONTMARKER_SIZE   POINT2MM(12)
805 #define DEFAULT_FONTMARKER_COLOR  QColor( 35, 35, 35 )
806 #define DEFAULT_FONTMARKER_BORDERCOLOR  QColor(Qt::white)
807 #define DEFAULT_FONTMARKER_JOINSTYLE    Qt::MiterJoin
808 #define DEFAULT_FONTMARKER_ANGLE  0
809 
810 /**
811  * \ingroup core
812  * \class QgsFontMarkerSymbolLayer
813  */
814 class CORE_EXPORT QgsFontMarkerSymbolLayer : public QgsMarkerSymbolLayer
815 {
816   public:
817 
818     //! Constructs a font marker symbol layer.
819     QgsFontMarkerSymbolLayer( const QString &fontFamily = DEFAULT_FONTMARKER_FONT,
820                               QString chr = DEFAULT_FONTMARKER_CHR,
821                               double pointSize = DEFAULT_FONTMARKER_SIZE,
822                               const QColor &color = DEFAULT_FONTMARKER_COLOR,
823                               double angle = DEFAULT_FONTMARKER_ANGLE );
824 
825     // static stuff
826 
827     /**
828      * Creates a new QgsFontMarkerSymbolLayer from a property map (see properties())
829      */
830     static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) SIP_FACTORY;
831 
832     /**
833      * Creates a new QgsFontMarkerSymbolLayer from an SLD XML \a element.
834      */
835     static QgsSymbolLayer *createFromSld( QDomElement &element ) SIP_FACTORY;
836 
837     // implemented from base classes
838 
839     QString layerType() const override;
840 
841     void startRender( QgsSymbolRenderContext &context ) override;
842 
843     void stopRender( QgsSymbolRenderContext &context ) override;
844 
845     void renderPoint( QPointF point, QgsSymbolRenderContext &context ) override;
846 
847     QgsStringMap properties() const override;
848 
849     QgsFontMarkerSymbolLayer *clone() const override SIP_FACTORY;
850 
851     void writeSldMarker( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const override;
852     bool usesMapUnits() const override;
853 
854     // new methods
855 
856     /**
857      * Returns the font family name for the associated font which will be used to render the point.
858      *
859      * \see setFontFamily()
860      */
fontFamily()861     QString fontFamily() const { return mFontFamily; }
862 
863     /**
864      * Sets the font \a family for the font which will be used to render the point.
865      *
866      * \see fontFamily()
867      */
setFontFamily(const QString & family)868     void setFontFamily( const QString &family ) { mFontFamily = family; }
869 
870     /**
871      * Returns the font style for the associated font which will be used to render the point.
872      *
873      * \see setFontStyle()
874      * \since QGIS 3.14
875      */
fontStyle()876     QString fontStyle() const { return mFontStyle; }
877 
878     /**
879      * Sets the font \a style for the font which will be used to render the point.
880      *
881      * \see fontStyle()
882      * \since QGIS 3.14
883      */
setFontStyle(const QString & style)884     void setFontStyle( const QString &style ) { mFontStyle = style; }
885 
886     /**
887      * Returns the character(s) used when rendering points.
888      *
889      * \see setCharacter()
890      */
character()891     QString character() const { return mString; }
892 
893     /**
894      * Sets the character(s) used when rendering points.
895      *
896      * \see character()
897      */
setCharacter(QString chr)898     void setCharacter( QString chr ) { mString = chr; }
899 
strokeColor()900     QColor strokeColor() const override { return mStrokeColor; }
setStrokeColor(const QColor & color)901     void setStrokeColor( const QColor &color ) override { mStrokeColor = color; }
902 
903     /**
904      * Returns the marker's stroke width. Units are retrieved by strokeWidthUnit()
905      *
906      * \see setStrokeWidth()
907      * \see strokeWidthUnit()
908      * \see strokeWidthMapUnitScale()
909      *
910      * \since QGIS 2.16
911     */
strokeWidth()912     double strokeWidth() const { return mStrokeWidth; }
913 
914     /**
915      * Set's the marker's stroke \a width. Units are set by setStrokeWidthUnit().
916      *
917      * \see strokeWidth()
918      * \see setStrokeWidthUnit()
919      * \see setStrokeWidthMapUnitScale()
920      *
921      * \since QGIS 2.16
922     */
setStrokeWidth(double width)923     void setStrokeWidth( double width ) { mStrokeWidth = width; }
924 
925     /**
926      * Returns the stroke width unit.
927      *
928      * \see setStrokeWidthUnit()
929      * \see strokeWidth()
930      * \see strokeWidthMapUnitScale()
931      *
932      * \since QGIS 2.16
933     */
strokeWidthUnit()934     QgsUnitTypes::RenderUnit strokeWidthUnit() const { return mStrokeWidthUnit; }
935 
936     /**
937      * Sets the stroke width \a unit.
938      *
939      * \see strokeWidthUnit()
940      * \see setStrokeWidth()
941      * \see setStrokeWidthMapUnitScale()
942      * \since QGIS 2.16
943     */
setStrokeWidthUnit(QgsUnitTypes::RenderUnit unit)944     void setStrokeWidthUnit( QgsUnitTypes::RenderUnit unit ) { mStrokeWidthUnit = unit; }
945 
946     /**
947      * Returns the stroke width map unit scale.
948      *
949      * \see setStrokeWidthMapUnitScale()
950      * \see strokeWidth()
951      * \see strokeWidthUnit()
952      *
953      * \since QGIS 2.16
954     */
strokeWidthMapUnitScale()955     const QgsMapUnitScale &strokeWidthMapUnitScale() const { return mStrokeWidthMapUnitScale; }
956 
957     /**
958      * Sets the stroke width map unit \a scale.
959      *
960      * \see strokeWidthMapUnitScale()
961      * \see setStrokeWidth()
962      * \see setStrokeWidthUnit()
963      *
964      * \since QGIS 2.16
965      */
setStrokeWidthMapUnitScale(const QgsMapUnitScale & scale)966     void setStrokeWidthMapUnitScale( const QgsMapUnitScale &scale ) { mStrokeWidthMapUnitScale = scale; }
967 
968     /**
969      * Returns the stroke join style.
970      *
971      * \see setPenJoinStyle()
972      *
973      * \since QGIS 2.16
974     */
penJoinStyle()975     Qt::PenJoinStyle penJoinStyle() const { return mPenJoinStyle; }
976 
977     /**
978      * Sets the stroke join \a style.
979      *
980      * \see penJoinStyle()
981      *
982      * \since QGIS 2.16
983     */
setPenJoinStyle(Qt::PenJoinStyle style)984     void setPenJoinStyle( Qt::PenJoinStyle style ) { mPenJoinStyle = style; }
985 
986     QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override;
987 
988   private:
989 
990     QString mFontFamily;
991     QString mFontStyle;
992     QFont mFont;
993     std::unique_ptr< QFontMetrics >mFontMetrics;
994 
995     QString mString;
996 
997     double mChrWidth = 0;
998     QPointF mChrOffset;
999     //! Scaling for font sizes, used if font size grows too large
1000     double mFontSizeScale = 1.0;
1001     double mOrigSize;
1002 
1003     QColor mStrokeColor;
1004     double mStrokeWidth;
1005     QgsUnitTypes::RenderUnit mStrokeWidthUnit;
1006     QgsMapUnitScale mStrokeWidthMapUnitScale;
1007     Qt::PenJoinStyle mPenJoinStyle;
1008 
1009     QPen mPen;
1010     QBrush mBrush;
1011 
1012     bool mUseCachedPath = false;
1013     QPainterPath mCachedPath;
1014 
1015     // If font has a zero (or nearly zero) size, we skip rendering altogether..
1016     bool mNonZeroFontSize = true;
1017 
1018     QString characterToRender( QgsSymbolRenderContext &context, QPointF &charOffset, double &charWidth );
1019     void calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedRotation, QPointF &offset, double &angle ) const;
1020     double calculateSize( QgsSymbolRenderContext &context );
1021 };
1022 
1023 // clazy:excludeall=qstring-allocations
1024 
1025 #endif
1026 
1027 
1028