QGIS API Documentation 3.41.0-Master (3440c17df1d)
Loading...
Searching...
No Matches
qgsannotation.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsannotation.cpp
3 -----------------
4 begin : January 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgsannotation.h"
19#include "moc_qgsannotation.cpp"
20#include "qgssymbollayerutils.h"
21#include "qgsmaplayer.h"
22#include "qgsproject.h"
24#include "qgsshapegenerator.h"
25#include "qgssymbol.h"
26#include "qgsmarkersymbol.h"
27#include "qgsfillsymbol.h"
28#include "qgspainting.h"
29
30#include <QPen>
31#include <QPainter>
32
34 : QObject( parent )
35 , mMarkerSymbol( new QgsMarkerSymbol() )
36{
37 QVariantMap props;
38 props.insert( QStringLiteral( "color" ), QStringLiteral( "white" ) );
39 props.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
40 props.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
41 props.insert( QStringLiteral( "color_border" ), QStringLiteral( "black" ) );
42 props.insert( QStringLiteral( "width_border" ), QStringLiteral( "0.3" ) );
43 props.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
44 mFillSymbol.reset( QgsFillSymbol::createSimple( props ) );
45}
46
48
49void QgsAnnotation::setVisible( bool visible )
50{
51 if ( mVisible == visible )
52 return;
53
54 mVisible = visible;
55 emit appearanceChanged();
56}
57
59{
60 if ( mHasFixedMapPosition == fixed )
61 return;
62
63 mHasFixedMapPosition = fixed;
64 emit moved();
65}
66
68{
69 mMapPosition = position;
70 emit moved();
71}
72
74{
75 mMapPositionCrs = crs;
76 emit moved();
77}
78
79void QgsAnnotation::setRelativePosition( QPointF position )
80{
81 mRelativePosition = position;
82 emit moved();
83}
84
86{
87 // convert from offset in pixels at 96 dpi to mm
88 setFrameOffsetFromReferencePointMm( offset / 3.7795275 );
89}
90
92{
93 return mOffsetFromReferencePoint / 3.7795275;
94}
95
97{
98 mOffsetFromReferencePoint = offset;
99
100 emit moved();
101 emit appearanceChanged();
102}
103
105{
106 // convert from size in pixels at 96 dpi to mm
107 setFrameSizeMm( size / 3.7795275 );
108}
109
111{
112 return mFrameSize / 3.7795275;
113}
114
116{
117 const QSizeF frameSize = minimumFrameSize().expandedTo( size ); //don't allow frame sizes below minimum
118 mFrameSize = frameSize;
119 emit moved();
120 emit appearanceChanged();
121}
122
124{
125 mContentsMargins = margins;
126 emit appearanceChanged();
127}
128
130{
131 mFillSymbol.reset( symbol );
132 emit appearanceChanged();
133}
134
136{
137 return mFillSymbol.get();
138}
139
141{
142 QPainter *painter = context.painter();
143 if ( !painter || ( context.feedback() && context.feedback()->isCanceled() ) )
144 {
145 return;
146 }
147
148 const QgsScopedQPainterState painterState( context.painter() );
150
151 drawFrame( context );
152 if ( mHasFixedMapPosition )
153 {
154 drawMarkerSymbol( context );
155 }
156 if ( mHasFixedMapPosition )
157 {
158 painter->translate( context.convertToPainterUnits( mOffsetFromReferencePoint.x(), Qgis::RenderUnit::Millimeters ) + context.convertToPainterUnits( mContentsMargins.left(), Qgis::RenderUnit::Millimeters ),
159 context.convertToPainterUnits( mOffsetFromReferencePoint.y(), Qgis::RenderUnit::Millimeters ) + context.convertToPainterUnits( mContentsMargins.top(), Qgis::RenderUnit::Millimeters ) );
160 }
161 else
162 {
163 painter->translate( context.convertToPainterUnits( mContentsMargins.left(), Qgis::RenderUnit::Millimeters ),
164 context.convertToPainterUnits( mContentsMargins.top(), Qgis::RenderUnit::Millimeters ) );
165 }
166 const QSizeF size( context.convertToPainterUnits( mFrameSize.width(), Qgis::RenderUnit::Millimeters ) - context.convertToPainterUnits( mContentsMargins.left() + mContentsMargins.right(), Qgis::RenderUnit::Millimeters ),
167 context.convertToPainterUnits( mFrameSize.height(), Qgis::RenderUnit::Millimeters ) - context.convertToPainterUnits( mContentsMargins.top() + mContentsMargins.bottom(), Qgis::RenderUnit::Millimeters ) );
168
169 // scale back from painter dpi to 96 dpi --
170// double dotsPerMM = context.painter()->device()->logicalDpiX() / ( 25.4 * 3.78 );
171// context.painter()->scale( dotsPerMM, dotsPerMM );
172
173 renderAnnotation( context, size );
174}
175
177{
178 mMarkerSymbol.reset( symbol );
179 emit appearanceChanged();
180}
181
183{
184 mMapLayer = layer;
185 emit mapLayerChanged();
186}
187
189{
190 mFeature = feature;
191}
192
194{
195 // NOTE: if visitEnter returns false it means "don't visit the annotation", not "abort all further visitations"
196 if ( !visitor->visitEnter( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Annotation, QStringLiteral( "annotation" ), tr( "Annotation" ) ) ) )
197 return true;
198
199 if ( mMarkerSymbol )
200 {
201 QgsStyleSymbolEntity entity( mMarkerSymbol.get() );
202 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "marker" ), QObject::tr( "Marker" ) ) ) )
203 return false;
204 }
205
206 if ( mFillSymbol )
207 {
208 QgsStyleSymbolEntity entity( mFillSymbol.get() );
209 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "fill" ), QObject::tr( "Fill" ) ) ) )
210 return false;
211 }
212
213 if ( !visitor->visitExit( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Annotation, QStringLiteral( "annotation" ), tr( "Annotation" ) ) ) )
214 return false;
215
216 return true;
217}
218
220{
221 return QSizeF( 0, 0 );
222}
223
224void QgsAnnotation::drawFrame( QgsRenderContext &context ) const
225{
226 if ( !mFillSymbol )
227 return;
228
229 auto scaleSize = [&context]( double size )->double
230 {
232 };
233
234 const QRectF frameRect( mHasFixedMapPosition ? scaleSize( mOffsetFromReferencePoint.x() ) : 0,
235 mHasFixedMapPosition ? scaleSize( mOffsetFromReferencePoint.y() ) : 0,
236 scaleSize( mFrameSize.width() ),
237 scaleSize( mFrameSize.height() ) );
238 const QgsPointXY origin = mHasFixedMapPosition ? QgsPointXY( 0, 0 ) : QgsPointXY( frameRect.center().x(), frameRect.center().y() );
239
240 const QPolygonF poly = QgsShapeGenerator::createBalloon( origin, frameRect, context.convertToPainterUnits( mSegmentPointWidthMm, Qgis::RenderUnit::Millimeters ) );
241
242 mFillSymbol->startRender( context );
243 const QVector<QPolygonF> rings; //empty list
244 mFillSymbol->renderPolygon( poly, &rings, nullptr, context );
245 mFillSymbol->stopRender( context );
246}
247
248void QgsAnnotation::drawMarkerSymbol( QgsRenderContext &context ) const
249{
250 if ( !context.painter() )
251 {
252 return;
253 }
254
255 if ( mMarkerSymbol )
256 {
257 mMarkerSymbol->startRender( context );
258 mMarkerSymbol->renderPoint( QPointF( 0, 0 ), nullptr, context );
259 mMarkerSymbol->stopRender( context );
260 }
261}
262
263void QgsAnnotation::_writeXml( QDomElement &itemElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
264{
265 if ( itemElem.isNull() )
266 {
267 return;
268 }
269 QDomElement annotationElem = doc.createElement( QStringLiteral( "AnnotationItem" ) );
270 annotationElem.setAttribute( QStringLiteral( "mapPositionFixed" ), mHasFixedMapPosition );
271 annotationElem.setAttribute( QStringLiteral( "mapPosX" ), qgsDoubleToString( mMapPosition.x() ) );
272 annotationElem.setAttribute( QStringLiteral( "mapPosY" ), qgsDoubleToString( mMapPosition.y() ) );
273 if ( mMapPositionCrs.isValid() )
274 mMapPositionCrs.writeXml( annotationElem, doc );
275 annotationElem.setAttribute( QStringLiteral( "offsetXMM" ), qgsDoubleToString( mOffsetFromReferencePoint.x() ) );
276 annotationElem.setAttribute( QStringLiteral( "offsetYMM" ), qgsDoubleToString( mOffsetFromReferencePoint.y() ) );
277 annotationElem.setAttribute( QStringLiteral( "frameWidthMM" ), qgsDoubleToString( mFrameSize.width() ) );
278 annotationElem.setAttribute( QStringLiteral( "frameHeightMM" ), qgsDoubleToString( mFrameSize.height() ) );
279 annotationElem.setAttribute( QStringLiteral( "canvasPosX" ), qgsDoubleToString( mRelativePosition.x() ) );
280 annotationElem.setAttribute( QStringLiteral( "canvasPosY" ), qgsDoubleToString( mRelativePosition.y() ) );
281 annotationElem.setAttribute( QStringLiteral( "contentsMargin" ), mContentsMargins.toString() );
282 annotationElem.setAttribute( QStringLiteral( "visible" ), isVisible() );
283 if ( mMapLayer )
284 {
285 annotationElem.setAttribute( QStringLiteral( "mapLayer" ), mMapLayer->id() );
286 }
287 if ( mMarkerSymbol )
288 {
289 const QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "marker symbol" ), mMarkerSymbol.get(), doc, context );
290 if ( !symbolElem.isNull() )
291 {
292 annotationElem.appendChild( symbolElem );
293 }
294 }
295 if ( mFillSymbol )
296 {
297 QDomElement fillElem = doc.createElement( QStringLiteral( "fillSymbol" ) );
298 const QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "fill symbol" ), mFillSymbol.get(), doc, context );
299 if ( !symbolElem.isNull() )
300 {
301 fillElem.appendChild( symbolElem );
302 annotationElem.appendChild( fillElem );
303 }
304 }
305 itemElem.appendChild( annotationElem );
306}
307
308void QgsAnnotation::_readXml( const QDomElement &annotationElem, const QgsReadWriteContext &context )
309{
310 if ( annotationElem.isNull() )
311 {
312 return;
313 }
314 QPointF pos;
315 pos.setX( annotationElem.attribute( QStringLiteral( "canvasPosX" ), QStringLiteral( "0" ) ).toDouble() );
316 pos.setY( annotationElem.attribute( QStringLiteral( "canvasPosY" ), QStringLiteral( "0" ) ).toDouble() );
317 if ( pos.x() >= 1 || pos.x() < 0 || pos.y() < 0 || pos.y() >= 1 )
318 mRelativePosition = QPointF();
319 else
320 mRelativePosition = pos;
321 QgsPointXY mapPos;
322 mapPos.setX( annotationElem.attribute( QStringLiteral( "mapPosX" ), QStringLiteral( "0" ) ).toDouble() );
323 mapPos.setY( annotationElem.attribute( QStringLiteral( "mapPosY" ), QStringLiteral( "0" ) ).toDouble() );
324 mMapPosition = mapPos;
325
326 if ( !mMapPositionCrs.readXml( annotationElem ) )
327 {
328 mMapPositionCrs = QgsCoordinateReferenceSystem();
329 }
330
331 mContentsMargins = QgsMargins::fromString( annotationElem.attribute( QStringLiteral( "contentsMargin" ) ) );
332 const double dpiScale = 25.4 / QgsPainting::qtDefaultDpiX();
333 if ( annotationElem.hasAttribute( QStringLiteral( "frameWidthMM" ) ) )
334 mFrameSize.setWidth( annotationElem.attribute( QStringLiteral( "frameWidthMM" ), QStringLiteral( "5" ) ).toDouble() );
335 else
336 mFrameSize.setWidth( dpiScale * annotationElem.attribute( QStringLiteral( "frameWidth" ), QStringLiteral( "50" ) ).toDouble() );
337 if ( annotationElem.hasAttribute( QStringLiteral( "frameHeightMM" ) ) )
338 mFrameSize.setHeight( annotationElem.attribute( QStringLiteral( "frameHeightMM" ), QStringLiteral( "3" ) ).toDouble() );
339 else
340 mFrameSize.setHeight( dpiScale * annotationElem.attribute( QStringLiteral( "frameHeight" ), QStringLiteral( "50" ) ).toDouble() );
341
342 if ( annotationElem.hasAttribute( QStringLiteral( "offsetXMM" ) ) )
343 mOffsetFromReferencePoint.setX( annotationElem.attribute( QStringLiteral( "offsetXMM" ), QStringLiteral( "0" ) ).toDouble() );
344 else
345 mOffsetFromReferencePoint.setX( dpiScale * annotationElem.attribute( QStringLiteral( "offsetX" ), QStringLiteral( "0" ) ).toDouble() );
346 if ( annotationElem.hasAttribute( QStringLiteral( "offsetYMM" ) ) )
347 mOffsetFromReferencePoint.setY( annotationElem.attribute( QStringLiteral( "offsetYMM" ), QStringLiteral( "0" ) ).toDouble() );
348 else
349 mOffsetFromReferencePoint.setY( dpiScale * annotationElem.attribute( QStringLiteral( "offsetY" ), QStringLiteral( "0" ) ).toDouble() );
350
351 mHasFixedMapPosition = annotationElem.attribute( QStringLiteral( "mapPositionFixed" ), QStringLiteral( "1" ) ).toInt();
352 mVisible = annotationElem.attribute( QStringLiteral( "visible" ), QStringLiteral( "1" ) ).toInt();
353 if ( annotationElem.hasAttribute( QStringLiteral( "mapLayer" ) ) )
354 {
355 mMapLayer = QgsProject::instance()->mapLayer( annotationElem.attribute( QStringLiteral( "mapLayer" ) ) ); // skip-keyword-check
356 }
357
358 //marker symbol
359 {
360 const QDomElement symbolElem = annotationElem.firstChildElement( QStringLiteral( "symbol" ) );
361 if ( !symbolElem.isNull() )
362 {
363 QgsMarkerSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context );
364 if ( symbol )
365 {
366 mMarkerSymbol.reset( symbol );
367 }
368 }
369 }
370
371 mFillSymbol.reset( nullptr );
372 const QDomElement fillElem = annotationElem.firstChildElement( QStringLiteral( "fillSymbol" ) );
373 if ( !fillElem.isNull() )
374 {
375 const QDomElement symbolElem = fillElem.firstChildElement( QStringLiteral( "symbol" ) );
376 if ( !symbolElem.isNull() )
377 {
378 QgsFillSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context );
379 if ( symbol )
380 {
381 mFillSymbol.reset( symbol );
382 }
383 }
384 }
385 if ( !mFillSymbol )
386 {
387 QColor frameColor;
388 frameColor.setNamedColor( annotationElem.attribute( QStringLiteral( "frameColor" ), QStringLiteral( "#000000" ) ) );
389 frameColor.setAlpha( annotationElem.attribute( QStringLiteral( "frameColorAlpha" ), QStringLiteral( "255" ) ).toInt() );
390 QColor frameBackgroundColor;
391 frameBackgroundColor.setNamedColor( annotationElem.attribute( QStringLiteral( "frameBackgroundColor" ) ) );
392 frameBackgroundColor.setAlpha( annotationElem.attribute( QStringLiteral( "frameBackgroundColorAlpha" ), QStringLiteral( "255" ) ).toInt() );
393 double frameBorderWidth = annotationElem.attribute( QStringLiteral( "frameBorderWidth" ), QStringLiteral( "0.5" ) ).toDouble();
394 // need to roughly convert border width from pixels to mm - just assume 96 dpi
395 frameBorderWidth = frameBorderWidth * 25.4 / 96.0;
396 QVariantMap props;
397 props.insert( QStringLiteral( "color" ), frameBackgroundColor.name() );
398 props.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
399 props.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
400 props.insert( QStringLiteral( "color_border" ), frameColor.name() );
401 props.insert( QStringLiteral( "width_border" ), QString::number( frameBorderWidth ) );
402 props.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
403 mFillSymbol.reset( QgsFillSymbol::createSimple( props ) );
404 }
405
406 emit mapLayerChanged();
407}
408
410{
411 target->mVisible = mVisible;
412 target->mHasFixedMapPosition = mHasFixedMapPosition;
413 target->mMapPosition = mMapPosition;
414 target->mMapPositionCrs = mMapPositionCrs;
415 target->mRelativePosition = mRelativePosition;
416 target->mOffsetFromReferencePoint = mOffsetFromReferencePoint;
417 target->mFrameSize = mFrameSize;
418 target->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() : nullptr );
419 target->mContentsMargins = mContentsMargins;
420 target->mFillSymbol.reset( mFillSymbol ? mFillSymbol->clone() : nullptr );
421 target->mSegmentPointWidthMm = mSegmentPointWidthMm;
422 target->mMapLayer = mMapLayer;
423 target->mFeature = mFeature;
424}
425
@ Millimeters
Millimeters.
Abstract base class for annotation items which are drawn over a map.
void appearanceChanged()
Emitted whenever the annotation's appearance changes.
Q_DECL_DEPRECATED void setFrameSize(QSizeF size)
Sets the size (in pixels) of the annotation's frame (the main area in which the annotation's content ...
void setFillSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used for rendering the annotation frame.
Q_DECL_DEPRECATED void setFrameOffsetFromReferencePoint(QPointF offset)
Sets the annotation's frame's offset (in pixels) from the mapPosition() reference point.
void setRelativePosition(QPointF position)
Sets the relative position of the annotation, if it is not attached to a fixed map position.
virtual void renderAnnotation(QgsRenderContext &context, QSizeF size) const =0
Renders the annotation's contents to a target /a context at the specified /a size.
void setMapPosition(const QgsPointXY &position)
Sets the map position of the annotation, if it is attached to a fixed map position.
void moved()
Emitted when the annotation's position has changed and items need to be moved to reflect this.
Q_DECL_DEPRECATED QPointF frameOffsetFromReferencePoint() const
Returns the annotation's frame's offset (in pixels) from the mapPosition() reference point.
void _writeXml(QDomElement &itemElem, QDomDocument &doc, const QgsReadWriteContext &context) const
Writes common annotation properties to a DOM element.
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated within ...
void setContentsMargin(const QgsMargins &margins)
Sets the margins (in millimeters) between the outside of the frame and the annotation content.
void setFrameSizeMm(QSizeF size)
Sets the size (in millimeters) of the annotation's frame (the main area in which the annotation's con...
virtual void setAssociatedFeature(const QgsFeature &feature)
Sets the feature associated with the annotation.
void setFrameOffsetFromReferencePointMm(QPointF offset)
Sets the annotation's frame's offset (in millimeters) from the mapPosition() reference point.
void setMapPositionCrs(const QgsCoordinateReferenceSystem &crs)
Sets the CRS of the map position.
~QgsAnnotation() override
void _readXml(const QDomElement &annotationElem, const QgsReadWriteContext &context)
Reads common annotation properties from a DOM element.
void copyCommonProperties(QgsAnnotation *target) const
Copies common annotation properties to the targe annotation.
void render(QgsRenderContext &context) const
Renders the annotation to a target render context.
virtual QSizeF minimumFrameSize() const
Returns the minimum frame size for the annotation.
bool isVisible() const
Returns true if the annotation is visible and should be rendered.
void setHasFixedMapPosition(bool fixed)
Sets whether the annotation is attached to a fixed map position, or uses a position relative to the c...
QgsAnnotation(QObject *parent=nullptr)
Constructor for QgsAnnotation.
void setMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the symbol that is drawn at the annotation's map position.
QgsFillSymbol * fillSymbol() const
Returns the symbol that is used for rendering the annotation frame.
void setVisible(bool visible)
Sets whether the annotation is visible and should be rendered.
void mapLayerChanged()
Emitted when the map layer associated with the annotation changes.
void setMapLayer(QgsMapLayer *layer)
Sets the map layer associated with the annotation.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
static QgsFillSymbol * createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
Base class for all map layer types.
Definition qgsmaplayer.h:76
The QgsMargins class defines the four margins of a rectangle.
Definition qgsmargins.h:37
double top() const
Returns the top margin.
Definition qgsmargins.h:77
static QgsMargins fromString(const QString &string)
Returns a QgsMargins object decoded from a string, or a null QgsMargins if the string could not be in...
double right() const
Returns the right margin.
Definition qgsmargins.h:83
double bottom() const
Returns the bottom margin.
Definition qgsmargins.h:89
QString toString() const
Returns the margins encoded to a string.
double left() const
Returns the left margin.
Definition qgsmargins.h:71
A marker symbol type, for rendering Point and MultiPoint geometries.
static int qtDefaultDpiX()
Returns the default Qt horizontal DPI.
A class to represent a 2D point.
Definition qgspointxy.h:60
void setY(double y)
Sets the y value of the point.
Definition qgspointxy.h:129
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
void setX(double x)
Sets the x value of the point.
Definition qgspointxy.h:119
static QgsProject * instance()
Returns the QgsProject singleton instance.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly during rendering to check if rendering shou...
Scoped object for saving and restoring a QPainter object's state.
static QPolygonF createBalloon(const QgsPointXY &origin, const QRectF &rect, double wedgeWidth)
Generates a "balloon"/"talking bubble" style shape (as a QPolygonF).
An interface for classes which can visit style entity (e.g.
@ Annotation
An individual annotation.
virtual bool visitExit(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor stops visiting a node.
virtual bool visitEnter(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor starts visiting a node.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A symbol entity for QgsStyle databases.
Definition qgsstyle.h:1396
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:5875
const QgsCoordinateReferenceSystem & crs
Contains information relating to a node (i.e.
Contains information relating to the style entity currently being visited.