QGIS API Documentation 3.40.0-Bratislava (b56115d8743)
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 "qgssymbollayerutils.h"
20#include "qgsmaplayer.h"
21#include "qgsproject.h"
23#include "qgsshapegenerator.h"
24#include "qgssymbol.h"
25#include "qgsmarkersymbol.h"
26#include "qgsfillsymbol.h"
27#include "qgspainting.h"
28
29#include <QPen>
30#include <QPainter>
31
33 : QObject( parent )
34 , mMarkerSymbol( new QgsMarkerSymbol() )
35{
36 QVariantMap props;
37 props.insert( QStringLiteral( "color" ), QStringLiteral( "white" ) );
38 props.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
39 props.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
40 props.insert( QStringLiteral( "color_border" ), QStringLiteral( "black" ) );
41 props.insert( QStringLiteral( "width_border" ), QStringLiteral( "0.3" ) );
42 props.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
43 mFillSymbol.reset( QgsFillSymbol::createSimple( props ) );
44}
45
47
48void QgsAnnotation::setVisible( bool visible )
49{
50 if ( mVisible == visible )
51 return;
52
53 mVisible = visible;
54 emit appearanceChanged();
55}
56
58{
59 if ( mHasFixedMapPosition == fixed )
60 return;
61
62 mHasFixedMapPosition = fixed;
63 emit moved();
64}
65
67{
68 mMapPosition = position;
69 emit moved();
70}
71
73{
74 mMapPositionCrs = crs;
75 emit moved();
76}
77
78void QgsAnnotation::setRelativePosition( QPointF position )
79{
80 mRelativePosition = position;
81 emit moved();
82}
83
85{
86 // convert from offset in pixels at 96 dpi to mm
87 setFrameOffsetFromReferencePointMm( offset / 3.7795275 );
88}
89
91{
92 return mOffsetFromReferencePoint / 3.7795275;
93}
94
96{
97 mOffsetFromReferencePoint = offset;
98
99 emit moved();
100 emit appearanceChanged();
101}
102
104{
105 // convert from size in pixels at 96 dpi to mm
106 setFrameSizeMm( size / 3.7795275 );
107}
108
110{
111 return mFrameSize / 3.7795275;
112}
113
115{
116 const QSizeF frameSize = minimumFrameSize().expandedTo( size ); //don't allow frame sizes below minimum
117 mFrameSize = frameSize;
118 emit moved();
119 emit appearanceChanged();
120}
121
123{
124 mContentsMargins = margins;
125 emit appearanceChanged();
126}
127
129{
130 mFillSymbol.reset( symbol );
131 emit appearanceChanged();
132}
133
135{
136 return mFillSymbol.get();
137}
138
140{
141 QPainter *painter = context.painter();
142 if ( !painter || ( context.feedback() && context.feedback()->isCanceled() ) )
143 {
144 return;
145 }
146
147 const QgsScopedQPainterState painterState( context.painter() );
149
150 drawFrame( context );
151 if ( mHasFixedMapPosition )
152 {
153 drawMarkerSymbol( context );
154 }
155 if ( mHasFixedMapPosition )
156 {
157 painter->translate( context.convertToPainterUnits( mOffsetFromReferencePoint.x(), Qgis::RenderUnit::Millimeters ) + context.convertToPainterUnits( mContentsMargins.left(), Qgis::RenderUnit::Millimeters ),
158 context.convertToPainterUnits( mOffsetFromReferencePoint.y(), Qgis::RenderUnit::Millimeters ) + context.convertToPainterUnits( mContentsMargins.top(), Qgis::RenderUnit::Millimeters ) );
159 }
160 else
161 {
162 painter->translate( context.convertToPainterUnits( mContentsMargins.left(), Qgis::RenderUnit::Millimeters ),
163 context.convertToPainterUnits( mContentsMargins.top(), Qgis::RenderUnit::Millimeters ) );
164 }
165 const QSizeF size( context.convertToPainterUnits( mFrameSize.width(), Qgis::RenderUnit::Millimeters ) - context.convertToPainterUnits( mContentsMargins.left() + mContentsMargins.right(), Qgis::RenderUnit::Millimeters ),
166 context.convertToPainterUnits( mFrameSize.height(), Qgis::RenderUnit::Millimeters ) - context.convertToPainterUnits( mContentsMargins.top() + mContentsMargins.bottom(), Qgis::RenderUnit::Millimeters ) );
167
168 // scale back from painter dpi to 96 dpi --
169// double dotsPerMM = context.painter()->device()->logicalDpiX() / ( 25.4 * 3.78 );
170// context.painter()->scale( dotsPerMM, dotsPerMM );
171
172 renderAnnotation( context, size );
173}
174
176{
177 mMarkerSymbol.reset( symbol );
178 emit appearanceChanged();
179}
180
182{
183 mMapLayer = layer;
184 emit mapLayerChanged();
185}
186
188{
189 mFeature = feature;
190}
191
193{
194 // NOTE: if visitEnter returns false it means "don't visit the annotation", not "abort all further visitations"
195 if ( !visitor->visitEnter( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Annotation, QStringLiteral( "annotation" ), tr( "Annotation" ) ) ) )
196 return true;
197
198 if ( mMarkerSymbol )
199 {
200 QgsStyleSymbolEntity entity( mMarkerSymbol.get() );
201 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "marker" ), QObject::tr( "Marker" ) ) ) )
202 return false;
203 }
204
205 if ( mFillSymbol )
206 {
207 QgsStyleSymbolEntity entity( mFillSymbol.get() );
208 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "fill" ), QObject::tr( "Fill" ) ) ) )
209 return false;
210 }
211
212 if ( !visitor->visitExit( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Annotation, QStringLiteral( "annotation" ), tr( "Annotation" ) ) ) )
213 return false;
214
215 return true;
216}
217
219{
220 return QSizeF( 0, 0 );
221}
222
223void QgsAnnotation::drawFrame( QgsRenderContext &context ) const
224{
225 if ( !mFillSymbol )
226 return;
227
228 auto scaleSize = [&context]( double size )->double
229 {
231 };
232
233 const QRectF frameRect( mHasFixedMapPosition ? scaleSize( mOffsetFromReferencePoint.x() ) : 0,
234 mHasFixedMapPosition ? scaleSize( mOffsetFromReferencePoint.y() ) : 0,
235 scaleSize( mFrameSize.width() ),
236 scaleSize( mFrameSize.height() ) );
237 const QgsPointXY origin = mHasFixedMapPosition ? QgsPointXY( 0, 0 ) : QgsPointXY( frameRect.center().x(), frameRect.center().y() );
238
239 const QPolygonF poly = QgsShapeGenerator::createBalloon( origin, frameRect, context.convertToPainterUnits( mSegmentPointWidthMm, Qgis::RenderUnit::Millimeters ) );
240
241 mFillSymbol->startRender( context );
242 const QVector<QPolygonF> rings; //empty list
243 mFillSymbol->renderPolygon( poly, &rings, nullptr, context );
244 mFillSymbol->stopRender( context );
245}
246
247void QgsAnnotation::drawMarkerSymbol( QgsRenderContext &context ) const
248{
249 if ( !context.painter() )
250 {
251 return;
252 }
253
254 if ( mMarkerSymbol )
255 {
256 mMarkerSymbol->startRender( context );
257 mMarkerSymbol->renderPoint( QPointF( 0, 0 ), nullptr, context );
258 mMarkerSymbol->stopRender( context );
259 }
260}
261
262void QgsAnnotation::_writeXml( QDomElement &itemElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
263{
264 if ( itemElem.isNull() )
265 {
266 return;
267 }
268 QDomElement annotationElem = doc.createElement( QStringLiteral( "AnnotationItem" ) );
269 annotationElem.setAttribute( QStringLiteral( "mapPositionFixed" ), mHasFixedMapPosition );
270 annotationElem.setAttribute( QStringLiteral( "mapPosX" ), qgsDoubleToString( mMapPosition.x() ) );
271 annotationElem.setAttribute( QStringLiteral( "mapPosY" ), qgsDoubleToString( mMapPosition.y() ) );
272 if ( mMapPositionCrs.isValid() )
273 mMapPositionCrs.writeXml( annotationElem, doc );
274 annotationElem.setAttribute( QStringLiteral( "offsetXMM" ), qgsDoubleToString( mOffsetFromReferencePoint.x() ) );
275 annotationElem.setAttribute( QStringLiteral( "offsetYMM" ), qgsDoubleToString( mOffsetFromReferencePoint.y() ) );
276 annotationElem.setAttribute( QStringLiteral( "frameWidthMM" ), qgsDoubleToString( mFrameSize.width() ) );
277 annotationElem.setAttribute( QStringLiteral( "frameHeightMM" ), qgsDoubleToString( mFrameSize.height() ) );
278 annotationElem.setAttribute( QStringLiteral( "canvasPosX" ), qgsDoubleToString( mRelativePosition.x() ) );
279 annotationElem.setAttribute( QStringLiteral( "canvasPosY" ), qgsDoubleToString( mRelativePosition.y() ) );
280 annotationElem.setAttribute( QStringLiteral( "contentsMargin" ), mContentsMargins.toString() );
281 annotationElem.setAttribute( QStringLiteral( "visible" ), isVisible() );
282 if ( mMapLayer )
283 {
284 annotationElem.setAttribute( QStringLiteral( "mapLayer" ), mMapLayer->id() );
285 }
286 if ( mMarkerSymbol )
287 {
288 const QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "marker symbol" ), mMarkerSymbol.get(), doc, context );
289 if ( !symbolElem.isNull() )
290 {
291 annotationElem.appendChild( symbolElem );
292 }
293 }
294 if ( mFillSymbol )
295 {
296 QDomElement fillElem = doc.createElement( QStringLiteral( "fillSymbol" ) );
297 const QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "fill symbol" ), mFillSymbol.get(), doc, context );
298 if ( !symbolElem.isNull() )
299 {
300 fillElem.appendChild( symbolElem );
301 annotationElem.appendChild( fillElem );
302 }
303 }
304 itemElem.appendChild( annotationElem );
305}
306
307void QgsAnnotation::_readXml( const QDomElement &annotationElem, const QgsReadWriteContext &context )
308{
309 if ( annotationElem.isNull() )
310 {
311 return;
312 }
313 QPointF pos;
314 pos.setX( annotationElem.attribute( QStringLiteral( "canvasPosX" ), QStringLiteral( "0" ) ).toDouble() );
315 pos.setY( annotationElem.attribute( QStringLiteral( "canvasPosY" ), QStringLiteral( "0" ) ).toDouble() );
316 if ( pos.x() >= 1 || pos.x() < 0 || pos.y() < 0 || pos.y() >= 1 )
317 mRelativePosition = QPointF();
318 else
319 mRelativePosition = pos;
320 QgsPointXY mapPos;
321 mapPos.setX( annotationElem.attribute( QStringLiteral( "mapPosX" ), QStringLiteral( "0" ) ).toDouble() );
322 mapPos.setY( annotationElem.attribute( QStringLiteral( "mapPosY" ), QStringLiteral( "0" ) ).toDouble() );
323 mMapPosition = mapPos;
324
325 if ( !mMapPositionCrs.readXml( annotationElem ) )
326 {
327 mMapPositionCrs = QgsCoordinateReferenceSystem();
328 }
329
330 mContentsMargins = QgsMargins::fromString( annotationElem.attribute( QStringLiteral( "contentsMargin" ) ) );
331 const double dpiScale = 25.4 / QgsPainting::qtDefaultDpiX();
332 if ( annotationElem.hasAttribute( QStringLiteral( "frameWidthMM" ) ) )
333 mFrameSize.setWidth( annotationElem.attribute( QStringLiteral( "frameWidthMM" ), QStringLiteral( "5" ) ).toDouble() );
334 else
335 mFrameSize.setWidth( dpiScale * annotationElem.attribute( QStringLiteral( "frameWidth" ), QStringLiteral( "50" ) ).toDouble() );
336 if ( annotationElem.hasAttribute( QStringLiteral( "frameHeightMM" ) ) )
337 mFrameSize.setHeight( annotationElem.attribute( QStringLiteral( "frameHeightMM" ), QStringLiteral( "3" ) ).toDouble() );
338 else
339 mFrameSize.setHeight( dpiScale * annotationElem.attribute( QStringLiteral( "frameHeight" ), QStringLiteral( "50" ) ).toDouble() );
340
341 if ( annotationElem.hasAttribute( QStringLiteral( "offsetXMM" ) ) )
342 mOffsetFromReferencePoint.setX( annotationElem.attribute( QStringLiteral( "offsetXMM" ), QStringLiteral( "0" ) ).toDouble() );
343 else
344 mOffsetFromReferencePoint.setX( dpiScale * annotationElem.attribute( QStringLiteral( "offsetX" ), QStringLiteral( "0" ) ).toDouble() );
345 if ( annotationElem.hasAttribute( QStringLiteral( "offsetYMM" ) ) )
346 mOffsetFromReferencePoint.setY( annotationElem.attribute( QStringLiteral( "offsetYMM" ), QStringLiteral( "0" ) ).toDouble() );
347 else
348 mOffsetFromReferencePoint.setY( dpiScale * annotationElem.attribute( QStringLiteral( "offsetY" ), QStringLiteral( "0" ) ).toDouble() );
349
350 mHasFixedMapPosition = annotationElem.attribute( QStringLiteral( "mapPositionFixed" ), QStringLiteral( "1" ) ).toInt();
351 mVisible = annotationElem.attribute( QStringLiteral( "visible" ), QStringLiteral( "1" ) ).toInt();
352 if ( annotationElem.hasAttribute( QStringLiteral( "mapLayer" ) ) )
353 {
354 mMapLayer = QgsProject::instance()->mapLayer( annotationElem.attribute( QStringLiteral( "mapLayer" ) ) ); // skip-keyword-check
355 }
356
357 //marker symbol
358 {
359 const QDomElement symbolElem = annotationElem.firstChildElement( QStringLiteral( "symbol" ) );
360 if ( !symbolElem.isNull() )
361 {
362 QgsMarkerSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context );
363 if ( symbol )
364 {
365 mMarkerSymbol.reset( symbol );
366 }
367 }
368 }
369
370 mFillSymbol.reset( nullptr );
371 const QDomElement fillElem = annotationElem.firstChildElement( QStringLiteral( "fillSymbol" ) );
372 if ( !fillElem.isNull() )
373 {
374 const QDomElement symbolElem = fillElem.firstChildElement( QStringLiteral( "symbol" ) );
375 if ( !symbolElem.isNull() )
376 {
377 QgsFillSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context );
378 if ( symbol )
379 {
380 mFillSymbol.reset( symbol );
381 }
382 }
383 }
384 if ( !mFillSymbol )
385 {
386 QColor frameColor;
387 frameColor.setNamedColor( annotationElem.attribute( QStringLiteral( "frameColor" ), QStringLiteral( "#000000" ) ) );
388 frameColor.setAlpha( annotationElem.attribute( QStringLiteral( "frameColorAlpha" ), QStringLiteral( "255" ) ).toInt() );
389 QColor frameBackgroundColor;
390 frameBackgroundColor.setNamedColor( annotationElem.attribute( QStringLiteral( "frameBackgroundColor" ) ) );
391 frameBackgroundColor.setAlpha( annotationElem.attribute( QStringLiteral( "frameBackgroundColorAlpha" ), QStringLiteral( "255" ) ).toInt() );
392 double frameBorderWidth = annotationElem.attribute( QStringLiteral( "frameBorderWidth" ), QStringLiteral( "0.5" ) ).toDouble();
393 // need to roughly convert border width from pixels to mm - just assume 96 dpi
394 frameBorderWidth = frameBorderWidth * 25.4 / 96.0;
395 QVariantMap props;
396 props.insert( QStringLiteral( "color" ), frameBackgroundColor.name() );
397 props.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
398 props.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
399 props.insert( QStringLiteral( "color_border" ), frameColor.name() );
400 props.insert( QStringLiteral( "width_border" ), QString::number( frameBorderWidth ) );
401 props.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
402 mFillSymbol.reset( QgsFillSymbol::createSimple( props ) );
403 }
404
405 emit mapLayerChanged();
406}
407
409{
410 target->mVisible = mVisible;
411 target->mHasFixedMapPosition = mHasFixedMapPosition;
412 target->mMapPosition = mMapPosition;
413 target->mMapPositionCrs = mMapPositionCrs;
414 target->mRelativePosition = mRelativePosition;
415 target->mOffsetFromReferencePoint = mOffsetFromReferencePoint;
416 target->mFrameSize = mFrameSize;
417 target->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() : nullptr );
418 target->mContentsMargins = mContentsMargins;
419 target->mFillSymbol.reset( mFillSymbol ? mFillSymbol->clone() : nullptr );
420 target->mSegmentPointWidthMm = mSegmentPointWidthMm;
421 target->mMapLayer = mMapLayer;
422 target->mFeature = mFeature;
423}
424
@ 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:5834
const QgsCoordinateReferenceSystem & crs
Contains information relating to a node (i.e.
Contains information relating to the style entity currently being visited.