/** * @RDE_HEADER@ * Rubberband class to define multiple ellipse/circle * $Id$ * $HeadURL$ * $Author$ */ #pragma once #include "rubberband.h" namespace SituationMap { namespace RB { class RubberbandHandle; class RubberbandFrameHandle; class DrawableEllipse; /** @class RubberbandMultiEllipseFeature rubberband_multi_circle_feature.h @brief Implementation of a rubberband to input multi point features, like areals or linears @see Rubberband */ class SITUATIONMAP_EXPORT RubberbandMultiEllipseFeature : public Rubberband { Q_OBJECT public: /** @name Construction & Destruction @{ */ private: friend class RubberbandFactory; friend class RubberbandArrow; friend class RubberbandCorridor; friend class RubberbandPolylineWidth; friend class RubberbandSmoothLine; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Constructor delegation doesn't work with Visual Studio 2013 explicit RubberbandMultiEllipseFeature( SituationMap::Map * map ); explicit RubberbandMultiEllipseFeature( SituationMap::Map * map, bool complexGeometry ); * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /** Construction of RubberbandMultiEllipseFeature in most common cases. The parameter parent is optional. */ explicit RubberbandMultiEllipseFeature(SituationMap::Map *map, QObject *parent = nullptr); /** Construction of RubberbandMultiEllipseFeature in case of controlling complex geometry objects, like splines or multi point symbols. In this case set complexGeometry true. */ explicit RubberbandMultiEllipseFeature(SituationMap::Map *map, bool complexGeometry, QObject *parent = nullptr); public: ~RubberbandMultiEllipseFeature(); /** @} */ bool selectAction(AbstractEventDispatcher *causer, int x, int y) override; bool setCoordinateAction(AbstractEventDispatcher *causer, int x, int y) override; bool moveAction(AbstractEventDispatcher *causer, int x, int y) override; bool movePickedAction(AbstractEventDispatcher *causer, int x, int y) override; void resetAction(AbstractEventDispatcher *causer, int x, int y) override; bool contextMenuAction(AbstractEventDispatcher *causer, int x, int y) override; bool completeStateAction(AbstractEventDispatcher *causer, int x, int y) override; bool deleteAction(AbstractEventDispatcher *causer, int x, int y) override; bool undoAction(AbstractEventDispatcher *causer, int x, int y) override; bool applyAndEndAction(AbstractEventDispatcher *causer, int x, int y) override; /** * @brief If set to true only quadratic rectangles can be created. */ void constrainQuadratic( bool on ); /** @name Setting Constrains @{ */ /** Defines minimum count of verticies that has to be defined by users input to complete the rubberband with apply signal. The default value is 2. */ inline void minimumRadiusCount(unsigned int x) { _minimumPointCount = x+1; } /** Defines maximum count of verticies that can be aceppted by the rubberband. A values of 0 stands for undefined. The default is 0. */ inline void maximumRadiusCount(unsigned int x) { _maximumPointCount = x+1; } /** Defines the maximum length of a segment (distance between to adjaced verticies). A value of 0 stands for no limit is set. The default is 0. */ inline void maximumSegmentLength(qreal x) { _maximumSegmentLength = (x > 0) ? x : 0.0; } inline qreal getMaximumSegmentLength() const { return _maximumSegmentLength; } /** Defines the maximum length of the complete polyline. \c enableClosed must be set to false. A value of 0 stands for no limit is set. The default is 0. */ inline void maximumLength(qreal x) { _maximumLength = (x > 0) ? x : 0.0; } /** @} */ inline qreal getMaximumLength() const { return _maximumLength; } QPointF centerCoordinate(CoordinateSystem cs = CoordinateSystem::Geo) const; /** * @brief radii get vector of radius (QPointF containing radiusX and radius Y in meter) * @return radii */ QVector radii() const; QPointF getBiggestRadius() const; struct RadiusWithContraints { // to be able to supply int, avoid explicit: RadiusWithContraints(double radius = 0.0, double minRadius = 0.0, double maxRadius = 0.0) : m_radius(radius), m_minRadius(minRadius), m_maxRadius(maxRadius) {} double m_radius{0}; double m_minRadius{0}; double m_maxRadius{0}; }; bool setCenterAndRadii(const QPointF ¢er, CoordinateSystem cs, const QVector &radii); // no constraints bool setCenterAndRadii2(const QPointF ¢er, CoordinateSystem cs, const QVector &radiiWithConstraints); void prepareFixedNumberOfRadiiWithConstraints(const QVector &radiiContraints); // get SectorStartEnd QPointF getRotatedPoint(const QPointF §or)const; void enableSector(bool on); bool isSectorEnabled() const; /** * @brief sectorStart in mathematical sense (starts counter-clockwise from 3 o'clock) * @return sectorStart */ QPointF sectorStart() const; qreal sectorStartDegMath() const; // in mathematical sense (starts counter-clockwise from 3 o'clock) /** * @brief sectorEnd in mathematical sense (starts counter-clockwise from 3 o'clock) * @return sectorEnd */ QPointF sectorEnd() const; qreal sectorEndDegMath() const; // in mathematical sense (starts counter-clockwise from 3 o'clock) void setSectorStart(qreal sinPhi, qreal cosPhi); void setSectorEnd(qreal sinPhi, qreal cosPhi); void setSectorAngleFixed(bool on); // true: start and end sectors positon can't be modifed bool isSectorFixedAngeEnabled() const; virtual QVector coordinateVector(CoordinateSystem cs = CoordinateSystem::Geo) const override; virtual QPointF singleCoordinate( unsigned int idx = 0, CoordinateSystem cs = CoordinateSystem::Geo ) const override; virtual void setCoordinateVector(const QVector &, CoordinateSystem cs = CoordinateSystem::Geo) override; signals: /** The signal will be emitted, when the mouse cursor has changed and the rubberband is in construction mode and is accepting new input coordinates. */ void currentCursorPositionChanged(const Point3D &mapCoord); protected: /* Forward declaration of InternalData to hold private member variables. Be careful the base class Rubberband has similary a class for internal data member with name "InternalData". Don't be confused it is not the same. */ struct InternalData; InternalData *_internal; bool _isClosed{false}; unsigned int _minimumRadius = 0; unsigned int _maximumRadius = 0; unsigned int _minimumPointCount{2}; // 2 Punkte == 1 Kreis unsigned int _maximumPointCount{0}; qreal _maximumSegmentLength; qreal _maximumLength; void activateButtons() override; void update() override; void updateFrameHandle(const QPointF &sceneCoordinate); // Unfortunately, RubberbandCoordinate canĀ“t be forwarded, so use sceneCoordinate void getSceneRotation(qreal &sinA, qreal &cosA) const; void updateSectorHandles(); void updateRotationHandle(); QPointF getScenePositionRotationHandle() const; QPointF getSceneOffsetRotationHandle(qreal margin); // some helper methodes bool getRadiusXY(const QPointF &scenePos, qreal &radiusX_out, qreal &radiusY_out); RubberbandHandle *constructPoint(const QPointF &scenePos); void constructPoint(const QPointF &point, CoordinateSystem cs); bool selectHandles(int x, int y, const QPointF &scenePos); void updateHandles(const QPointF &scenePos, const QPointF &deltaMove); bool checkLengthConstrains(unsigned int checkHandleIdx, const QPointF &scenePos); bool checkLengthConstrains(const QPointF &scenePos, const QPointF &deltaScenePos); bool checkMinMaxRadiusConstraint(const QPointF &curScenePos); bool checkMinMaxRadiusConstraint(qreal radiusX, qreal radiusY, int idxOfConstraint = -1); void updatePreviewEllipse(const QPointF &scenePosition); RubberbandFrameHandle *getFrameHandle() const; }; /* RubberbandMultiEllipseFeature */ } } /* namespace SituationMap::RB */