501 lines
20 KiB
Objective-C
Executable File
501 lines
20 KiB
Objective-C
Executable File
/**
|
|
**
|
|
** @RDE_HEADER@
|
|
** Definition of base class for rubberbands
|
|
** $Id$
|
|
** $HeadURL$
|
|
** $Author$
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
**
|
|
** Hardware-Environment: Intel-PC
|
|
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
|
**
|
|
** Language ........: C++ 11
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
**
|
|
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
**
|
|
** Notes .........:
|
|
**
|
|
** 27.03.2015, JT : First edition for use with Qt5
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
|
|
#include "event_dispatcher.h"
|
|
#include "event_delegater.h"
|
|
|
|
#include <Map/map.h>
|
|
#include <Common/ref_pointer.h>
|
|
|
|
#include <QtCore/QList>
|
|
#include <QtCore/QObject>
|
|
#include <QtCore/QPointer>
|
|
|
|
#include <QtGui/QColor>
|
|
|
|
#include <memory>
|
|
|
|
|
|
namespace Esri {
|
|
namespace ArcGISRuntime {
|
|
class MapGraphicsView;
|
|
class Point;
|
|
} }
|
|
|
|
|
|
|
|
namespace SituationMap
|
|
{
|
|
|
|
/**
|
|
Namespace for all rubberband stuff (is part of namespace SituationMap)
|
|
*/
|
|
namespace RB
|
|
{
|
|
/**
|
|
*/
|
|
enum class CoordinateSystem
|
|
{
|
|
Map,
|
|
Geo
|
|
};
|
|
|
|
|
|
/**
|
|
@class RubberbandBase rubberband_base.h
|
|
@brief Base class of all Rubberbands
|
|
|
|
Rubberbands are used to create or modifiy geometries like lines, circles, polygons etc. by processing
|
|
Qt input events like keyboard and mouse events. To create a rubberband the RubberbandFactory has to be used.
|
|
At end of rubberband processing the signal \c abort or\c apply are emitted. To delete the rubberband the
|
|
function deleteMySelf must be called. To use the delete operator is dangerous because at end of signal
|
|
processing some program code may be performed.
|
|
|
|
Example to how to use rubberband:
|
|
|
|
@code
|
|
|
|
SituationMap::Map & map = ...
|
|
|
|
const RubberbandFactory & rubberbandFactory = map.rubberbandFactory();
|
|
|
|
RubberbandPointFeature * rubberband = rubberbandFactory.create<RubberbandPointFeature>();
|
|
if (rubberband != nullptr)
|
|
{
|
|
QObject::connect( rubberband, &SiMapRubBnd::Rubberband::apply, [=](SiMapRubBnd::Rubberband * rubberband )
|
|
{
|
|
// rubberband has finished input
|
|
if (rubberband)
|
|
{
|
|
const QVector<QPointF> & vertexList = rubberband->coordinateVector();
|
|
|
|
// do something with vertexList
|
|
|
|
rubberband->deleteMySelf(); // notice don't call here delete rubberband directly !!!
|
|
}
|
|
} );
|
|
|
|
QObject::connect( rubberband, &SiMapRubBnd::Rubberband::abort, this, [=](SiMapRubBnd::Rubberband * rubberband )
|
|
{
|
|
// Rubberband has been aborted by user
|
|
if (rubberband)
|
|
{
|
|
rubberband->deleteMySelf(); // notice don't call here delete rubberband directly !!!
|
|
}
|
|
} );
|
|
}
|
|
|
|
@endcode
|
|
|
|
Following keyboard commands are available in active rubberbands:
|
|
|
|
| Key | Modifier | Funktion |
|
|
| :----: |:-------: | :--------------------------------------------------------------------------- |
|
|
| Esc | | Rubberband abbrechen |
|
|
| Return | | Rubberband abschließen und Eingabe übernehmen wenn möglich, sonst Abbruch |
|
|
| Left | | Selektierten Handle (Punkt,Frame) um 1 Pixel nach links schieben |
|
|
| Right | | Selektierten Handle (Punkt,Frame) um 1 Pixel nach rechts schieben |
|
|
| Up | | Selektierten Handle (Punkt,Frame) um 1 Pixel nach oben schieben |
|
|
| Down | | Selektierten Handle (Punkt,Frame) um 1 Pixel nach unten schieben |
|
|
| Left | Shift | Selektierten Handle (Punkt,Frame) um 10 Pixel nach links schieben |
|
|
| Right | Shift | Selektierten Handle (Punkt,Frame) um 10 Pixel nach rechts schieben |
|
|
| Up | Shift | Selektierten Handle (Punkt,Frame) um 10 Pixel nach oben schieben |
|
|
| Down | Shift | Selektierten Handle (Punkt,Frame) um 10 Pixel nach unten schieben |
|
|
|
|
@see EventDispatcher
|
|
@see Rubberband, RubberbandPointFeature, RubberbandPointCluster, RubberbandMultiPointFeature, RubberbandRectangle, RubberbandEllipse, RubberbandCorridor, RubberbandArrow
|
|
Rubberband3D, RubberbandPointFeature3D, RubberbandMultiPointFeature3D
|
|
|
|
*/
|
|
|
|
class SITUATIONMAP_EXPORT RubberbandBase : public QObject, public EventDispatcher::EventActionInterface
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
* Because class EventDispatcher::EventActionInterface is a pure virtual interface function the classic way of declaration would be
|
|
*
|
|
* SITUATIONMAP_EXPORT Rubberband : public QObject, public virtual EventDispatcher::EventActionInterface
|
|
*
|
|
* But with Visual Studio 2013 virtual inheritance combined with constructor delegation doesn't work and may crash the program. In
|
|
* this case the virtual inheritance of EventActionInterface isn't need because in the derived classes multiple inheritance will
|
|
* not be used.
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
/**
|
|
@name Construction & Destruction
|
|
@{
|
|
*/
|
|
|
|
public:
|
|
|
|
/**
|
|
Constructs a Rubberband for a situation map. Use \c RubberbandFactor to create a rubberband.
|
|
In case of the user actions the autoDelete mechanism can be used to delete the rubberband. Sometimes
|
|
the application wants to finish a running rubberband. This can be done by calling \c deleteMySelf. The
|
|
rubberband will be destroyed also automatically if the parent QObject or the map (see
|
|
SituationMap::Map::beginDestroy signal) will be destroyed.
|
|
|
|
@param map Pointer to SituationMap::Map
|
|
@param parent Pointer to QObject to use as parent.
|
|
@isActive If set to false the Rubberband is not active and have to be actived to start the input.
|
|
@see RubberbandFactory
|
|
*/
|
|
RubberbandBase( SituationMap::Map * map, QObject * parent, bool isActive = true );
|
|
|
|
~RubberbandBase();
|
|
/** @} */
|
|
|
|
/**
|
|
Activate rubberband if it has been created with \c isActive = false.
|
|
*/
|
|
void activate();
|
|
|
|
/**
|
|
Provides a list of active rubberbands for a situation map.
|
|
*/
|
|
static QList<RubberbandBase*> activeRubberbands( SituationMap::Map * map );
|
|
|
|
/**
|
|
Delete active rubberbands for a situation map.
|
|
*/
|
|
static void deleteAllActiveRubberbands( SituationMap::Map * map );
|
|
|
|
/**
|
|
Use deleteMySelft instead of delete operator to avoid dangling this pointerin Qt signal processing. It calls delete this; later on.
|
|
*/
|
|
void deleteMySelf();
|
|
|
|
/**
|
|
If setting auto delete flag to true the delete will be done automatically after sending signal abort or apply.
|
|
The default value of auto delete flag is false.
|
|
@{
|
|
*/
|
|
inline void setAutoDelete(bool on) { _autoDelete = on; }
|
|
|
|
|
|
inline bool autoDelete() const { return _autoDelete; }
|
|
/** @} */
|
|
|
|
/**
|
|
Returns true if the rubberband is already alive. Should be tested after creation of a rubberband because it is
|
|
possibled to create not living rubberbands, e.g. a rubberband was create twice and the first one has not finished
|
|
*/
|
|
inline bool rubberbandIsAlive() const { return !_viewPortEventDispatcher.isNull(); }
|
|
|
|
/** A single user action step has finished. Interim results can be used to show a preview now.
|
|
*/
|
|
void userActionFinished() override { emit interimResultsChanged(this); }
|
|
|
|
/**
|
|
@name ColorSettings Methodes to define visual behaviour of rubberband
|
|
@{
|
|
*/
|
|
inline void setDrawColor (const QColor & col ) { _drawColor = col; update(); } ///< set color for general drawing
|
|
inline void setFillColor (const QColor & col ) { _fillColor = col; update(); } ///< set color for general filling
|
|
inline void setHandleDrawColor (const QColor & col ) { _handleDrawColor = col; update(); } ///< set color for drawing handles
|
|
inline void setHandleFillColor (const QColor & col ) { _handleFillColor = col; update(); } ///< set color for filling handles
|
|
inline void setHandleSelectionColor(const QColor & col ) { _handleSelectionColor = col; update(); } ///< set handle selection color
|
|
inline void setFrameColor (const QColor & col ) { _frameColor = col; update(); } ///< set frame handle outline color
|
|
inline void setFrameFillColor (const QColor & col ) { _frameFillColor = col; update(); } ///< set frame handle fill color
|
|
inline void setFrameHandleMargin (int margin ) { _frameHandleMargin = margin; update(); } ///< set margin of frame in pixel
|
|
|
|
inline void setPickingRatio (unsigned int size ) { _pickingRatio = size; update(); } ///< set size of point handles
|
|
inline void setLineHandleWidth (unsigned int width ) { _lineHandleWidth = width; update(); } ///< set width of line handles
|
|
|
|
inline const QColor getDrawColor () const { return _drawColor; } ///< get color for general drawing
|
|
inline const QColor getFillColor () const { return _fillColor; } ///< get color for general filling
|
|
inline const QColor getHandleDrawColor() const { return _handleDrawColor; } ///< get color for drawing handles
|
|
inline const QColor getHandleFillColor() const { return _handleFillColor; } ///< get color for filling handles
|
|
inline const QColor getHandleSelectionColor() const { return _handleSelectionColor; } ///< get handle selection color
|
|
inline const QColor getFrameColor() const { return _frameColor; } ///< get frame handle outline color
|
|
inline const QColor getFrameFillColor() const { return _frameFillColor; } ///< get frame handle fill color
|
|
inline int getFrameHandleMargin() const { return _frameHandleMargin; } ///< get margin of frame in pixel
|
|
|
|
inline unsigned int getPickingRatio() const { return _pickingRatio; } ///< get size of point handles
|
|
/** @} */
|
|
|
|
bool applyAndEndAction ( AbstractEventDispatcher * causer, int x, int y ) override;
|
|
bool abortAction ( AbstractEventDispatcher * causer, int x, int y ) override;
|
|
|
|
/**
|
|
@name Set icons for rubberband buttons
|
|
|
|
In case of the application doesn't use the default rubberband icons other icons can be set with the setIcon functions. This redefine
|
|
of the button icons have to be done before creating a rubberband.
|
|
@{
|
|
*/
|
|
static void setIconApply( const QPixmap & );
|
|
static void setIconAbort( const QPixmap & );
|
|
static void setIconUndo ( const QPixmap & );
|
|
|
|
static void resetIconsToDefault();
|
|
/** @} */
|
|
|
|
/**
|
|
Start Rubberband mouse input automatically by program
|
|
*/
|
|
bool autoSelectAction( int x, int y );
|
|
|
|
/**
|
|
If set to true the rubberband will send apply signal after leaving construction state and ends
|
|
otherwise it continues in modification state. Default value is true.
|
|
*/
|
|
inline void enableFinishAfterConstruction(bool flag) { _finishAfterConstruction = flag; }
|
|
|
|
|
|
/**
|
|
Defines fixed widget position of rubberband button box
|
|
*/
|
|
void setFixedButtonBoxPosition( QPoint widgetPos );
|
|
|
|
|
|
/**
|
|
Undefines fixed widget position. The rubberband button box will be placed at the bottom right coner of
|
|
the rubberbands bounding box.
|
|
*/
|
|
void unsetFixedButtonBoxPosition();
|
|
|
|
/**
|
|
Returns true if a fixed widget position of rubberband button box is used.
|
|
*/
|
|
bool isButtonBoxPositionFixed();
|
|
|
|
/**
|
|
@name EventHandlerInterface Methodes of AbstractEventDispatcher::EventActionInterface
|
|
The interface between EventDispatcher and Rubberband are defined in class AbstractEventDispatcher.
|
|
To Implement the interface these methodes have to be override again in the derived classes of the Rubberband class. */
|
|
/**
|
|
@{
|
|
*/
|
|
|
|
bool buttonPositionAction ( AbstractEventDispatcher * causer, int x, int y ) override;
|
|
|
|
void unlinkEventDispatcher ( AbstractEventDispatcher * causer ) override;
|
|
|
|
/** @} */
|
|
|
|
|
|
/**
|
|
Returns true if the coordinates are valid elsewise false
|
|
*/
|
|
virtual bool coordinatesAreValid() const { return true; }
|
|
|
|
|
|
/**
|
|
Returns count of coordinates
|
|
*/
|
|
virtual unsigned int coordinateCount() const = 0;
|
|
|
|
/**
|
|
Returns constructed or modified coordinates
|
|
@param cs Defines the coordinate system of returned coordinates.
|
|
*/
|
|
virtual QVector<QPointF> coordinateVector( CoordinateSystem cs = CoordinateSystem::Geo ) const = 0;
|
|
|
|
/**
|
|
Returns a single coordinate from rubberbands coordinate list
|
|
@param idx index of coordinate
|
|
@param cs Defines the coordinate system of returned coordinate.
|
|
*/
|
|
virtual QPointF singleCoordinate( unsigned int idx = 0, CoordinateSystem cs = CoordinateSystem::Geo ) const = 0;
|
|
|
|
/**
|
|
Sets coordinates to modify to internal coordinate list
|
|
|
|
@param pntList List of coordinates to modify
|
|
@param cs Defines the coordinate system of input coordinates.
|
|
*/
|
|
virtual void setCoordinateVector( const QVector<QPointF> & pntList, CoordinateSystem cs = CoordinateSystem::Geo ) = 0;
|
|
|
|
/**
|
|
Set user defined informations to this rubberband
|
|
*/
|
|
inline void setUserData(void * p)
|
|
{
|
|
_userData = p;
|
|
}
|
|
|
|
/**
|
|
returns the user defined informations, which are set with methode userData(void*)
|
|
*/
|
|
inline void * userData() { return _userData; }
|
|
|
|
|
|
/**
|
|
Draw rubberband manually by calling the update function. In general it is not neccessary to call draw function.
|
|
But in some cases, for example the color setting functions, the graphic view update will not be done automatically.
|
|
Here calling draw forces an update of graphic view.
|
|
*/
|
|
inline void draw() { update(); }
|
|
|
|
|
|
/**
|
|
Sets call back function to realize an external update. The updateFunctor should return false to abort update process. In other case it have to return true.
|
|
*/
|
|
void installExternalUpdate(const std::function<bool(RubberbandBase*)> & updateFunctor);
|
|
|
|
|
|
/**
|
|
Returns true if there is a active rubberband on map.
|
|
@param map Pointer to map
|
|
*/
|
|
static bool isRubberbandActive( SituationMap::Map * map );
|
|
|
|
/**
|
|
Abort all active rubberbands on map.
|
|
@param map Pointer to map
|
|
*/
|
|
static void abortActiveRubberbands( SituationMap::Map * map );
|
|
|
|
|
|
protected:
|
|
|
|
Q_REQUIRED_RESULT QPointF projectCoordinateToMap( CoordinateSystem cs, const QPointF &loc ) const;
|
|
Q_REQUIRED_RESULT QPointF projectCoordinateFromMap( CoordinateSystem cs, const QPointF & loc ) const;
|
|
Q_REQUIRED_RESULT QPointF projectCoordinateFromMap( CoordinateSystem cs, const Esri::ArcGISRuntime::Point & loc ) const;
|
|
|
|
inline void doAutoDelete() { if (_autoDelete) deleteMySelf(); }
|
|
|
|
void updateButtonPosition();
|
|
|
|
QPointF pixel2ScenePosition( int x, int y ) const;
|
|
|
|
virtual void update() = 0;
|
|
|
|
void externalUpdate();
|
|
|
|
/*
|
|
Forward declaration of internal container class for member variables. The derived classes of Rubberband
|
|
often have also a declaration of InternalData for there own internal members.
|
|
*/
|
|
class BaseInternalData;
|
|
|
|
BaseInternalData *_baseInternal;
|
|
|
|
QColor _drawColor;
|
|
QColor _fillColor;
|
|
QColor _handleDrawColor;
|
|
QColor _handleFillColor;
|
|
QColor _handleSelectionColor;
|
|
QColor _frameColor;
|
|
QColor _frameFillColor;
|
|
QColor _frameSelectionColor;
|
|
int _frameHandleMargin;
|
|
|
|
unsigned int _lineHandleWidth;
|
|
|
|
unsigned int _pickingRatio;
|
|
|
|
bool _finishAfterConstruction;
|
|
bool _autoDelete;
|
|
|
|
QPointer<EventDispatcher> _viewPortEventDispatcher;
|
|
QPointer<EventDelegater> _windowEventDispatcher;
|
|
|
|
virtual QRectF sceneBbox() const = 0;
|
|
|
|
virtual void activateButtons();
|
|
virtual void deactivateButtons();
|
|
virtual void adjustButtons();
|
|
virtual void applyButtonClicked();
|
|
virtual void cancelButtonClicked();
|
|
virtual void undoButtonClicked();
|
|
|
|
protected slots:
|
|
|
|
void onDo_applyButtonClicked() { applyButtonClicked(); }
|
|
void onDo_cancelButtonClicked() { cancelButtonClicked(); }
|
|
void onDo_undoButtonClicked() { undoButtonClicked(); }
|
|
|
|
void onDo_updateButtonFixCoordinates();
|
|
|
|
private:
|
|
|
|
void * _userData;
|
|
|
|
friend class RubberbandFactory;
|
|
|
|
static void * operator new(size_t);
|
|
|
|
/**
|
|
The function \c allowMultipleRubberbands set a flag to allow new to create more than one rubberband
|
|
per situation map for the next new operator call. The function is used in class RubberbandFactory. The
|
|
value will be resetted to \c false at end of new operator.
|
|
*/
|
|
static void allowMultipleRubberbands( bool ok );
|
|
|
|
/**
|
|
The function \c currentFactoryMap defines the calling situation map for the next new operator call. The
|
|
function is used in class RubberbandFactory.The value will be resetted to \c nullptr at end of new operator.
|
|
*/
|
|
static void currentFactoryMap( SituationMap::Map * map );
|
|
|
|
|
|
signals:
|
|
|
|
/**
|
|
The abort signal will be emitted, when the abortAction has been called by one of the attached event handlers.
|
|
Before emtting the signal the event handler are closed and deleted. To avoid memory leaks the application has to
|
|
ensure that the delete function is called for this rubberband. See also example code at beginning.
|
|
|
|
@param rbnd pointer to this Rubberband
|
|
*/
|
|
void abort( RubberbandBase * rbnd );
|
|
|
|
/**
|
|
The apply signal will be emitted, when the applyAndEndAction has been called by one of the attached event handler. The connected slot can now
|
|
read the geometry information. Before emtting the signal the event handler are closed and deleted.To avoid memory leaks the application has to
|
|
ensure that the delete function is called for this rubberband. See also example code at beginning.
|
|
|
|
@param rbnd pointer to this Rubberband.
|
|
*/
|
|
void apply( RubberbandBase * rbnd );
|
|
|
|
/**
|
|
The finished signal will be emitted, when the rubberband is going to terminate and all user actions are done.
|
|
|
|
@param rbnd pointer to this Rubberband.
|
|
*/
|
|
void finished( RubberbandBase * rbnd );
|
|
|
|
/**
|
|
The coordinatesChanged signal will be emitted , when the user has changed, removed or added coordinates. Can be used to implement
|
|
a preview of interim results.
|
|
*/
|
|
void interimResultsChanged( RubberbandBase * rbnd );
|
|
|
|
}; /* Rubberband */
|
|
|
|
} } /* namespace SituationMap::RB */
|