QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsmapcanvasannotationitem.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmapcanvasannotationitem.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 
19 #include "qgsannotation.h"
20 #include "qgsmapcanvas.h"
21 #include "qgsmaptool.h"
22 #include "qgsvectorlayer.h"
23 #include "qgsfeatureiterator.h"
24 #include "qgsexception.h"
25 #include "qgssymbollayerutils.h"
26 #include "qgsproject.h"
27 #include "qgsannotationmanager.h"
28 #include <QPainter>
29 
30 
32  : QgsMapCanvasItem( mapCanvas )
33  , mAnnotation( annotation )
34 {
35  setFlag( QGraphicsItem::ItemIsSelectable, true );
36  if ( mapCanvas && !mapCanvas->annotationsVisible() )
37  setVisible( false );
38 
39  connect( mAnnotation, &QgsAnnotation::appearanceChanged, this, [this] { update(); } );
40  connect( mAnnotation, &QgsAnnotation::moved, this, [this] { updatePosition(); } );
41  connect( mAnnotation, &QgsAnnotation::moved, this, &QgsMapCanvasAnnotationItem::setFeatureForMapPosition );
42  connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, [ = ] { updatePosition(); } );
43 
44  connect( mAnnotation, &QgsAnnotation::appearanceChanged, this, &QgsMapCanvasAnnotationItem::updateBoundingRect );
45 
46  connect( mMapCanvas, &QgsMapCanvas::layersChanged, this, &QgsMapCanvasAnnotationItem::onCanvasLayersChanged );
47  connect( mAnnotation, &QgsAnnotation::mapLayerChanged, this, &QgsMapCanvasAnnotationItem::onCanvasLayersChanged );
48 
49  //lifetime is tied to annotation!
50  connect( mAnnotation, &QgsAnnotation::destroyed, this, &QgsMapCanvasAnnotationItem::annotationDeleted );
51 
53  setFeatureForMapPosition();
54 }
55 
57 {
58  if ( !mAnnotation )
59  return;
60 
61  if ( mAnnotation->hasFixedMapPosition() )
62  {
64  QgsPointXY coord = mAnnotation->mapPosition();
65  try
66  {
67  coord = t.transform( coord );
68  }
69  catch ( QgsCsException & )
70  {}
71  setPos( toCanvasCoordinates( coord ) );
72  }
73  else
74  {
75  //relative position
76 
77  double x = mAnnotation->relativePosition().x() * mMapCanvas->width();
78  double y = mAnnotation->relativePosition().y() * mMapCanvas->height();
79  setPos( x, y );
80  }
81  updateBoundingRect();
82 }
83 
85 {
86  return mBoundingRect;
87 }
88 
89 void QgsMapCanvasAnnotationItem::updateBoundingRect()
90 {
91  prepareGeometryChange();
92 
94  double fillSymbolBleed = mAnnotation && mAnnotation->fillSymbol() ?
96 
97  const double mmToPixelScale = mMapCanvas->logicalDpiX() / 25.4;
98 
99  if ( mAnnotation && !mAnnotation->hasFixedMapPosition() )
100  {
101  mBoundingRect = QRectF( - fillSymbolBleed, -fillSymbolBleed,
102  mmToPixelScale * mAnnotation->frameSizeMm().width() + fillSymbolBleed * 2,
103  mmToPixelScale * mAnnotation->frameSizeMm().height() + fillSymbolBleed * 2 );
104  }
105  else
106  {
107  double halfSymbolSize = 0.0;
108  if ( mAnnotation && mAnnotation->markerSymbol() )
109  {
110  halfSymbolSize = scaledSymbolSize() / 2.0;
111  }
112 
113  QPointF offset = mAnnotation ? QPointF( mAnnotation->frameOffsetFromReferencePointMm().x() * mmToPixelScale,
114  mAnnotation->frameOffsetFromReferencePointMm().y() * mmToPixelScale ) : QPointF( 0, 0 );
115 
116  QSizeF frameSize = mAnnotation ? QSizeF( mAnnotation->frameSizeMm().width() * mmToPixelScale,
117  mAnnotation->frameSizeMm().height() * mmToPixelScale ) : QSizeF( 0.0, 0.0 );
118 
119  double xMinPos = std::min( -halfSymbolSize, offset.x() - fillSymbolBleed );
120  double xMaxPos = std::max( halfSymbolSize, offset.x() + frameSize.width() + fillSymbolBleed );
121  double yMinPos = std::min( -halfSymbolSize, offset.y() - fillSymbolBleed );
122  double yMaxPos = std::max( halfSymbolSize, offset.y() + frameSize.height() + fillSymbolBleed );
123  mBoundingRect = QRectF( xMinPos, yMinPos, xMaxPos - xMinPos, yMaxPos - yMinPos );
124  }
125 }
126 
127 void QgsMapCanvasAnnotationItem::onCanvasLayersChanged()
128 {
129  if ( !mAnnotation )
130  return;
131  if ( !mMapCanvas->annotationsVisible() )
132  {
133  setVisible( false );
134  }
135  else if ( !mAnnotation->mapLayer() )
136  {
137  setVisible( true );
138  }
139  else
140  {
141  setVisible( mMapCanvas->mapSettings().layers().contains( mAnnotation->mapLayer() ) );
142  }
143 }
144 
145 void QgsMapCanvasAnnotationItem::setFeatureForMapPosition()
146 {
147  if ( !mAnnotation || !mAnnotation->hasFixedMapPosition() )
148  return;
149 
150  QgsVectorLayer *vectorLayer = qobject_cast< QgsVectorLayer * >( mAnnotation->mapLayer() );
151  if ( !vectorLayer )
152  return;
153 
154  double halfIdentifyWidth = QgsMapTool::searchRadiusMU( mMapCanvas );
155  QgsPointXY mapPosition = mAnnotation->mapPosition();
156 
157  try
158  {
160  if ( ct.isValid() )
161  mapPosition = ct.transform( mapPosition );
162  }
163  catch ( QgsCsException & )
164  {
165  }
166 
167  QgsRectangle searchRect( mapPosition.x() - halfIdentifyWidth, mapPosition.y() - halfIdentifyWidth,
168  mapPosition.x() + halfIdentifyWidth, mapPosition.y() + halfIdentifyWidth );
169 
170  searchRect = mMapCanvas->mapSettings().mapToLayerCoordinates( vectorLayer, searchRect );
171 
172  QgsFeatureIterator fit = vectorLayer->getFeatures( QgsFeatureRequest().setFilterRect( searchRect ).setFlags( QgsFeatureRequest::ExactIntersect ).setLimit( 1 ) );
173 
174  QgsFeature currentFeature;
175  ( void )fit.nextFeature( currentFeature );
176  mAnnotation->setAssociatedFeature( currentFeature );
177 }
178 
179 void QgsMapCanvasAnnotationItem::annotationDeleted()
180 {
181  mAnnotation = nullptr;
182  deleteLater();
183 }
184 
185 void QgsMapCanvasAnnotationItem::drawSelectionBoxes( QPainter *p ) const
186 {
187  if ( !p )
188  {
189  return;
190  }
191 
192  double handlerSize = 10;
193  p->setPen( Qt::NoPen );
194  p->setBrush( QColor( 200, 200, 210, 120 ) );
195  p->drawRect( QRectF( mBoundingRect.left(), mBoundingRect.top(), handlerSize, handlerSize ) );
196  p->drawRect( QRectF( mBoundingRect.right() - handlerSize, mBoundingRect.top(), handlerSize, handlerSize ) );
197  p->drawRect( QRectF( mBoundingRect.right() - handlerSize, mBoundingRect.bottom() - handlerSize, handlerSize, handlerSize ) );
198  p->drawRect( QRectF( mBoundingRect.left(), mBoundingRect.bottom() - handlerSize, handlerSize, handlerSize ) );
199 }
200 
202 {
203  QPointF itemPos = mapFromScene( pos );
204 
205  int cursorSensitivity = 7;
206 
207  if ( mAnnotation && mAnnotation->hasFixedMapPosition() &&
208  std::fabs( itemPos.x() ) < cursorSensitivity && std::fabs( itemPos.y() ) < cursorSensitivity ) //move map point if position is close to the origin
209  {
210  return MoveMapPosition;
211  }
212 
213  const double mmToPixelScale = mMapCanvas->logicalDpiX() / 25.4;
214 
215  QPointF offset = mAnnotation && mAnnotation->hasFixedMapPosition() ? mAnnotation->frameOffsetFromReferencePointMm() * mmToPixelScale : QPointF( 0, 0 );
216  QSizeF frameSize = mAnnotation ? mAnnotation->frameSizeMm() * mmToPixelScale : QSizeF( 0, 0 );
217 
218  bool left, right, up, down;
219  left = std::fabs( itemPos.x() - offset.x() ) < cursorSensitivity;
220  right = std::fabs( itemPos.x() - ( offset.x() + frameSize.width() ) ) < cursorSensitivity;
221  up = std::fabs( itemPos.y() - offset.y() ) < cursorSensitivity;
222  down = std::fabs( itemPos.y() - ( offset.y() + frameSize.height() ) ) < cursorSensitivity;
223 
224  if ( left && up )
225  {
226  return ResizeFrameLeftUp;
227  }
228  else if ( right && up )
229  {
230  return ResizeFrameRightUp;
231  }
232  else if ( left && down )
233  {
234  return ResizeFrameLeftDown;
235  }
236  else if ( right && down )
237  {
238  return ResizeFrameRightDown;
239  }
240  if ( left )
241  {
242  return ResizeFrameLeft;
243  }
244  if ( right )
245  {
246  return ResizeFrameRight;
247  }
248  if ( up )
249  {
250  return ResizeFrameUp;
251  }
252  if ( down )
253  {
254  return ResizeFrameDown;
255  }
256 
257  //finally test if pos is in the frame area
258  if ( itemPos.x() >= offset.x() && itemPos.x() <= ( offset.x() + frameSize.width() )
259  && itemPos.y() >= offset.y() && itemPos.y() <= ( offset.y() + frameSize.height() ) )
260  {
261  return MoveFramePosition;
262  }
263  return NoAction;
264 }
265 
267 {
268  switch ( moveAction )
269  {
270  case NoAction:
271  return Qt::ArrowCursor;
272  case MoveMapPosition:
273  case MoveFramePosition:
274  return Qt::SizeAllCursor;
275  case ResizeFrameUp:
276  case ResizeFrameDown:
277  return Qt::SizeVerCursor;
278  case ResizeFrameLeft:
279  case ResizeFrameRight:
280  return Qt::SizeHorCursor;
281  case ResizeFrameLeftUp:
283  return Qt::SizeFDiagCursor;
284  case ResizeFrameRightUp:
285  case ResizeFrameLeftDown:
286  return Qt::SizeBDiagCursor;
287  default:
288  return Qt::ArrowCursor;
289  }
290 }
291 
292 double QgsMapCanvasAnnotationItem::scaledSymbolSize() const
293 {
294  if ( !mAnnotation || !mAnnotation->markerSymbol() )
295  {
296  return 0.0;
297  }
298 
299  if ( !mMapCanvas )
300  {
301  return mAnnotation->markerSymbol()->size();
302  }
303 
304  double dpmm = mMapCanvas->logicalDpiX() / 25.4;
305  return dpmm * mAnnotation->markerSymbol()->size();
306 }
307 
308 void QgsMapCanvasAnnotationItem::paint( QPainter *painter )
309 {
310  if ( !mAnnotation || !mAnnotation->isVisible() )
311  return;
312 
315 
316  if ( mAnnotation )
317  mAnnotation->render( rc );
318 
319  if ( isSelected() )
320  {
321  drawSelectionBoxes( painter );
322  }
323 }
QgsAnnotation::mapLayerChanged
void mapLayerChanged()
Emitted when the map layer associated with the annotation changes.
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:993
QgsMapCanvasAnnotationItem::MoveMapPosition
@ MoveMapPosition
Moving annotation map position.
Definition: qgsmapcanvasannotationitem.h:58
QgsMapCanvasAnnotationItem::ResizeFrameLeft
@ ResizeFrameLeft
Resize frame left.
Definition: qgsmapcanvasannotationitem.h:62
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsMapCanvasAnnotationItem::NoAction
@ NoAction
No action.
Definition: qgsmapcanvasannotationitem.h:57
QgsMapSettings::mapToLayerCoordinates
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
Definition: qgsmapsettings.cpp:537
QgsAnnotation::mapPosition
QgsPointXY mapPosition
Definition: qgsannotation.h:69
QgsMapCanvas::destinationCrsChanged
void destinationCrsChanged()
Emitted when map CRS has changed.
QgsFeatureRequest::ExactIntersect
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
Definition: qgsfeaturerequest.h:83
qgsmapcanvas.h
qgsannotation.h
QgsAnnotation::frameSizeMm
QSizeF frameSizeMm() const
Returns the size (in millimeters) of the annotation's frame (the main area in which the annotation's ...
Definition: qgsannotation.h:217
QgsMapCanvasItem::mMapCanvas
QgsMapCanvas * mMapCanvas
pointer to map canvas
Definition: qgsmapcanvasitem.h:82
QgsMarkerSymbol::size
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
Definition: qgssymbol.cpp:1638
QgsMapCanvasAnnotationItem::ResizeFrameLeftUp
@ ResizeFrameLeftUp
Resize frame left up.
Definition: qgsmapcanvasannotationitem.h:64
QgsMapCanvas::mapSettings
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
Definition: qgsmapcanvas.cpp:391
QgsPointXY::x
Q_GADGET double x
Definition: qgspointxy.h:47
QgsRenderContext::setFlag
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Definition: qgsrendercontext.cpp:179
QgsAnnotation::render
void render(QgsRenderContext &context) const
Renders the annotation to a target render context.
Definition: qgsannotation.cpp:133
qgssymbollayerutils.h
qgsfeatureiterator.h
QgsMapCanvas
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:85
qgsmapcanvasannotationitem.h
QgsMapCanvasAnnotationItem::cursorShapeForAction
Qt::CursorShape cursorShapeForAction(MouseMoveAction moveAction) const
Returns matching cursor shape for a mouse move action.
Definition: qgsmapcanvasannotationitem.cpp:266
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:58
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:468
QgsMapCanvasAnnotationItem::ResizeFrameUp
@ ResizeFrameUp
Resize frame up.
Definition: qgsmapcanvasannotationitem.h:60
QgsCoordinateTransform::transform
QgsPointXY transform(const QgsPointXY &point, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:239
QgsMapCanvasAnnotationItem::paint
void paint(QPainter *painter) override
function to be implemented by derived classes
Definition: qgsmapcanvasannotationitem.cpp:308
QgsMapCanvasAnnotationItem::MoveFramePosition
@ MoveFramePosition
Moving position of frame relative to annotation.
Definition: qgsmapcanvasannotationitem.h:59
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsAnnotation::mapLayer
QgsMapLayer * mapLayer() const
Returns the map layer associated with the annotation.
Definition: qgsannotation.h:286
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:76
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
QgsAnnotation
Abstract base class for annotation items which are drawn over a map.
Definition: qgsannotation.h:50
QgsMapCanvasItem
An abstract class for items that can be placed on the map canvas.
Definition: qgsmapcanvasitem.h:34
QgsMapCanvasAnnotationItem::MouseMoveAction
MouseMoveAction
Mouse actions for interacting with item.
Definition: qgsmapcanvasannotationitem.h:56
QgsMapCanvasAnnotationItem::QgsMapCanvasAnnotationItem
QgsMapCanvasAnnotationItem(QgsAnnotation *annotation, QgsMapCanvas *mapCanvas)
Constructor for QgsMapCanvasAnnotationItem.
Definition: qgsmapcanvasannotationitem.cpp:31
QgsMapCanvasItem::toCanvasCoordinates
QPointF toCanvasCoordinates(const QgsPointXY &point) const
transformation from map coordinates to screen coordinates
Definition: qgsmapcanvasitem.cpp:61
QgsAnnotation::fillSymbol
QgsFillSymbol * fillSymbol() const
Returns the symbol that is used for rendering the annotation frame.
Definition: qgsannotation.h:244
QgsMapCanvas::layersChanged
void layersChanged()
Emitted when a new set of layers has been received.
qgsmaptool.h
QgsMapCanvasAnnotationItem::ResizeFrameLeftDown
@ ResizeFrameLeftDown
Resize frame left down.
Definition: qgsmapcanvasannotationitem.h:66
QgsAnnotation::isVisible
bool isVisible() const
Returns true if the annotation is visible and should be rendered.
Definition: qgsannotation.h:89
qgsannotationmanager.h
QgsAnnotation::hasFixedMapPosition
bool hasFixedMapPosition
Definition: qgsannotation.h:68
QgsAnnotation::setAssociatedFeature
virtual void setAssociatedFeature(const QgsFeature &feature)
Sets the feature associated with the annotation.
Definition: qgsannotation.cpp:181
qgsvectorlayer.h
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsMapSettings::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
Definition: qgsmapsettings.cpp:318
QgsMapCanvasAnnotationItem::boundingRect
QRectF boundingRect() const override
Definition: qgsmapcanvasannotationitem.cpp:84
QgsMapCanvas::annotationsVisible
bool annotationsVisible() const
Returns true if annotations are visible within the map canvas.
Definition: qgsmapcanvas.h:686
QgsAnnotation::markerSymbol
QgsMarkerSymbol * markerSymbol() const
Returns the symbol that is drawn at the annotation's map position.
Definition: qgsannotation.h:278
QgsMapCanvasAnnotationItem::moveActionForPosition
MouseMoveAction moveActionForPosition(QPointF pos) const
Returns the mouse move behavior for a given position in scene coordinates.
Definition: qgsmapcanvasannotationitem.cpp:201
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:374
QgsMapCanvasAnnotationItem::updatePosition
void updatePosition() override
called on changed extent or resize event to update position of the item
Definition: qgsmapcanvasannotationitem.cpp:56
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsMapCanvasAnnotationItem::ResizeFrameDown
@ ResizeFrameDown
Resize frame down.
Definition: qgsmapcanvasannotationitem.h:61
QgsRenderContext::fromQPainter
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
Definition: qgsrendercontext.cpp:119
QgsMapCanvasAnnotationItem::ResizeFrameRight
@ ResizeFrameRight
Resize frame right.
Definition: qgsmapcanvasannotationitem.h:63
QgsAnnotation::frameOffsetFromReferencePointMm
QPointF frameOffsetFromReferencePointMm() const
Returns the annotation's frame's offset (in millimeters) from the mapPosition() reference point.
Definition: qgsannotation.h:185
QgsAnnotation::appearanceChanged
void appearanceChanged()
Emitted whenever the annotation's appearance changes.
QgsAnnotation::relativePosition
QPointF relativePosition() const
Returns the relative position of the annotation, if it is not attached to a fixed map position.
Definition: qgsannotation.h:149
QgsMapTool::searchRadiusMU
static double searchRadiusMU(const QgsRenderContext &context)
Gets search radius in map units for given context.
Definition: qgsmaptool.cpp:212
QgsRenderContext::Antialiasing
@ Antialiasing
Use antialiasing while drawing.
Definition: qgsrendercontext.h:79
QgsMapSettings::layers
QList< QgsMapLayer * > layers() const
Gets list of layers for map rendering The layers are stored in the reverse order of how they are rend...
Definition: qgsmapsettings.cpp:282
QgsAnnotation::mapPositionCrs
QgsCoordinateReferenceSystem mapPositionCrs() const
Returns the CRS of the map position, or an invalid CRS if the annotation does not have a fixed map po...
Definition: qgsannotation.h:135
qgsexception.h
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsSymbolLayerUtils::estimateMaxSymbolBleed
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
Definition: qgssymbollayerutils.cpp:822
QgsMapCanvasAnnotationItem::ResizeFrameRightDown
@ ResizeFrameRightDown
Resize frame right down.
Definition: qgsmapcanvasannotationitem.h:67
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:53
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:265
QgsAnnotation::moved
void moved()
Emitted when the annotation's position has changed and items need to be moved to reflect this.
qgsproject.h
QgsMapCanvasAnnotationItem::ResizeFrameRightUp
@ ResizeFrameRightUp
Resize frame right up.
Definition: qgsmapcanvasannotationitem.h:65