30 props.insert( QStringLiteral(
"color" ), QStringLiteral(
"white" ) );
31 props.insert( QStringLiteral(
"style" ), QStringLiteral(
"solid" ) );
32 props.insert( QStringLiteral(
"style_border" ), QStringLiteral(
"solid" ) );
33 props.insert( QStringLiteral(
"color_border" ), QStringLiteral(
"black" ) );
34 props.insert( QStringLiteral(
"width_border" ), QStringLiteral(
"0.3" ) );
35 props.insert( QStringLiteral(
"joinstyle" ), QStringLiteral(
"miter" ) );
41 if ( mVisible == visible )
50 if ( mHasFixedMapPosition == fixed )
53 mHasFixedMapPosition = fixed;
60 mMapPosition = position;
66 mMapPositionCrs =
crs;
72 mRelativePosition = position;
78 mOffsetFromReferencePoint = offset;
95 mContentsMargins = margins;
101 mFillSymbol.reset( symbol );
107 QPainter *painter = context.
painter();
114 drawFrame( context );
115 if ( mHasFixedMapPosition )
117 drawMarkerSymbol( context );
119 if ( mHasFixedMapPosition )
138 mMarkerSymbol.reset( symbol );
155 return QSizeF( 0, 0 );
158 void QgsAnnotation::updateBalloon()
161 if ( !mHasFixedMapPosition ||
162 ( mOffsetFromReferencePoint.x() < 0 && ( mOffsetFromReferencePoint.x() + mFrameSize.width() ) > 0
163 && mOffsetFromReferencePoint.y() < 0 && ( mOffsetFromReferencePoint.y() + mFrameSize.height() ) > 0 ) )
165 mBalloonSegment = -1;
170 QList<QLineF> segmentList;
171 segmentList << segment( 0 );
172 segmentList << segment( 1 );
173 segmentList << segment( 2 );
174 segmentList << segment( 3 );
177 double minEdgeDist = std::numeric_limits<double>::max();
178 int minEdgeIndex = -1;
183 for (
int i = 0; i < 4; ++i )
185 QLineF currentSegment = segmentList.at( i );
187 double currentMinDist = origin.
sqrDistToSegment( currentSegment.x1(), currentSegment.y1(), currentSegment.x2(), currentSegment.y2(), currentMinDistPoint );
188 if ( currentMinDist < minEdgeDist )
191 minEdgePoint = currentMinDistPoint;
192 minEdgeDist = currentMinDist;
193 minEdge = currentSegment;
197 if ( minEdgeIndex < 0 )
203 double segmentPointWidth = 10;
205 mBalloonSegment = minEdgeIndex;
206 QPointF minEdgeEnd = minEdge.p2();
207 mBalloonSegmentPoint1 = QPointF( minEdgePoint.
x(), minEdgePoint.
y() );
208 if ( std::sqrt( minEdgePoint.
sqrDist( minEdgeEnd.x(), minEdgeEnd.y() ) ) < segmentPointWidth )
210 mBalloonSegmentPoint1 = pointOnLineWithDistance( minEdge.p2(), minEdge.p1(), segmentPointWidth );
213 mBalloonSegmentPoint2 = pointOnLineWithDistance( mBalloonSegmentPoint1, minEdge.p2(), 10 );
216 QLineF QgsAnnotation::segment(
int index )
const 218 if ( mHasFixedMapPosition )
223 return QLineF( mOffsetFromReferencePoint.x(), mOffsetFromReferencePoint.y(), mOffsetFromReferencePoint.x()
224 + mFrameSize.width(), mOffsetFromReferencePoint.y() );
226 return QLineF( mOffsetFromReferencePoint.x() + mFrameSize.width(), mOffsetFromReferencePoint.y(),
227 mOffsetFromReferencePoint.x() + mFrameSize.width(), mOffsetFromReferencePoint.y() + mFrameSize.height() );
229 return QLineF( mOffsetFromReferencePoint.x() + mFrameSize.width(), mOffsetFromReferencePoint.y() + mFrameSize.height(),
230 mOffsetFromReferencePoint.x(), mOffsetFromReferencePoint.y() + mFrameSize.height() );
232 return QLineF( mOffsetFromReferencePoint.x(), mOffsetFromReferencePoint.y() + mFrameSize.height(),
233 mOffsetFromReferencePoint.x(), mOffsetFromReferencePoint.y() );
243 return QLineF( 0, 0, mFrameSize.width(), 0 );
245 return QLineF( mFrameSize.width(), 0,
246 mFrameSize.width(), mFrameSize.height() );
248 return QLineF( mFrameSize.width(), mFrameSize.height(),
249 0, mFrameSize.height() );
251 return QLineF( 0, mFrameSize.height(),
260 QPointF QgsAnnotation::pointOnLineWithDistance( QPointF startPoint, QPointF directionPoint,
double distance )
const 262 double dx = directionPoint.x() - startPoint.x();
263 double dy = directionPoint.y() - startPoint.y();
264 double length = std::sqrt( dx * dx + dy * dy );
265 double scaleFactor = distance / length;
266 return QPointF( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
277 QList<QPolygonF> rings;
278 for (
int i = 0; i < 4; ++i )
280 QLineF currentSegment = segment( i );
281 poly << currentSegment.p1();
282 if ( i == mBalloonSegment && mHasFixedMapPosition )
284 poly << mBalloonSegmentPoint1;
285 poly << QPointF( 0, 0 );
286 poly << mBalloonSegmentPoint2;
288 poly << currentSegment.p2();
290 if ( poly.at( 0 ) != poly.at( poly.count() - 1 ) )
291 poly << poly.at( 0 );
293 mFillSymbol->startRender( context );
294 mFillSymbol->renderPolygon( poly, &rings,
nullptr, context );
295 mFillSymbol->stopRender( context );
307 mMarkerSymbol->startRender( context );
308 mMarkerSymbol->renderPoint( QPointF( 0, 0 ),
nullptr, context );
309 mMarkerSymbol->stopRender( context );
315 if ( itemElem.isNull() )
319 QDomElement annotationElem = doc.createElement( QStringLiteral(
"AnnotationItem" ) );
320 annotationElem.setAttribute( QStringLiteral(
"mapPositionFixed" ), mHasFixedMapPosition );
321 annotationElem.setAttribute( QStringLiteral(
"mapPosX" ),
qgsDoubleToString( mMapPosition.
x() ) );
322 annotationElem.setAttribute( QStringLiteral(
"mapPosY" ),
qgsDoubleToString( mMapPosition.
y() ) );
323 if ( mMapPositionCrs.
isValid() )
324 mMapPositionCrs.
writeXml( annotationElem, doc );
325 annotationElem.setAttribute( QStringLiteral(
"offsetX" ),
qgsDoubleToString( mOffsetFromReferencePoint.x() ) );
326 annotationElem.setAttribute( QStringLiteral(
"offsetY" ),
qgsDoubleToString( mOffsetFromReferencePoint.y() ) );
327 annotationElem.setAttribute( QStringLiteral(
"frameWidth" ),
qgsDoubleToString( mFrameSize.width() ) );
328 annotationElem.setAttribute( QStringLiteral(
"frameHeight" ),
qgsDoubleToString( mFrameSize.height() ) );
329 annotationElem.setAttribute( QStringLiteral(
"canvasPosX" ),
qgsDoubleToString( mRelativePosition.x() ) );
330 annotationElem.setAttribute( QStringLiteral(
"canvasPosY" ),
qgsDoubleToString( mRelativePosition.y() ) );
331 annotationElem.setAttribute( QStringLiteral(
"contentsMargin" ), mContentsMargins.
toString() );
332 annotationElem.setAttribute( QStringLiteral(
"visible" ),
isVisible() );
335 annotationElem.setAttribute( QStringLiteral(
"mapLayer" ), mMapLayer->id() );
340 if ( !symbolElem.isNull() )
342 annotationElem.appendChild( symbolElem );
347 QDomElement fillElem = doc.createElement( QStringLiteral(
"fillSymbol" ) );
349 if ( !symbolElem.isNull() )
351 fillElem.appendChild( symbolElem );
352 annotationElem.appendChild( fillElem );
355 itemElem.appendChild( annotationElem );
360 if ( annotationElem.isNull() )
365 pos.setX( annotationElem.attribute( QStringLiteral(
"canvasPosX" ), QStringLiteral(
"0" ) ).toDouble() );
366 pos.setY( annotationElem.attribute( QStringLiteral(
"canvasPosY" ), QStringLiteral(
"0" ) ).toDouble() );
367 if ( pos.x() >= 1 || pos.x() < 0 || pos.y() < 0 || pos.y() >= 1 )
368 mRelativePosition = QPointF();
370 mRelativePosition = pos;
372 mapPos.
setX( annotationElem.attribute( QStringLiteral(
"mapPosX" ), QStringLiteral(
"0" ) ).toDouble() );
373 mapPos.
setY( annotationElem.attribute( QStringLiteral(
"mapPosY" ), QStringLiteral(
"0" ) ).toDouble() );
374 mMapPosition = mapPos;
376 if ( !mMapPositionCrs.
readXml( annotationElem ) )
381 mContentsMargins =
QgsMargins::fromString( annotationElem.attribute( QStringLiteral(
"contentsMargin" ) ) );
382 mFrameSize.setWidth( annotationElem.attribute( QStringLiteral(
"frameWidth" ), QStringLiteral(
"50" ) ).toDouble() );
383 mFrameSize.setHeight( annotationElem.attribute( QStringLiteral(
"frameHeight" ), QStringLiteral(
"50" ) ).toDouble() );
384 mOffsetFromReferencePoint.setX( annotationElem.attribute( QStringLiteral(
"offsetX" ), QStringLiteral(
"0" ) ).toDouble() );
385 mOffsetFromReferencePoint.setY( annotationElem.attribute( QStringLiteral(
"offsetY" ), QStringLiteral(
"0" ) ).toDouble() );
386 mHasFixedMapPosition = annotationElem.attribute( QStringLiteral(
"mapPositionFixed" ), QStringLiteral(
"1" ) ).toInt();
387 mVisible = annotationElem.attribute( QStringLiteral(
"visible" ), QStringLiteral(
"1" ) ).toInt();
388 if ( annotationElem.hasAttribute( QStringLiteral(
"mapLayer" ) ) )
394 QDomElement symbolElem = annotationElem.firstChildElement( QStringLiteral(
"symbol" ) );
395 if ( !symbolElem.isNull() )
397 QgsMarkerSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context );
400 mMarkerSymbol.reset( symbol );
404 mFillSymbol.reset(
nullptr );
405 QDomElement fillElem = annotationElem.firstChildElement( QStringLiteral(
"fillSymbol" ) );
406 if ( !fillElem.isNull() )
408 QDomElement symbolElem = fillElem.firstChildElement( QStringLiteral(
"symbol" ) );
409 if ( !symbolElem.isNull() )
411 QgsFillSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context );
414 mFillSymbol.reset( symbol );
421 frameColor.setNamedColor( annotationElem.attribute( QStringLiteral(
"frameColor" ), QStringLiteral(
"#000000" ) ) );
422 frameColor.setAlpha( annotationElem.attribute( QStringLiteral(
"frameColorAlpha" ), QStringLiteral(
"255" ) ).toInt() );
423 QColor frameBackgroundColor;
424 frameBackgroundColor.setNamedColor( annotationElem.attribute( QStringLiteral(
"frameBackgroundColor" ) ) );
425 frameBackgroundColor.setAlpha( annotationElem.attribute( QStringLiteral(
"frameBackgroundColorAlpha" ), QStringLiteral(
"255" ) ).toInt() );
426 double frameBorderWidth = annotationElem.attribute( QStringLiteral(
"frameBorderWidth" ), QStringLiteral(
"0.5" ) ).toDouble();
428 frameBorderWidth = frameBorderWidth * 25.4 / 96.0;
430 props.insert( QStringLiteral(
"color" ), frameBackgroundColor.name() );
431 props.insert( QStringLiteral(
"style" ), QStringLiteral(
"solid" ) );
432 props.insert( QStringLiteral(
"style_border" ), QStringLiteral(
"solid" ) );
433 props.insert( QStringLiteral(
"color_border" ), frameColor.name() );
434 props.insert( QStringLiteral(
"width_border" ), QString::number( frameBorderWidth ) );
435 props.insert( QStringLiteral(
"joinstyle" ), QStringLiteral(
"miter" ) );
445 target->mVisible = mVisible;
446 target->mHasFixedMapPosition = mHasFixedMapPosition;
447 target->mMapPosition = mMapPosition;
448 target->mMapPositionCrs = mMapPositionCrs;
449 target->mRelativePosition = mRelativePosition;
450 target->mOffsetFromReferencePoint = mOffsetFromReferencePoint;
451 target->mFrameSize = mFrameSize;
452 target->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() : nullptr );
453 target->mContentsMargins = mContentsMargins;
454 target->mFillSymbol.reset( mFillSymbol ? mFillSymbol->clone() : nullptr );
455 target->mBalloonSegment = mBalloonSegment;
456 target->mBalloonSegmentPoint1 = mBalloonSegmentPoint1;
457 target->mBalloonSegmentPoint2 = mBalloonSegmentPoint2;
458 target->mMapLayer = mMapLayer;
459 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.
void setFrameOffsetFromReferencePoint(QPointF offset)
Sets the annotation's frame's offset 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
A marker symbol type, for rendering Point and MultiPoint geometries.
Abstract base class for annotation items which are drawn over a map.
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 _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.
void setFrameSize(QSizeF size)
Sets the size of the annotation's frame (the main area in which the annotation's content is drawn)...
void setMapPosition(const QgsPointXY &position)
Sets the map position of the annotation, if it is attached to a fixed map position.
QSizeF frameSize() const
Returns the size of the annotation's frame (the main area in which the annotation's content is drawn)...
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...
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.
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.
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.