33 props.insert( QStringLiteral(
"color" ), QStringLiteral(
"white" ) );
34 props.insert( QStringLiteral(
"style" ), QStringLiteral(
"solid" ) );
35 props.insert( QStringLiteral(
"style_border" ), QStringLiteral(
"solid" ) );
36 props.insert( QStringLiteral(
"color_border" ), QStringLiteral(
"black" ) );
37 props.insert( QStringLiteral(
"width_border" ), QStringLiteral(
"0.3" ) );
38 props.insert( QStringLiteral(
"joinstyle" ), QStringLiteral(
"miter" ) );
44 if ( mVisible == visible )
53 if ( mHasFixedMapPosition == fixed )
56 mHasFixedMapPosition = fixed;
63 mMapPosition = position;
69 mMapPositionCrs =
crs;
75 mRelativePosition = position;
87 return mOffsetFromReferencePoint / 3.7795275;
92 mOffsetFromReferencePoint = offset;
107 return mFrameSize / 3.7795275;
121 mContentsMargins = margins;
127 mFillSymbol.reset( symbol );
133 QPainter *painter = context.
painter();
140 drawFrame( context );
141 if ( mHasFixedMapPosition )
143 drawMarkerSymbol( context );
145 if ( mHasFixedMapPosition )
168 mMarkerSymbol.reset( symbol );
185 return QSizeF( 0, 0 );
188 void QgsAnnotation::updateBalloon()
191 if ( !mHasFixedMapPosition ||
192 ( mOffsetFromReferencePoint.x() < 0 && ( mOffsetFromReferencePoint.x() + mFrameSize.width() ) > 0
193 && mOffsetFromReferencePoint.y() < 0 && ( mOffsetFromReferencePoint.y() + mFrameSize.height() ) > 0 ) )
195 mBalloonSegment = -1;
200 QList<QLineF> segmentList;
201 segmentList << segment( 0,
nullptr );
202 segmentList << segment( 1,
nullptr );
203 segmentList << segment( 2,
nullptr );
204 segmentList << segment( 3,
nullptr );
207 double minEdgeDist = std::numeric_limits<double>::max();
208 int minEdgeIndex = -1;
213 for (
int i = 0; i < 4; ++i )
215 QLineF currentSegment = segmentList.at( i );
217 double currentMinDist = origin.
sqrDistToSegment( currentSegment.x1(), currentSegment.y1(), currentSegment.x2(), currentSegment.y2(), currentMinDistPoint );
218 bool isPreferredSegment =
false;
222 const double angle = fmod( origin.
azimuth( currentMinDistPoint ) + 360.0, 360.0 );
223 if ( angle < 45 || angle > 315 )
224 isPreferredSegment = i == 0;
225 else if ( angle < 135 )
226 isPreferredSegment = i == 3;
227 else if ( angle < 225 )
228 isPreferredSegment = i == 2;
230 isPreferredSegment = i == 1;
232 else if ( currentMinDist < minEdgeDist )
233 isPreferredSegment =
true;
235 if ( isPreferredSegment )
238 minEdgePoint = currentMinDistPoint;
239 minEdgeDist = currentMinDist;
240 minEdge = currentSegment;
244 if ( minEdgeIndex < 0 )
249 mBalloonSegment = minEdgeIndex;
250 QPointF minEdgeEnd = minEdge.p2();
251 mBalloonSegmentPoint1 = QPointF( minEdgePoint.
x(), minEdgePoint.
y() );
252 if ( std::sqrt( minEdgePoint.
sqrDist( minEdgeEnd.x(), minEdgeEnd.y() ) ) < mSegmentPointWidthMm )
257 mBalloonSegmentPoint1 = QPointF( x, y );
264 mBalloonSegmentPoint2 = QPointF( x, y );
271 auto scaleSize = [context](
double size )->
double 275 if ( mHasFixedMapPosition )
280 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
281 scaleSize( mOffsetFromReferencePoint.y() ),
282 scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
283 scaleSize( mOffsetFromReferencePoint.y() ) );
285 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
286 scaleSize( mOffsetFromReferencePoint.y() ),
287 scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
288 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ) );
290 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
291 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ),
292 scaleSize( mOffsetFromReferencePoint.x() ),
293 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ) );
295 return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
296 scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ),
297 scaleSize( mOffsetFromReferencePoint.x() ),
298 scaleSize( mOffsetFromReferencePoint.y() ) );
308 return QLineF( 0, 0, scaleSize( mFrameSize.width() ), 0 );
310 return QLineF( scaleSize( mFrameSize.width() ), 0,
311 scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ) );
313 return QLineF( scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ),
314 0, scaleSize( mFrameSize.height() ) );
316 return QLineF( 0, scaleSize( mFrameSize.height() ),
332 poly.reserve( 9 + ( mHasFixedMapPosition ? 3 : 0 ) );
333 QList<QPolygonF> rings;
334 for (
int i = 0; i < 4; ++i )
336 QLineF currentSegment = segment( i, &context );
337 poly << QPointF( currentSegment.p1().x(),
338 currentSegment.p1().y() );
339 if ( i == mBalloonSegment && mHasFixedMapPosition )
343 poly << QPointF( 0, 0 );
347 poly << QPointF( currentSegment.p2().x(), currentSegment.p2().y() );
349 if ( poly.at( 0 ) != poly.at( poly.count() - 1 ) )
350 poly << poly.at( 0 );
352 mFillSymbol->startRender( context );
353 mFillSymbol->renderPolygon( poly, &rings,
nullptr, context );
354 mFillSymbol->stopRender( context );
366 mMarkerSymbol->startRender( context );
367 mMarkerSymbol->renderPoint( QPointF( 0, 0 ),
nullptr, context );
368 mMarkerSymbol->stopRender( context );
374 if ( itemElem.isNull() )
378 QDomElement annotationElem = doc.createElement( QStringLiteral(
"AnnotationItem" ) );
379 annotationElem.setAttribute( QStringLiteral(
"mapPositionFixed" ), mHasFixedMapPosition );
380 annotationElem.setAttribute( QStringLiteral(
"mapPosX" ),
qgsDoubleToString( mMapPosition.
x() ) );
381 annotationElem.setAttribute( QStringLiteral(
"mapPosY" ),
qgsDoubleToString( mMapPosition.
y() ) );
382 if ( mMapPositionCrs.
isValid() )
383 mMapPositionCrs.
writeXml( annotationElem, doc );
384 annotationElem.setAttribute( QStringLiteral(
"offsetXMM" ),
qgsDoubleToString( mOffsetFromReferencePoint.x() ) );
385 annotationElem.setAttribute( QStringLiteral(
"offsetYMM" ),
qgsDoubleToString( mOffsetFromReferencePoint.y() ) );
386 annotationElem.setAttribute( QStringLiteral(
"frameWidthMM" ),
qgsDoubleToString( mFrameSize.width() ) );
387 annotationElem.setAttribute( QStringLiteral(
"frameHeightMM" ),
qgsDoubleToString( mFrameSize.height() ) );
388 annotationElem.setAttribute( QStringLiteral(
"canvasPosX" ),
qgsDoubleToString( mRelativePosition.x() ) );
389 annotationElem.setAttribute( QStringLiteral(
"canvasPosY" ),
qgsDoubleToString( mRelativePosition.y() ) );
390 annotationElem.setAttribute( QStringLiteral(
"contentsMargin" ), mContentsMargins.
toString() );
391 annotationElem.setAttribute( QStringLiteral(
"visible" ),
isVisible() );
394 annotationElem.setAttribute( QStringLiteral(
"mapLayer" ), mMapLayer->id() );
399 if ( !symbolElem.isNull() )
401 annotationElem.appendChild( symbolElem );
406 QDomElement fillElem = doc.createElement( QStringLiteral(
"fillSymbol" ) );
408 if ( !symbolElem.isNull() )
410 fillElem.appendChild( symbolElem );
411 annotationElem.appendChild( fillElem );
414 itemElem.appendChild( annotationElem );
419 if ( annotationElem.isNull() )
424 pos.setX( annotationElem.attribute( QStringLiteral(
"canvasPosX" ), QStringLiteral(
"0" ) ).toDouble() );
425 pos.setY( annotationElem.attribute( QStringLiteral(
"canvasPosY" ), QStringLiteral(
"0" ) ).toDouble() );
426 if ( pos.x() >= 1 || pos.x() < 0 || pos.y() < 0 || pos.y() >= 1 )
427 mRelativePosition = QPointF();
429 mRelativePosition = pos;
431 mapPos.
setX( annotationElem.attribute( QStringLiteral(
"mapPosX" ), QStringLiteral(
"0" ) ).toDouble() );
432 mapPos.
setY( annotationElem.attribute( QStringLiteral(
"mapPosY" ), QStringLiteral(
"0" ) ).toDouble() );
433 mMapPosition = mapPos;
435 if ( !mMapPositionCrs.
readXml( annotationElem ) )
440 mContentsMargins =
QgsMargins::fromString( annotationElem.attribute( QStringLiteral(
"contentsMargin" ) ) );
442 if ( annotationElem.hasAttribute( QStringLiteral(
"frameWidthMM" ) ) )
443 mFrameSize.setWidth( annotationElem.attribute( QStringLiteral(
"frameWidthMM" ), QStringLiteral(
"5" ) ).toDouble() );
445 mFrameSize.setWidth( dpiScale * annotationElem.attribute( QStringLiteral(
"frameWidth" ), QStringLiteral(
"50" ) ).toDouble() );
446 if ( annotationElem.hasAttribute( QStringLiteral(
"frameHeightMM" ) ) )
447 mFrameSize.setHeight( annotationElem.attribute( QStringLiteral(
"frameHeightMM" ), QStringLiteral(
"3" ) ).toDouble() );
449 mFrameSize.setHeight( dpiScale * annotationElem.attribute( QStringLiteral(
"frameHeight" ), QStringLiteral(
"50" ) ).toDouble() );
451 if ( annotationElem.hasAttribute( QStringLiteral(
"offsetXMM" ) ) )
452 mOffsetFromReferencePoint.setX( annotationElem.attribute( QStringLiteral(
"offsetXMM" ), QStringLiteral(
"0" ) ).toDouble() );
454 mOffsetFromReferencePoint.setX( dpiScale * annotationElem.attribute( QStringLiteral(
"offsetX" ), QStringLiteral(
"0" ) ).toDouble() );
455 if ( annotationElem.hasAttribute( QStringLiteral(
"offsetYMM" ) ) )
456 mOffsetFromReferencePoint.setY( annotationElem.attribute( QStringLiteral(
"offsetYMM" ), QStringLiteral(
"0" ) ).toDouble() );
458 mOffsetFromReferencePoint.setY( dpiScale * annotationElem.attribute( QStringLiteral(
"offsetY" ), QStringLiteral(
"0" ) ).toDouble() );
460 mHasFixedMapPosition = annotationElem.attribute( QStringLiteral(
"mapPositionFixed" ), QStringLiteral(
"1" ) ).toInt();
461 mVisible = annotationElem.attribute( QStringLiteral(
"visible" ), QStringLiteral(
"1" ) ).toInt();
462 if ( annotationElem.hasAttribute( QStringLiteral(
"mapLayer" ) ) )
468 QDomElement symbolElem = annotationElem.firstChildElement( QStringLiteral(
"symbol" ) );
469 if ( !symbolElem.isNull() )
471 QgsMarkerSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context );
474 mMarkerSymbol.reset( symbol );
478 mFillSymbol.reset(
nullptr );
479 QDomElement fillElem = annotationElem.firstChildElement( QStringLiteral(
"fillSymbol" ) );
480 if ( !fillElem.isNull() )
482 QDomElement symbolElem = fillElem.firstChildElement( QStringLiteral(
"symbol" ) );
483 if ( !symbolElem.isNull() )
485 QgsFillSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context );
488 mFillSymbol.reset( symbol );
495 frameColor.setNamedColor( annotationElem.attribute( QStringLiteral(
"frameColor" ), QStringLiteral(
"#000000" ) ) );
496 frameColor.setAlpha( annotationElem.attribute( QStringLiteral(
"frameColorAlpha" ), QStringLiteral(
"255" ) ).toInt() );
497 QColor frameBackgroundColor;
498 frameBackgroundColor.setNamedColor( annotationElem.attribute( QStringLiteral(
"frameBackgroundColor" ) ) );
499 frameBackgroundColor.setAlpha( annotationElem.attribute( QStringLiteral(
"frameBackgroundColorAlpha" ), QStringLiteral(
"255" ) ).toInt() );
500 double frameBorderWidth = annotationElem.attribute( QStringLiteral(
"frameBorderWidth" ), QStringLiteral(
"0.5" ) ).toDouble();
502 frameBorderWidth = frameBorderWidth * 25.4 / 96.0;
504 props.insert( QStringLiteral(
"color" ), frameBackgroundColor.name() );
505 props.insert( QStringLiteral(
"style" ), QStringLiteral(
"solid" ) );
506 props.insert( QStringLiteral(
"style_border" ), QStringLiteral(
"solid" ) );
507 props.insert( QStringLiteral(
"color_border" ), frameColor.name() );
508 props.insert( QStringLiteral(
"width_border" ), QString::number( frameBorderWidth ) );
509 props.insert( QStringLiteral(
"joinstyle" ), QStringLiteral(
"miter" ) );
519 target->mVisible = mVisible;
520 target->mHasFixedMapPosition = mHasFixedMapPosition;
521 target->mMapPosition = mMapPosition;
522 target->mMapPositionCrs = mMapPositionCrs;
523 target->mRelativePosition = mRelativePosition;
524 target->mOffsetFromReferencePoint = mOffsetFromReferencePoint;
525 target->mFrameSize = mFrameSize;
526 target->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() : nullptr );
527 target->mContentsMargins = mContentsMargins;
528 target->mFillSymbol.reset( mFillSymbol ? mFillSymbol->clone() : nullptr );
529 target->mBalloonSegment = mBalloonSegment;
530 target->mBalloonSegmentPoint1 = mBalloonSegmentPoint1;
531 target->mBalloonSegmentPoint2 = mBalloonSegmentPoint2;
532 target->mSegmentPointWidthMm = mSegmentPointWidthMm;
533 target->mMapLayer = mMapLayer;
534 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.
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.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
const QgsCoordinateReferenceSystem & crs
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.
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.
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.
double top() const
Returns the top margin.
virtual QSizeF minimumFrameSize() const
Returns the minimum frame size for the 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.
static QgsProject * instance()
Returns the QgsProject singleton instance.
This class represents a coordinate reference system (CRS).
static QDomElement saveSymbol(const QString &symbolName, QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
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.
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.
The QgsMargins class defines the four margins of a rectangle.
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.