QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 
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  QList<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  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  mFillSymbol.reset( nullptr );
507  QDomElement fillElem = annotationElem.firstChildElement( QStringLiteral( "fillSymbol" ) );
508  if ( !fillElem.isNull() )
509  {
510  QDomElement symbolElem = fillElem.firstChildElement( QStringLiteral( "symbol" ) );
511  if ( !symbolElem.isNull() )
512  {
513  QgsFillSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context );
514  if ( symbol )
515  {
516  mFillSymbol.reset( symbol );
517  }
518  }
519  }
520  if ( !mFillSymbol )
521  {
522  QColor frameColor;
523  frameColor.setNamedColor( annotationElem.attribute( QStringLiteral( "frameColor" ), QStringLiteral( "#000000" ) ) );
524  frameColor.setAlpha( annotationElem.attribute( QStringLiteral( "frameColorAlpha" ), QStringLiteral( "255" ) ).toInt() );
525  QColor frameBackgroundColor;
526  frameBackgroundColor.setNamedColor( annotationElem.attribute( QStringLiteral( "frameBackgroundColor" ) ) );
527  frameBackgroundColor.setAlpha( annotationElem.attribute( QStringLiteral( "frameBackgroundColorAlpha" ), QStringLiteral( "255" ) ).toInt() );
528  double frameBorderWidth = annotationElem.attribute( QStringLiteral( "frameBorderWidth" ), QStringLiteral( "0.5" ) ).toDouble();
529  // need to roughly convert border width from pixels to mm - just assume 96 dpi
530  frameBorderWidth = frameBorderWidth * 25.4 / 96.0;
531  QgsStringMap props;
532  props.insert( QStringLiteral( "color" ), frameBackgroundColor.name() );
533  props.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
534  props.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
535  props.insert( QStringLiteral( "color_border" ), frameColor.name() );
536  props.insert( QStringLiteral( "width_border" ), QString::number( frameBorderWidth ) );
537  props.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
538  mFillSymbol.reset( QgsFillSymbol::createSimple( props ) );
539  }
540 
541  updateBalloon();
542  emit mapLayerChanged();
543 }
544 
546 {
547  target->mVisible = mVisible;
548  target->mHasFixedMapPosition = mHasFixedMapPosition;
549  target->mMapPosition = mMapPosition;
550  target->mMapPositionCrs = mMapPositionCrs;
551  target->mRelativePosition = mRelativePosition;
552  target->mOffsetFromReferencePoint = mOffsetFromReferencePoint;
553  target->mFrameSize = mFrameSize;
554  target->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() : nullptr );
555  target->mContentsMargins = mContentsMargins;
556  target->mFillSymbol.reset( mFillSymbol ? mFillSymbol->clone() : nullptr );
557  target->mBalloonSegment = mBalloonSegment;
558  target->mBalloonSegmentPoint1 = mBalloonSegmentPoint1;
559  target->mBalloonSegmentPoint2 = mBalloonSegmentPoint2;
560  target->mSegmentPointWidthMm = mSegmentPointWidthMm;
561  target->mMapLayer = mMapLayer;
562  target->mFeature = mFeature;
563 }
564 
double right() const
Returns the right margin.
Definition: qgsmargins.h:84
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.
Definition: qgsmaplayer.h:79
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:971
bool isVisible() const
Returns true if the annotation is visible and should be rendered.
Definition: qgsannotation.h:89
void appearanceChanged()
Emitted whenever the annotation&#39;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.
double y
Definition: qgspointxy.h:48
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
Definition: qgssymbol.cpp:1251
A class to represent a 2D point.
Definition: qgspointxy.h:43
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:280
void setFrameOffsetFromReferencePointMm(QPointF offset)
Sets the annotation&#39;s frame&#39;s offset (in millimeters) from the mapPosition() reference point...
Q_DECL_DEPRECATED void setFrameOffsetFromReferencePoint(QPointF offset)
Sets the annotation&#39;s frame&#39;s offset (in pixels) from the mapPosition() reference point...
Flags flags() const
Returns combination of flags used for rendering.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
const QgsCoordinateReferenceSystem & crs
An interface for classes which can visit style entity (e.g.
void copyCommonProperties(QgsAnnotation *target) const
Copies common annotation properties to the targe annotation.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:612
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
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:860
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
Abstract base class for annotation items which are drawn over a map.
Definition: qgsannotation.h:49
double azimuth(const QgsPointXY &other) const
Calculates azimuth between this point and other one (clockwise in degree, starting from north) ...
Definition: qgspointxy.cpp:80
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.
Definition: qgspointxy.h:175
virtual void renderAnnotation(QgsRenderContext &context, QSizeF size) const =0
Renders the annotation&#39;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.
Definition: qgspointxy.cpp:95
virtual bool visitExit(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor stops visiting a node.
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.
Definition: qgsmargins.h:90
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:240
void setY(double y)
Sets the y value of the point.
Definition: qgspointxy.h:117
void render(QgsRenderContext &context) const
Renders the annotation to a target render context.
Contains information relating to a node (i.e.
double top() const
Returns the top margin.
Definition: qgsmargins.h:78
virtual QSizeF minimumFrameSize() const
Returns the minimum frame size for the annotation.
void setFrameSizeMm(QSizeF size)
Sets the size (in millimeters) of the annotation&#39;s frame (the main area in which the annotation&#39;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.
Definition: qgspointxy.h:107
double x
Definition: qgspointxy.h:47
Q_DECL_DEPRECATED void setFrameSize(QSizeF size)
Sets the size (in pixels) of the annotation&#39;s frame (the main area in which the annotation&#39;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&#39;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&#39;s map position.
Q_DECL_DEPRECATED QPointF frameOffsetFromReferencePoint() const
Returns the annotation&#39;s frame&#39;s offset (in pixels) from the mapPosition() reference point...
QPainter * painter()
Returns the destination QPainter for the render operation.
virtual bool visitEnter(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor starts visiting a node.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:442
This class represents a coordinate reference system (CRS).
Q_DECL_DEPRECATED QSizeF frameSize() const
Returns the size (in pixels) of the annotation&#39;s frame (the main area in which the annotation&#39;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...
Definition: qgsmargins.cpp:27
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
Q_INVOKABLE 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.
Definition: qgssymbol.h:1155
QString toString() const
Returns the margins encoded to a string.
Definition: qgsmargins.cpp:18
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.
Definition: qgsmargins.h:72
Contains information relating to the style entity currently being visited.
The QgsMargins class defines the four margins of a rectangle.
Definition: qgsmargins.h:37
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated within ...
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.