42#include "moc_qgsmaptoolmodifyannotation.cpp"
44using namespace Qt::StringLiterals;
47class QgsAnnotationItemNodesSpatialIndex :
public RTree<int, float, 2, float>
50 void insert(
int index,
const QgsRectangle &bounds )
52 std::array<float, 4> scaledBounds = scaleBounds( bounds );
53 const float aMin[2] { scaledBounds[0], scaledBounds[1] };
54 const float aMax[2] { scaledBounds[2], scaledBounds[3] };
55 this->Insert( aMin, aMax, index );
64 void remove(
int index,
const QgsRectangle &bounds )
66 std::array<float, 4> scaledBounds = scaleBounds( bounds );
67 const float aMin[2] { scaledBounds[0], scaledBounds[1] };
68 const float aMax[2] { scaledBounds[2], scaledBounds[3] };
69 this->Remove( aMin, aMax, index );
77 bool intersects(
const QgsRectangle &bounds,
const std::function<
bool(
int index )> &callback )
const
79 std::array<float, 4> scaledBounds = scaleBounds( bounds );
80 const float aMin[2] { scaledBounds[0], scaledBounds[1] };
81 const float aMax[2] { scaledBounds[2], scaledBounds[3] };
82 this->Search( aMin, aMax, callback );
87 std::array<float, 4> scaleBounds(
const QgsRectangle &bounds )
const
89 return {
static_cast<float>( bounds.
xMinimum() ),
static_cast<float>( bounds.
yMinimum() ),
static_cast<float>( bounds.
xMaximum() ),
static_cast<float>( bounds.
yMaximum() ) };
97 const QgsPointXY fixedPixel = mapToPixel->
transform( fixedMapPoint );
98 const QgsPointXY cursorPixel = mapToPixel->
transform( cursorMapPoint );
102 unrotate.rotate( -angle );
103 const QPointF diagonal = unrotate.map( QPointF( cursorPixel.
x() - fixedPixel.
x(), cursorPixel.
y() - fixedPixel.
y() ) );
104 const double widthPixels = std::fabs( diagonal.x() );
105 const double heightPixels = std::fabs( diagonal.y() );
106 const QPointF centerPixel( ( fixedPixel.
x() + cursorPixel.
x() ) / 2.0, ( fixedPixel.
y() + cursorPixel.
y() ) / 2.0 );
111QgsPointXY QgsMapToolModifyAnnotation::oppositeVertexMapPoint(
const QList<QgsAnnotationItemNode> &nodes,
int draggedVertex,
bool &found )
114 const int fixedVertex = ( draggedVertex + 2 ) % 4;
115 for (
const QgsAnnotationItemNode &node : nodes )
117 if ( node.id().part == 0 && node.id().vertex == fixedVertex )
128 const int draggedVertex = mTargetNode.id().vertex;
133 bool foundFixed =
false;
134 const QgsPointXY fixedMapPoint = oppositeVertexMapPoint( mHoveredItemNodes, draggedVertex, foundFixed );
138 const QgsRectangle newMapBounds = reconstructRotatedResizeBounds(
canvas()->getCoordinateTransform(), angle, fixedMapPoint, cursorMapPoint );
143 return newLayerBounds;
167 mLastHoverPoint =
event->originalPixelPoint();
171 const QgsPointXY mapPoint =
event->mapPoint();
178 switch ( mCurrentAction )
180 case Action::NoAction:
182 setHoveredItemFromPoint( mapPoint );
186 case Action::MoveItem:
193 operation( mSelectedItemId, delta.
x(), delta.
y(), event->
pixelPoint().x() - mMoveStartPointPixels.x(), event->
pixelPoint().y() - mMoveStartPointPixels.y() );
194 std::unique_ptr<QgsAnnotationItemEditOperationTransientResults> operationResults( item->transientEditResultsV2( &operation, context ) );
195 if ( operationResults )
198 const double scaleFactor =
canvas()->fontMetrics().xHeight() * .2;
199 mTemporaryRubberBand->setWidth( scaleFactor );
200 mTemporaryRubberBand->setToGeometry( operationResults->representativeGeometry(),
layer->crs() );
204 mTemporaryRubberBand.reset();
210 case Action::MoveNode:
214 bool previewDone =
false;
218 if (
const std::optional<QgsRectangle> newLayerBounds = rotatedResizeLayerBounds( rectItem,
layer, event->
mapPoint() ) )
222 const double scaleFactor =
canvas()->fontMetrics().xHeight() * .2;
223 mTemporaryRubberBand->setWidth( scaleFactor );
224 mTemporaryRubberBand->setToGeometry( preview,
layer->crs() );
237 event->
pixelPoint().x() - mMoveStartPointPixels.x(),
238 event->
pixelPoint().y() - mMoveStartPointPixels.y()
240 std::unique_ptr<QgsAnnotationItemEditOperationTransientResults> operationResults( item->transientEditResultsV2( &operation, context ) );
241 if ( operationResults )
244 const double scaleFactor =
canvas()->fontMetrics().xHeight() * .2;
245 mTemporaryRubberBand->setWidth( scaleFactor );
246 mTemporaryRubberBand->setToGeometry( operationResults->representativeGeometry(),
layer->crs() );
250 mTemporaryRubberBand.reset();
267 switch ( mCurrentAction )
269 case Action::NoAction:
271 if ( event->button() != Qt::LeftButton )
274 if ( mHoveredItemId.isEmpty() || !mHoverRubberBand )
278 else if ( mHoveredItemId == mSelectedItemId && mHoveredItemLayerId == mSelectedItemLayerId )
283 const QgsPointXY mapPoint =
event->mapPoint();
288 double currentNodeDistance = std::numeric_limits<double>::max();
289 mHoveredItemNodesSpatialIndex->intersects( searchRect, [&hoveredNode, ¤tNodeDistance, &mapPoint,
this](
int index ) ->
bool {
291 const double nodeDistance = thisNode.
point().
sqrDist( mapPoint );
292 if ( nodeDistance < currentNodeDistance )
294 hoveredNode = thisNode;
295 currentNodeDistance = nodeDistance;
300 mMoveStartPointCanvasCrs = mapPoint;
301 mMoveStartPointPixels =
event->pixelPoint();
303 if ( mHoverRubberBand )
304 mHoverRubberBand->hide();
305 if ( mSelectedRubberBand )
306 mSelectedRubberBand->hide();
310 mCurrentAction = Action::MoveItem;
314 mCurrentAction = Action::MoveNode;
315 mTargetNode = hoveredNode;
322 mSelectedItemId = mHoveredItemId;
323 mSelectedItemLayerId = mHoveredItemLayerId;
324 mSelectedItemBounds = mHoveredItemBounds;
326 if ( !mSelectedRubberBand )
327 createSelectedItemBand();
329 mSelectedRubberBand->copyPointsFrom( mHoverRubberBand );
330 mSelectedRubberBand->show();
339 case Action::MoveItem:
341 if ( event->button() == Qt::RightButton )
343 mCurrentAction = Action::NoAction;
344 mTemporaryRubberBand.reset();
345 if ( mSelectedRubberBand )
347 mSelectedRubberBand->setTranslationOffset( 0, 0 );
348 mSelectedRubberBand->show();
350 mHoveredItemNodeRubberBands.clear();
353 else if ( event->button() == Qt::LeftButton )
361 operation( mSelectedItemId, delta.
x(), delta.
y(), event->
pixelPoint().x() - mMoveStartPointPixels.x(), event->
pixelPoint().y() - mMoveStartPointPixels.y() );
362 switch (
layer->applyEditV2( &operation, context ) )
366 mRefreshSelectedItemAfterRedraw =
true;
374 mTemporaryRubberBand.reset();
375 mCurrentAction = Action::NoAction;
381 case Action::MoveNode:
383 if ( event->button() == Qt::RightButton )
385 mCurrentAction = Action::NoAction;
386 mTemporaryRubberBand.reset();
387 mHoveredItemNodeRubberBands.clear();
388 mTemporaryRubberBand.reset();
391 else if ( event->button() == Qt::LeftButton )
395 bool handled =
false;
400 if (
const std::optional<QgsRectangle> newLayerBounds = rotatedResizeLayerBounds( rectItem,
layer, event->
mapPoint() ) )
407 mRefreshSelectedItemAfterRedraw =
true;
420 event->
pixelPoint().x() - mMoveStartPointPixels.x(),
421 event->
pixelPoint().y() - mMoveStartPointPixels.y()
423 switch (
layer->applyEditV2( &operation, context ) )
427 mRefreshSelectedItemAfterRedraw =
true;
437 mTemporaryRubberBand.reset();
438 mHoveredItemNodeRubberBands.clear();
439 mHoveredItemNodes.clear();
440 mTemporaryRubberBand.reset();
441 mCurrentAction = Action::NoAction;
451 switch ( mCurrentAction )
453 case Action::NoAction:
454 case Action::MoveItem:
456 if ( event->button() != Qt::LeftButton )
459 mCurrentAction = Action::NoAction;
460 if ( mHoveredItemId == mSelectedItemId && mHoveredItemLayerId == mSelectedItemLayerId )
471 switch (
layer->applyEditV2( &operation, context ) )
475 mRefreshSelectedItemAfterRedraw =
true;
487 mSelectedItemId = mHoveredItemId;
488 mSelectedItemLayerId = mHoveredItemLayerId;
489 mSelectedItemBounds = mHoveredItemBounds;
491 if ( !mSelectedRubberBand )
492 createSelectedItemBand();
494 mSelectedRubberBand->copyPointsFrom( mHoverRubberBand );
495 mSelectedRubberBand->show();
504 case Action::MoveNode:
516 switch ( mCurrentAction )
518 case Action::NoAction:
520 if ( event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete )
522 if ( !
layer || mSelectedItemId.isEmpty() )
525 layer->removeItem( mSelectedItemId );
530 else if ( event->key() == Qt::Key_Left || event->key() == Qt::Key_Right || event->key() == Qt::Key_Up || event->key() == Qt::Key_Down )
535 const QSizeF deltaLayerCoordinates = deltaForKeyEvent(
layer, mSelectedRubberBand->asGeometry().centroid().asPoint(), event );
538 switch (
layer->applyEditV2( &operation, context ) )
542 mRefreshSelectedItemAfterRedraw =
true;
553 case Action::MoveNode:
555 if ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace )
560 switch (
layer->applyEditV2( &operation, context ) )
564 mRefreshSelectedItemAfterRedraw =
true;
574 mTemporaryRubberBand.reset();
575 mHoveredItemNodeRubberBands.clear();
576 mHoveredItemNodes.clear();
577 mTemporaryRubberBand.reset();
578 mCurrentAction = Action::NoAction;
586 case Action::MoveItem:
589 if ( event->key() == Qt::Key_Escape )
591 mCurrentAction = Action::NoAction;
592 mTemporaryRubberBand.reset();
593 if ( mSelectedRubberBand )
595 mSelectedRubberBand->setTranslationOffset( 0, 0 );
596 mSelectedRubberBand->show();
598 mHoveredItemNodeRubberBands.clear();
607void QgsMapToolModifyAnnotation::onCanvasRefreshed()
609 bool needsSelectedItemRefresh = mRefreshSelectedItemAfterRedraw;
614 needsSelectedItemRefresh =
true;
618 if ( needsSelectedItemRefresh )
621 if ( !renderedItemResults )
626 const QList<QgsRenderedItemDetails *> items = renderedItemResults->
renderedItems();
627 auto it = std::find_if( items.begin(), items.end(), [
this](
const QgsRenderedItemDetails *item ) {
628 if ( const QgsRenderedAnnotationItemDetails *annotationItem = dynamic_cast<const QgsRenderedAnnotationItemDetails *>( item ) )
630 if ( annotationItem->itemId() == mSelectedItemId && annotationItem->layerId() == mSelectedItemLayerId )
635 if ( it != items.end() )
637 const QgsRectangle itemBounds = ( *it )->boundingBox();
639 setHoveredItem(
dynamic_cast<const QgsRenderedAnnotationItemDetails *
>( *it ), itemBounds );
640 if ( !mSelectedRubberBand )
641 createSelectedItemBand();
643 mSelectedRubberBand->copyPointsFrom( mHoverRubberBand );
644 mSelectedRubberBand->show();
645 mSelectedItemBounds = mHoveredItemBounds;
651 const QgsPointXY mapPoint = canvas()->mapSettings().mapToPixel().toMapCoordinates( mLastHoverPoint );
652 setHoveredItemFromPoint( mapPoint );
654 mRefreshSelectedItemAfterRedraw =
false;
659 mHoveredItemNodeRubberBands.clear();
660 if ( mHoveredNodeRubberBand )
661 mHoveredNodeRubberBand->hide();
662 mHoveredItemId = item->
itemId();
663 mHoveredItemLayerId = item->
layerId();
664 mHoveredItemBounds = itemMapBounds;
665 if ( !mHoverRubberBand )
668 mHoverRubberBand->show();
671 if ( !annotationItem )
675 mHoverRubberBand->addPoint( QgsPointXY( itemMapBounds.
xMinimum(), itemMapBounds.
yMinimum() ) );
676 mHoverRubberBand->addPoint( QgsPointXY( itemMapBounds.
xMaximum(), itemMapBounds.
yMinimum() ) );
677 mHoverRubberBand->addPoint( QgsPointXY( itemMapBounds.
xMaximum(), itemMapBounds.
yMaximum() ) );
678 mHoverRubberBand->addPoint( QgsPointXY( itemMapBounds.
xMinimum(), itemMapBounds.
yMaximum() ) );
679 mHoverRubberBand->addPoint( QgsPointXY( itemMapBounds.
xMinimum(), itemMapBounds.
yMinimum() ) );
684 const QgsCoordinateTransform layerToMapTransform = QgsCoordinateTransform(
layer->crs(),
canvas()->mapSettings().destinationCrs(),
canvas()->mapSettings().transformContext() );
689 const QgsAnnotationRectItem *rectItem =
dynamic_cast<const QgsAnnotationRectItem *
>( annotationItem );
691 const double frameRotation = rectItem ? rectItem->
appliedRotation( mapRotation ) - mapRotation : 0;
693 bool rotated = rectItem && !
qgsDoubleNear( frameRotation, 0 );
695 QgsPointXY centerMap;
702 catch ( QgsCsException & )
705 QgsDebugError( u
"Error transforming annotation item center"_s );
710 QTransform rotationTransform;
713 const QgsPointXY centerPixel = mapToPixel->
transform( centerMap );
714 rotationTransform.translate( centerPixel.
x(), centerPixel.
y() );
715 rotationTransform.rotate( frameRotation );
716 rotationTransform.translate( -centerPixel.
x(), -centerPixel.
y() );
719 auto rotateMapPoint = [&](
const QgsPointXY &p ) -> QgsPointXY {
722 const QgsPointXY pPixel = mapToPixel->
transform( p );
723 const QPointF r = rotationTransform.map( QPointF( pPixel.
x(), pPixel.
y() ) );
727 const double scaleFactor =
canvas()->fontMetrics().xHeight() * .2;
729 QgsAnnotationItemEditContext context;
733 const QList<QgsAnnotationItemNode> itemNodes = annotationItem->
nodesV2( context );
737 vertexNodeBand->
setWidth( scaleFactor );
739 vertexNodeBand->
setColor( QColor( 200, 0, 120, 255 ) );
742 calloutNodeBand->
setWidth( scaleFactor );
744 calloutNodeBand->
setColor( QColor( 120, 200, 0, 255 ) );
749 mHoveredItemNodesSpatialIndex = std::make_unique<QgsAnnotationItemNodesSpatialIndex>();
751 mHoveredItemNodes.clear();
752 mHoveredItemNodes.reserve( itemNodes.size() );
753 QVector<QgsPointXY> vertexFramePoints;
754 for (
const QgsAnnotationItemNode &node : itemNodes )
756 QgsPointXY nodeMapPoint;
759 nodeMapPoint = layerToMapTransform.
transform( node.point() );
761 catch ( QgsCsException & )
766 switch ( node.type() )
770 nodeMapPoint = rotateMapPoint( nodeMapPoint );
771 vertexNodeBand->
addPoint( nodeMapPoint );
772 vertexFramePoints.append( nodeMapPoint );
776 calloutNodeBand->
addPoint( nodeMapPoint );
780 mHoveredItemNodesSpatialIndex->insert( index, QgsRectangle( nodeMapPoint.
x(), nodeMapPoint.
y(), nodeMapPoint.
x(), nodeMapPoint.
y() ) );
782 QgsAnnotationItemNode transformedNode = node;
783 transformedNode.
setPoint( nodeMapPoint );
784 mHoveredItemNodes.append( transformedNode );
789 mHoveredItemNodeRubberBands.emplace_back( vertexNodeBand );
790 mHoveredItemNodeRubberBands.emplace_back( calloutNodeBand );
797 for (
const QgsPointXY &framePoint : vertexFramePoints )
798 mHoverRubberBand->addPoint( framePoint );
799 mHoverRubberBand->addPoint( vertexFramePoints.constFirst() );
803 mHoverRubberBand->addPoint( QgsPointXY( itemMapBounds.
xMinimum(), itemMapBounds.
yMinimum() ) );
804 mHoverRubberBand->addPoint( QgsPointXY( itemMapBounds.
xMaximum(), itemMapBounds.
yMinimum() ) );
805 mHoverRubberBand->addPoint( QgsPointXY( itemMapBounds.
xMaximum(), itemMapBounds.
yMaximum() ) );
806 mHoverRubberBand->addPoint( QgsPointXY( itemMapBounds.
xMinimum(), itemMapBounds.
yMaximum() ) );
807 mHoverRubberBand->addPoint( QgsPointXY( itemMapBounds.
xMinimum(), itemMapBounds.
yMinimum() ) );
811QSizeF QgsMapToolModifyAnnotation::deltaForKeyEvent(
QgsAnnotationLayer *layer,
const QgsPointXY &originalCanvasPoint, QKeyEvent *event )
813 const double canvasDpi =
canvas()->window()->windowHandle()->screen()->physicalDotsPerInch();
816 double incrementPixels = 0.0;
817 if ( event->modifiers() & Qt::ShiftModifier )
820 incrementPixels = 20.0 / 25.4 * canvasDpi;
822 else if ( event->modifiers() & Qt::AltModifier )
830 incrementPixels = 5.0 / 25.4 * canvasDpi;
833 double deltaXPixels = 0;
834 double deltaYPixels = 0;
835 switch ( event->key() )
838 deltaXPixels = -incrementPixels;
841 deltaXPixels = incrementPixels;
844 deltaYPixels = -incrementPixels;
847 deltaYPixels = incrementPixels;
856 const QgsPointXY afterMoveCanvasPoint( originalCanvasPoint.
x() + deltaXPixels, originalCanvasPoint.
y() + deltaYPixels );
860 return QSizeF( afterMoveLayerPoint.
x() - beforeMoveLayerPoint.
x(), afterMoveLayerPoint.
y() - beforeMoveLayerPoint.
y() );
863void QgsMapToolModifyAnnotation::setHoveredItemFromPoint(
const QgsPointXY &mapPoint )
865 QgsRectangle searchRect = QgsRectangle( mapPoint.
x(), mapPoint.
y(), mapPoint.
x(), mapPoint.
y() );
869 if ( !renderedItemResults )
883 QgsRectangle itemBounds;
884 const QgsRenderedAnnotationItemDetails *closestItem =
findClosestItemToPoint( mapPoint, items, itemBounds );
891 if ( closestItem->
itemId() != mHoveredItemId || closestItem->
layerId() != mHoveredItemLayerId )
893 setHoveredItem( closestItem, itemBounds );
897 QgsAnnotationItemNode hoveredNode;
898 if ( closestItem->
itemId() == mSelectedItemId && closestItem->
layerId() == mSelectedItemLayerId )
900 double currentNodeDistance = std::numeric_limits<double>::max();
901 mHoveredItemNodesSpatialIndex->intersects( searchRect, [&hoveredNode, ¤tNodeDistance, &mapPoint,
this](
int index ) ->
bool {
902 if ( index >= mHoveredItemNodes.size() )
905 const QgsAnnotationItemNode &thisNode = mHoveredItemNodes.at( index );
906 const double nodeDistance = thisNode.
point().
sqrDist( mapPoint );
907 if ( nodeDistance < currentNodeDistance )
909 hoveredNode = thisNode;
910 currentNodeDistance = nodeDistance;
919 if ( mHoveredNodeRubberBand )
920 mHoveredNodeRubberBand->hide();
921 setCursor( mHoveredItemId == mSelectedItemId && mHoveredItemLayerId == mSelectedItemLayerId ? Qt::OpenHandCursor : Qt::ArrowCursor );
925 if ( !mHoveredNodeRubberBand )
926 createHoveredNodeBand();
929 mHoveredNodeRubberBand->addPoint( hoveredNode.
point() );
930 mHoveredNodeRubberBand->show();
936void QgsMapToolModifyAnnotation::clearHoveredItem()
938 if ( mHoverRubberBand )
939 mHoverRubberBand->hide();
940 if ( mHoveredNodeRubberBand )
941 mHoveredNodeRubberBand->hide();
943 mHoveredItemId.clear();
944 mHoveredItemLayerId.clear();
945 mHoveredItemNodeRubberBands.clear();
946 mHoveredItemNodesSpatialIndex.reset();
951void QgsMapToolModifyAnnotation::clearSelectedItem()
953 if ( mSelectedRubberBand )
954 mSelectedRubberBand->hide();
956 const bool hadSelection = !mSelectedItemId.isEmpty();
957 mSelectedItemId.clear();
958 mSelectedItemLayerId.clear();
963void QgsMapToolModifyAnnotation::createHoverBand()
965 const double scaleFactor =
canvas()->fontMetrics().xHeight() * .2;
968 mHoverRubberBand->setWidth( scaleFactor );
969 mHoverRubberBand->setSecondaryStrokeColor( QColor( 255, 255, 255, 100 ) );
970 mHoverRubberBand->setColor( QColor( 100, 100, 100, 155 ) );
973void QgsMapToolModifyAnnotation::createHoveredNodeBand()
975 const double scaleFactor =
canvas()->fontMetrics().xHeight() * .2;
979 mHoveredNodeRubberBand->setWidth( scaleFactor );
980 mHoveredNodeRubberBand->setIconSize( scaleFactor * 5 );
981 mHoveredNodeRubberBand->setColor( QColor( 200, 0, 120, 255 ) );
984void QgsMapToolModifyAnnotation::createSelectedItemBand()
986 const double scaleFactor =
canvas()->fontMetrics().xHeight() * .2;
989 mSelectedRubberBand->setWidth( scaleFactor );
990 mSelectedRubberBand->setSecondaryStrokeColor( QColor( 255, 255, 255, 100 ) );
991 mSelectedRubberBand->setColor( QColor( 50, 50, 50, 200 ) );
@ VertexHandle
Node is a handle for manipulating vertices.
@ CalloutHandle
Node is a handle for manipulating callouts.
@ ScaleDependentBoundingBox
Item's bounding box will vary depending on map scale.
@ Invalid
Operation has invalid parameters for the item, no change occurred.
@ Success
Item was modified successfully.
@ ItemCleared
The operation results in the item being cleared, and the item should be removed from the layer as a r...
@ Box
A box is used to highlight points (□).
@ BoxFilled
A filled box is used to highlight points (■).
@ CrossX
A cross is used to highlight points (x).
@ SpatialBounds
Item is rendered inside fixed spatial bounds, and size will depend on map scale.
Encapsulates the context for an annotation item edit operation.
void setCurrentItemBounds(const QgsRectangle &bounds)
Sets the current rendered bounds of the item, in the annotation layer's CRS.
QgsRenderContext renderContext() const
Returns the render context associated with the edit operation.
void setRenderContext(const QgsRenderContext &context)
Sets the render context associated with the edit operation.
Annotation item edit operation consisting of adding a node.
Annotation item edit operation consisting of deleting a node.
Annotation item edit operation consisting of moving a node.
Annotation item edit operation consisting of setting the bounds of an item.
Annotation item edit operation consisting of translating (moving) an item.
Contains information about a node used for editing an annotation item.
void setPoint(QgsPointXY point)
Sets the node's position, in geographic coordinates.
QgsPointXY point() const
Returns the node's position, in geographic coordinates.
Qt::CursorShape cursor() const
Returns the mouse cursor shape to use when hovering the node.
Abstract base class for annotation items which are drawn with QgsAnnotationLayers.
virtual QList< QgsAnnotationItemNode > nodesV2(const QgsAnnotationItemEditContext &context) const
Returns the nodes for the item, used for editing the item.
Represents a map layer containing a set of georeferenced annotations, e.g.
Abstract base class for annotation items which render annotations in a rectangular shape.
QgsGeometry rotatedBoundsGeometry(const QgsRectangle &layerBounds, const QgsRenderContext &renderContext) const
Returns the polygon geometry (in layer coordinates) for the item occupying the given layerBounds,...
static QgsRectangle boundsFromPixelRect(const QgsMapToPixel *mapToPixel, const QPointF ¢erPixel, double widthPixels, double heightPixels)
Returns the axis-aligned bounds, in map coordinates, of a rectangle centered on centerPixel with size...
double appliedRotation(double mapRotation) const
Returns the effective on-screen rotation of the item, in degrees clockwise.
QgsRectangle bounds() const
Returns the bounds of the item.
Qgis::AnnotationPlacementMode placementMode() const
Returns the placement mode for the item.
A geometry is the spatial representation of a feature.
Map canvas is a class for displaying all GIS data types on a canvas.
const QgsRenderedItemResults * renderedItemResults(bool allowOutdatedResults=true) const
Gets access to the rendered item results (may be nullptr), which includes the results of rendering an...
void mapCanvasRefreshed()
Emitted when canvas finished a refresh request.
const QgsMapToPixel * getCoordinateTransform()
Gets the current coordinate transform.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
A mouse event which is the result of a user interaction with a QgsMapCanvas.
QgsPointXY mapPoint() const
mapPoint returns the point in coordinates
QPoint pixelPoint() const
The snapped mouse cursor in pixel coordinates.
QgsPointLocator::Match mapPointMatch() const
Returns the matching data from the most recently snapped point.
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
Perform transforms between map coordinates and device coordinates.
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
bool isEmpty() const
Returns true if the geometry is empty.
Point geometry type, with support for z-dimension and m-values.
static QgsProject * instance()
Returns the QgsProject singleton instance.
void setDirty(bool b=true)
Flag the project as dirty (modified).
A rectangle specified with double values.
void grow(double delta)
Grows the rectangle in place by the specified amount.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
Contains information about a rendered annotation item.
QString itemId() const
Returns the item ID of the associated annotation item.
QString layerId() const
Returns the layer ID of the associated map layer.
QList< const QgsRenderedAnnotationItemDetails * > renderedAnnotationItemsInBounds(const QgsRectangle &bounds) const
Returns a list with details of the rendered annotation items within the specified bounds.
QList< QgsRenderedItemDetails * > renderedItems() const
Returns a list of all rendered items.
void setIconSize(double iconSize)
Sets the size of the point icons.
void setIcon(Qgis::RubberBandIconType icon)
Sets the icon type to highlight point geometries.
void setWidth(double width)
Sets the width of the line.
void setSecondaryStrokeColor(const QColor &color)
Sets a secondary stroke color for the rubberband which will be drawn under the main stroke color.
void setColor(const QColor &color)
Sets the color for the rubberband.
void addPoint(const QgsPointXY &p, bool doUpdate=true, int geometryIndex=0, int ringIndex=0)
Adds a vertex to the rubberband and update canvas.
Shows a snapping marker on map canvas for the current snapping match.
Represent a 2-dimensional vector.
double y() const
Returns the vector's y-component.
double x() const
Returns the vector's x-component.
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).
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
#define QgsDebugError(str)
constexpr QObjectUniquePtr< Tp > make_qobject_unique(Args &&...args)
Create an object owned by a QObjectUniquePtr.