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" ) );
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();
144 drawFrame( context );
145 if ( mHasFixedMapPosition )
147 drawMarkerSymbol( context );
149 if ( mHasFixedMapPosition )
171 mMarkerSymbol.reset( symbol );
214 return QSizeF( 0, 0 );
217 void QgsAnnotation::updateBalloon()
220 if ( !mHasFixedMapPosition ||
221 ( mOffsetFromReferencePoint.x() < 0 && ( mOffsetFromReferencePoint.x() + mFrameSize.width() ) > 0
222 && mOffsetFromReferencePoint.y() < 0 && ( mOffsetFromReferencePoint.y() + mFrameSize.height() ) > 0 ) )
224 mBalloonSegment = -1;
229 QList<QLineF> segmentList;
230 segmentList << segment( 0,
nullptr );
231 segmentList << segment( 1,
nullptr );
232 segmentList << segment( 2,
nullptr );
233 segmentList << segment( 3,
nullptr );
236 double minEdgeDist = std::numeric_limits<double>::max();
237 int minEdgeIndex = -1;
242 for (
int i = 0; i < 4; ++i )
244 QLineF currentSegment = segmentList.at( i );
246 double currentMinDist = origin.
sqrDistToSegment( currentSegment.x1(), currentSegment.y1(), currentSegment.x2(), currentSegment.y2(), currentMinDistPoint );
247 bool isPreferredSegment =
false;
251 const double angle = fmod( origin.azimuth( currentMinDistPoint ) + 360.0, 360.0 );
252 if ( angle < 45 || angle > 315 )
253 isPreferredSegment = i == 0;
254 else if (
angle < 135 )
255 isPreferredSegment = i == 3;
256 else if (
angle < 225 )
257 isPreferredSegment = i == 2;
259 isPreferredSegment = i == 1;
261 else if ( currentMinDist < minEdgeDist )
262 isPreferredSegment =
true;
264 if ( isPreferredSegment )
267 minEdgePoint = currentMinDistPoint;
268 minEdgeDist = currentMinDist;
269 minEdge = currentSegment;
273 if ( minEdgeIndex < 0 )
278 mBalloonSegment = minEdgeIndex;
279 QPointF minEdgeEnd = minEdge.p2();
280 mBalloonSegmentPoint1 = QPointF( minEdgePoint.
x(), minEdgePoint.
y() );
281 if ( std::sqrt( minEdgePoint.
sqrDist( minEdgeEnd.x(), minEdgeEnd.y() ) ) < mSegmentPointWidthMm )
286 mBalloonSegmentPoint1 = QPointF( x, y );
293 mBalloonSegmentPoint2 = QPointF( x, y );
300 auto scaleSize = [context](
double size )->
double
304 if ( mHasFixedMapPosition )
309 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
310 scaleSize( mOffsetFromReferencePoint.y() ),
311 scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
312 scaleSize( mOffsetFromReferencePoint.y() ) );
314 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
315 scaleSize( mOffsetFromReferencePoint.y() ),
316 scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
317 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ) );
319 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
320 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ),
321 scaleSize( mOffsetFromReferencePoint.x() ),
322 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ) );
324 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
325 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ),
326 scaleSize( mOffsetFromReferencePoint.x() ),
327 scaleSize( mOffsetFromReferencePoint.y() ) );
337 return QLineF( 0, 0, scaleSize( mFrameSize.width() ), 0 );
339 return QLineF( scaleSize( mFrameSize.width() ), 0,
340 scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ) );
342 return QLineF( scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ),
343 0, scaleSize( mFrameSize.height() ) );
345 return QLineF( 0, scaleSize( mFrameSize.height() ),
359 poly.reserve( 9 + ( mHasFixedMapPosition ? 3 : 0 ) );
360 QVector<QPolygonF> rings;
361 for (
int i = 0; i < 4; ++i )
363 QLineF currentSegment = segment( i, &context );
364 poly << QPointF( currentSegment.p1().x(),
365 currentSegment.p1().y() );
366 if ( i == mBalloonSegment && mHasFixedMapPosition )
370 poly << QPointF( 0, 0 );
374 poly << QPointF( currentSegment.p2().x(), currentSegment.p2().y() );
376 if ( poly.at( 0 ) != poly.at( poly.count() - 1 ) )
377 poly << poly.at( 0 );
379 mFillSymbol->startRender( context );
380 mFillSymbol->renderPolygon( poly, &rings,
nullptr, context );
381 mFillSymbol->stopRender( context );
393 mMarkerSymbol->startRender( context );
394 mMarkerSymbol->renderPoint( QPointF( 0, 0 ),
nullptr, context );
395 mMarkerSymbol->stopRender( context );
401 if ( itemElem.isNull() )
405 QDomElement annotationElem = doc.createElement( QStringLiteral(
"AnnotationItem" ) );
406 annotationElem.setAttribute( QStringLiteral(
"mapPositionFixed" ), mHasFixedMapPosition );
407 annotationElem.setAttribute( QStringLiteral(
"mapPosX" ),
qgsDoubleToString( mMapPosition.
x() ) );
408 annotationElem.setAttribute( QStringLiteral(
"mapPosY" ),
qgsDoubleToString( mMapPosition.
y() ) );
409 if ( mMapPositionCrs.
isValid() )
410 mMapPositionCrs.
writeXml( annotationElem, doc );
411 annotationElem.setAttribute( QStringLiteral(
"offsetXMM" ),
qgsDoubleToString( mOffsetFromReferencePoint.x() ) );
412 annotationElem.setAttribute( QStringLiteral(
"offsetYMM" ),
qgsDoubleToString( mOffsetFromReferencePoint.y() ) );
413 annotationElem.setAttribute( QStringLiteral(
"frameWidthMM" ),
qgsDoubleToString( mFrameSize.width() ) );
414 annotationElem.setAttribute( QStringLiteral(
"frameHeightMM" ),
qgsDoubleToString( mFrameSize.height() ) );
415 annotationElem.setAttribute( QStringLiteral(
"canvasPosX" ),
qgsDoubleToString( mRelativePosition.x() ) );
416 annotationElem.setAttribute( QStringLiteral(
"canvasPosY" ),
qgsDoubleToString( mRelativePosition.y() ) );
417 annotationElem.setAttribute( QStringLiteral(
"contentsMargin" ), mContentsMargins.
toString() );
418 annotationElem.setAttribute( QStringLiteral(
"visible" ),
isVisible() );
421 annotationElem.setAttribute( QStringLiteral(
"mapLayer" ), mMapLayer->id() );
426 if ( !symbolElem.isNull() )
428 annotationElem.appendChild( symbolElem );
433 QDomElement fillElem = doc.createElement( QStringLiteral(
"fillSymbol" ) );
435 if ( !symbolElem.isNull() )
437 fillElem.appendChild( symbolElem );
438 annotationElem.appendChild( fillElem );
441 itemElem.appendChild( annotationElem );
446 if ( annotationElem.isNull() )
451 pos.setX( annotationElem.attribute( QStringLiteral(
"canvasPosX" ), QStringLiteral(
"0" ) ).toDouble() );
452 pos.setY( annotationElem.attribute( QStringLiteral(
"canvasPosY" ), QStringLiteral(
"0" ) ).toDouble() );
453 if ( pos.x() >= 1 || pos.x() < 0 || pos.y() < 0 || pos.y() >= 1 )
454 mRelativePosition = QPointF();
456 mRelativePosition = pos;
458 mapPos.
setX( annotationElem.attribute( QStringLiteral(
"mapPosX" ), QStringLiteral(
"0" ) ).toDouble() );
459 mapPos.
setY( annotationElem.attribute( QStringLiteral(
"mapPosY" ), QStringLiteral(
"0" ) ).toDouble() );
460 mMapPosition = mapPos;
462 if ( !mMapPositionCrs.
readXml( annotationElem ) )
467 mContentsMargins =
QgsMargins::fromString( annotationElem.attribute( QStringLiteral(
"contentsMargin" ) ) );
469 if ( annotationElem.hasAttribute( QStringLiteral(
"frameWidthMM" ) ) )
470 mFrameSize.setWidth( annotationElem.attribute( QStringLiteral(
"frameWidthMM" ), QStringLiteral(
"5" ) ).toDouble() );
472 mFrameSize.setWidth( dpiScale * annotationElem.attribute( QStringLiteral(
"frameWidth" ), QStringLiteral(
"50" ) ).toDouble() );
473 if ( annotationElem.hasAttribute( QStringLiteral(
"frameHeightMM" ) ) )
474 mFrameSize.setHeight( annotationElem.attribute( QStringLiteral(
"frameHeightMM" ), QStringLiteral(
"3" ) ).toDouble() );
476 mFrameSize.setHeight( dpiScale * annotationElem.attribute( QStringLiteral(
"frameHeight" ), QStringLiteral(
"50" ) ).toDouble() );
478 if ( annotationElem.hasAttribute( QStringLiteral(
"offsetXMM" ) ) )
479 mOffsetFromReferencePoint.setX( annotationElem.attribute( QStringLiteral(
"offsetXMM" ), QStringLiteral(
"0" ) ).toDouble() );
481 mOffsetFromReferencePoint.setX( dpiScale * annotationElem.attribute( QStringLiteral(
"offsetX" ), QStringLiteral(
"0" ) ).toDouble() );
482 if ( annotationElem.hasAttribute( QStringLiteral(
"offsetYMM" ) ) )
483 mOffsetFromReferencePoint.setY( annotationElem.attribute( QStringLiteral(
"offsetYMM" ), QStringLiteral(
"0" ) ).toDouble() );
485 mOffsetFromReferencePoint.setY( dpiScale * annotationElem.attribute( QStringLiteral(
"offsetY" ), QStringLiteral(
"0" ) ).toDouble() );
487 mHasFixedMapPosition = annotationElem.attribute( QStringLiteral(
"mapPositionFixed" ), QStringLiteral(
"1" ) ).toInt();
488 mVisible = annotationElem.attribute( QStringLiteral(
"visible" ), QStringLiteral(
"1" ) ).toInt();
489 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 );
507 mFillSymbol.reset(
nullptr );
508 QDomElement fillElem = annotationElem.firstChildElement( QStringLiteral(
"fillSymbol" ) );
509 if ( !fillElem.isNull() )
511 QDomElement symbolElem = fillElem.firstChildElement( QStringLiteral(
"symbol" ) );
512 if ( !symbolElem.isNull() )
514 QgsFillSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context );
517 mFillSymbol.reset( symbol );
524 frameColor.setNamedColor( annotationElem.attribute( QStringLiteral(
"frameColor" ), QStringLiteral(
"#000000" ) ) );
525 frameColor.setAlpha( annotationElem.attribute( QStringLiteral(
"frameColorAlpha" ), QStringLiteral(
"255" ) ).toInt() );
526 QColor frameBackgroundColor;
527 frameBackgroundColor.setNamedColor( annotationElem.attribute( QStringLiteral(
"frameBackgroundColor" ) ) );
528 frameBackgroundColor.setAlpha( annotationElem.attribute( QStringLiteral(
"frameBackgroundColorAlpha" ), QStringLiteral(
"255" ) ).toInt() );
529 double frameBorderWidth = annotationElem.attribute( QStringLiteral(
"frameBorderWidth" ), QStringLiteral(
"0.5" ) ).toDouble();
531 frameBorderWidth = frameBorderWidth * 25.4 / 96.0;
533 props.insert( QStringLiteral(
"color" ), frameBackgroundColor.name() );
534 props.insert( QStringLiteral(
"style" ), QStringLiteral(
"solid" ) );
535 props.insert( QStringLiteral(
"style_border" ), QStringLiteral(
"solid" ) );
536 props.insert( QStringLiteral(
"color_border" ), frameColor.name() );
537 props.insert( QStringLiteral(
"width_border" ), QString::number( frameBorderWidth ) );
538 props.insert( QStringLiteral(
"joinstyle" ), QStringLiteral(
"miter" ) );
548 target->mVisible = mVisible;
549 target->mHasFixedMapPosition = mHasFixedMapPosition;
550 target->mMapPosition = mMapPosition;
551 target->mMapPositionCrs = mMapPositionCrs;
552 target->mRelativePosition = mRelativePosition;
553 target->mOffsetFromReferencePoint = mOffsetFromReferencePoint;
554 target->mFrameSize = mFrameSize;
555 target->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() :
nullptr );
556 target->mContentsMargins = mContentsMargins;
557 target->mFillSymbol.reset( mFillSymbol ? mFillSymbol->clone() :
nullptr );
558 target->mBalloonSegment = mBalloonSegment;
559 target->mBalloonSegmentPoint1 = mBalloonSegmentPoint1;
560 target->mBalloonSegmentPoint2 = mBalloonSegmentPoint2;
561 target->mSegmentPointWidthMm = mSegmentPointWidthMm;
562 target->mMapLayer = mMapLayer;
563 target->mFeature = mFeature;
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.
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.
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 id, geometry and a list of field/values...
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.
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance) SIP_HOLDGIL
Returns a point a specified distance toward a second point.
Base class for all map layer types.
The QgsMargins class defines the four margins of a rectangle.
double top() const
Returns the top margin.
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.
double bottom() const
Returns the bottom margin.
QString toString() const
Returns the margins encoded to a string.
double left() const
Returns the left margin.
A marker symbol type, for rendering Point and MultiPoint geometries.
A class to represent a 2D point.
double sqrDist(double x, double y) const SIP_HOLDGIL
Returns the squared distance between this point a specified x, y coordinate.
void setX(double x) SIP_HOLDGIL
Sets the x value of the point.
void setY(double y) SIP_HOLDGIL
Sets the y value of the point.
double sqrDistToSegment(double x1, double y1, double x2, double y2, QgsPointXY &minDistPoint, double epsilon=DEFAULT_SEGMENT_EPSILON) const SIP_HOLDGIL
Returns the minimum distance between this point and a segment.
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.
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 ...
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
Scoped object for saving and restoring a QPainter object's state.
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.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
@ RenderMillimeters
Millimeters.
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)
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Q_GUI_EXPORT int qt_defaultDpiX()
const QgsCoordinateReferenceSystem & crs
Contains information relating to a node (i.e.
Contains information relating to the style entity currently being visited.