1 /***************************************************************************
2  qgsellipsesymbollayer.h
3  ---------------------
4  begin                : June 2011
5  copyright            : (C) 2011 by Marco Hugentobler
6  email                : marco dot hugentobler at sourcepole dot ch
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 #ifndef QGSELLIPSESYMBOLLAYER_H
16 #define QGSELLIPSESYMBOLLAYER_H
17 
18 #define DEFAULT_ELLIPSE_JOINSTYLE    Qt::MiterJoin
19 
20 #include "qgis_core.h"
21 #include "qgis.h"
22 #include "qgsmarkersymbollayer.h"
23 #include <QPainterPath>
24 
25 class QgsExpression;
26 
27 /**
28  * \ingroup core
29  * \brief A symbol layer for rendering objects with major and minor axis (e.g. ellipse, rectangle, etc).
30 */
31 class CORE_EXPORT QgsEllipseSymbolLayer: public QgsMarkerSymbolLayer
32 {
33   public:
34 
35     //! Marker symbol shapes
36     enum Shape
37     {
38       Circle, //!< Circle
39       Rectangle, //!< Rectangle
40       Diamond, //!< Diamond
41       Cross, //!< Stroke-only cross
42       Arrow, //!< Stroke-only arrow (since QGIS 3.20)
43       HalfArc, //!< Stroke-only half arc (since QGIS 3.20)
44       Triangle, //!< Triangle
45       RightHalfTriangle, //!< Right half of a triangle
46       LeftHalfTriangle, //!< Left half of a triangle
47       SemiCircle, //!< Semi circle
48     };
49 
50     //! Returns a list of all available shape types.
51     static QList< QgsEllipseSymbolLayer::Shape > availableShapes();
52 
53     /**
54      * Returns TRUE if a \a shape has a fill.
55      * \returns TRUE if shape uses a fill, or FALSE if shape uses lines only
56      * \since QGIS 3.20
57      */
58     static bool shapeIsFilled( const QgsEllipseSymbolLayer::Shape &shape );
59 
60     QgsEllipseSymbolLayer();
61     ~QgsEllipseSymbolLayer() override;
62 
63     //! Creates the symbol layer
64     static QgsSymbolLayer *create( const QVariantMap &properties = QVariantMap() ) SIP_FACTORY;
65     static QgsSymbolLayer *createFromSld( QDomElement &element ) SIP_FACTORY;
66 
67     void renderPoint( QPointF point, QgsSymbolRenderContext &context ) override;
68     QString layerType() const override;
69     void startRender( QgsSymbolRenderContext &context ) override;
70     void stopRender( QgsSymbolRenderContext &context ) override;
71     QgsEllipseSymbolLayer *clone() const override SIP_FACTORY;
72     QVariantMap properties() const override;
73 
74     void toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const override;
75     void writeSldMarker( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const override;
76 
77     bool writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift = QPointF( 0.0, 0.0 ) ) const override;
78 
79     /**
80      * Sets the rendered ellipse marker shape using a symbol \a name.
81      * \see setShape()
82      * \see shape()
83      * \deprecated since QGIS 3.20
84      */
setSymbolName(const QString & name)85     Q_DECL_DEPRECATED void setSymbolName( const QString &name ) SIP_DEPRECATED { mShape = decodeShape( name ); }
86 
87     /**
88      * Returns the shape name for the rendered ellipse marker symbol.
89      * \see shape()
90      * \see setShape()
91      * \deprecated since QGIS 3.20
92      */
symbolName()93     Q_DECL_DEPRECATED QString symbolName() const SIP_DEPRECATED { return encodeShape( mShape ); }
94 
95     /**
96      * Returns the shape for the rendered ellipse marker symbol.
97      * \see setShape()
98      * \since QGIS 3.20
99      */
shape()100     QgsEllipseSymbolLayer::Shape shape() const { return mShape; }
101 
102     /**
103      * Sets the rendered ellipse marker shape.
104      * \param shape new ellipse marker shape
105      * \see shape()
106      * \since QGIS 3.20
107      */
setShape(QgsEllipseSymbolLayer::Shape shape)108     void setShape( QgsEllipseSymbolLayer::Shape shape ) { mShape = shape; }
109 
110     /**
111      * Attempts to decode a string representation of a shape name to the corresponding
112      * shape.
113      * \param name encoded shape name
114      * \param ok if specified, will be set to TRUE if shape was successfully decoded
115      * \returns decoded name
116      * \see encodeShape()
117      * \since QGIS 3.20
118      */
119     static QgsEllipseSymbolLayer::Shape decodeShape( const QString &name, bool *ok = nullptr );
120 
121     /**
122      * Encodes a shape to its string representation.
123      * \param shape shape to encode
124      * \returns encoded string
125      * \see decodeShape()
126      * \since QGIS 3.20
127      */
128     static QString encodeShape( QgsEllipseSymbolLayer::Shape shape );
129 
130     void setSize( double size ) override;
131 
132     void setSymbolWidth( double w );
symbolWidth()133     double symbolWidth() const { return mSymbolWidth; }
134 
135     void setSymbolHeight( double h );
symbolHeight()136     double symbolHeight() const { return mSymbolHeight; }
137 
strokeStyle()138     Qt::PenStyle strokeStyle() const { return mStrokeStyle; }
setStrokeStyle(Qt::PenStyle strokeStyle)139     void setStrokeStyle( Qt::PenStyle strokeStyle ) { mStrokeStyle = strokeStyle; }
140 
141     /**
142      * Gets stroke join style.
143      * \since QGIS 2.16
144      */
penJoinStyle()145     Qt::PenJoinStyle penJoinStyle() const { return mPenJoinStyle; }
146 
147     /**
148      * Set stroke join style.
149      * \since QGIS 2.16
150     */
setPenJoinStyle(Qt::PenJoinStyle style)151     void setPenJoinStyle( Qt::PenJoinStyle style ) { mPenJoinStyle = style; }
152 
153     /**
154      * Returns the marker's stroke cap style (e.g., flat, round, etc).
155      * \see setPenCapStyle()
156      * \see penJoinStyle()
157      * \see strokeColor()
158      * \see strokeStyle()
159      * \since QGIS 3.20
160     */
penCapStyle()161     Qt::PenCapStyle penCapStyle() const { return mPenCapStyle; }
162 
163     /**
164      * Sets the marker's stroke cap \a style (e.g., flat, round, etc).
165      * \see penCapStyle()
166      * \see penJoinStyle()
167      * \see setStrokeColor()
168      * \see setStrokeStyle()
169      * \since QGIS 3.20
170     */
setPenCapStyle(Qt::PenCapStyle style)171     void setPenCapStyle( Qt::PenCapStyle style ) { mPenCapStyle = style; }
172 
setStrokeWidth(double w)173     void setStrokeWidth( double w ) { mStrokeWidth = w; }
strokeWidth()174     double strokeWidth() const { return mStrokeWidth; }
175 
setFillColor(const QColor & c)176     void setFillColor( const QColor &c ) override { setColor( c ); }
fillColor()177     QColor fillColor() const override { return color(); }
178 
setStrokeColor(const QColor & c)179     void setStrokeColor( const QColor &c ) override { mStrokeColor = c; }
strokeColor()180     QColor strokeColor() const override { return mStrokeColor; }
181 
182     /**
183      * Sets the units for the symbol's width.
184      * \param unit symbol units
185      * \see symbolWidthUnit()
186      * \see setSymbolHeightUnit()
187     */
setSymbolWidthUnit(QgsUnitTypes::RenderUnit unit)188     void setSymbolWidthUnit( QgsUnitTypes::RenderUnit unit ) { mSymbolWidthUnit = unit; }
189 
190     /**
191      * Returns the units for the symbol's width.
192      * \see setSymbolWidthUnit()
193      * \see symbolHeightUnit()
194     */
symbolWidthUnit()195     QgsUnitTypes::RenderUnit symbolWidthUnit() const { return mSymbolWidthUnit; }
196 
setSymbolWidthMapUnitScale(const QgsMapUnitScale & scale)197     void setSymbolWidthMapUnitScale( const QgsMapUnitScale &scale ) { mSymbolWidthMapUnitScale = scale; }
symbolWidthMapUnitScale()198     const QgsMapUnitScale &symbolWidthMapUnitScale() const { return mSymbolWidthMapUnitScale; }
199 
200     /**
201      * Sets the units for the symbol's height.
202      * \param unit symbol units
203      * \see symbolHeightUnit()
204      * \see setSymbolWidthUnit()
205     */
setSymbolHeightUnit(QgsUnitTypes::RenderUnit unit)206     void setSymbolHeightUnit( QgsUnitTypes::RenderUnit unit ) { mSymbolHeightUnit = unit; }
207 
208     /**
209      * Returns the units for the symbol's height.
210      * \see setSymbolHeightUnit()
211      * \see symbolWidthUnit()
212     */
symbolHeightUnit()213     QgsUnitTypes::RenderUnit symbolHeightUnit() const { return mSymbolHeightUnit; }
214 
setSymbolHeightMapUnitScale(const QgsMapUnitScale & scale)215     void setSymbolHeightMapUnitScale( const QgsMapUnitScale &scale ) { mSymbolHeightMapUnitScale = scale; }
symbolHeightMapUnitScale()216     const QgsMapUnitScale &symbolHeightMapUnitScale() const { return mSymbolHeightMapUnitScale; }
217 
218     /**
219      * Sets the units for the symbol's stroke width.
220      * \param unit symbol units
221      * \see strokeWidthUnit()
222     */
setStrokeWidthUnit(QgsUnitTypes::RenderUnit unit)223     void setStrokeWidthUnit( QgsUnitTypes::RenderUnit unit ) { mStrokeWidthUnit = unit; }
224 
225     /**
226      * Returns the units for the symbol's stroke width.
227      * \see setStrokeWidthUnit()
228     */
strokeWidthUnit()229     QgsUnitTypes::RenderUnit strokeWidthUnit() const { return mStrokeWidthUnit; }
230 
setStrokeWidthMapUnitScale(const QgsMapUnitScale & scale)231     void setStrokeWidthMapUnitScale( const QgsMapUnitScale &scale ) { mStrokeWidthMapUnitScale = scale; }
strokeWidthMapUnitScale()232     const QgsMapUnitScale &strokeWidthMapUnitScale() const { return mStrokeWidthMapUnitScale; }
233 
234     void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override;
235     QgsUnitTypes::RenderUnit outputUnit() const override;
236     bool usesMapUnits() const override;
237 
238     void setMapUnitScale( const QgsMapUnitScale &scale ) override;
239     QgsMapUnitScale mapUnitScale() const override;
240 
241     QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override;
242 
243   private:
244     Shape mShape = Circle;
245     double mSymbolWidth = 4;
246     QgsUnitTypes::RenderUnit mSymbolWidthUnit = QgsUnitTypes::RenderMillimeters;
247     QgsMapUnitScale mSymbolWidthMapUnitScale;
248     double mSymbolHeight = 3;
249     QgsUnitTypes::RenderUnit mSymbolHeightUnit = QgsUnitTypes::RenderMillimeters;
250     QgsMapUnitScale mSymbolHeightMapUnitScale;
251     QColor mStrokeColor;
252     Qt::PenStyle mStrokeStyle = Qt::SolidLine;
253     Qt::PenJoinStyle mPenJoinStyle = DEFAULT_ELLIPSE_JOINSTYLE;
254     Qt::PenCapStyle mPenCapStyle = Qt::SquareCap;
255     double mStrokeWidth = 0;
256     QgsUnitTypes::RenderUnit mStrokeWidthUnit = QgsUnitTypes::RenderMillimeters;
257     QgsMapUnitScale mStrokeWidthMapUnitScale;
258 
259     QPainterPath mPainterPath;
260 
261     QPen mPen;
262     QBrush mBrush;
263     //! QPen to use as stroke of selected symbols
264     QPen mSelPen;
265     //! QBrush to use as fill of selected symbols
266     QBrush mSelBrush;
267 
268     /**
269      * Setup mPainterPath
270      * \param shape name of symbol
271      * \param context render context
272      * \param scaledWidth optional width
273      * \param scaledHeight optional height
274      * \param f optional feature to render (0 if no data defined rendering)
275      */
276     void preparePath( const QgsEllipseSymbolLayer::Shape &shape, QgsSymbolRenderContext &context, double *scaledWidth = nullptr, double *scaledHeight = nullptr, const QgsFeature *f = nullptr );
277     QSizeF calculateSize( QgsSymbolRenderContext &context, double *scaledWidth = nullptr, double *scaledHeight = nullptr );
278     void calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledWidth, double scaledHeight, bool &hasDataDefinedRotation, QPointF &offset, double &angle ) const;
279 };
280 
281 // clazy:excludeall=qstring-allocations
282 
283 #endif // QGSELLIPSESYMBOLLAYER_H
284 
285 
286