QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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::deleteLater );
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 ( !mMapCanvas->annotationsVisible() )
130  {
131  setVisible( false );
132  }
133  else if ( !mAnnotation->mapLayer() )
134  {
135  setVisible( true );
136  }
137  else
138  {
139  setVisible( mMapCanvas->mapSettings().layers().contains( mAnnotation->mapLayer() ) );
140  }
141 }
142 
143 void QgsMapCanvasAnnotationItem::setFeatureForMapPosition()
144 {
145  if ( !mAnnotation || !mAnnotation->hasFixedMapPosition() )
146  return;
147 
148  QgsVectorLayer *vectorLayer = qobject_cast< QgsVectorLayer * >( mAnnotation->mapLayer() );
149  if ( !vectorLayer )
150  return;
151 
152  double halfIdentifyWidth = QgsMapTool::searchRadiusMU( mMapCanvas );
153  QgsPointXY mapPosition = mAnnotation->mapPosition();
154 
155  try
156  {
158  if ( ct.isValid() )
159  mapPosition = ct.transform( mapPosition );
160  }
161  catch ( QgsCsException & )
162  {
163  }
164 
165  QgsRectangle searchRect( mapPosition.x() - halfIdentifyWidth, mapPosition.y() - halfIdentifyWidth,
166  mapPosition.x() + halfIdentifyWidth, mapPosition.y() + halfIdentifyWidth );
167 
168  searchRect = mMapCanvas->mapSettings().mapToLayerCoordinates( vectorLayer, searchRect );
169 
170  QgsFeatureIterator fit = vectorLayer->getFeatures( QgsFeatureRequest().setFilterRect( searchRect ).setFlags( QgsFeatureRequest::ExactIntersect ).setLimit( 1 ) );
171 
172  QgsFeature currentFeature;
173  ( void )fit.nextFeature( currentFeature );
174  mAnnotation->setAssociatedFeature( currentFeature );
175 }
176 
177 void QgsMapCanvasAnnotationItem::drawSelectionBoxes( QPainter *p ) const
178 {
179  if ( !p )
180  {
181  return;
182  }
183 
184  double handlerSize = 10;
185  p->setPen( Qt::NoPen );
186  p->setBrush( QColor( 200, 200, 210, 120 ) );
187  p->drawRect( QRectF( mBoundingRect.left(), mBoundingRect.top(), handlerSize, handlerSize ) );
188  p->drawRect( QRectF( mBoundingRect.right() - handlerSize, mBoundingRect.top(), handlerSize, handlerSize ) );
189  p->drawRect( QRectF( mBoundingRect.right() - handlerSize, mBoundingRect.bottom() - handlerSize, handlerSize, handlerSize ) );
190  p->drawRect( QRectF( mBoundingRect.left(), mBoundingRect.bottom() - handlerSize, handlerSize, handlerSize ) );
191 }
192 
194 {
195  QPointF itemPos = mapFromScene( pos );
196 
197  int cursorSensitivity = 7;
198 
199  if ( mAnnotation && mAnnotation->hasFixedMapPosition() &&
200  std::fabs( itemPos.x() ) < cursorSensitivity && std::fabs( itemPos.y() ) < cursorSensitivity ) //move map point if position is close to the origin
201  {
202  return MoveMapPosition;
203  }
204 
205  const double mmToPixelScale = mMapCanvas->logicalDpiX() / 25.4;
206 
207  QPointF offset = mAnnotation && mAnnotation->hasFixedMapPosition() ? mAnnotation->frameOffsetFromReferencePointMm() * mmToPixelScale : QPointF( 0, 0 );
208  QSizeF frameSize = mAnnotation ? mAnnotation->frameSizeMm() * mmToPixelScale : QSizeF( 0, 0 );
209 
210  bool left, right, up, down;
211  left = std::fabs( itemPos.x() - offset.x() ) < cursorSensitivity;
212  right = std::fabs( itemPos.x() - ( offset.x() + frameSize.width() ) ) < cursorSensitivity;
213  up = std::fabs( itemPos.y() - offset.y() ) < cursorSensitivity;
214  down = std::fabs( itemPos.y() - ( offset.y() + frameSize.height() ) ) < cursorSensitivity;
215 
216  if ( left && up )
217  {
218  return ResizeFrameLeftUp;
219  }
220  else if ( right && up )
221  {
222  return ResizeFrameRightUp;
223  }
224  else if ( left && down )
225  {
226  return ResizeFrameLeftDown;
227  }
228  else if ( right && down )
229  {
230  return ResizeFrameRightDown;
231  }
232  if ( left )
233  {
234  return ResizeFrameLeft;
235  }
236  if ( right )
237  {
238  return ResizeFrameRight;
239  }
240  if ( up )
241  {
242  return ResizeFrameUp;
243  }
244  if ( down )
245  {
246  return ResizeFrameDown;
247  }
248 
249  //finally test if pos is in the frame area
250  if ( itemPos.x() >= offset.x() && itemPos.x() <= ( offset.x() + frameSize.width() )
251  && itemPos.y() >= offset.y() && itemPos.y() <= ( offset.y() + frameSize.height() ) )
252  {
253  return MoveFramePosition;
254  }
255  return NoAction;
256 }
257 
259 {
260  switch ( moveAction )
261  {
262  case NoAction:
263  return Qt::ArrowCursor;
264  case MoveMapPosition:
265  case MoveFramePosition:
266  return Qt::SizeAllCursor;
267  case ResizeFrameUp:
268  case ResizeFrameDown:
269  return Qt::SizeVerCursor;
270  case ResizeFrameLeft:
271  case ResizeFrameRight:
272  return Qt::SizeHorCursor;
273  case ResizeFrameLeftUp:
275  return Qt::SizeFDiagCursor;
276  case ResizeFrameRightUp:
277  case ResizeFrameLeftDown:
278  return Qt::SizeBDiagCursor;
279  default:
280  return Qt::ArrowCursor;
281  }
282 }
283 
284 double QgsMapCanvasAnnotationItem::scaledSymbolSize() const
285 {
286  if ( !mAnnotation || !mAnnotation->markerSymbol() )
287  {
288  return 0.0;
289  }
290 
291  if ( !mMapCanvas )
292  {
293  return mAnnotation->markerSymbol()->size();
294  }
295 
296  double dpmm = mMapCanvas->logicalDpiX() / 25.4;
297  return dpmm * mAnnotation->markerSymbol()->size();
298 }
299 
300 void QgsMapCanvasAnnotationItem::paint( QPainter *painter )
301 {
302  if ( !mAnnotation || !mAnnotation->isVisible() )
303  return;
304 
307 
308  if ( mAnnotation )
309  mAnnotation->render( rc );
310 
311  if ( isSelected() )
312  {
313  drawSelectionBoxes( painter );
314  }
315 }
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:516
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:109
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:1597
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:390
QgsRenderContext::setFlag
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Definition: qgsrendercontext.cpp:152
QgsAnnotation::render
void render(QgsRenderContext &context) const
Renders the annotation to a target render context.
Definition: qgsannotation.cpp:133
qgssymbollayerutils.h
qgsfeatureiterator.h
QgsMapCanvas
Definition: qgsmapcanvas.h:83
qgsmapcanvasannotationitem.h
QgsMapCanvasAnnotationItem::cursorShapeForAction
Qt::CursorShape cursorShapeForAction(MouseMoveAction moveAction) const
Returns matching cursor shape for a mouse move action.
Definition: qgsmapcanvasannotationitem.cpp:258
QgsRenderContext
Definition: qgsrendercontext.h:57
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
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:300
QgsMapCanvasAnnotationItem::MoveFramePosition
@ MoveFramePosition
Moving position of frame relative to annotation.
Definition: qgsmapcanvasannotationitem.h:59
QgsRectangle
Definition: qgsrectangle.h:41
QgsAnnotation::mapLayer
QgsMapLayer * mapLayer() const
Returns the map layer associated with the annotation.
Definition: qgsannotation.h:286
QgsFeatureRequest
Definition: qgsfeaturerequest.h:75
QgsCsException
Definition: qgsexception.h:65
QgsAnnotation
Abstract base class for annotation items which are drawn over a map.
Definition: qgsannotation.h:49
QgsMapCanvasItem
Definition: qgsmapcanvasitem.h:33
QgsMapCanvasAnnotationItem::MouseMoveAction
MouseMoveAction
Mouse actions for interacting with item.
Definition: qgsmapcanvasannotationitem.h:55
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:180
qgsvectorlayer.h
QgsPointXY
Definition: qgspointxy.h:43
QgsMapSettings::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
Definition: qgsmapsettings.cpp:317
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:663
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:193
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:373
QgsMapCanvasAnnotationItem::updatePosition
void updatePosition() override
called on changed extent or resize event to update position of the item
Definition: qgsmapcanvasannotationitem.cpp:56
QgsVectorLayer
Definition: qgsvectorlayer.h:385
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:111
QgsMapCanvasAnnotationItem::ResizeFrameRight
@ ResizeFrameRight
Resize frame right.
Definition: qgsmapcanvasannotationitem.h:63
QgsPointXY::x
double x
Definition: qgspointxy.h:47
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:215
QgsRenderContext::Antialiasing
@ Antialiasing
Use antialiasing while drawing.
Definition: qgsrendercontext.h:78
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:281
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
Definition: qgsfeature.h:55
QgsSymbolLayerUtils::estimateMaxSymbolBleed
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
Definition: qgssymbollayerutils.cpp:820
QgsMapCanvasAnnotationItem::ResizeFrameRightDown
@ ResizeFrameRightDown
Resize frame right down.
Definition: qgsmapcanvasannotationitem.h:67
QgsCoordinateTransform
Definition: qgscoordinatetransform.h:52
QgsFeatureIterator
Definition: qgsfeatureiterator.h:263
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