QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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  QgsStringMap 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 
107 QSizeF QgsAnnotation::frameSize() const
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  painter->save();
142  drawFrame( context );
143  if ( mHasFixedMapPosition )
144  {
145  drawMarkerSymbol( context );
146  }
147  if ( mHasFixedMapPosition )
148  {
149  painter->translate( context.convertToPainterUnits( mOffsetFromReferencePoint.x(), QgsUnitTypes::RenderMillimeters ) + context.convertToPainterUnits( mContentsMargins.left(), QgsUnitTypes::RenderMillimeters ),
150  context.convertToPainterUnits( mOffsetFromReferencePoint.y(), QgsUnitTypes::RenderMillimeters ) + context.convertToPainterUnits( mContentsMargins.top(), QgsUnitTypes::RenderMillimeters ) );
151  }
152  else
153  {
154  painter->translate( context.convertToPainterUnits( mContentsMargins.left(), QgsUnitTypes::RenderMillimeters ),
155  context.convertToPainterUnits( mContentsMargins.top(), QgsUnitTypes::RenderMillimeters ) );
156  }
157  QSizeF size( context.convertToPainterUnits( mFrameSize.width(), QgsUnitTypes::RenderMillimeters ) - context.convertToPainterUnits( mContentsMargins.left() + mContentsMargins.right(), QgsUnitTypes::RenderMillimeters ),
158  context.convertToPainterUnits( mFrameSize.height(), QgsUnitTypes::RenderMillimeters ) - context.convertToPainterUnits( mContentsMargins.top() + mContentsMargins.bottom(), QgsUnitTypes::RenderMillimeters ) );
159 
160  // scale back from painter dpi to 96 dpi --
161 // double dotsPerMM = context.painter()->device()->logicalDpiX() / ( 25.4 * 3.78 );
162 // context.painter()->scale( dotsPerMM, dotsPerMM );
163 
164  renderAnnotation( context, size );
165  painter->restore();
166 }
167 
169 {
170  mMarkerSymbol.reset( symbol );
171  emit appearanceChanged();
172 }
173 
175 {
176  mMapLayer = layer;
177  emit mapLayerChanged();
178 }
179 
181 {
182  mFeature = feature;
183 }
184 
186 {
187  // NOTE: if visitEnter returns false it means "don't visit the annotation", not "abort all further visitations"
188  if ( !visitor->visitEnter( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Annotation, QStringLiteral( "annotation" ), tr( "Annotation" ) ) ) )
189  return true;
190 
191  if ( mMarkerSymbol )
192  {
193  QgsStyleSymbolEntity entity( mMarkerSymbol.get() );
194  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "marker" ), QObject::tr( "Marker" ) ) ) )
195  return false;
196  }
197 
198  if ( mFillSymbol )
199  {
200  QgsStyleSymbolEntity entity( mFillSymbol.get() );
201  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "fill" ), QObject::tr( "Fill" ) ) ) )
202  return false;
203  }
204 
205  if ( !visitor->visitExit( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Annotation, QStringLiteral( "annotation" ), tr( "Annotation" ) ) ) )
206  return false;
207 
208  return true;
209 }
210 
212 {
213  return QSizeF( 0, 0 );
214 }
215 
216 void QgsAnnotation::updateBalloon()
217 {
218  //first test if the point is in the frame. In that case we don't need a balloon.
219  if ( !mHasFixedMapPosition ||
220  ( mOffsetFromReferencePoint.x() < 0 && ( mOffsetFromReferencePoint.x() + mFrameSize.width() ) > 0
221  && mOffsetFromReferencePoint.y() < 0 && ( mOffsetFromReferencePoint.y() + mFrameSize.height() ) > 0 ) )
222  {
223  mBalloonSegment = -1;
224  return;
225  }
226 
227  //edge list
228  QList<QLineF> segmentList;
229  segmentList << segment( 0, nullptr );
230  segmentList << segment( 1, nullptr );
231  segmentList << segment( 2, nullptr );
232  segmentList << segment( 3, nullptr );
233 
234  //find closest edge / closest edge point
235  double minEdgeDist = std::numeric_limits<double>::max();
236  int minEdgeIndex = -1;
237  QLineF minEdge;
238  QgsPointXY minEdgePoint;
239  QgsPointXY origin( 0, 0 );
240 
241  for ( int i = 0; i < 4; ++i )
242  {
243  QLineF currentSegment = segmentList.at( i );
244  QgsPointXY currentMinDistPoint;
245  double currentMinDist = origin.sqrDistToSegment( currentSegment.x1(), currentSegment.y1(), currentSegment.x2(), currentSegment.y2(), currentMinDistPoint );
246  bool isPreferredSegment = false;
247  if ( qgsDoubleNear( currentMinDist, minEdgeDist ) )
248  {
249  // two segments are close - work out which looks nicer
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;
257  else
258  isPreferredSegment = i == 1;
259  }
260  else if ( currentMinDist < minEdgeDist )
261  isPreferredSegment = true;
262 
263  if ( isPreferredSegment )
264  {
265  minEdgeIndex = i;
266  minEdgePoint = currentMinDistPoint;
267  minEdgeDist = currentMinDist;
268  minEdge = currentSegment;
269  }
270  }
271 
272  if ( minEdgeIndex < 0 )
273  {
274  return;
275  }
276 
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 )
281  {
282  double x = 0;
283  double y = 0;
284  QgsGeometryUtils::pointOnLineWithDistance( minEdge.p2().x(), minEdge.p2().y(), minEdge.p1().x(), minEdge.p1().y(), mSegmentPointWidthMm, x, y );
285  mBalloonSegmentPoint1 = QPointF( x, y );
286  }
287 
288  {
289  double x = 0;
290  double y = 0;
291  QgsGeometryUtils::pointOnLineWithDistance( mBalloonSegmentPoint1.x(), mBalloonSegmentPoint1.y(), minEdge.p2().x(), minEdge.p2().y(), mSegmentPointWidthMm, x, y );
292  mBalloonSegmentPoint2 = QPointF( x, y );
293  }
294 
295 }
296 
297 QLineF QgsAnnotation::segment( int index, QgsRenderContext *context ) const
298 {
299  auto scaleSize = [context]( double size )->double
300  {
301  return context ? context->convertToPainterUnits( size, QgsUnitTypes::RenderMillimeters ) : size;
302  };
303  if ( mHasFixedMapPosition )
304  {
305  switch ( index )
306  {
307  case 0:
308  return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
309  scaleSize( mOffsetFromReferencePoint.y() ),
310  scaleSize( mOffsetFromReferencePoint.x() ) + scaleSize( mFrameSize.width() ),
311  scaleSize( mOffsetFromReferencePoint.y() ) );
312  case 1:
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() ) );
317  case 2:
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() ) );
322  case 3:
323  return QLineF( scaleSize( mOffsetFromReferencePoint.x() ),
324  scaleSize( mOffsetFromReferencePoint.y() ) + scaleSize( mFrameSize.height() ),
325  scaleSize( mOffsetFromReferencePoint.x() ),
326  scaleSize( mOffsetFromReferencePoint.y() ) );
327  default:
328  return QLineF();
329  }
330  }
331  else
332  {
333  switch ( index )
334  {
335  case 0:
336  return QLineF( 0, 0, scaleSize( mFrameSize.width() ), 0 );
337  case 1:
338  return QLineF( scaleSize( mFrameSize.width() ), 0,
339  scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ) );
340  case 2:
341  return QLineF( scaleSize( mFrameSize.width() ), scaleSize( mFrameSize.height() ),
342  0, scaleSize( mFrameSize.height() ) );
343  case 3:
344  return QLineF( 0, scaleSize( mFrameSize.height() ),
345  0, 0 );
346  default:
347  return QLineF();
348  }
349  }
350 }
351 
352 void QgsAnnotation::drawFrame( QgsRenderContext &context ) const
353 {
354  if ( !mFillSymbol )
355  return;
356 
357  context.painter()->setRenderHint( QPainter::Antialiasing, context.flags() & QgsRenderContext::Antialiasing );
358 
359  QPolygonF poly;
360  poly.reserve( 9 + ( mHasFixedMapPosition ? 3 : 0 ) );
361  QVector<QPolygonF> rings; //empty list
362  for ( int i = 0; i < 4; ++i )
363  {
364  QLineF currentSegment = segment( i, &context );
365  poly << QPointF( currentSegment.p1().x(),
366  currentSegment.p1().y() );
367  if ( i == mBalloonSegment && mHasFixedMapPosition )
368  {
369  poly << QPointF( context.convertToPainterUnits( mBalloonSegmentPoint1.x(), QgsUnitTypes::RenderMillimeters ),
370  context.convertToPainterUnits( mBalloonSegmentPoint1.y(), QgsUnitTypes::RenderMillimeters ) );
371  poly << QPointF( 0, 0 );
372  poly << QPointF( context.convertToPainterUnits( mBalloonSegmentPoint2.x(), QgsUnitTypes::RenderMillimeters ),
373  context.convertToPainterUnits( mBalloonSegmentPoint2.y(), QgsUnitTypes::RenderMillimeters ) );
374  }
375  poly << QPointF( currentSegment.p2().x(), currentSegment.p2().y() );
376  }
377  if ( poly.at( 0 ) != poly.at( poly.count() - 1 ) )
378  poly << poly.at( 0 );
379 
380  mFillSymbol->startRender( context );
381  mFillSymbol->renderPolygon( poly, &rings, nullptr, context );
382  mFillSymbol->stopRender( context );
383 }
384 
385 void QgsAnnotation::drawMarkerSymbol( QgsRenderContext &context ) const
386 {
387  if ( !context.painter() )
388  {
389  return;
390  }
391 
392  if ( mMarkerSymbol )
393  {
394  mMarkerSymbol->startRender( context );
395  mMarkerSymbol->renderPoint( QPointF( 0, 0 ), nullptr, context );
396  mMarkerSymbol->stopRender( context );
397  }
398 }
399 
400 void QgsAnnotation::_writeXml( QDomElement &itemElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
401 {
402  if ( itemElem.isNull() )
403  {
404  return;
405  }
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() );
420  if ( mMapLayer )
421  {
422  annotationElem.setAttribute( QStringLiteral( "mapLayer" ), mMapLayer->id() );
423  }
424  if ( mMarkerSymbol )
425  {
426  QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "marker symbol" ), mMarkerSymbol.get(), doc, context );
427  if ( !symbolElem.isNull() )
428  {
429  annotationElem.appendChild( symbolElem );
430  }
431  }
432  if ( mFillSymbol )
433  {
434  QDomElement fillElem = doc.createElement( QStringLiteral( "fillSymbol" ) );
435  QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "fill symbol" ), mFillSymbol.get(), doc, context );
436  if ( !symbolElem.isNull() )
437  {
438  fillElem.appendChild( symbolElem );
439  annotationElem.appendChild( fillElem );
440  }
441  }
442  itemElem.appendChild( annotationElem );
443 }
444 
445 void QgsAnnotation::_readXml( const QDomElement &annotationElem, const QgsReadWriteContext &context )
446 {
447  if ( annotationElem.isNull() )
448  {
449  return;
450  }
451  QPointF pos;
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();
456  else
457  mRelativePosition = pos;
458  QgsPointXY mapPos;
459  mapPos.setX( annotationElem.attribute( QStringLiteral( "mapPosX" ), QStringLiteral( "0" ) ).toDouble() );
460  mapPos.setY( annotationElem.attribute( QStringLiteral( "mapPosY" ), QStringLiteral( "0" ) ).toDouble() );
461  mMapPosition = mapPos;
462 
463  if ( !mMapPositionCrs.readXml( annotationElem ) )
464  {
465  mMapPositionCrs = QgsCoordinateReferenceSystem();
466  }
467 
468  mContentsMargins = QgsMargins::fromString( annotationElem.attribute( QStringLiteral( "contentsMargin" ) ) );
469  const double dpiScale = 25.4 / qt_defaultDpiX();
470  if ( annotationElem.hasAttribute( QStringLiteral( "frameWidthMM" ) ) )
471  mFrameSize.setWidth( annotationElem.attribute( QStringLiteral( "frameWidthMM" ), QStringLiteral( "5" ) ).toDouble() );
472  else
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() );
476  else
477  mFrameSize.setHeight( dpiScale * annotationElem.attribute( QStringLiteral( "frameHeight" ), QStringLiteral( "50" ) ).toDouble() );
478 
479  if ( annotationElem.hasAttribute( QStringLiteral( "offsetXMM" ) ) )
480  mOffsetFromReferencePoint.setX( annotationElem.attribute( QStringLiteral( "offsetXMM" ), QStringLiteral( "0" ) ).toDouble() );
481  else
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() );
485  else
486  mOffsetFromReferencePoint.setY( dpiScale * annotationElem.attribute( QStringLiteral( "offsetY" ), QStringLiteral( "0" ) ).toDouble() );
487 
488  mHasFixedMapPosition = annotationElem.attribute( QStringLiteral( "mapPositionFixed" ), QStringLiteral( "1" ) ).toInt();
489  mVisible = annotationElem.attribute( QStringLiteral( "visible" ), QStringLiteral( "1" ) ).toInt();
490  if ( annotationElem.hasAttribute( QStringLiteral( "mapLayer" ) ) )
491  {
492  mMapLayer = QgsProject::instance()->mapLayer( annotationElem.attribute( QStringLiteral( "mapLayer" ) ) );
493  }
494 
495  //marker symbol
496  {
497  QDomElement symbolElem = annotationElem.firstChildElement( QStringLiteral( "symbol" ) );
498  if ( !symbolElem.isNull() )
499  {
500  QgsMarkerSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElem, context );
501  if ( symbol )
502  {
503  mMarkerSymbol.reset( symbol );
504  }
505  }
506  }
507 
508  mFillSymbol.reset( nullptr );
509  QDomElement fillElem = annotationElem.firstChildElement( QStringLiteral( "fillSymbol" ) );
510  if ( !fillElem.isNull() )
511  {
512  QDomElement symbolElem = fillElem.firstChildElement( QStringLiteral( "symbol" ) );
513  if ( !symbolElem.isNull() )
514  {
515  QgsFillSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context );
516  if ( symbol )
517  {
518  mFillSymbol.reset( symbol );
519  }
520  }
521  }
522  if ( !mFillSymbol )
523  {
524  QColor frameColor;
525  frameColor.setNamedColor( annotationElem.attribute( QStringLiteral( "frameColor" ), QStringLiteral( "#000000" ) ) );
526  frameColor.setAlpha( annotationElem.attribute( QStringLiteral( "frameColorAlpha" ), QStringLiteral( "255" ) ).toInt() );
527  QColor frameBackgroundColor;
528  frameBackgroundColor.setNamedColor( annotationElem.attribute( QStringLiteral( "frameBackgroundColor" ) ) );
529  frameBackgroundColor.setAlpha( annotationElem.attribute( QStringLiteral( "frameBackgroundColorAlpha" ), QStringLiteral( "255" ) ).toInt() );
530  double frameBorderWidth = annotationElem.attribute( QStringLiteral( "frameBorderWidth" ), QStringLiteral( "0.5" ) ).toDouble();
531  // need to roughly convert border width from pixels to mm - just assume 96 dpi
532  frameBorderWidth = frameBorderWidth * 25.4 / 96.0;
533  QgsStringMap props;
534  props.insert( QStringLiteral( "color" ), frameBackgroundColor.name() );
535  props.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
536  props.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
537  props.insert( QStringLiteral( "color_border" ), frameColor.name() );
538  props.insert( QStringLiteral( "width_border" ), QString::number( frameBorderWidth ) );
539  props.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
540  mFillSymbol.reset( QgsFillSymbol::createSimple( props ) );
541  }
542 
543  updateBalloon();
544  emit mapLayerChanged();
545 }
546 
548 {
549  target->mVisible = mVisible;
550  target->mHasFixedMapPosition = mHasFixedMapPosition;
551  target->mMapPosition = mMapPosition;
552  target->mMapPositionCrs = mMapPositionCrs;
553  target->mRelativePosition = mRelativePosition;
554  target->mOffsetFromReferencePoint = mOffsetFromReferencePoint;
555  target->mFrameSize = mFrameSize;
556  target->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() : nullptr );
557  target->mContentsMargins = mContentsMargins;
558  target->mFillSymbol.reset( mFillSymbol ? mFillSymbol->clone() : nullptr );
559  target->mBalloonSegment = mBalloonSegment;
560  target->mBalloonSegmentPoint1 = mBalloonSegmentPoint1;
561  target->mBalloonSegmentPoint2 = mBalloonSegmentPoint2;
562  target->mSegmentPointWidthMm = mSegmentPointWidthMm;
563  target->mMapLayer = mMapLayer;
564  target->mFeature = mFeature;
565 }
566 
QgsMargins::bottom
double bottom() const
Returns the bottom margin.
Definition: qgsmargins.h:90
QgsAnnotation::mapLayerChanged
void mapLayerChanged()
Emitted when the map layer associated with the annotation changes.
QgsAnnotation::setMapPositionCrs
void setMapPositionCrs(const QgsCoordinateReferenceSystem &crs)
Sets the CRS of the map position.
Definition: qgsannotation.cpp:69
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsRenderContext::convertToPainterUnits
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
Definition: qgsrendercontext.cpp:287
QgsMargins::top
double top() const
Returns the top margin.
Definition: qgsmargins.h:78
QgsAnnotation::_readXml
void _readXml(const QDomElement &annotationElem, const QgsReadWriteContext &context)
Reads common annotation properties from a DOM element.
Definition: qgsannotation.cpp:445
QgsReadWriteContext
Definition: qgsreadwritecontext.h:34
qgsannotation.h
QgsGeometryUtils::pointOnLineWithDistance
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance)
Returns a point a specified distance toward a second point.
Definition: qgsgeometryutils.cpp:600
QgsStyleSymbolEntity
Definition: qgsstyle.h:1134
QgsPointXY::sqrDist
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
Definition: qgspointxy.h:175
QgsAnnotation::setContentsMargin
void setContentsMargin(const QgsMargins &margins)
Sets the margins (in millimeters) between the outside of the frame and the annotation content.
Definition: qgsannotation.cpp:121
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:105
QgsAnnotation::render
void render(QgsRenderContext &context) const
Renders the annotation to a target render context.
Definition: qgsannotation.cpp:133
qgssymbollayerutils.h
QgsRenderContext
Definition: qgsrendercontext.h:57
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
QgsStyleEntityVisitorInterface::NodeType::Annotation
@ Annotation
An individual annotation.
QgsStyleEntityVisitorInterface
Definition: qgsstyleentityvisitor.h:33
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:168
QgsStyleEntityVisitorInterface::visitExit
virtual bool visitExit(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor stops visiting a node.
Definition: qgsstyleentityvisitor.h:183
QgsProject::mapLayer
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
Definition: qgsproject.cpp:3124
QgsCoordinateReferenceSystem::readXml
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
Definition: qgscoordinatereferencesystem.cpp:1995
QgsAnnotation::setFrameSize
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 ...
Definition: qgsannotation.cpp:101
QgsAnnotation::renderAnnotation
virtual void renderAnnotation(QgsRenderContext &context, QSizeF size) const =0
Renders the annotation's contents to a target /a context at the specified /a size.
QgsAnnotation::setFrameOffsetFromReferencePointMm
void setFrameOffsetFromReferencePointMm(QPointF offset)
Sets the annotation's frame's offset (in millimeters) from the mapPosition() reference point.
Definition: qgsannotation.cpp:92
QgsStyleEntityVisitorInterface::StyleLeaf
Contains information relating to the style entity currently being visited.
Definition: qgsstyleentityvisitor.h:60
qgsDoubleToString
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:275
QgsAnnotation::setMapPosition
void setMapPosition(const QgsPointXY &position)
Sets the map position of the annotation, if it is attached to a fixed map position.
Definition: qgsannotation.cpp:63
QgsAnnotation::setRelativePosition
void setRelativePosition(QPointF position)
Sets the relative position of the annotation, if it is not attached to a fixed map position.
Definition: qgsannotation.cpp:75
QgsMargins::fromString
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
QgsAnnotation::setMarkerSymbol
void setMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the symbol that is drawn at the annotation's map position.
Definition: qgsannotation.cpp:168
QgsMargins::left
double left() const
Returns the left margin.
Definition: qgsmargins.h:72
QgsPointXY::sqrDistToSegment
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.
Definition: qgspointxy.cpp:95
QgsAnnotation
Abstract base class for annotation items which are drawn over a map.
Definition: qgsannotation.h:49
QgsMargins::toString
QString toString() const
Returns the margins encoded to a string.
Definition: qgsmargins.cpp:18
QgsCoordinateReferenceSystem::writeXml
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
Definition: qgscoordinatereferencesystem.cpp:2094
QgsMarkerSymbol
Definition: qgssymbol.h:917
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
qgsmaplayer.h
qt_defaultDpiX
Q_GUI_EXPORT int qt_defaultDpiX()
QgsPointXY::setY
void setY(double y)
Sets the y value of the point.
Definition: qgspointxy.h:117
QgsMargins
The QgsMargins class defines the four margins of a rectangle.
Definition: qgsmargins.h:37
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:902
QgsAnnotation::setVisible
void setVisible(bool visible)
Sets whether the annotation is visible and should be rendered.
Definition: qgsannotation.cpp:44
QgsAnnotation::isVisible
bool isVisible() const
Returns true if the annotation is visible and should be rendered.
Definition: qgsannotation.h:89
QgsMargins::right
double right() const
Returns the right margin.
Definition: qgsmargins.h:84
QgsAnnotation::_writeXml
void _writeXml(QDomElement &itemElem, QDomDocument &doc, const QgsReadWriteContext &context) const
Writes common annotation properties to a DOM element.
Definition: qgsannotation.cpp:400
QgsStyleEntityVisitorInterface::Node
Contains information relating to a node (i.e.
Definition: qgsstyleentityvisitor.h:110
QgsAnnotation::setAssociatedFeature
virtual void setAssociatedFeature(const QgsFeature &feature)
Sets the feature associated with the annotation.
Definition: qgsannotation.cpp:180
QgsCoordinateReferenceSystem
Definition: qgscoordinatereferencesystem.h:206
qgsgeometryutils.h
QgsAnnotation::setFrameSizeMm
void setFrameSizeMm(QSizeF size)
Sets the size (in millimeters) of the annotation's frame (the main area in which the annotation's con...
Definition: qgsannotation.cpp:112
QgsPointXY
Definition: qgspointxy.h:43
QgsStyleEntityVisitorInterface::visitEnter
virtual bool visitEnter(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor starts visiting a node.
Definition: qgsstyleentityvisitor.h:169
QgsAnnotation::accept
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated within ...
Definition: qgsannotation.cpp:185
QgsAnnotation::minimumFrameSize
virtual QSizeF minimumFrameSize() const
Returns the minimum frame size for the annotation.
Definition: qgsannotation.cpp:211
QgsAnnotation::frameSize
QSizeF frameSize
Definition: qgsannotation.h:70
QgsStringMap
QMap< QString, QString > QgsStringMap
Definition: qgis.h:714
QgsAnnotation::setHasFixedMapPosition
void setHasFixedMapPosition(bool fixed)
Sets whether the annotation is attached to a fixed map position, or uses a position relative to the c...
Definition: qgsannotation.cpp:53
QgsAnnotation::QgsAnnotation
QgsAnnotation(QObject *parent=nullptr)
Constructor for QgsAnnotation.
Definition: qgsannotation.cpp:30
QgsMapLayer
Definition: qgsmaplayer.h:81
QgsPointXY::x
double x
Definition: qgspointxy.h:47
QgsFillSymbol
Definition: qgssymbol.h:1212
QgsAnnotation::appearanceChanged
void appearanceChanged()
Emitted whenever the annotation's appearance changes.
QgsStyleEntityVisitorInterface::visit
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
Definition: qgsstyleentityvisitor.h:153
QgsAnnotation::setFillSymbol
void setFillSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used for rendering the annotation frame.
Definition: qgsannotation.cpp:127
QgsRenderContext::Antialiasing
@ Antialiasing
Use antialiasing while drawing.
Definition: qgsrendercontext.h:78
QgsAnnotation::frameOffsetFromReferencePoint
Q_DECL_DEPRECATED QPointF frameOffsetFromReferencePoint() const
Returns the annotation's frame's offset (in pixels) from the mapPosition() reference point.
Definition: qgsannotation.cpp:87
QgsPointXY::setX
void setX(double x)
Sets the x value of the point.
Definition: qgspointxy.h:107
QgsFeature
Definition: qgsfeature.h:55
QgsFillSymbol::createSimple
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
Definition: qgssymbol.cpp:1440
QgsAnnotation::visible
bool visible
Definition: qgsannotation.h:67
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:174
QgsAnnotation::setFrameOffsetFromReferencePoint
Q_DECL_DEPRECATED void setFrameOffsetFromReferencePoint(QPointF offset)
Sets the annotation's frame's offset (in pixels) from the mapPosition() reference point.
Definition: qgsannotation.cpp:81
MathUtils::angle
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
QgsSymbolLayerUtils::saveSymbol
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
Definition: qgssymbollayerutils.cpp:1180
QgsAnnotation::moved
void moved()
Emitted when the annotation's position has changed and items need to be moved to reflect this.
qgsproject.h
qgsstyleentityvisitor.h
QgsAnnotation::copyCommonProperties
void copyCommonProperties(QgsAnnotation *target) const
Copies common annotation properties to the targe annotation.
Definition: qgsannotation.cpp:547
QgsRenderContext::flags
Flags flags() const
Returns combination of flags used for rendering.
Definition: qgsrendercontext.cpp:160
QgsAnnotation::setMapLayer
void setMapLayer(QgsMapLayer *layer)
Sets the map layer associated with the annotation.
Definition: qgsannotation.cpp:174