QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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"
22 #include "qgsgeometryutils.h"
23 #include "qgsstyleentityvisitor.h"
24 
25 #include <QPen>
26 #include <QPainter>
27 
28 Q_GUI_EXPORT extern int qt_defaultDpiX();
29 
30 QgsAnnotation::QgsAnnotation( QObject *parent )
31  : QObject( parent )
32  , mMarkerSymbol( new QgsMarkerSymbol() )
33 {
34  QVariantMap props;
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" ) );
41  mFillSymbol.reset( QgsFillSymbol::createSimple( props ) );
42 }
43 
44 void QgsAnnotation::setVisible( bool visible )
45 {
46  if ( mVisible == visible )
47  return;
48 
49  mVisible = visible;
50  emit appearanceChanged();
51 }
52 
54 {
55  if ( mHasFixedMapPosition == fixed )
56  return;
57 
58  mHasFixedMapPosition = fixed;
59  updateBalloon();
60  emit moved();
61 }
62 
64 {
65  mMapPosition = position;
66  emit moved();
67 }
68 
70 {
71  mMapPositionCrs = crs;
72  emit moved();
73 }
74 
75 void QgsAnnotation::setRelativePosition( QPointF position )
76 {
77  mRelativePosition = position;
78  emit moved();
79 }
80 
82 {
83  // convert from offset in pixels at 96 dpi to mm
84  setFrameOffsetFromReferencePointMm( offset / 3.7795275 );
85 }
86 
88 {
89  return mOffsetFromReferencePoint / 3.7795275;
90 }
91 
93 {
94  mOffsetFromReferencePoint = offset;
95 
96  updateBalloon();
97  emit moved();
98  emit appearanceChanged();
99 }
100 
101 void QgsAnnotation::setFrameSize( QSizeF size )
102 {
103  // convert from size in pixels at 96 dpi to mm
104  setFrameSizeMm( size / 3.7795275 );
105 }
106 
108 {
109  return mFrameSize / 3.7795275;
110 }
111 
112 void QgsAnnotation::setFrameSizeMm( QSizeF size )
113 {
114  QSizeF frameSize = minimumFrameSize().expandedTo( size ); //don't allow frame sizes below minimum
115  mFrameSize = frameSize;
116  updateBalloon();
117  emit moved();
118  emit appearanceChanged();
119 }
120 
122 {
123  mContentsMargins = margins;
124  emit appearanceChanged();
125 }
126 
128 {
129  mFillSymbol.reset( symbol );
130  emit appearanceChanged();
131 }
132 
134 {
135  QPainter *painter = context.painter();
136  if ( !painter )
137  {
138  return;
139  }
140 
141  QgsScopedQPainterState painterState( context.painter() );
142  context.setPainterFlagsUsingContext();
143 
144  drawFrame( context );
145  if ( mHasFixedMapPosition )
146  {
147  drawMarkerSymbol( context );
148  }
149  if ( mHasFixedMapPosition )
150  {
151  painter->translate( context.convertToPainterUnits( mOffsetFromReferencePoint.x(), QgsUnitTypes::RenderMillimeters ) + context.convertToPainterUnits( mContentsMargins.left(), QgsUnitTypes::RenderMillimeters ),
152  context.convertToPainterUnits( mOffsetFromReferencePoint.y(), QgsUnitTypes::RenderMillimeters ) + context.convertToPainterUnits( mContentsMargins.top(), QgsUnitTypes::RenderMillimeters ) );
153  }
154  else
155  {
156  painter->translate( context.convertToPainterUnits( mContentsMargins.left(), QgsUnitTypes::RenderMillimeters ),
157  context.convertToPainterUnits( mContentsMargins.top(), QgsUnitTypes::RenderMillimeters ) );
158  }
159  QSizeF size( context.convertToPainterUnits( mFrameSize.width(), QgsUnitTypes::RenderMillimeters ) - context.convertToPainterUnits( mContentsMargins.left() + mContentsMargins.right(), QgsUnitTypes::RenderMillimeters ),
160  context.convertToPainterUnits( mFrameSize.height(), QgsUnitTypes::RenderMillimeters ) - context.convertToPainterUnits( mContentsMargins.top() + mContentsMargins.bottom(), QgsUnitTypes::RenderMillimeters ) );
161 
162  // scale back from painter dpi to 96 dpi --
163 // double dotsPerMM = context.painter()->device()->logicalDpiX() / ( 25.4 * 3.78 );
164 // context.painter()->scale( dotsPerMM, dotsPerMM );
165 
166  renderAnnotation( context, size );
167 }
168 
170 {
171  mMarkerSymbol.reset( symbol );
172  emit appearanceChanged();
173 }
174 
176 {
177  mMapLayer = layer;
178  emit mapLayerChanged();
179 }
180 
182 {
183  mFeature = feature;
184 }
185 
187 {
188  // NOTE: if visitEnter returns false it means "don't visit the annotation", not "abort all further visitations"
189  if ( !visitor->visitEnter( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Annotation, QStringLiteral( "annotation" ), tr( "Annotation" ) ) ) )
190  return true;
191 
192  if ( mMarkerSymbol )
193  {
194  QgsStyleSymbolEntity entity( mMarkerSymbol.get() );
195  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "marker" ), QObject::tr( "Marker" ) ) ) )
196  return false;
197  }
198 
199  if ( mFillSymbol )
200  {
201  QgsStyleSymbolEntity entity( mFillSymbol.get() );
202  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "fill" ), QObject::tr( "Fill" ) ) ) )
203  return false;
204  }
205 
206  if ( !visitor->visitExit( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Annotation, QStringLiteral( "annotation" ), tr( "Annotation" ) ) ) )
207  return false;
208 
209  return true;
210 }
211 
213 {
214  return QSizeF( 0, 0 );
215 }
216 
217 void QgsAnnotation::updateBalloon()
218 {
219  //first test if the point is in the frame. In that case we don't need a balloon.
220  if ( !mHasFixedMapPosition ||
221  ( mOffsetFromReferencePoint.x() < 0 && ( mOffsetFromReferencePoint.x() + mFrameSize.width() ) > 0
222  && mOffsetFromReferencePoint.y() < 0 && ( mOffsetFromReferencePoint.y() + mFrameSize.height() ) > 0 ) )
223  {
224  mBalloonSegment = -1;
225  return;
226  }
227 
228  //edge list
229  QList<QLineF> segmentList;
230  segmentList << segment( 0, nullptr );
231  segmentList << segment( 1, nullptr );
232  segmentList << segment( 2, nullptr );
233  segmentList << segment( 3, nullptr );
234 
235  //find closest edge / closest edge point
236  double minEdgeDist = std::numeric_limits<double>::max();
237  int minEdgeIndex = -1;
238  QLineF minEdge;
239  QgsPointXY minEdgePoint;
240  QgsPointXY origin( 0, 0 );
241 
242  for ( int i = 0; i < 4; ++i )
243  {
244  QLineF currentSegment = segmentList.at( i );
245  QgsPointXY currentMinDistPoint;
246  double currentMinDist = origin.sqrDistToSegment( currentSegment.x1(), currentSegment.y1(), currentSegment.x2(), currentSegment.y2(), currentMinDistPoint );
247  bool isPreferredSegment = false;
248  if ( qgsDoubleNear( currentMinDist, minEdgeDist ) )
249  {
250  // two segments are close - work out which looks nicer
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;
258  else
259  isPreferredSegment = i == 1;
260  }
261  else if ( currentMinDist < minEdgeDist )
262  isPreferredSegment = true;
263 
264  if ( isPreferredSegment )
265  {
266  minEdgeIndex = i;
267  minEdgePoint = currentMinDistPoint;
268  minEdgeDist = currentMinDist;
269  minEdge = currentSegment;
270  }
271  }
272 
273  if ( minEdgeIndex < 0 )
274  {
275  return;
276  }
277 
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 )
282  {
283  double x = 0;
284  double y = 0;
285  QgsGeometryUtils::pointOnLineWithDistance( minEdge.p2().x(), minEdge.p2().y(), minEdge.p1().x(), minEdge.p1().y(), mSegmentPointWidthMm, x, y );
286  mBalloonSegmentPoint1 = QPointF( x, y );
287  }
288 
289  {
290  double x = 0;
291  double y = 0;
292  QgsGeometryUtils::pointOnLineWithDistance( mBalloonSegmentPoint1.x(), mBalloonSegmentPoint1.y(), minEdge.p2().x(), minEdge.p2().y(), mSegmentPointWidthMm, x, y );
293  mBalloonSegmentPoint2 = QPointF( x, y );
294  }
295 
296 }
297 
298 QLineF QgsAnnotation::segment( int index, QgsRenderContext *context ) const
299 {
300  auto scaleSize = [context]( double size )->double
301  {
302  return context ? context->convertToPainterUnits( size, QgsUnitTypes::RenderMillimeters ) : size;
303  };
304  if ( mHasFixedMapPosition )
305  {
306  switch ( index )
307  {
308  case 0:
309  return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
310  scaleSize( mOffsetFromReferencePoint.y() ),
311  scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
312  scaleSize( mOffsetFromReferencePoint.y() ) );
313  case 1:
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() ) );
318  case 2:
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() ) );
323  case 3:
324  return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
325  scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ),
326  scaleSize( mOffsetFromReferencePoint.x() ),
327  scaleSize( mOffsetFromReferencePoint.y() ) );
328  default:
329  return QLineF();
330  }
331  }
332  else
333  {
334  switch ( index )
335  {
336  case 0:
337  return QLineF( 0, 0, scaleSize( mFrameSize.width() ), 0 );
338  case 1:
339  return QLineF( scaleSize( mFrameSize.width() ), 0,
340  scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ) );
341  case 2:
342  return QLineF( scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ),
343  0, scaleSize( mFrameSize.height() ) );
344  case 3:
345  return QLineF( 0, scaleSize( mFrameSize.height() ),
346  0, 0 );
347  default:
348  return QLineF();
349  }
350  }
351 }
352 
353 void QgsAnnotation::drawFrame( QgsRenderContext &context ) const
354 {
355  if ( !mFillSymbol )
356  return;
357 
358  QPolygonF poly;
359  poly.reserve( 9 + ( mHasFixedMapPosition ? 3 : 0 ) );
360  QVector<QPolygonF> rings; //empty list
361  for ( int i = 0; i < 4; ++i )
362  {
363  QLineF currentSegment = segment( i, &context );
364  poly << QPointF( currentSegment.p1().x(),
365  currentSegment.p1().y() );
366  if ( i == mBalloonSegment && mHasFixedMapPosition )
367  {
368  poly << QPointF( context.convertToPainterUnits( mBalloonSegmentPoint1.x(), QgsUnitTypes::RenderMillimeters ),
369  context.convertToPainterUnits( mBalloonSegmentPoint1.y(), QgsUnitTypes::RenderMillimeters ) );
370  poly << QPointF( 0, 0 );
371  poly << QPointF( context.convertToPainterUnits( mBalloonSegmentPoint2.x(), QgsUnitTypes::RenderMillimeters ),
372  context.convertToPainterUnits( mBalloonSegmentPoint2.y(), QgsUnitTypes::RenderMillimeters ) );
373  }
374  poly << QPointF( currentSegment.p2().x(), currentSegment.p2().y() );
375  }
376  if ( poly.at( 0 ) != poly.at( poly.count() - 1 ) )
377  poly << poly.at( 0 );
378 
379  mFillSymbol->startRender( context );
380  mFillSymbol->renderPolygon( poly, &rings, nullptr, context );
381  mFillSymbol->stopRender( context );
382 }
383 
384 void QgsAnnotation::drawMarkerSymbol( QgsRenderContext &context ) const
385 {
386  if ( !context.painter() )
387  {
388  return;
389  }
390 
391  if ( mMarkerSymbol )
392  {
393  mMarkerSymbol->startRender( context );
394  mMarkerSymbol->renderPoint( QPointF( 0, 0 ), nullptr, context );
395  mMarkerSymbol->stopRender( context );
396  }
397 }
398 
399 void QgsAnnotation::_writeXml( QDomElement &itemElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
400 {
401  if ( itemElem.isNull() )
402  {
403  return;
404  }
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() );
419  if ( mMapLayer )
420  {
421  annotationElem.setAttribute( QStringLiteral( "mapLayer" ), mMapLayer->id() );
422  }
423  if ( mMarkerSymbol )
424  {
425  QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "marker symbol" ), mMarkerSymbol.get(), doc, context );
426  if ( !symbolElem.isNull() )
427  {
428  annotationElem.appendChild( symbolElem );
429  }
430  }
431  if ( mFillSymbol )
432  {
433  QDomElement fillElem = doc.createElement( QStringLiteral( "fillSymbol" ) );
434  QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "fill symbol" ), mFillSymbol.get(), doc, context );
435  if ( !symbolElem.isNull() )
436  {
437  fillElem.appendChild( symbolElem );
438  annotationElem.appendChild( fillElem );
439  }
440  }
441  itemElem.appendChild( annotationElem );
442 }
443 
444 void QgsAnnotation::_readXml( const QDomElement &annotationElem, const QgsReadWriteContext &context )
445 {
446  if ( annotationElem.isNull() )
447  {
448  return;
449  }
450  QPointF pos;
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();
455  else
456  mRelativePosition = pos;
457  QgsPointXY mapPos;
458  mapPos.setX( annotationElem.attribute( QStringLiteral( "mapPosX" ), QStringLiteral( "0" ) ).toDouble() );
459  mapPos.setY( annotationElem.attribute( QStringLiteral( "mapPosY" ), QStringLiteral( "0" ) ).toDouble() );
460  mMapPosition = mapPos;
461 
462  if ( !mMapPositionCrs.readXml( annotationElem ) )
463  {
464  mMapPositionCrs = QgsCoordinateReferenceSystem();
465  }
466 
467  mContentsMargins = QgsMargins::fromString( annotationElem.attribute( QStringLiteral( "contentsMargin" ) ) );
468  const double dpiScale = 25.4 / qt_defaultDpiX();
469  if ( annotationElem.hasAttribute( QStringLiteral( "frameWidthMM" ) ) )
470  mFrameSize.setWidth( annotationElem.attribute( QStringLiteral( "frameWidthMM" ), QStringLiteral( "5" ) ).toDouble() );
471  else
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() );
475  else
476  mFrameSize.setHeight( dpiScale * annotationElem.attribute( QStringLiteral( "frameHeight" ), QStringLiteral( "50" ) ).toDouble() );
477 
478  if ( annotationElem.hasAttribute( QStringLiteral( "offsetXMM" ) ) )
479  mOffsetFromReferencePoint.setX( annotationElem.attribute( QStringLiteral( "offsetXMM" ), QStringLiteral( "0" ) ).toDouble() );
480  else
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() );
484  else
485  mOffsetFromReferencePoint.setY( dpiScale * annotationElem.attribute( QStringLiteral( "offsetY" ), QStringLiteral( "0" ) ).toDouble() );
486 
487  mHasFixedMapPosition = annotationElem.attribute( QStringLiteral( "mapPositionFixed" ), QStringLiteral( "1" ) ).toInt();
488  mVisible = annotationElem.attribute( QStringLiteral( "visible" ), QStringLiteral( "1" ) ).toInt();
489  if ( annotationElem.hasAttribute( QStringLiteral( "mapLayer" ) ) )
490  {
491  mMapLayer = QgsProject::instance()->mapLayer( annotationElem.attribute( QStringLiteral( "mapLayer" ) ) );
492  }
493 
494  //marker symbol
495  {
496  QDomElement symbolElem = annotationElem.firstChildElement( QStringLiteral( "symbol" ) );
497  if ( !symbolElem.isNull() )
498  {
499  QgsMarkerSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context );
500  if ( symbol )
501  {
502  mMarkerSymbol.reset( symbol );
503  }
504  }
505  }
506 
507  mFillSymbol.reset( nullptr );
508  QDomElement fillElem = annotationElem.firstChildElement( QStringLiteral( "fillSymbol" ) );
509  if ( !fillElem.isNull() )
510  {
511  QDomElement symbolElem = fillElem.firstChildElement( QStringLiteral( "symbol" ) );
512  if ( !symbolElem.isNull() )
513  {
514  QgsFillSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context );
515  if ( symbol )
516  {
517  mFillSymbol.reset( symbol );
518  }
519  }
520  }
521  if ( !mFillSymbol )
522  {
523  QColor frameColor;
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();
530  // need to roughly convert border width from pixels to mm - just assume 96 dpi
531  frameBorderWidth = frameBorderWidth * 25.4 / 96.0;
532  QVariantMap props;
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" ) );
539  mFillSymbol.reset( QgsFillSymbol::createSimple( props ) );
540  }
541 
542  updateBalloon();
543  emit mapLayerChanged();
544 }
545 
547 {
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;
564 }
565 
Abstract base class for annotation items which are drawn over a map.
Definition: qgsannotation.h:52
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.
Definition: qgsannotation.h:91
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.
QSizeF frameSize
Definition: qgsannotation.h:72
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...
Definition: qgsfeature.h:56
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgssymbol.h:1307
static QgsFillSymbol * createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
Definition: qgssymbol.cpp:1578
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.
Definition: qgsmaplayer.h:85
The QgsMargins class defines the four margins of a rectangle.
Definition: qgsmargins.h:38
double top() const
Returns the top margin.
Definition: qgsmargins.h:78
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...
Definition: qgsmargins.cpp:27
double right() const
Returns the right margin.
Definition: qgsmargins.h:84
double bottom() const
Returns the bottom margin.
Definition: qgsmargins.h:90
QString toString() const
Returns the margins encoded to a string.
Definition: qgsmargins.cpp:18
double left() const
Returns the left margin.
Definition: qgsmargins.h:72
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:1004
A class to represent a 2D point.
Definition: qgspointxy.h:44
double sqrDist(double x, double y) const SIP_HOLDGIL
Returns the squared distance between this point a specified x, y coordinate.
Definition: qgspointxy.h:175
void setX(double x) SIP_HOLDGIL
Sets the x value of the point.
Definition: qgspointxy.h:107
double y
Definition: qgspointxy.h:48
Q_GADGET double x
Definition: qgspointxy.h:47
void setY(double y) SIP_HOLDGIL
Sets the y value of the point.
Definition: qgspointxy.h:117
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.
Definition: qgspointxy.cpp:95
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:501
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.
Definition: qgsstyle.h:1201
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:168
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)
Definition: MathUtils.cpp:786
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:276
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:316
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.