File indexing completed on 2024-05-05 03:50:38

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2009 Andrew Manson <g.real.ate@gmail.com>
0004 // SPDX-FileCopyrightText: 2013 Thibaut Gridel <tgridel@free.fr>
0005 // SPDX-FileCopyrightText: 2014 Calin Cruceru <crucerucalincristian@gmail.com>
0006 //
0007 
0008 #ifndef AREAANNOTATION_H
0009 #define AREAANNOTATION_H
0010 
0011 #include <QPointer>
0012 
0013 #include "SceneGraphicsItem.h"
0014 #include "GeoDataCoordinates.h"
0015 
0016 
0017 namespace Marble
0018 {
0019 
0020 class PolylineNode;
0021 class MergingPolygonNodesAnimation;
0022 
0023 /**
0024  * @brief The AreaAnnotation class controls everything related to Polygons Editing Mode.
0025  * It includes polygons actions implementation and, at the same time, deals with painting
0026  * polygons on the map according to user's preference or to some particular states.
0027  */
0028 class AreaAnnotation : public SceneGraphicsItem
0029 {
0030     friend class MergingPolygonNodesAnimation;
0031 
0032 public:
0033     explicit AreaAnnotation( GeoDataPlacemark *placemark );
0034 
0035     ~AreaAnnotation() override;
0036 
0037     /**
0038      * @brief Paints the nodes on the screen and updates the regions which correspond
0039      * to each node using the given GeoPainter.
0040      */
0041     void paint( GeoPainter *painter, const ViewportParams *viewport, const QString &layer, int tileZoomLevel ) override;
0042 
0043     /**
0044      * @brief Returns true if the given QPoint is contained by the current polygon. Note
0045      * that the return value depends on the state (e.g. in the AddingPolylineNodes state a
0046      * point is considered to be contained by the polygon if the virtual nodes or the
0047      * polygon's interior contain it, while in the Editing state, it is contained by the
0048      * polygon if either polygon's interior, the outer nodes or the inner nodes contain
0049      * it).
0050      */
0051     bool containsPoint( const QPoint &point ) const override;
0052 
0053     /**
0054      * @brief It is used so far to remove the hover effect while being in the
0055      * AddingPolylineNodes state (@see SceneGraphicsItem::dealWithItemChange documentation).
0056      */
0057     void dealWithItemChange( const SceneGraphicsItem *other ) override;
0058 
0059     /**
0060      * @brief Moves the whole polygon to the destination coordinates.
0061      */
0062     void move( const GeoDataCoordinates &source, const GeoDataCoordinates &destination ) override;
0063 
0064     /**
0065      * @brief Changes the busy state of the object according to @p enabled. It is mostly
0066      * used by Annotate Plugin to not send events to this object anymore but is different than
0067      * the focus property (you can have a focused polygon which does not accept events because
0068      * is busy).
0069      *
0070      * @param enabled the busy state of the object
0071      */
0072     void setBusy( bool enabled );
0073 
0074     /**
0075      * @brief Returns whether the annotation is 'busy' or not - this usually means that something
0076      * is being performed and it does not accept events anymore.
0077      */
0078     bool isBusy() const;
0079 
0080     /**
0081      * @brief Iterates through all nodes which form the polygon's outer boundary as well
0082      * as all its inner boundaries and sets the IsSelected flag to false.
0083      */
0084     void deselectAllNodes();
0085 
0086     /**
0087      * @brief Iterates through all nodes which form the polygon's outer boundary as well
0088      * as all its inner boundaries and deletes the selected ones.
0089      */
0090     void deleteAllSelectedNodes();
0091 
0092     /**
0093      * @brief Deletes the last clicked node while being in the Editing state.
0094      */
0095     void deleteClickedNode();
0096 
0097     /**
0098      * @brief If the last clicked node is selected, set its IsSelected flag to false and
0099      * vice versa.
0100      */
0101     void changeClickedNodeSelection();
0102 
0103     /**
0104      * @brief Tests if there are any selected nodes.
0105      */
0106     bool hasNodesSelected() const;
0107 
0108     /**
0109      * @brief Tests if the last clicked node is selected.
0110      */
0111     bool clickedNodeIsSelected() const;
0112 
0113     /**
0114      * @brief Returns the animation to be handled by a QObject which can connect signals
0115      * and slots.
0116      */
0117     QPointer<MergingPolygonNodesAnimation> animation();
0118 
0119     /**
0120      * @brief Provides information for downcasting a SceneGraphicsItem.
0121      */
0122     const char *graphicType() const override;
0123 
0124 protected:
0125     /**
0126      * @brief Protected methods which handle mouse events and are called by
0127      * SceneGraphicsItem::sceneEvent() (@see Template Method pattern). Each of these
0128      * event handlers are structured according to the state.
0129      */
0130     bool mousePressEvent( QMouseEvent *event ) override;
0131     bool mouseMoveEvent( QMouseEvent *event ) override;
0132     bool mouseReleaseEvent( QMouseEvent *event ) override;
0133 
0134     /**
0135      * @brief Protected method which applies the Polygons modifications when changing
0136      * states.
0137      */
0138     void dealWithStateChange( SceneGraphicsItem::ActionState previousState ) override;
0139 
0140 private:
0141     /**
0142      * @brief Returns true if the Polygon has a valid shape (so far, the only times when
0143      * it could have an invalid shape would be when deleting/merging nodes from its outer
0144      * boundary and it would not contains anymore all the nodes which form its inner
0145      * boundaries).
0146      */
0147     bool isValidPolygon() const;
0148 
0149     /**
0150      * @brief It is called when the ::paint method is called for the first time. It
0151      * initializes the m_outerNodesList by creating the PolylineNodes.
0152      * @see updateRegions() method for more detailed explanation.
0153      */
0154     void setupRegionsLists( GeoPainter *painter );
0155 
0156     /**
0157      * @brief As briefly mentioned above, the PolylineNodes instances are not created at
0158      * each ::paint call, but only at its first call. Every time the ::paint method is
0159      * called after that, each node from the lists of PolylineNodes gets its setRegion()
0160      * method called. We need the GeoPainter for doing this because we have to get the
0161      * ellipse around the GeoDataCoordinates.
0162      */
0163     void updateRegions( GeoPainter *painter );
0164 
0165     /**
0166      * @brief It iterates through all nodes and paints them on the map. It takes into
0167      * consideration the active flags of each PolylineNode.
0168      */
0169     void drawNodes( GeoPainter *painter );
0170 
0171     /**
0172      * @brief The following functions test whether the given @p point is contained by
0173      * each list.
0174      * @return The QPair<int, int> returned by innerNodeContains is extensively used
0175      * within the implementation and has the following interpretation: the node which
0176      * contains the given point is the '.second'h node from the '.first'h inner boundary.
0177      */
0178     int outerNodeContains( const QPoint &point ) const;
0179     QPair<int, int> innerNodeContains( const QPoint &point ) const;
0180     QPair<int, int> virtualNodeContains( const QPoint &point ) const;
0181     int innerBoundsContain( const QPoint &point ) const;
0182     bool polygonContains( const QPoint &point ) const;
0183 
0184     /**
0185      * @brief It is called from processOnMove functions and deals with polygons
0186      * hovering.
0187      */
0188     bool dealWithHovering( QMouseEvent *mouseEvent );
0189 
0190     /**
0191      * @brief Each state has its corresponding event handler, since in each state the
0192      * item may behave differently. These are the event handlers for the Editing state.
0193      */
0194     bool processEditingOnPress( QMouseEvent *mouseEvent );
0195     bool processEditingOnMove( QMouseEvent *mouseEvent );
0196     bool processEditingOnRelease( QMouseEvent *mouseEvent );
0197 
0198     /**
0199      * @brief These are the event handlers for the AddingPolygonHole state.
0200      */
0201     bool processAddingHoleOnPress( QMouseEvent *mouseEvent );
0202     static bool processAddingHoleOnMove(QMouseEvent *mouseEvent);
0203     static bool processAddingHoleOnRelease(QMouseEvent *mouseEvent);
0204 
0205     /**
0206      * @brief These are the event handlers for the MergingPolylineNodes state.
0207      */
0208     bool processMergingOnPress( QMouseEvent *mouseEvent );
0209     bool processMergingOnMove( QMouseEvent *mouseEvent );
0210     static bool processMergingOnRelease(QMouseEvent *mouseEvent);
0211 
0212     /**
0213      * @brief These are the event handlers for the AddingPolylineNodes state.
0214      */
0215     bool processAddingNodesOnPress( QMouseEvent *mouseEvent );
0216     bool processAddingNodesOnMove( QMouseEvent *mouseEvent );
0217     bool processAddingNodesOnRelease( QMouseEvent *mouseEvent );
0218 
0219     /**
0220      * @brief Since they are used in many functions, the size and color of nodes for each
0221      * state are static and have class scope.
0222      */
0223     static const int regularDim;
0224     static const int selectedDim;
0225     static const int mergedDim;
0226     static const int hoveredDim;
0227     static const QColor regularColor;
0228     static const QColor mergedColor;
0229 
0230     const ViewportParams *m_viewport;
0231     bool m_regionsInitialized;
0232     bool m_busy;
0233 
0234     QVector<PolylineNode>            m_outerNodesList;
0235     QVector<PolylineNode>            m_outerVirtualNodes;
0236     QVector< QVector<PolylineNode> > m_innerNodesList;
0237     QVector< QVector<PolylineNode> > m_innerVirtualNodes;
0238     QVector<QRegion>                 m_boundariesList;
0239 
0240     // Used in the Editing state
0241     enum EditingInteractingObject {
0242         InteractingNothing, // e.g. when hovering
0243         InteractingNode,
0244         InteractingPolygon
0245     };
0246     GeoDataCoordinates       m_movedPointCoords;
0247     QPair<int, int>          m_clickedNodeIndexes;
0248     QPair<int, int>          m_hoveredNode;
0249     EditingInteractingObject m_interactingObj;
0250 
0251     // Used in Merging Nodes state
0252     QPair<int, int>    m_firstMergedNode;
0253     QPair<int, int>    m_secondMergedNode;
0254     QPointer<MergingPolygonNodesAnimation> m_animation;
0255 
0256     // Used in Adding Nodes state
0257     QPair<int, int> m_virtualHovered;
0258 
0259     // It can have the following values:
0260     //     -> -2 - means there is no node being adjusted;
0261     //     -> -1 - means the node which is being adjusted is a node from polygon's
0262     //             outer boundary (more exactly, the last; see below);
0263     //     -> i  - (i >= 0) means the node which is being adjusted is a node from
0264     //             the i'th inner boundary (more exactly, the last one; see below).
0265     // Due to the way the node appending is done (by rotating the vector which
0266     // contains the coordinates), we can be sure that the node we want to adjust
0267     // is every time the last one.
0268     int             m_adjustedNode;
0269 };
0270 
0271 }
0272 
0273 #endif