35 props.insert( QStringLiteral(
"color" ), QStringLiteral(
"white" ) );
36 props.insert( QStringLiteral(
"style" ), QStringLiteral(
"solid" ) );
37 props.insert( QStringLiteral(
"style_border" ), QStringLiteral(
"solid" ) );
38 props.insert( QStringLiteral(
"color_border" ), QStringLiteral(
"black" ) );
39 props.insert( QStringLiteral(
"width_border" ), QStringLiteral(
"0.3" ) );
40 props.insert( QStringLiteral(
"joinstyle" ), QStringLiteral(
"miter" ) );
46 if ( mVisible == visible )
55 if ( mHasFixedMapPosition == fixed )
58 mHasFixedMapPosition = fixed;
65 mMapPosition = position;
71 mMapPositionCrs =
crs;
77 mRelativePosition = position;
89 return mOffsetFromReferencePoint / 3.7795275;
94 mOffsetFromReferencePoint = offset;
109 return mFrameSize / 3.7795275;
123 mContentsMargins = margins;
129 mFillSymbol.reset( symbol );
135 QPainter *painter = context.
painter();
142 drawFrame( context );
143 if ( mHasFixedMapPosition )
145 drawMarkerSymbol( context );
147 if ( mHasFixedMapPosition )
170 mMarkerSymbol.reset( symbol );
213 return QSizeF( 0, 0 );
216 void QgsAnnotation::updateBalloon()
219 if ( !mHasFixedMapPosition ||
220 ( mOffsetFromReferencePoint.x() < 0 && ( mOffsetFromReferencePoint.x() + mFrameSize.width() ) > 0
221 && mOffsetFromReferencePoint.y() < 0 && ( mOffsetFromReferencePoint.y() + mFrameSize.height() ) > 0 ) )
223 mBalloonSegment = -1;
228 QList<QLineF> segmentList;
229 segmentList << segment( 0,
nullptr );
230 segmentList << segment( 1,
nullptr );
231 segmentList << segment( 2,
nullptr );
232 segmentList << segment( 3,
nullptr );
235 double minEdgeDist = std::numeric_limits<double>::max();
236 int minEdgeIndex = -1;
241 for (
int i = 0; i < 4; ++i )
243 QLineF currentSegment = segmentList.at( i );
245 double currentMinDist = origin.
sqrDistToSegment( currentSegment.x1(), currentSegment.y1(), currentSegment.x2(), currentSegment.y2(), currentMinDistPoint );
246 bool isPreferredSegment =
false;
250 const double angle = fmod( origin.
azimuth( currentMinDistPoint ) + 360.0, 360.0 );
251 if ( angle < 45 || angle > 315 )
252 isPreferredSegment = i == 0;
253 else if ( angle < 135 )
254 isPreferredSegment = i == 3;
255 else if ( angle < 225 )
256 isPreferredSegment = i == 2;
258 isPreferredSegment = i == 1;
260 else if ( currentMinDist < minEdgeDist )
261 isPreferredSegment =
true;
263 if ( isPreferredSegment )
266 minEdgePoint = currentMinDistPoint;
267 minEdgeDist = currentMinDist;
268 minEdge = currentSegment;
272 if ( minEdgeIndex < 0 )
277 mBalloonSegment = minEdgeIndex;
278 QPointF minEdgeEnd = minEdge.p2();
279 mBalloonSegmentPoint1 = QPointF( minEdgePoint.
x(), minEdgePoint.
y() );
280 if ( std::sqrt( minEdgePoint.
sqrDist( minEdgeEnd.x(), minEdgeEnd.y() ) ) < mSegmentPointWidthMm )
285 mBalloonSegmentPoint1 = QPointF( x, y );
292 mBalloonSegmentPoint2 = QPointF( x, y );
299 auto scaleSize = [context](
double size )->
double 303 if ( mHasFixedMapPosition )
308 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
309 scaleSize( mOffsetFromReferencePoint.y() ),
310 scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
311 scaleSize( mOffsetFromReferencePoint.y() ) );
313 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
314 scaleSize( mOffsetFromReferencePoint.y() ),
315 scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
316 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ) );
318 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
319 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ),
320 scaleSize( mOffsetFromReferencePoint.x() ),
321 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ) );
323 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
324 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ),
325 scaleSize( mOffsetFromReferencePoint.x() ),
326 scaleSize( mOffsetFromReferencePoint.y() ) );
336 return QLineF( 0, 0, scaleSize( mFrameSize.width() ), 0 );
338 return QLineF( scaleSize( mFrameSize.width() ), 0,
339 scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ) );
341 return QLineF( scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ),
342 0, scaleSize( mFrameSize.height() ) );
344 return QLineF( 0, scaleSize( mFrameSize.height() ),
360 poly.reserve( 9 + ( mHasFixedMapPosition ? 3 : 0 ) );
361 QList<QPolygonF> rings;
362 for (
int i = 0; i < 4; ++i )
364 QLineF currentSegment = segment( i, &context );
365 poly << QPointF( currentSegment.p1().x(),
366 currentSegment.p1().y() );
367 if ( i == mBalloonSegment && mHasFixedMapPosition )
371 poly << QPointF( 0, 0 );
375 poly << QPointF( currentSegment.p2().x(), currentSegment.p2().y() );
377 if ( poly.at( 0 ) != poly.at( poly.count() - 1 ) )
378 poly << poly.at( 0 );
380 mFillSymbol->startRender( context );
381 mFillSymbol->renderPolygon( poly, &rings,
nullptr, context );
382 mFillSymbol->stopRender( context );
394 mMarkerSymbol->startRender( context );
395 mMarkerSymbol->renderPoint( QPointF( 0, 0 ),
nullptr, context );
396 mMarkerSymbol->stopRender( context );
402 if ( itemElem.isNull() )
406 QDomElement annotationElem = doc.createElement( QStringLiteral(
"AnnotationItem" ) );
407 annotationElem.setAttribute( QStringLiteral(
"mapPositionFixed" ), mHasFixedMapPosition );
408 annotationElem.setAttribute( QStringLiteral(
"mapPosX" ),
qgsDoubleToString( mMapPosition.
x() ) );
409 annotationElem.setAttribute( QStringLiteral(
"mapPosY" ),
qgsDoubleToString( mMapPosition.
y() ) );
410 if ( mMapPositionCrs.
isValid() )
411 mMapPositionCrs.
writeXml( annotationElem, doc );
412 annotationElem.setAttribute( QStringLiteral(
"offsetXMM" ),
qgsDoubleToString( mOffsetFromReferencePoint.x() ) );
413 annotationElem.setAttribute( QStringLiteral(
"offsetYMM" ),
qgsDoubleToString( mOffsetFromReferencePoint.y() ) );
414 annotationElem.setAttribute( QStringLiteral(
"frameWidthMM" ),
qgsDoubleToString( mFrameSize.width() ) );
415 annotationElem.setAttribute( QStringLiteral(
"frameHeightMM" ),
qgsDoubleToString( mFrameSize.height() ) );
416 annotationElem.setAttribute( QStringLiteral(
"canvasPosX" ),
qgsDoubleToString( mRelativePosition.x() ) );
417 annotationElem.setAttribute( QStringLiteral(
"canvasPosY" ),
qgsDoubleToString( mRelativePosition.y() ) );
418 annotationElem.setAttribute( QStringLiteral(
"contentsMargin" ), mContentsMargins.
toString() );
419 annotationElem.setAttribute( QStringLiteral(
"visible" ),
isVisible() );
422 annotationElem.setAttribute( QStringLiteral(
"mapLayer" ), mMapLayer->id() );
427 if ( !symbolElem.isNull() )
429 annotationElem.appendChild( symbolElem );
434 QDomElement fillElem = doc.createElement( QStringLiteral(
"fillSymbol" ) );
436 if ( !symbolElem.isNull() )
438 fillElem.appendChild( symbolElem );
439 annotationElem.appendChild( fillElem );
442 itemElem.appendChild( annotationElem );
447 if ( annotationElem.isNull() )
452 pos.setX( annotationElem.attribute( QStringLiteral(
"canvasPosX" ), QStringLiteral(
"0" ) ).toDouble() );
453 pos.setY( annotationElem.attribute( QStringLiteral(
"canvasPosY" ), QStringLiteral(
"0" ) ).toDouble() );
454 if ( pos.x() >= 1 || pos.x() < 0 || pos.y() < 0 || pos.y() >= 1 )
455 mRelativePosition = QPointF();
457 mRelativePosition = pos;
459 mapPos.
setX( annotationElem.attribute( QStringLiteral(
"mapPosX" ), QStringLiteral(
"0" ) ).toDouble() );
460 mapPos.
setY( annotationElem.attribute( QStringLiteral(
"mapPosY" ), QStringLiteral(
"0" ) ).toDouble() );
461 mMapPosition = mapPos;
463 if ( !mMapPositionCrs.
readXml( annotationElem ) )
468 mContentsMargins =
QgsMargins::fromString( annotationElem.attribute( QStringLiteral(
"contentsMargin" ) ) );
470 if ( annotationElem.hasAttribute( QStringLiteral(
"frameWidthMM" ) ) )
471 mFrameSize.setWidth( annotationElem.attribute( QStringLiteral(
"frameWidthMM" ), QStringLiteral(
"5" ) ).toDouble() );
473 mFrameSize.setWidth( dpiScale * annotationElem.attribute( QStringLiteral(
"frameWidth" ), QStringLiteral(
"50" ) ).toDouble() );
474 if ( annotationElem.hasAttribute( QStringLiteral(
"frameHeightMM" ) ) )
475 mFrameSize.setHeight( annotationElem.attribute( QStringLiteral(
"frameHeightMM" ), QStringLiteral(
"3" ) ).toDouble() );
477 mFrameSize.setHeight( dpiScale * annotationElem.attribute( QStringLiteral(
"frameHeight" ), QStringLiteral(
"50" ) ).toDouble() );
479 if ( annotationElem.hasAttribute( QStringLiteral(
"offsetXMM" ) ) )
480 mOffsetFromReferencePoint.setX( annotationElem.attribute( QStringLiteral(
"offsetXMM" ), QStringLiteral(
"0" ) ).toDouble() );
482 mOffsetFromReferencePoint.setX( dpiScale * annotationElem.attribute( QStringLiteral(
"offsetX" ), QStringLiteral(
"0" ) ).toDouble() );
483 if ( annotationElem.hasAttribute( QStringLiteral(
"offsetYMM" ) ) )
484 mOffsetFromReferencePoint.setY( annotationElem.attribute( QStringLiteral(
"offsetYMM" ), QStringLiteral(
"0" ) ).toDouble() );
486 mOffsetFromReferencePoint.setY( dpiScale * annotationElem.attribute( QStringLiteral(
"offsetY" ), QStringLiteral(
"0" ) ).toDouble() );
488 mHasFixedMapPosition = annotationElem.attribute( QStringLiteral(
"mapPositionFixed" ), QStringLiteral(
"1" ) ).toInt();
489 mVisible = annotationElem.attribute( QStringLiteral(
"visible" ), QStringLiteral(
"1" ) ).toInt();
490 if ( annotationElem.hasAttribute( QStringLiteral(
"mapLayer" ) ) )
496 QDomElement symbolElem = annotationElem.firstChildElement( QStringLiteral(
"symbol" ) );
497 if ( !symbolElem.isNull() )
499 QgsMarkerSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context );
502 mMarkerSymbol.reset( symbol );
506 mFillSymbol.reset(
nullptr );
507 QDomElement fillElem = annotationElem.firstChildElement( QStringLiteral(
"fillSymbol" ) );
508 if ( !fillElem.isNull() )
510 QDomElement symbolElem = fillElem.firstChildElement( QStringLiteral(
"symbol" ) );
511 if ( !symbolElem.isNull() )
513 QgsFillSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context );
516 mFillSymbol.reset( symbol );
523 frameColor.setNamedColor( annotationElem.attribute( QStringLiteral(
"frameColor" ), QStringLiteral(
"#000000" ) ) );
524 frameColor.setAlpha( annotationElem.attribute( QStringLiteral(
"frameColorAlpha" ), QStringLiteral(
"255" ) ).toInt() );
525 QColor frameBackgroundColor;
526 frameBackgroundColor.setNamedColor( annotationElem.attribute( QStringLiteral(
"frameBackgroundColor" ) ) );
527 frameBackgroundColor.setAlpha( annotationElem.attribute( QStringLiteral(
"frameBackgroundColorAlpha" ), QStringLiteral(
"255" ) ).toInt() );
528 double frameBorderWidth = annotationElem.attribute( QStringLiteral(
"frameBorderWidth" ), QStringLiteral(
"0.5" ) ).toDouble();
530 frameBorderWidth = frameBorderWidth * 25.4 / 96.0;
532 props.insert( QStringLiteral(
"color" ), frameBackgroundColor.name() );
533 props.insert( QStringLiteral(
"style" ), QStringLiteral(
"solid" ) );
534 props.insert( QStringLiteral(
"style_border" ), QStringLiteral(
"solid" ) );
535 props.insert( QStringLiteral(
"color_border" ), frameColor.name() );
536 props.insert( QStringLiteral(
"width_border" ), QString::number( frameBorderWidth ) );
537 props.insert( QStringLiteral(
"joinstyle" ), QStringLiteral(
"miter" ) );
547 target->mVisible = mVisible;
548 target->mHasFixedMapPosition = mHasFixedMapPosition;
549 target->mMapPosition = mMapPosition;
550 target->mMapPositionCrs = mMapPositionCrs;
551 target->mRelativePosition = mRelativePosition;
552 target->mOffsetFromReferencePoint = mOffsetFromReferencePoint;
553 target->mFrameSize = mFrameSize;
554 target->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() : nullptr );
555 target->mContentsMargins = mContentsMargins;
556 target->mFillSymbol.reset( mFillSymbol ? mFillSymbol->clone() : nullptr );
557 target->mBalloonSegment = mBalloonSegment;
558 target->mBalloonSegmentPoint1 = mBalloonSegmentPoint1;
559 target->mBalloonSegmentPoint2 = mBalloonSegmentPoint2;
560 target->mSegmentPointWidthMm = mSegmentPointWidthMm;
561 target->mMapLayer = mMapLayer;
562 target->mFeature = mFeature;
double right() const
Returns the right margin.
The class is used as a container of context for various read/write operations on other objects...
void setVisible(bool visible)
Sets whether the annotation is visible and should be rendered.
Base class for all map layer types.
A symbol entity for QgsStyle databases.
bool isVisible() const
Returns true if the annotation is visible and should be rendered.
void appearanceChanged()
Emitted whenever the annotation's appearance changes.
void _writeXml(QDomElement &itemElem, QDomDocument &doc, const QgsReadWriteContext &context) const
Writes common annotation properties to a DOM element.
void setMapLayer(QgsMapLayer *layer)
Sets the map layer associated with the annotation.
Use antialiasing while drawing.
void mapLayerChanged()
Emitted when the map layer associated with the annotation changes.
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
A class to represent a 2D point.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
void setFrameOffsetFromReferencePointMm(QPointF offset)
Sets the annotation's frame's offset (in millimeters) from the mapPosition() reference point...
Q_DECL_DEPRECATED void setFrameOffsetFromReferencePoint(QPointF offset)
Sets the annotation's frame's offset (in pixels) from the mapPosition() reference point...
Flags flags() const
Returns combination of flags used for rendering.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
const QgsCoordinateReferenceSystem & crs
An interface for classes which can visit style entity (e.g.
void copyCommonProperties(QgsAnnotation *target) const
Copies common annotation properties to the targe annotation.
QMap< QString, QString > QgsStringMap
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
A marker symbol type, for rendering Point and MultiPoint geometries.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
Abstract base class for annotation items which are drawn over a map.
double azimuth(const QgsPointXY &other) const
Calculates azimuth between this point and other one (clockwise in degree, starting from north) ...
Q_GUI_EXPORT int qt_defaultDpiX()
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
virtual void renderAnnotation(QgsRenderContext &context, QSizeF size) const =0
Renders the annotation's contents to a target /a context at the specified /a size.
double sqrDistToSegment(double x1, double y1, double x2, double y2, QgsPointXY &minDistPoint, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Returns the minimum distance between this point and a segment.
virtual bool visitExit(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor stops visiting a node.
void setContentsMargin(const QgsMargins &margins)
Sets the margins (in millimeters) between the outside of the frame and the annotation content...
double bottom() const
Returns the bottom margin.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
void setY(double y)
Sets the y value of the point.
void render(QgsRenderContext &context) const
Renders the annotation to a target render context.
Contains information relating to a node (i.e.
double top() const
Returns the top margin.
virtual QSizeF minimumFrameSize() const
Returns the minimum frame size for the annotation.
An individual annotation.
void setFrameSizeMm(QSizeF size)
Sets the size (in millimeters) of the annotation's frame (the main area in which the annotation's con...
void _readXml(const QDomElement &annotationElem, const QgsReadWriteContext &context)
Reads common annotation properties from a DOM element.
void setX(double x)
Sets the x value of the point.
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 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...
void setHasFixedMapPosition(bool fixed)
Sets whether the annotation is attached to a fixed map position, or uses a position relative to the c...
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance)
Returns a point a specified distance toward a second point.
QgsAnnotation(QObject *parent=nullptr)
Constructor for QgsAnnotation.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
void setMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the symbol that is drawn at the annotation's map position.
Q_DECL_DEPRECATED QPointF frameOffsetFromReferencePoint() const
Returns the annotation's frame's offset (in pixels) from the mapPosition() reference point...
QPainter * painter()
Returns the destination QPainter for the render operation.
virtual bool visitEnter(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor starts visiting a node.
static QgsProject * instance()
Returns the QgsProject singleton instance.
This class represents a coordinate reference system (CRS).
Q_DECL_DEPRECATED QSizeF frameSize() const
Returns the size (in pixels) of the annotation's frame (the main area in which the annotation's conte...
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...
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
QString toString() const
Returns the margins encoded to a string.
void setFillSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used for rendering the annotation frame.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
virtual void setAssociatedFeature(const QgsFeature &feature)
Sets the feature associated with the annotation.
void setMapPositionCrs(const QgsCoordinateReferenceSystem &crs)
Sets the CRS of the map position.
double left() const
Returns the left margin.
Contains information relating to the style entity currently being visited.
The QgsMargins class defines the four margins of a rectangle.
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated within ...
void setRelativePosition(QPointF position)
Sets the relative position of the annotation, if it is not attached to a fixed map position...
bool isValid() const
Returns whether this CRS is correctly initialized and usable.