Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+34
View File
@@ -0,0 +1,34 @@
// @RDE_HEADER@
// Notizen zu den Rubberbands
// $Id$
// $HeadURL$
// $Author$
// Created by Norbert Thoden, SLSE, 2023-08-26
Notizen zu den Rubberbands
- Sie wurden von Jörg Turla erstellt
- 2023: Erweiterung durch Steve Kemayou and Norbert Thoden
Norbert Thoden, 08/2023 :
- Habe ein neues RB erstellt: RubberbandMultiEllipseFeature
- Vorlage war RubberbandMultiPointFeature (Polyline)
Weiterer Stützpunte habe nicht mehr die Linie verlängtert, sondern neue Ellipse/Kreise eingefügt.
- API & Name wurden überwiegend für Ellipse konzipiert, getestet wurde aber im Wesentlichen mit Kreis (constrainQuadratic=true9
Probleme/ToDo sind u.a:
- Screenresolution führt dazu, das bei eng gefassten Constraints (z.B. radius =5m, min/Max ebenfalls bei 5m)
die checkMinMaxRadiusConstraint nicht bestehen und als Fehler betrachtet werden... :-(
- Setzen der Predefines Values (setCenterAndRadii) unterstützt noch keine Constraints
Empfehlung für neues RB
- Bedeutung erlernen von: selectAction, moveAction, movePickedAction und ihrer returnValues.
- Hilfsfile für rotations methoden etc. um ständiges kopieren (von Lmabdas!?) zu vermeiden.
- ...
: Norbert Thoden, 08/2023:
+149
View File
@@ -0,0 +1,149 @@
/* XPM */
static const char * abort_xpm[] = {
"24 24 122 2",
" c None",
". c #E98774",
"+ c #F6866F",
"@ c #FB6C50",
"# c #F28773",
"$ c #F8856E",
"% c #EF8672",
"& c #F5846E",
"* c #F96346",
"= c #F96042",
"- c #F96649",
"; c #F28670",
"> c #8E5246",
", c #F7836C",
"' c #F96245",
") c #F9674B",
"! c #F18570",
"~ c #F3836D",
"{ c #F76245",
"] c #F75F41",
"^ c #F76447",
"/ c #F2846E",
"( c #945549",
"_ c #F7806A",
": c #F76143",
"< c #F76548",
"[ c #F0856F",
"} c #E47B66",
"| c #F56043",
"1 c #F55D3F",
"2 c #F56144",
"3 c #9A574A",
"4 c #F57E67",
"5 c #F55E41",
"6 c #F56245",
"7 c #D1725F",
"8 c #E55539",
"9 c #F35A3C",
"0 c #F35D40",
"a c #F27F68",
"b c #9F5A4C",
"c c #F47B63",
"d c #F35B3E",
"e c #D44E34",
"f c #E35337",
"g c #F1583A",
"h c #F15B3D",
"i c #F17D66",
"j c #F37860",
"k c #F1593B",
"l c #D14C32",
"m c #DF5034",
"n c #EE5638",
"o c #EE583A",
"p c #EE5739",
"q c #CC4A30",
"r c #DC4D31",
"s c #EC5335",
"t c #CA472D",
"u c #D94B2F",
"v c #E95133",
"w c #C7452C",
"x c #DF4B2E",
"y c #E74E30",
"z c #CE462B",
"A c #A45949",
"B c #E55235",
"C c #E44C2E",
"D c #E35A3F",
"E c #975244",
"F c #E76950",
"G c #E2492B",
"H c #E24B2D",
"I c #E47059",
"J c #83473C",
"K c #E36A52",
"L c #DF4628",
"M c #E04A2C",
"N c #E06F59",
"O c #E16C55",
"P c #DC4528",
"Q c #DC4426",
"R c #DD482B",
"S c #DC6F59",
"T c #DD6C56",
"U c #DA4326",
"V c #DA4123",
"W c #D74022",
"X c #D84123",
"Y c #DB472A",
"Z c #D96E59",
"` c #DA6A55",
" . c #D94325",
".. c #D83F21",
"+. c #D13D20",
"@. c #D63F21",
"#. c #DA472B",
"$. c #D46C58",
"%. c #D26A55",
"&. c #D64326",
"*. c #D53D1F",
"=. c #CF3B1E",
"-. c #D33C1F",
";. c #D7482B",
">. c #C36552",
",. c #D03A1D",
"'. c #D33B1D",
"). c #CB391C",
"!. c #D13A1D",
"~. c #CA381C",
"{. c #CD381A",
"]. c #D2391B",
"^. c #CB371A",
"/. c #D0381B",
"(. c #C7361A",
"_. c #CA3518",
":. c #D03719",
"<. c #C93518",
"[. c #CD3619",
"}. c #C43417",
"|. c #BF3216",
"1. c #BD3116",
" ",
" . . ",
" + @ # $ @ % ",
" & * = - ; > , ' = ) ! ",
" ~ { ] ] ] ^ / ( _ : ] ] ] < [ ",
" } | 1 1 1 1 1 2 ~ 3 4 5 1 1 1 1 1 6 7 ",
" 8 9 9 9 9 9 9 0 a b c d 9 9 9 9 9 9 e ",
" f g g g g g g h i j k g g g g g g l ",
" m n n n n n n o p n n n n n n q ",
" r s s s s s s s s s s s s t ",
" u v v v v v v v v v v w ",
" x y y y y y y y y z ",
" A B C C C C C C C C D ",
" E F G G G G G G G G G H I ",
" J K L L L L L L L L L L L M N ",
" O P Q Q Q Q Q Q Q Q Q Q Q Q R S ",
" T U V V V V V V W X V V V V V V Y Z ",
" ` .............+. @.............#.$. ",
" %.&.*.*.*.*.*.*.=. -.*.*.*.*.*.*.;.>. ",
" ,.'.'.'.'.'.). !.'.'.'.'.'.~. ",
" {.].].].^. /.].].].(. ",
" _.:.<. [.:.}. ",
" |. 1. ",
" "};
@@ -0,0 +1,291 @@
/**
**
** @RDE_HEADER@
** Abstract Event Dispatcher for Qt5
** $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 .........:
**
** 28.04.2003, JT : First edition for use with Qt4 in START Feature Editor fee
** 25.03.2015, JT : Refactoring for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "abstract_event_dispatcher.h"
#include "gestures.h"
#include <math.h>
#include <QtWidgets/QWidget>
#include <QtCore/QCoreApplication>
namespace SituationMap { namespace RB
{
static QHash<QWidget*, QList<AbstractEventDispatcher*>> &runningDispatcher()
{
static QHash<QWidget*, QList<AbstractEventDispatcher*>> hashTable;
return hashTable;
} // runningDispatcher()
QGestureRecognizer * AbstractEventDispatcher::_applyGestureDetection = nullptr;
unsigned int AbstractEventDispatcher::_applyGestureID = 0;
AbstractEventDispatcher::AbstractEventDispatcher( QWidget * getEventsFrom )
: QObject(getEventsFrom)
, _getEventsFrom(getEventsFrom)
, _logger(getLogger("EventDispatcher"))
, _cursorIsInWidget(false)
, _synthesisTouchFromMouseEvents(false)
, _deleteRequested(false)
, _hasGrab(false)
, _finishFlag(false)
, _activeEvent(false)
, _dispatcherCursor()
, _whatsThisBackup()
, _eventActions(nullptr)
{
DEBUG_LOG(_logger) << LOGFUNCTION << " " << this;
initDispatcher();
} /* AbstractEventDispatcher::AbstractEventDispatcher */
AbstractEventDispatcher::AbstractEventDispatcher( QWidget * getEventsFrom, EventActionInterface * eventActions )
: QObject(getEventsFrom)
, _getEventsFrom(getEventsFrom)
, _logger(getLogger("EventDispatcher"))
, _cursorIsInWidget(false)
, _synthesisTouchFromMouseEvents(false)
, _deleteRequested(false)
, _hasGrab(false)
, _finishFlag(false)
, _activeEvent(false)
, _dispatcherCursor()
, _whatsThisBackup()
, _eventActions(eventActions)
{
DEBUG_LOG(_logger) << LOGFUNCTION << " " << this;
initDispatcher();
} /* AbstractEventDispatcher::AbstractEventDispatcher */
void AbstractEventDispatcher::initDispatcher()
{
_restoreCursor = _getEventsFrom->testAttribute(Qt::WA_SetCursor);
if (_restoreCursor)
{
_cursorToRestore = getCursorFromWidget();
DEBUG_LOG(_logger) << LOGFUNCTION << " this=" << this << " get cursorToRestore";
}
_restoreMouseTracking = _getEventsFrom->hasMouseTracking();
// {
// bool activeEvent = _activeEvent;
// _activeEvent = true; // don't process events while init has not been finished
// QCoreApplication::process Events(); // remove events from event queue; in which circumstances this is necessary?
// _activeEvent = activeEvent;
// }
_getEventsFrom->setMouseTracking(true);
_getEventsFrom->raise();
_getEventsFrom->installEventFilter(this);
_synthesisTouchFromMouseEvents = QCoreApplication::testAttribute( Qt::AA_SynthesizeTouchForUnhandledMouseEvents );
QCoreApplication::setAttribute( Qt::AA_SynthesizeTouchForUnhandledMouseEvents, false );
QCoreApplication::setAttribute( Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true );
static const Qt::GestureType gestures[] = { Qt::GestureType::TapGesture
, Qt::GestureType::TapAndHoldGesture
, Qt::GestureType::PanGesture
, Qt::GestureType::PinchGesture
, Qt::GestureType::SwipeGesture };
for (auto gestureType : gestures) _getEventsFrom->grabGesture(gestureType);
if (_applyGestureDetection == nullptr)
{
_applyGestureDetection = new ApplyGestureRecognizer();
_applyGestureID = QGestureRecognizer::registerRecognizer( _applyGestureDetection );
}
_getEventsFrom->grabGesture( (Qt::GestureType)_applyGestureID );
_getEventsFrom->setAttribute( Qt::WA_AcceptTouchEvents, true );
runningDispatcher()[_getEventsFrom].append(this);
} /* AbstractEventDispatcher::initDispatcher */
AbstractEventDispatcher::~AbstractEventDispatcher()
{
DEBUG_LOG(_logger) << LOGFUNCTION << " " << this;
_finishFlag = true;
if (_getEventsFrom)
{
_getEventsFrom->removeEventFilter(this);
_getEventsFrom->setMouseTracking( _restoreMouseTracking );
ungrab();
if (!_whatsThisBackup.isNull())
{
_getEventsFrom->setWhatsThis(_whatsThisBackup);
}
runningDispatcher()[_getEventsFrom].removeAll(this);
}
QCoreApplication::setAttribute( Qt::AA_SynthesizeTouchForUnhandledMouseEvents, _synthesisTouchFromMouseEvents );
} /* AbstractEventDispatcher::~AbstractEventDispatcher */
unsigned int AbstractEventDispatcher::numberOfEventDispatcher() const
{
return static_cast<unsigned int>( runningDispatcher()[_getEventsFrom].size() );
} /* AbstractEventDispatcher::numberOfEventDispatcher */
void AbstractEventDispatcher::onDo_delete()
{
if (_deleteRequested) return;
_deleteRequested = true;
QObject::deleteLater();
} /* AbstractEventDispatcher::onDo_delete */
void AbstractEventDispatcher::KickTheBucket()
{
if (_getEventsFrom == nullptr) return;
_finishFlag = true;
unlinkEventDispatcher();
_getEventsFrom->removeEventFilter(this);
_getEventsFrom->setMouseTracking( _restoreMouseTracking );
ungrab();
if (!_whatsThisBackup.isNull())
{
_getEventsFrom->setWhatsThis(_whatsThisBackup);
}
runningDispatcher()[_getEventsFrom].removeAll(this);
_getEventsFrom = nullptr;
emit signalKickTheBucket();
// QCoreApplication::sendPostedEvents();
// QCoreApplication::process Events(); // dispatch window system events
onDo_delete();
} /* AbstractEventDispatcher::KickTheBucket */
void AbstractEventDispatcher::onDo_kickTheBucket() { KickTheBucket(); }
void AbstractEventDispatcher::setWhatsThis(const QString & whatsThis)
{
if (_whatsThisBackup.isNull())
{
_whatsThisBackup = _getEventsFrom->whatsThis();
}
_getEventsFrom->setWhatsThis(whatsThis);
} /* AbstractEventDispatcher::setWhatsThis */
void AbstractEventDispatcher::grab()
{
if (_hasGrab) return;
_hasGrab = true;
DEBUG_LOG(_logger) << LOGFUNCTION << " this=" << this << " set dispatcherCursor = " << (int)_dispatcherCursor.shape();
setCursorToWidget( _dispatcherCursor );
_getEventsFrom -> setFocus();
} /* AbstractEventDispatcher::Grab */
void AbstractEventDispatcher::ungrab()
{
if (!_hasGrab) return;
_hasGrab = false;
if (_restoreCursor)
{
DEBUG_LOG(_logger) << LOGFUNCTION << " this=" << this << " set cursorToRestore = " << (int)_cursorToRestore.shape();
setCursorToWidget( _cursorToRestore );
}
else _getEventsFrom -> unsetCursor();
_getEventsFrom -> clearFocus();
} /* AbstractEventDispatcher::Ungrab */
bool AbstractEventDispatcher::eventFilter( QObject * widget, QEvent * e )
{
if (widget != ((QObject*)_getEventsFrom)) return false;
if (_logger.isDebugEnabled())
{
switch (e->type())
{
case QEvent::CursorChange:
{
QCursor cursor = _getEventsFrom->cursor();
DEBUG_LOG(_logger) << LOGFUNCTION << " Cursor has changed, this = " << this << " cursor = " << cursor.shape();
} break;
case QEvent::Enter :
{
_cursorIsInWidget = true;
QCursor cursor = _getEventsFrom->cursor();
DEBUG_LOG(_logger) << LOGFUNCTION << " Enter event, this = " << this << " cursor = " << cursor.shape();
} break;
case QEvent::Leave :
{
_cursorIsInWidget = false;
QCursor cursor = _getEventsFrom->cursor();
DEBUG_LOG(_logger) << LOGFUNCTION << " Leave event, this = " << " cursor = " << cursor.shape();
} break;
default: break;
}
}
return false;
} /* AbstractEventDispatcher::eventFilter */
void AbstractEventDispatcher::setCursorToWidget( const QCursor & cursor ) { _getEventsFrom -> setCursor( cursor ); }
QCursor AbstractEventDispatcher::getCursorFromWidget() const { return _getEventsFrom->cursor(); }
} } /* namespace SituationMap::RB */
@@ -0,0 +1,234 @@
/**
**
** @RDE_HEADER@
** Abstract Event Dispatcher for Qt5
** $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 .........:
**
** 28.04.2003, JT : First edition for use with Qt4 in START Feature Editor fee
** 25.03.2015, JT : Refactoring for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <functional>
#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtGui/QCursor>
#include <Common/situation_map_logging.h>
class QEvent;
class QWidget;
class QGestureRecognizer;
namespace SituationMap { namespace RB
{
/**
@class AbstractEventDispatcher abstract_event_dispatcher.h
@brief Base class of Qt event filter implementations to handle user interactions of map window
An EventDispatcher installs an event filter on a QWidget to receive all events that are send to
the widget. Depending on the type of event and the state of the event dispatcher the event will
be processed by the dispatcher and stopped or forwarded to the QWidget. In case of processing
the event methodes of the EventActionInterface are called to controll a rubberband.
@see EventDelegater, EventDispatcher, EventMouseNavigator
*/
class AbstractEventDispatcher : public QObject
{
friend class EventDelegater;
Q_OBJECT
public:
/**
@brief Logical interface between EventDispatcher and Rubberband
Defines interface functions the EventDispatcher will call to control a rubberband. The rubberband class
is derived from EventActionInterface and overrides the interface functions to implement them. The mapping
user interaction to interface action is defined the derived classes of AbstractEventDispatcher.
*/
class EventActionInterface
{
public:
EventActionInterface() = default;
virtual ~EventActionInterface() = default;
virtual void unlinkEventDispatcher ( AbstractEventDispatcher * causer ) = 0;
virtual void resetAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); }
virtual bool selectAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool multiSelectActionPress ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool multiSelectActionRelease( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool setCoordinateAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool moveAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool movePickedAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool contextMenuAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool completeStateAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool deleteAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool undoAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool applyAndEndAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool abortAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual bool buttonPositionAction ( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); Q_UNUSED(x); Q_UNUSED(y); return false; }
virtual void userActionFinished() = 0;
}; /* EventActionInterface */
/**
@name Construction & Destruction
@{
*/
explicit AbstractEventDispatcher( QWidget * getEventsFrom );
explicit AbstractEventDispatcher( QWidget * getEventsFrom, EventActionInterface* );
virtual ~AbstractEventDispatcher();
AbstractEventDispatcher(const AbstractEventDispatcher &) = delete;
AbstractEventDispatcher & operator = (const AbstractEventDispatcher &) = delete;
/** @} */
/**
Conceal deleteLater slot. Use onDo_delete() instead to avoid "QCoreApplication::postEvent: Unexpected null receiver" warning.
*/
void deleteLater() = delete;
/**
Provides the number of EventDispatcher installed to the QWidget of this EventDispatcher
*/
unsigned int numberOfEventDispatcher() const;
inline void setEventActions(EventActionInterface * eventActions) { _eventActions = eventActions; }
inline bool hasGrab() const { return _hasGrab; }
inline void setCursor(const QCursor & cursor) { _dispatcherCursor = cursor; }
void setWhatsThis(const QString & whatsThis);
void grab();
void ungrab();
public slots:
/**
@brief Slot calling internal \c KickTheBucket methode
Calls internal methode \c KickTheBucket. Be careful using this function. Should only be used
from implementations of \c EventActionInterface methodes or \c EventDelegater class.
*/
void onDo_kickTheBucket();
/**
@brief Slot calling \c deleteLater function of QObject
Never use \c delete directly for EventDispatcher class. Instead of use \c onDo_delete() function.
*/
void onDo_delete();
protected:
QWidget * _getEventsFrom;
LOGGER_T _logger;
bool _cursorIsInWidget;
inline bool hasFinished() { return _finishFlag; }
inline bool hasActiveEvent() { return _activeEvent; }
inline void setActiveEvent(bool val) { _activeEvent = val; }
/**
@brief Destroying EventDispatcher as result of an incoming event.
As result of an incomming event (e.g. Keypress ESC) the EventDispatcher will stop, emiting signal \c signalKickTheBucket()
and calls methode \c EventActionInterface::unlinkEventDispatcher() before setup \c deleteLater() call to destroy it self.
*/
virtual void KickTheBucket();
inline void unlinkEventDispatcher()
{
if (_eventActions)
{
_eventActions -> unlinkEventDispatcher( this );
_eventActions = nullptr;
}
} /* unlinkEventDispatcher */
inline bool callEventAction( bool( EventActionInterface::*actionMethodePtr)( AbstractEventDispatcher*,int,int), int x, int y )
{
if (_eventActions == nullptr) return false;
return (_eventActions->*actionMethodePtr)( this, x, y );
} /* callEventAction */
/**
Event filter function to override to implement event handling. To workaround a cursor handling bug in QGraphicsView it is
necessary to call the eventFilter function of this base class, which will monitor enter and leave events.
*/
virtual bool eventFilter( QObject * widget, QEvent * e );
inline EventActionInterface * getEventActions() { return _eventActions; }
void setCursorToWidget( const QCursor & cursor );
QCursor getCursorFromWidget() const;
bool _synthesisTouchFromMouseEvents;
static unsigned int _applyGestureID;
private:
void initDispatcher();
bool _deleteRequested;
bool _hasGrab;
bool _finishFlag;
bool _restoreCursor;
bool _restoreMouseTracking;
QCursor _cursorToRestore;
bool _activeEvent;
QCursor _dispatcherCursor;
QString _whatsThisBackup;
EventActionInterface * _eventActions;
static QGestureRecognizer * _applyGestureDetection;
signals:
void signalKickTheBucket();
}; /* EventDispatcher */
} } /* namespace SituationMap::RB */
+110
View File
@@ -0,0 +1,110 @@
/* XPM */
static const char * apply_xpm[] = {
"24 24 83 1",
" c None",
". c #7FBD7C",
"+ c #8BCF88",
"@ c #84C582",
"# c #588456",
"$ c #63BE5F",
"% c #57B953",
"& c #73BF70",
"* c #56B752",
"= c #499B45",
"- c #699F66",
"; c #59B755",
"> c #54B550",
", c #52B14E",
"' c #6ABC67",
") c #52B34E",
"! c #377334",
"~ c #6FAF6C",
"{ c #50B24C",
"] c #4FB14B",
"^ c #48A144",
"/ c #4C734A",
"( c #5DB559",
"_ c #4DAE49",
": c #4CAD48",
"< c #6BB569",
"[ c #4AAC46",
"} c #377F35",
"| c #5E915C",
"1 c #50AD4C",
"2 c #48A944",
"3 c #44A040",
"4 c #61B05E",
"5 c #45A641",
"6 c #527F50",
"7 c #7BBF78",
"8 c #78BA75",
"9 c #639C60",
"0 c #46A542",
"a c #42A33E",
"b c #368633",
"c c #389035",
"d c #3FA13B",
"e c #43A33F",
"f c #619B5E",
"g c #56AC53",
"h c #3D9D39",
"i c #3B9C37",
"j c #3C9E38",
"k c #54A951",
"l c #64A761",
"m c #3D9E39",
"n c #2A6B26",
"o c #3A9B35",
"p c #3B9B36",
"q c #62A55F",
"r c #4B7749",
"s c #48A243",
"t c #33892F",
"u c #328B2F",
"v c #379833",
"w c #459F41",
"x c #4F7E4D",
"y c #5CA659",
"z c #369632",
"A c #349530",
"B c #349630",
"C c #59A955",
"D c #3A9936",
"E c #276C25",
"F c #256C22",
"G c #32932E",
"H c #2F892B",
"I c #2C8728",
"J c #2F912B",
"K c #2F902B",
"L c #2D8E29",
"M c #2D8F29",
"N c #257322",
"O c #226E1F",
"P c #2B8D27",
"Q c #298826",
"R c #288424",
" ",
" ",
" .+++@ ",
" #$%%% ",
" &***= ",
" -;>>, ",
" ')))! ",
" ~{]]^ ",
" /(__: ",
" <[[[} ",
" |1223 ",
" 4555 ",
" 67778 90aab ",
" cddef gddh ",
" ijjk lmjj ",
" noopq rsoot ",
" uvvwxyvvz ",
" ABBCDBBE ",
" FGGGGGH ",
" IJJJK ",
" LMMN ",
" OPQ ",
" R ",
" "};
+200
View File
@@ -0,0 +1,200 @@
/* XPM */
static const char * constrainsMarker_xpm[] = {
"24 24 173 2",
" c None",
". c #AE6557",
"+ c #DF826F",
"@ c #F18C78",
"# c #FE947F",
"$ c #FD937E",
"% c #EC8976",
"& c #E08270",
"* c #A35F51",
"= c #C17060",
"- c #F88C77",
"; c #FD7F67",
"> c #FC7257",
", c #FC6A4E",
"' c #FC6345",
") c #FC6446",
"! c #FC6C50",
"~ c #FD8269",
"{ c #B86A5B",
"] c #EA8672",
"^ c #FC7A61",
"/ c #FB6548",
"( c #FB6244",
"_ c #F45F42",
": c #E85B3F",
"< c #EF5D41",
"[ c #FC7C64",
"} c #EA8673",
"| c #EF846F",
"1 c #F9694D",
"2 c #F96042",
"3 c #F55E41",
"4 c #BB4832",
"5 c #C04A33",
"6 c #F65F41",
"7 c #EE8571",
"8 c #E9816C",
"9 c #F76548",
"0 c #F75E40",
"a c #F66143",
"b c #E6573C",
"c c #F76649",
"d c #E67F6B",
"e c #B86959",
"f c #F56549",
"g c #F45C3E",
"h c #E8583B",
"i c #F45D3F",
"j c #F27D66",
"k c #E25539",
"l c #F5674B",
"m c #F0725A",
"n c #F2593B",
"o c #EE583A",
"p c #B8442D",
"q c #F25C3F",
"r c #EA7C67",
"s c #EE7259",
"t c #A95E4F",
"u c #EF593B",
"v c #EF5638",
"w c #B4432D",
"x c #CF4B30",
"y c #F05D41",
"z c #DF7A66",
"A c #B9452E",
"B c #EF593C",
"C c #A75C4E",
"D c #D36650",
"E c #EC5436",
"F c #DA4E32",
"G c #ED6044",
"H c #CE7361",
"I c #D16550",
"J c #E35E44",
"K c #EA5133",
"L c #DF4D31",
"M c #E24E31",
"N c #EC6449",
"O c #B36354",
"P c #DF5D43",
"Q c #E75436",
"R c #E74E30",
"S c #D04D34",
"T c #E44D2F",
"U c #EB6A51",
"V c #8D4E42",
"W c #D54D32",
"X c #E45539",
"Y c #E34C2E",
"Z c #E44B2D",
"` c #CE5138",
" . c #E76F57",
".. c #D45036",
"+. c #E14E30",
"@. c #D94729",
"#. c #E1492A",
"$. c #D85339",
"%. c #A0341E",
"&. c #E14B2D",
"*. c #E0725B",
"=. c #DB5236",
"-. c #D8492C",
";. c #C24329",
">. c #DE4628",
",. c #E04F32",
"'. c #BB3B22",
"). c #DF4C2F",
"!. c #D56F5B",
"~. c #C2432A",
"{. c #963B28",
"]. c #DC4325",
"^. c #B25C4B",
"/. c #C93D22",
"(. c #DE4F33",
"_. c #C86A57",
":. c #B95D4A",
"<. c #913927",
"[. c #D53F21",
"}. c #D94022",
"|. c #DC5B42",
"1. c #CF3D21",
"2. c #DD5338",
"3. c #B25F4F",
"4. c #DB583F",
"5. c #9D311B",
"6. c #D73E20",
"7. c #D84123",
"8. c #D16A55",
"9. c #D33D1F",
"0. c #DD5A40",
"a. c #D86B55",
"b. c #D74023",
"c. c #9A2F1B",
"d. c #C3371C",
"e. c #D43C1E",
"f. c #D7472B",
"g. c #D06C58",
"h. c #D33C1E",
"i. c #D64326",
"j. c #C4381C",
"k. c #C7361A",
"l. c #D2391B",
"m. c #D54529",
"n. c #DB6B56",
"o. c #B35E4D",
"p. c #B85441",
"q. c #D0391C",
"r. c #CA371A",
"s. c #C13418",
"t. c #D0381A",
"u. c #D13A1D",
"v. c #D65339",
"w. c #DC6A53",
"x. c #D7715D",
"y. c #CF6C59",
"z. c #DC735E",
"A. c #DC6953",
"B. c #D64F35",
"C. c #BD3318",
"D. c #972812",
"E. c #CC3518",
"F. c #CF3618",
"G. c #D03C1E",
"H. c #D24226",
"I. c #D0381B",
"J. c #CA3517",
"K. c #912611",
"L. c #B12E14",
"M. c #BE3115",
"N. c #CA3417",
"O. c #CC3517",
"P. c #AF2D14",
" ",
" . + @ # $ % & * ",
" = - ; > , ' ) ! > ~ - { ",
" ] ^ / ( ( _ : : < ( ( / [ } ",
" | 1 2 3 4 5 6 2 1 7 ",
" 8 9 0 0 a b 0 c d ",
" e f g h g i j k g l e ",
" m n o p n q r o n s ",
" t u v w x v y z A v B C ",
" D E E F E G H E E I ",
" J K L M K N O M K P ",
" Q R S T R U V W R X ",
" Y Z ` Z Z . ..Z +. ",
" @.#.$. %.#.&.*. =.#.-. ",
" ;.>.,. '.>.).!. ).>.~. ",
" {.].].^. /.].(._. :.].].<. ",
" [.}.|. 1.}.2.3. 4.}.[. ",
" 5.6.7.8. 9.6.0.a.b.6.c. ",
" d.e.f.g. h.e.i.e.j. ",
" k.l.m.n.o. p.q.l.l.r. ",
" s.t.u.v.w.x.y.y.z.A.B.u.t.C. ",
" D.E.F.F.G.H.H.I.F.F.J.K. ",
" L.M.N.O.M.P. ",
" "};
+127
View File
@@ -0,0 +1,127 @@
/**
**
** @RDE_HEADER@
** Definition of ellipse drawable
** $Id$
** $HeadURL$
** $Author$
*/
#include "drawable_ellipse.h"
#include <MathUtils/math_const.h>
#include <QtWidgets/QGraphicsEllipseItem>
namespace SituationMap { namespace RB
{
DrawableEllipse::DrawableEllipse(Esri::ArcGISRuntime::MapGraphicsView * map) : DrawableEllipse(map,map->scene()) {;}
DrawableEllipse::DrawableEllipse(Esri::ArcGISRuntime::MapGraphicsView * map, QGraphicsScene * scene)
: RubberbandDrawable(map, scene)
, _elliItem(nullptr)
, _center()
, _radiusX(0)
, _radiusY(0)
, _elliStyle()
, _sinRect(0)
, _cosRect(1)
, _sectorStart()
, _sectorEnd()
{
_elliItem = new QGraphicsEllipseItem();
_scene -> addItem( _elliItem );
makeLineStyle( false, _elliStyle );
_elliItem -> setPen( _elliStyle );
_sectItem = new QGraphicsEllipseItem();
_scene -> addItem( _sectItem );
makeLineStyle( false, _elliStyle );
_sectItem -> setPen( _elliStyle );
} /* DrawableLine::DrawableLine */
DrawableEllipse::~DrawableEllipse()
{
if (_scene)
{
if (_elliItem) _scene->removeItem(_elliItem);
if (_sectItem) _scene->removeItem(_sectItem);
delete _elliItem;
delete _sectItem;
}
_elliItem = nullptr;
_sectItem = nullptr;
} /* DrawableEllipse::~DrawableEllipse */
void DrawableEllipse::updateGraphic()
{
auto length = []( const QPointF & p ) -> qreal { return sqrt(p.x()*p.x()+p.y()*p.y()); };
qreal mapRotatePhi = _mapView->mapRotation() * MathConst::pi / 180.0;
qreal sinMap = sin(mapRotatePhi);
qreal cosMap = cos(mapRotatePhi);
qreal sinPhi = _sinRect * cosMap + _cosRect * sinMap;
qreal cosPhi = _cosRect * cosMap - _sinRect * sinMap;
_center.mapToScene(_mapView);
QPointF mapCenter( _center._mapCoordinate.x(), _center._mapCoordinate.y() );
RubberbandCoordinate x0y0(_mapView, convert( mapCenter+QPointF(-_radiusX,-_radiusY), _mapView->map()->spatialReference()) );
RubberbandCoordinate x1y0(_mapView, convert( mapCenter+QPointF( _radiusX,-_radiusY), _mapView->map()->spatialReference()) );
RubberbandCoordinate x0y1(_mapView, convert( mapCenter+QPointF(-_radiusX, _radiusY), _mapView->map()->spatialReference()) );
qreal width = length(x1y0._sceneCoordinate-x0y0._sceneCoordinate);
qreal height = length(x0y1._sceneCoordinate-x0y0._sceneCoordinate);
makeLineStyle( false, _elliStyle );
QColor fillColor = transparentFillColor();
//fillColor.setAlpha(0);
QPen pen(_drawColor);
pen.setWidth(_lineWidth);
if (_sectorStart != _sectorEnd)
{
auto getAngle = [](qreal sinPhi, qreal cosPhi) -> int
{
qreal phi = acos( cosPhi );
if (sinPhi < 0) phi = MathConst::pi_two - phi;
return int( (phi * 180.0 / MathConst::pi) * 16);
}; // getAngle
int startAngle = getAngle(_sectorStart.y(), _sectorStart.x());
int endAngle = getAngle( _sectorEnd.y(), _sectorEnd.x());
int spanAngle = (endAngle > startAngle) ? endAngle-startAngle : 5760-startAngle+endAngle;
_sectItem -> setRect( -width*0.5, -height*0.5, width, height );
_sectItem -> setPen( pen );
_sectItem -> setBrush( (fillColor.alpha() > 0) ? QBrush(fillColor) : QBrush() );
_sectItem -> setTransform( QTransform( cosPhi, -sinPhi, sinPhi, cosPhi, _center._sceneCoordinate.x(), _center._sceneCoordinate.y() ));
_sectItem -> setStartAngle( startAngle );
_sectItem -> setSpanAngle( spanAngle );
_sectItem -> setVisible( true );
fillColor.setAlphaF(fillColor.alphaF() * 0.5 );
}
else _sectItem -> setVisible( false );
_elliItem -> setRect( -width*0.5, -height*0.5, width, height );
_elliItem -> setPen(pen);
_elliItem -> setBrush( (fillColor.alpha() > 0) ? QBrush(fillColor) : QBrush() );
_elliItem -> setTransform( QTransform( cosPhi, -sinPhi, sinPhi, cosPhi, _center._sceneCoordinate.x(), _center._sceneCoordinate.y() ));
} /* DrawableEllipse::updateGraphic */
void DrawableEllipse::adjustCoordinates() { updateGraphic(); }
void DrawableEllipse::adjustWindow( const QRectF& ) { updateGraphic(); }
} } /* namespace SituationMap::RB */
+72
View File
@@ -0,0 +1,72 @@
/**
**
** @RDE_HEADER@
** Definition of ellipse drawable
** $Id$
** $HeadURL$
** $Author$
*/
#pragma once
#include "rubberband_drawable.h"
#include <arcgis/Map.h>
namespace SituationMap { namespace RB
{
class DrawableEllipse : public RubberbandDrawable
{
Q_OBJECT
public:
explicit DrawableEllipse( Esri::ArcGISRuntime::MapGraphicsView * );
explicit DrawableEllipse( Esri::ArcGISRuntime::MapGraphicsView *, QGraphicsScene * );
~DrawableEllipse();
DrawableEllipse(const RubberbandDrawable &) = delete;
DrawableEllipse & operator = (const RubberbandDrawable &) = delete;
inline void setRect(const QPointF & center, qreal radiusX, qreal radiusY, qreal sin, qreal cos, const QPointF & sectorStart = QPointF(), const QPointF & sectorEnd = QPointF() )
{
// p1,p2 = corner points of unrotated ellipse in scene coordinates
_center = RubberbandCoordinate( _mapView, convert(center, _mapView->map()->spatialReference()) );
_radiusX = radiusX;
_radiusY = radiusY;
_sinRect = sin;
_cosRect = cos;
_sectorStart = sectorStart;
_sectorEnd = sectorEnd;
updateGraphic();
}
qreal radiusX() { return _radiusX; }
qreal radiusY() { return _radiusY; }
protected:
QGraphicsEllipseItem * _elliItem;
QGraphicsEllipseItem * _sectItem;
RubberbandDrawable::RubberbandCoordinate _center;
qreal _radiusX;
qreal _radiusY;
QPen _elliStyle;
qreal _sinRect;
qreal _cosRect;
QPointF _sectorStart;
QPointF _sectorEnd;
void updateGraphic() override;
void adjustCoordinates() override;
void adjustWindow( const QRectF& ) override;
}; /* DrawableEllipse */
} } /* namespace SituationMap::RB */
+109
View File
@@ -0,0 +1,109 @@
/**
**
** @RDE_HEADER@
** Implementation of line drawables
** $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 .........:
**
** 06.08.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "drawable_line.h"
#include <QtWidgets/QGraphicsLineItem>
namespace SituationMap { namespace RB
{
DrawableLine::DrawableLine(Esri::ArcGISRuntime::MapGraphicsView * map)
: RubberbandDrawable(map)
, _lineItem(nullptr)
, _lineStyle()
, _dottedLine(false)
{
_lineItem = new QGraphicsLineItem();
_scene -> addItem( _lineItem );
makeLineStyle( _dottedLine, _lineStyle );
_lineItem -> setPen( _lineStyle );
} /* DrawableLine::DrawableLine */
DrawableLine::DrawableLine(Esri::ArcGISRuntime::MapGraphicsView * map, QGraphicsScene * scene)
: RubberbandDrawable(map, scene)
, _lineItem(nullptr)
, _lineStyle()
, _dottedLine(false)
{
_lineItem = new QGraphicsLineItem();
_scene -> addItem( _lineItem );
makeLineStyle( _dottedLine, _lineStyle );
_lineItem -> setPen( _lineStyle );
} /* DrawableLine::DrawableLine */
DrawableLine::~DrawableLine()
{
if (_scene)
{
if (_lineItem)
{
_scene->removeItem(_lineItem);
delete _lineItem;
}
}
_lineItem = nullptr;
} /* DrawableLine::~DrawableLine */
void DrawableLine::setLine( const RubberbandDrawable::RubberbandCoordinate & p1, const RubberbandDrawable::RubberbandCoordinate & p2 )
{
_lineCoordinates[0] = p1;
_lineCoordinates[1] = p2;
updateGraphic();
} /* DrawableLine::setPath */
void DrawableLine::updateGraphic()
{
_lineCoordinates[0].mapToScene(_mapView);
_lineCoordinates[1].mapToScene(_mapView);
qreal x1 = _lineCoordinates[0]._sceneCoordinate.x();
qreal y1 = _lineCoordinates[0]._sceneCoordinate.y();
qreal x2 = _lineCoordinates[1]._sceneCoordinate.x();
qreal y2 = _lineCoordinates[1]._sceneCoordinate.y();
makeLineStyle( _dottedLine, _lineStyle );
_lineItem -> setLine( x1,y1,x2,y2 );
_lineItem -> setPen( _lineStyle );
_lineItem -> setVisible( _isVisible );
} /* DrawableLine::updateGraphic */
void DrawableLine::adjustCoordinates() { updateGraphic(); }
void DrawableLine::adjustWindow( const QRectF& ) { updateGraphic(); }
} } /* namespace SituationMap::RB */
+68
View File
@@ -0,0 +1,68 @@
/**
**
** @RDE_HEADER@
** Definition of line drawable
** $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 "rubberband_drawable.h"
namespace SituationMap { namespace RB
{
class DrawableLine : public RubberbandDrawable
{
Q_OBJECT
public:
explicit DrawableLine( Esri::ArcGISRuntime::MapGraphicsView * );
explicit DrawableLine( Esri::ArcGISRuntime::MapGraphicsView *, QGraphicsScene * );
~DrawableLine();
DrawableLine(const RubberbandDrawable &) = delete;
DrawableLine & operator = (const RubberbandDrawable &) = delete;
void setLine( const RubberbandDrawable::RubberbandCoordinate & p1, const RubberbandDrawable::RubberbandCoordinate & p2 );
inline void dottedLine(bool on = true) { _dottedLine = on; }
protected:
QGraphicsLineItem * _lineItem;
RubberbandDrawable::RubberbandCoordinate _lineCoordinates[2];
QPen _lineStyle;
bool _dottedLine;
void updateGraphic() override;
void adjustCoordinates() override;
void adjustWindow( const QRectF& ) override;
}; /* DrawableLine */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,152 @@
/**
**
** @RDE_HEADER@
** Implementation of path drawables
** $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.07.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "drawable_painter_path.h"
#include <QGraphicsPathItem>
#include <QPainterPath>
namespace SituationMap { namespace RB
{
DrawablePainterPath::DrawablePainterPath(Esri::ArcGISRuntime::MapGraphicsView * map)
: RubberbandDrawable(map)
, _painterPathItem(nullptr)
, _pathCoordinates()
, _lineStyle()
, _dottedPath(false)
, _closedLine(false)
, _fillSolid(false)
{
_painterPathItem = _scene->addPath( QPainterPath() );
_painterPathItem -> setFlags( QGraphicsItem::ItemIgnoresTransformations );
makeLineStyle( _dottedPath, _lineStyle );
_painterPathItem -> setPen ( (_drawColor.alpha()) ? QPen(_drawColor) : QPen() );
_fillColor.setAlpha(0);
_painterPathItem -> setBrush( (_fillColor.alpha()) ? QBrush(_fillColor) : QBrush() );
} /* DrawablePainterPath::DrawablePainterPath */
DrawablePainterPath::DrawablePainterPath(Esri::ArcGISRuntime::MapGraphicsView * map, QGraphicsScene * scene)
: RubberbandDrawable(map, scene)
, _painterPathItem(nullptr)
, _pathCoordinates()
, _lineStyle()
, _dottedPath(false)
, _closedLine(false)
, _fillSolid(false)
{
_painterPathItem = _scene->addPath( QPainterPath() );
_painterPathItem -> setFlags( QGraphicsItem::ItemIgnoresTransformations );
makeLineStyle( _dottedPath, _lineStyle );
_painterPathItem -> setPen ( (_drawColor.alpha()) ? _lineStyle : QPen() );
_fillColor.setAlpha(0);
_painterPathItem -> setBrush( (_fillColor.alpha()) ? QBrush(_fillColor) : QBrush() );
} /* DrawablePainterPath::DrawablePainterPath */
DrawablePainterPath::~DrawablePainterPath()
{
if (_scene)
{
if (_painterPathItem)
{
_scene->removeItem(_painterPathItem);
delete _painterPathItem;
}
_painterPathItem = nullptr;
}
} /* DrawablePainterPath::~DrawablePainterPath */
void DrawablePainterPath::setPath( const QVector<RubberbandDrawable::RubberbandCoordinate> & path )
{
_pathCoordinates = path;
updateGraphic();
} /* DrawablePainterPath::setPath */
void DrawablePainterPath::setPath( const QVector<QPointF> & scenePath )
{
_pathCoordinates.clear();
_pathCoordinates.reserve( scenePath.size() );
for ( auto p : scenePath )
{
_pathCoordinates.append( RubberbandDrawable::RubberbandCoordinate(_mapView,p) );
}
updateGraphic();
} /* DrawablePainterPath::setPath */
void DrawablePainterPath::updateGraphic()
{
DEBUG_LOG(_logger) << LOGFUNCTION;
if ((_closedLine) && (_pathCoordinates.size() < 3))
{
_painterPathItem -> setVisible( false );
return;
}
QPainterPath painterPath;
QVector<RubberbandDrawable::RubberbandCoordinate>::iterator it = _pathCoordinates.begin();
if (it != _pathCoordinates.end())
{
painterPath.moveTo( it->mapToScene(_mapView) );
DEBUG_LOG(_logger) << LOGFUNCTION << " map-x = " << it->_mapCoordinate.x() << " map-y = " << it->_mapCoordinate.y();
while (true)
{
++it;
if (it == _pathCoordinates.end()) break;
painterPath.lineTo( it->mapToScene(_mapView) );
DEBUG_LOG(_logger) << LOGFUNCTION << " map-x = " << it->_mapCoordinate.x() << " map-y = " << it->_mapCoordinate.y();
}
if (_closedLine) painterPath.closeSubpath();
}
const QColor &fillColor = transparentFillColor();
makeLineStyle( _dottedPath, _lineStyle );
_painterPathItem -> setVisible( _isVisible );
_painterPathItem -> setPen ( (_drawColor.alpha() > 0) ? _lineStyle : QPen() );
_painterPathItem -> setBrush( ( fillColor.alpha() > 0) ? QBrush(fillColor) : QBrush() );
_painterPathItem -> setZValue( _zBufferValue );
_painterPathItem -> setPath( painterPath );
} /* DrawablePainterPath::updateGraphic */
void DrawablePainterPath::adjustCoordinates() { updateGraphic(); }
void DrawablePainterPath::adjustWindow( const QRectF& ) { updateGraphic(); }
} } /* namespace SituationMap::RB */
@@ -0,0 +1,75 @@
/**
**
** @RDE_HEADER@
** Definition of base class for rubberband drawing objects
** $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 "rubberband_drawable.h"
namespace SituationMap { namespace RB
{
class DrawablePainterPath : public RubberbandDrawable
{
Q_OBJECT
public:
explicit DrawablePainterPath( Esri::ArcGISRuntime::MapGraphicsView * );
explicit DrawablePainterPath( Esri::ArcGISRuntime::MapGraphicsView *, QGraphicsScene * );
~DrawablePainterPath();
DrawablePainterPath(const RubberbandDrawable &) = delete;
DrawablePainterPath & operator = (const RubberbandDrawable &) = delete;
void setPath( const QVector<QPointF> & scenePath );
void setPath( const QVector<RubberbandDrawable::RubberbandCoordinate> & path );
inline void enableClosedLine(bool on = true) { _closedLine = on; }
inline void dottedPath(bool on = true) { _dottedPath = on; }
inline void fillSolid(bool on = true) { _fillSolid = on; }
protected:
QGraphicsPathItem * _painterPathItem;
QVector<RubberbandDrawable::RubberbandCoordinate> _pathCoordinates;
QPen _lineStyle;
bool _dottedPath;
bool _closedLine;
bool _fillSolid;
void updateGraphic() override;
void adjustCoordinates() override;
void adjustWindow( const QRectF& ) override;
}; /* DrawablePainterPath */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,127 @@
/**
**
** @RDE_HEADER@
** Implementation of line drawables
** $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 .........:
**
** 06.08.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "drawable_smooth_path.h"
#include <QPainterPath>
#include <QGraphicsPathItem>
#include <MathUtils/curve.h>
#include <MathUtils/path_rasterer.h>
namespace SituationMap { namespace RB
{
DrawableSmoothPath::DrawableSmoothPath(Esri::ArcGISRuntime::MapGraphicsView * map)
: DrawablePainterPath(map)
, _smoothLine( new SituationMap::MathUtils::SmoothLine() )
{
_pathRasterer = _smoothLine->createPathRaster();
} /* DrawableSmoothPath::DrawableLine */
DrawableSmoothPath::DrawableSmoothPath(Esri::ArcGISRuntime::MapGraphicsView * map, QGraphicsScene * scene)
: DrawablePainterPath(map, scene)
, _smoothLine( new SituationMap::MathUtils::SmoothLine() )
{
_pathRasterer = _smoothLine->createPathRaster();
} /* DrawableSmoothLine::DrawableLine */
DrawableSmoothPath::~DrawableSmoothPath()
{
delete _pathRasterer;
delete _smoothLine;
_pathRasterer = nullptr;
_smoothLine = nullptr;
} /* DrawableSmoothPath::~DrawableSmoothPath */
void DrawableSmoothPath::setPath( const QVector<RubberbandDrawable::RubberbandCoordinate> & vertexVector )
{
_pathCoordinates = vertexVector;
updateGraphic();
} /* DrawableSmoothPath::setPath */
void DrawableSmoothPath::updateGraphic()
{
if (_pathCoordinates.size() > 2)
{
makeLineStyle( _dottedPath, _lineStyle );
_painterPathItem -> setPen( _lineStyle );
_painterPathItem -> setVisible( _isVisible );
if (_closedLine)
{
const QColor &fillColor = transparentFillColor();
_painterPathItem -> setBrush( (fillColor.alpha() > 0) ? QBrush(fillColor) : QBrush() );
}
else _painterPathItem -> setBrush( QBrush() );
QVector<QPointF> vertexVector;
vertexVector.reserve( _pathCoordinates.size() );
for (auto vertex : qAsConst(_pathCoordinates))
{
vertex.mapToScene(_mapView);
vertexVector.append( vertex._sceneCoordinate );
}
_smoothLine -> vertexVector( vertexVector, _closedLine );
_pathRasterer -> epsilon( 2 );
_pathRasterer -> maxVertexCount( 1000 );
_pathRasterer -> rasterize( _smoothLine->minimumCurveParameter(), _smoothLine->maximumCurveParameter(), vertexVector );
QPainterPath path;
if (vertexVector.size() > 1)
{
QVector<QPointF>::const_iterator vit = vertexVector.constBegin();
path.moveTo( *vit );
for (++vit; vit != vertexVector.end(); ++vit)
{
path.lineTo( *vit );
}
if (_closedLine) path.lineTo( QPointF(path.elementAt(0)) );
}
_painterPathItem->setPath(path);
}
else _painterPathItem ->setVisible(false);
} /* DrawableSmoothPath::updateGraphic */
void DrawableSmoothPath::adjustCoordinates() { updateGraphic(); }
void DrawableSmoothPath::adjustWindow( const QRectF& ) { updateGraphic(); }
} } /* namespace SituationMap::RB */
+77
View File
@@ -0,0 +1,77 @@
/**
**
** @RDE_HEADER@
** Definition of line drawable
** $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 "drawable_painter_path.h"
namespace SituationMap {
namespace MathUtils
{
class SmoothLine;
class PathRasterer;
}
namespace RB
{
class DrawableSmoothPath : public DrawablePainterPath
{
Q_OBJECT
public:
explicit DrawableSmoothPath( Esri::ArcGISRuntime::MapGraphicsView * );
explicit DrawableSmoothPath( Esri::ArcGISRuntime::MapGraphicsView *, QGraphicsScene * );
~DrawableSmoothPath();
DrawableSmoothPath(const DrawableSmoothPath &) = delete;
DrawableSmoothPath & operator = (const DrawableSmoothPath &) = delete;
void setPath( const QVector<RubberbandDrawable::RubberbandCoordinate> & vertexVector );
protected:
SituationMap::MathUtils::SmoothLine * _smoothLine;
SituationMap::MathUtils::PathRasterer * _pathRasterer;
void updateGraphic() override;
void adjustCoordinates() override;
void adjustWindow( const QRectF& ) override;
}; /* DrawableSmoothPath */
} /* namespace RB */
} /* namespace SituationMap */
+72
View File
@@ -0,0 +1,72 @@
/**
**
** @RDE_HEADER@
** Event Dispatcher for Qt5 to delegate mouse and keyboard event to another event dispatcher
** $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 .........:
**
** 15.04.2015, JT : First edition
**
** -----------------------------------------------------------------------------------------------
*/
#include "event_delegater.h"
namespace SituationMap { namespace RB
{
EventDelegater::EventDelegater(QWidget * getEventsFrom, AbstractEventDispatcher * delegateEventTo)
: AbstractEventDispatcher(getEventsFrom), _delegateEventTo(delegateEventTo)
{
connect( delegateEventTo, &AbstractEventDispatcher::signalKickTheBucket,
this , &AbstractEventDispatcher::onDo_kickTheBucket );
connect( this , &AbstractEventDispatcher::signalKickTheBucket,
delegateEventTo, &AbstractEventDispatcher::onDo_kickTheBucket );
_restoreMouseTracking = delegateEventTo->_restoreMouseTracking;
_whatsThisBackup = delegateEventTo->_whatsThisBackup;
} /* EventDispatcher::EventDispatcher */
bool EventDelegater::eventFilter(QObject * watched, QEvent * e)
{
if (hasFinished()) return true; // don't accept new events if dispatcher is going to finish
if (hasActiveEvent()) return true; // don't accept new events before last event has been handled completly
if (_delegateEventTo != nullptr)
{
return _delegateEventTo->eventFilter( watched, e );
}
return false;
} /* EventDispatcher::eventFilter */
void EventDelegater::KickTheBucket()
{
if (_delegateEventTo != nullptr)
{
_delegateEventTo->unlinkEventDispatcher();
}
AbstractEventDispatcher::KickTheBucket();
} /* EventDelegater::KickTheBucket */
} } /* namespace SituationMap::RB */
+72
View File
@@ -0,0 +1,72 @@
/**
**
** @RDE_HEADER@
** Event Dispatcher for Qt5 to delegate mouse and keyboard event to another event dispatcher
** $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 .........:
**
** 15.04.2015, JT : first edition
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <QtCore/QPointer>
#include "abstract_event_dispatcher.h"
namespace SituationMap { namespace RB
{
/**
@class EventDelegater event_delegater.h
@brief Event filter that delegates events to another event filter
Some Qt-Widgets have a special viewport widget. In this case keyboard and mouse events
are sended to different widgets. To concentrate the event handling in one event filter
for both types of events, it is necessary to forward events from event filter to another
one.
@see AbstractEventDispatcher, EventDispatcher, EventMouseNavigator
*/
class EventDelegater final : public AbstractEventDispatcher
{
Q_OBJECT
public:
EventDelegater( QWidget * getEventsFrom, AbstractEventDispatcher * delegateEventTo );
~EventDelegater() = default;
EventDelegater(const EventDelegater &) = delete;
EventDelegater & operator = (const EventDelegater &) = delete;
protected:
QPointer<AbstractEventDispatcher> _delegateEventTo;
bool eventFilter(QObject*, QEvent*) override;
void KickTheBucket() override;
}; /* EventDelegater */
} } /* namespace SituationMap::RB */
+626
View File
@@ -0,0 +1,626 @@
/**
**
** @RDE_HEADER@
** Event Dispatcher for Qt5 to handle mouse and keyboard event
** $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 .........:
**
** 28.04.2003, JT : First edition for use with Qt4 in START Feature Editor fee
** 25.03.2015, JT : Refactoring for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "event_dispatcher.h"
#include "gestures.h"
#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
#include <QtGui/QWheelEvent>
#include <QtWidgets/QGesture>
#include <QtWidgets/QWidget>
#include <QMetaMethod>
namespace SituationMap { namespace RB
{
EventDispatcher::EventDispatcher(QWidget * getEventsFrom)
: AbstractEventDispatcher(getEventsFrom)
, _snapEnabled(false)
, _snapRatio(5)
, _drawRatio(false)
, _doubleClickHandled(false)
, _leftPressHandled(false)
{
} /* EventDispatcher::EventDispatcher */
EventDispatcher::EventDispatcher(QWidget * getEventsFrom, EventActionInterface * eventActions )
: AbstractEventDispatcher(getEventsFrom, eventActions)
, _snapEnabled(false)
, _snapRatio(5)
, _drawRatio(false)
, _doubleClickHandled(false)
, _leftPressHandled(false)
{
} /* EventDispatcher::EventDispatcher */
bool EventDispatcher::eventFilterKey( int key, Qt::KeyboardModifiers mod )
{
QPoint moveDelta;
int multiply ( (mod.testFlag(Qt::KeyboardModifier::ShiftModifier)) ? 10 : 1);
bool controlKey( (mod.testFlag(Qt::KeyboardModifier::ControlModifier)) );
switch (key)
{
case Qt::Key_Delete : return onDoDelete(); break;
case Qt::Key_Z : if (controlKey) return onDoUndo(); break;
case Qt::Key_Escape : return onDoEscape(); break;
case Qt::Key_Return : return onDoEnd(); break;
case Qt::Key_Left : moveDelta = QPoint(-1, 0)*multiply; break;
case Qt::Key_Right : moveDelta = QPoint( 1, 0)*multiply; break;
case Qt::Key_Up : moveDelta = QPoint( 0,-1)*multiply; break;
case Qt::Key_Down : moveDelta = QPoint( 0, 1)*multiply; break;
default : return false;
} /* switch */
if (_getEventsFrom != nullptr)
{
QPoint cursorPos = _getEventsFrom->mapFromGlobal( QCursor::pos() );
onPress( cursorPos.x(), cursorPos.y(), mod );
cursorPos += moveDelta;
onMove ( cursorPos.x(), cursorPos.y(), Qt::MouseButton::LeftButton, mod );
onClick( cursorPos.x(), cursorPos.y(), mod );
QCursor::setPos( _getEventsFrom->mapToGlobal(cursorPos) );
}
return true;
} /* EventDispatcher::eventFilterKey */
bool EventDispatcher::eventFilterGesture( QGestureEvent * gestureEvent )
{
bool handled = false;
if (gestureEvent)
{
const QList<QGesture*> & gestureList = gestureEvent->gestures();
for (auto gesture : gestureList)
{
Qt::GestureType gestureType = gesture->gestureType();
Qt::GestureState gestureState = gesture->state();
QTapGesture * tapGesture = nullptr;
QTapAndHoldGesture * tapAndHoldGesture = nullptr;
QPanGesture * panGesture = nullptr;
QPinchGesture * pinchGesture = nullptr;
QSwipeGesture * swipeGesture = nullptr;
ApplyGesture * applyGesture = nullptr;
QString typeName;
QString stateName;
switch (gestureType)
{
case Qt::TapGesture : tapGesture = static_cast<QTapGesture *>(gesture); typeName = QLatin1String("TapGesture"); break;
case Qt::TapAndHoldGesture : tapAndHoldGesture = static_cast<QTapAndHoldGesture*>(gesture); typeName = QLatin1String("TapAndHoldGesture"); break;
case Qt::PanGesture : panGesture = static_cast<QPanGesture *>(gesture); typeName = QLatin1String("PanGesture"); break;
case Qt::PinchGesture : pinchGesture = static_cast<QPinchGesture *>(gesture); typeName = QLatin1String("PinchGesture"); break;
case Qt::SwipeGesture : swipeGesture = static_cast<QSwipeGesture *>(gesture); typeName = QLatin1String("SwipeGesture"); break;
default:
{
if (gestureType == _applyGestureID)
{
applyGesture = static_cast<ApplyGesture*>(gesture);
typeName = QLatin1String("ApplyGesture");
}
} break;
}
switch (gestureState)
{
case Qt::NoGesture : stateName = QLatin1String("NoGesture"); break;
case Qt::GestureStarted : stateName = QLatin1String("GestureStarted"); break;
case Qt::GestureUpdated : stateName = QLatin1String("GestureUpdated"); break;
case Qt::GestureFinished : stateName = QLatin1String("GestureFinished"); break;
case Qt::GestureCanceled : stateName = QLatin1String("GestureCanceled"); break;
}
DEBUG_LOG(_logger) << LOGFUNCTION << " Gesture type=" << typeName << " Gesture state=" << stateName;
if (panGesture)
{
const QPoint & offset = panGesture->offset().toPoint();
const QPoint & hotSpot = _getEventsFrom->mapFromGlobal( panGesture->hotSpot().toPoint() );
switch (gestureState)
{
case Qt::GestureStarted:
{
handled = onPress( hotSpot.x(), hotSpot.y(), nullptr );
if (handled) gestureEvent -> accept( panGesture );
} break;
case Qt::GestureUpdated:
handled = onMove ( hotSpot.x() + offset.x(), hotSpot.y() + offset.y(), Qt::MouseButton::LeftButton, nullptr );
break;
case Qt::GestureFinished:
// handled = onMove ( hotSpot.x() + offset.x(), hotSpot.y() + offset.y(), Qt::MouseButton::LeftButton, 0 );
handled = onClick( hotSpot.x() + offset.x(), hotSpot.y() + offset.y(), nullptr );
break;
case Qt::GestureCanceled:
getEventActions()->resetAction( this, 0, 0 );
break;
default:
break;
}
}
if (applyGesture)
{
switch (gestureState)
{
case Qt::GestureStarted : gestureEvent -> accept( applyGesture ); break;
case Qt::GestureFinished :
{
getEventActions()->resetAction( this, qRound(applyGesture->position().x()), qRound(applyGesture->position().y()) );
handled = onDoubleClick( qRound(applyGesture->position().x()), qRound(applyGesture->position().y()), nullptr );
if (handled)
{
gestureEvent -> accept( applyGesture );
return true;
}
} break;
default : break;
}
}
// currently not used
Q_UNUSED(handled);
Q_UNUSED(tapGesture);
Q_UNUSED(tapAndHoldGesture);
Q_UNUSED(pinchGesture);
Q_UNUSED(swipeGesture);
}
}
return handled;
} /* EventDispatcher::eventFilerGesture */
bool EventDispatcher::eventFilterWheel( QWheelEvent * e )
{
const int WHEEL_DELTA = 120; // natural mouse driver constant
if (e->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier) &&
e->buttons().testFlag(Qt::MidButton))
{
int newValue = (int)_snapRatio + (e->angleDelta() / WHEEL_DELTA).manhattanLength();
_snapRatio = (newValue < 5) ? 5 : newValue;
return onMove( e->x(), e->y(), e->buttons(), e->modifiers() );
}
return false;
} /* EventDispatcher::eventFilterWheel */
bool EventDispatcher::eventFilter( QObject * watched, QEvent * e )
{
// Maybe ???
// qCritical() << " _getEventsFrom = " << _getEventsFrom
// << " watched = " << watched
// << " e->type() = " << e->type();
// if (watched != _getEventsFrom)
// return AbstractEventDispatcher::eventFilter(watched,e);
Q_UNUSED(watched);
QString debugString(QLatin1String("unhandled event"));
if (hasFinished()) return true; // don't accept new events if dispatcher is going to finish
if (hasActiveEvent()) return true; // don't accept new events before last event has been handled completly
if (e)
{
bool handled( false );
setActiveEvent( true );
switch( e->type() )
{
case QEvent::Enter :
{
debugString = QLatin1String("enter event");
_getEventsFrom -> setFocus();
_doubleClickHandled = false;
_leftPressHandled = false;
} break;
case QEvent::Leave : _doubleClickHandled = _leftPressHandled = false; break;
case QEvent::GraphicsSceneMousePress : break;
case QEvent::MouseButtonPress :
{
debugString = QLatin1String("mouse button press event");
_doubleClickHandled = false;
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
if (Qt::RightButton == mouseEvent->button())
{
handled = onMenuPress( mouseEvent->x()
, mouseEvent->y()
, mouseEvent->modifiers() );
}
if (Qt::LeftButton == mouseEvent->button())
{
if (!(mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier)))
{
handled = onPress( mouseEvent->x()
, mouseEvent->y()
, mouseEvent->modifiers() );
if (handled) _leftPressHandled = true;
}
}
if (Qt::MidButton == mouseEvent->button())
{
handled = mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier);
}
} break;
case QEvent::TouchBegin:
{
debugString = QLatin1String("mouse button press event TOUCH");
_doubleClickHandled = false;
QTouchEvent *mouseEvent = static_cast<QTouchEvent*>(e);
if (mouseEvent->touchPoints().size() > 0)
{
const QTouchEvent::TouchPoint tp = mouseEvent->touchPoints().at(0);
handled = onPress( tp.pos().x()
, tp.pos().y()
, mouseEvent->modifiers() );
if (handled) _leftPressHandled = true;
}
break;
}
case QEvent::GraphicsSceneMouseDoubleClick : break;
case QEvent::MouseButtonDblClick :
{
debugString = QLatin1String("mouse double click event");
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
if (Qt::LeftButton == mouseEvent->button())
{
if (!(mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier)))
{
onDoubleClick( mouseEvent->x()
, mouseEvent->y()
, mouseEvent->modifiers() );
_doubleClickHandled = handled = true;
}
}
} break;
case QEvent::GraphicsSceneMouseRelease : break;
case QEvent::MouseButtonRelease :
{
if (!_doubleClickHandled)
{
debugString = QLatin1String("mouse button release event");
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
if (Qt::RightButton == mouseEvent->button())
{
handled = onMenuClick( mouseEvent->x()
, mouseEvent->y()
, mouseEvent->modifiers() );
}
if (Qt::LeftButton == mouseEvent->button())
{
if (!(mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier)))
{
// The mouse button press event must had be handled before. If not skip button release ...
if (_leftPressHandled)
{
_leftPressHandled = false;
handled = onClick( mouseEvent->x()
, mouseEvent->y()
, mouseEvent->modifiers() );
}
else callEventAction( &EventActionInterface::buttonPositionAction, mouseEvent->x(), mouseEvent->y() );
}
}
if (Qt::MidButton == mouseEvent->button())
{
handled = mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier);
}
}
else _doubleClickHandled = false;
} break;
case QEvent::TouchEnd:
{
debugString = QLatin1String("mouse button release event TOUCH");
QTouchEvent *mouseEvent = static_cast<QTouchEvent*>(e);
// The mouse button press event must had be handled before. If not skip button release ...
if (mouseEvent->touchPoints().size() > 0)
{
const QTouchEvent::TouchPoint tp = mouseEvent->touchPoints().at(0);
if (_leftPressHandled)
{
_leftPressHandled = false;
handled = onClick( tp.pos().x()
, tp.pos().y()
, mouseEvent->modifiers() );
}
else
{
callEventAction( &EventActionInterface::buttonPositionAction, tp.pos().x(), tp.pos().y() );
}
}
break;
}
case QEvent::GraphicsSceneMouseMove : break;
case QEvent::MouseMove :
{
debugString = QLatin1String("mouse move event");
_doubleClickHandled = false;
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
if (mouseEvent->buttons() != Qt::MidButton)
{
if (!(mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier)))
{
if (_drawRatio)
{
if (!(mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::AltModifier)))
{
_drawRatio = false;
}
}
else
{
if (mouseEvent->modifiers().testFlag(Qt::KeyboardModifier::AltModifier))
{
_drawRatio = true;
}
}
handled = onMove( mouseEvent->x()
, mouseEvent->y()
, mouseEvent->buttons()
, mouseEvent->modifiers());
// REGG-5230 - PlanEditor: Position beim Erstellen und Modifizieren
// von Elementen wird nicht aktualisiert
// Next handler is EventMouseNavigator. ::eventFilter() will handle
// QEvent::MouseMove and emit mouseMovedEvent to update PositionStr.
// If handled == true, the next handler is NOT called.
// So emit here alternatively.
if (handled)
emit mouseMovedEvent(mouseEvent->pos().x(), mouseEvent->pos().y());
}
}
} break;
case QEvent::TouchUpdate:
{
debugString = QLatin1String("mouse move event Touch");
_doubleClickHandled = false;
QTouchEvent* mouseEvent = static_cast<QTouchEvent*>(e);
if (mouseEvent->touchPoints().size() > 0)
{
const QTouchEvent::TouchPoint tp = mouseEvent->touchPoints().at(0);
handled = onMove( tp.pos().x()
, tp.pos().y()
, Qt::LeftButton
, mouseEvent->modifiers());
}
break;
}
case QEvent::KeyPress :
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(e);
debugString = QStringLiteral("key press event (%1)").arg(keyEvent->key());
handled = eventFilterKey( keyEvent->key(),keyEvent->modifiers() );
if ((keyEvent->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier)) || (keyEvent->key() == Qt::Key_Control))
{
setSnapEnabled( true );
_drawRatio = true;
handled = true;
}
} break;
case QEvent::KeyRelease :
{
debugString = QLatin1String("key release event");
if (_drawRatio)
{
_drawRatio = false;
setSnapEnabled( true );
}
// handled = true;
} break;
case QEvent::Wheel :
{
debugString = QLatin1String("mouse wheel event");
QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(e);
if (wheelEvent->modifiers() & (Qt::KeyboardModifier::ShiftModifier | Qt::KeyboardModifier::ControlModifier))
{
handled = eventFilterWheel( wheelEvent );
}
} break;
case QEvent::Gesture:
{
handled = eventFilterGesture( static_cast<QGestureEvent*>(e) );
} break;
default: break;
} /* switch */
if (!hasFinished()) setActiveEvent( false );
if (handled) e->accept();
TRACE_LOG(_logger) << LOGFUNCTION << " Event " << debugString << " handled = " << handled;
if (handled) return true;
}
return AbstractEventDispatcher::eventFilter(watched,e);
} /* EventDispatcher::eventFilter */
bool EventDispatcher::onMove(int x, int y, Qt::MouseButtons buttons, Qt::KeyboardModifiers mod)
{
Q_UNUSED(mod);
if (buttons.testFlag(Qt::MouseButton::LeftButton)) return callEventAction( &EventActionInterface::movePickedAction, x, y );
return callEventAction( &EventActionInterface::moveAction, x, y );
} /* EventDispatcher::onMove */
bool EventDispatcher::onPress(int x, int y, Qt::KeyboardModifiers mod)
{
if (mod == Qt::NoModifier)
return callEventAction( &EventActionInterface::selectAction, x, y );
if (mod.testFlag(Qt::KeyboardModifier::ShiftModifier))
return callEventAction( &EventActionInterface::multiSelectActionPress, x, y );
return false;
} /* EventDispatcher::onPress */
bool EventDispatcher::onClick(int x, int y, Qt::KeyboardModifiers mod)
{
Q_UNUSED(x);
Q_UNUSED(y);
if (mod == Qt::NoModifier)
{
bool ret = callEventAction( &EventActionInterface::setCoordinateAction, x, y );
if (ret)
{
EventActionInterface * eaIf = getEventActions();
if (eaIf) eaIf->userActionFinished();
}
return ret;
}
if (mod.testFlag( Qt::KeyboardModifier::ShiftModifier ))
return callEventAction( &EventActionInterface::multiSelectActionRelease, x, y );
return false;
} /* EventDispatcher::onClick */
bool EventDispatcher::onMenuPress(int x, int y, Qt::KeyboardModifiers mod)
{
Q_UNUSED(x);
Q_UNUSED(y);
Q_UNUSED(mod);
return false;
} /* EventDispatcher::onMenuPress */
bool EventDispatcher::onMenuClick(int x, int y, Qt::KeyboardModifiers mod)
{
Q_UNUSED(mod);
return callEventAction( &EventActionInterface::contextMenuAction, x, y );
} /* EventDispatcher::onMenuClick */
bool EventDispatcher::onDoubleClick(int x, int y, Qt::KeyboardModifiers )
{
callEventAction( &EventActionInterface::completeStateAction, x, y );
return true;
} /* EventDispatcher::onDoubleClick */
bool EventDispatcher::onDoDelete()
{
if (_getEventsFrom != nullptr)
{
QPoint cursorPos = _getEventsFrom->mapFromGlobal( QCursor::pos() );
callEventAction( &EventActionInterface::selectAction, cursorPos.x(), cursorPos.y() );
bool ret = callEventAction( &EventActionInterface::deleteAction, cursorPos.x(), cursorPos.y() );
if (ret)
{
EventActionInterface * eaIf = getEventActions();
if (eaIf) eaIf->userActionFinished();
}
return ret;
}
return false;
} /* EventDispatcher::onDoDelete */
bool EventDispatcher::onDoUndo()
{
bool ret = callEventAction( &EventActionInterface::undoAction, 0, 0 );
if (ret)
{
EventActionInterface * eaIf = getEventActions();
if (eaIf) eaIf->userActionFinished();
}
return ret;
} /* EventDispatcher::onDoUndo */
bool EventDispatcher::onDoEscape()
{
EventActionInterface * eventActions = getEventActions();
KickTheBucket();
if (eventActions) eventActions->abortAction( this, 0, 0 );
return true;
} /* EventDispatcher::onDoEscape */
bool EventDispatcher::onDoEnd()
{
EventActionInterface * eventActions = getEventActions();
KickTheBucket();
if (eventActions) eventActions->applyAndEndAction( this, 0, 0 );
return true;
} /* EventDispatcher::onDoEnd */
} } /* namespace SituationMap::RB */
+140
View File
@@ -0,0 +1,140 @@
/**
**
** @RDE_HEADER@
** Event Dispatcher for Qt5 to handle mouse and keyboard event
** $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 .........:
**
** 28.04.2003, JT : First edition for use with Qt4 in START Feature Editor fee
** 25.03.2015, JT : Refactoring for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "abstract_event_dispatcher.h"
class QGestureEvent;
class QWheelEvent;
namespace SituationMap { namespace RB
{
/**
@class EventDispatcher event_dispatcher.h
@brief Event filter that handles events when a rubberband it active.
Implements class \c AbstractEventDispatcher to manage event handling for rubberbands. Following events are handled:
| Input-Event | Interface Function | Description |
| :--------------------------------------------- | : ----------------- | : ------------------------------------------------------------------------------------------------------ |
| Mouse move without any modifier | moveAction | Move Cursor or preview |
| Mouse move with pressed left button | movePickedAction | Move selected items. If movePickedAction == false redirect to \c EventMouseNavigator for panning of map. |
| Mouse move with pressed middle button | | Redirect to \c EventMouseNavigator for panning of map |
| Mouse wheel | | Redirect to \c EventMouseNavigator for zooming of map |
| Left mouse button press | selectAction | Do selection of single item or panning of map. |
| Left mouse button press with pressed SHIFT key | multiSelectAction | Do selection of multiple items. |
| Left mouse button release | setCoordinateAction | Set final coordinate to selected items and deselects item. |
| Double click left mouse button | completeStateAction | Finish input. |
| Right mouse button release | contextMenuAction | Show context menu. |
| Key release CTRL-Z | undoMenuAction | Undo last left mouse button click if possible. |
| Key release Delete | deleteMenuAction | Delete selected item. |
| Key release ESC | abortAction | Abort rubberband without saving data. The rubberband emits the abort signal. |
| Key release RETURN | applyAndEndAction | Finish rubberband. The rubberband emits the apply signal. |
| Key release UP | moveAction | Moves 1 pixel up. |
| Key release DOWN | moveAction | Moves 1 pixel down. |
| Key release LEFT | moveAction | Moves 1 pixel left. |
| Key release RIGHT | moveAction | Moves 1 pixel right. |
| Key release UP with SHIFT key pressed | moveAction | Moves 10 pixel up. |
| Key release DOWN with SHIFT key pressed | moveAction | Moves 10 pixel down. |
| Key release LEFT with SHIFT key pressed | moveAction | Moves 10 pixel left. |
| Key release RIGHT with SHIFT key pressed | moveAction | Moves 10 pixel right. |
@see AbstractEventDispatcher, EventDelegater, EventMouseNavigator,
Rubberband, RubberbandPointFeature, RubberbandPointCluster,
RubberbandMultiPointFeature, RubberbandCorridor, RubberbandRectangle, RubberbandEllipse,
EventMouseNavigator
*/
class EventDispatcher final : public AbstractEventDispatcher
{
friend class RubberbandBase;
Q_OBJECT
public:
/**
@name Construction & Destruction
@{
*/
explicit EventDispatcher( QWidget * getEventsFrom );
explicit EventDispatcher( QWidget * getEventsFrom, EventActionInterface* );
~EventDispatcher() = default;
EventDispatcher(const EventDispatcher &) = delete;
EventDispatcher & operator = (const EventDispatcher &) = delete;
/** @} */
inline void setSnapEnabled(bool) {}
inline bool SnapEnabled() { return _snapEnabled; }
signals:
/**
Signal will be emitted if a mouse move is done (and if event is handled)
*/
void mouseMovedEvent(int windowPosX, int windowPosY);
protected:
bool eventFilter(QObject*, QEvent*) override;
bool eventFilterKey( int key, Qt::KeyboardModifiers mod );
bool eventFilterGesture( QGestureEvent * gestureEvent );
bool eventFilterWheel( QWheelEvent * );
private:
bool onMove (int x, int y, Qt::MouseButtons buttons, Qt::KeyboardModifiers mod); //!< Handle a mouse move event.
bool onPress ( int x, int y, Qt::KeyboardModifiers mod); //!< Handle left mouse button press event.
bool onClick ( int x, int y, Qt::KeyboardModifiers mod); //!< Handle left mouse button release event.
bool onMenuPress ( int x, int y, Qt::KeyboardModifiers mod); //!< Handle right mouse button press event.
bool onMenuClick ( int x, int y, Qt::KeyboardModifiers mod); //!< Handle right mouse button release event.
bool onDoubleClick( int x, int y, Qt::KeyboardModifiers mod); //!< Handle left mouse button double click event.
bool onDoDelete(); //!< Handle del key press event.
bool onDoUndo(); //!< Handle ctrl-c key press event.
bool onDoEscape(); //!< Handle esc key press event.
bool onDoEnd(); //!< Handle enter key press event.
bool _snapEnabled;
uint _snapRatio;
bool _drawRatio;
bool _doubleClickHandled;
bool _leftPressHandled;
}; /* EventDispatcher */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,643 @@
/**
**
** @RDE_HEADER@
** Event Dispatcher for Qt5 to delegate mouse and keyboard event to another event dispatcher
** $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 .........:
**
** 15.04.2015, JT : First edition
**
** -----------------------------------------------------------------------------------------------
*/
#include "event_mouse_navigator.h"
#include "rubberband.h"
#include <QtCore/QMetaMethod>
#include <QtCore/QtMath>
#include <QtGui/QMouseEvent>
#include <QtGui/QWheelEvent>
#include <QtWidgets/QGesture>
#include <QtWidgets/QWidget>
#include <MapImpl/map_impl.h>
#include <Map/situation_map_utils.h>
#include <arcgis/Map.h>
#include <arcgis/Layer.h>
#include <arcgis/FeatureLayer.h>
#include <arcgis/GraphicsOverlay.h>
#include <arcgis/Graphic.h>
#include <arcgis/MapGraphicsView.h>
#include <arcgis/SceneGraphicsView.h>
namespace SituationMap { namespace RB
{
int EventMouseNavigator::_pickTolerance = 5;
qreal EventMouseNavigator::_zoomFactorBase = 1.002;
EventMouseNavigator::EventMouseNavigator(QWidget * getEventsFrom, SituationMap::MapImpl *sitMap )
: AbstractEventDispatcher(getEventsFrom)
, _sitMap(sitMap)
, _cursorChanged(false)
, _viewPortPos(QPointF(-1, -1))
, _selectionMode(SelectionMode::NoSelection)
, _pendingRequest(RequestType::None)
, _mousePanningActive(false)
, _mousePanningActiveForCenterMapMidButton(false)
#ifdef SITUATIONMAP_OWN_WHEEL_HANDLING
, _mouseZoomTaskWatcher()
#endif
, _pressedMouseButton(Qt::NoButton)
{
// prepare identify:
switch (_sitMap->mode())
{
case Mode::Mode_2D:
connect( _sitMap->getEsriMapGraphicsView()
, &Esri::ArcGISRuntime::MapGraphicsView::identifyGraphicsOverlaysCompleted
, this
, &EventMouseNavigator::onGetPickingResult );
break;
case Mode::Mode_3D:
connect( _sitMap->getEsriSceneGraphicsView()
, &Esri::ArcGISRuntime::SceneGraphicsView::identifyGraphicsOverlaysCompleted
, this
, &EventMouseNavigator::onGetPickingResult );
break;
default:
// empty
break;
}
} // EventMouseNavigator::EventMouseNavigator
bool EventMouseNavigator::eventFilter(QObject * watched, QEvent * e)
{
Q_UNUSED(watched);
QString debugString(QLatin1String("unhandled event"));
if (hasFinished()) return true; // don't accept new events if dispatcher is going to finish
if (hasActiveEvent()) return true; // don't accept new events before last event has been handled completly
if (e)
{
bool handled( false );
setActiveEvent( true );
switch( e->type() )
{
case QEvent::Enter :
{
_pressedMouseButton = Qt::NoButton;
emit enterEvent();
} break;
case QEvent::Leave :
{
emit leaveEvent();
_pressedMouseButton = Qt::NoButton;
} break;
case QEvent::MouseButtonPress :
{
handled = false;
debugString = QLatin1String("mouse button press event");
QMouseEvent * mouseEvent = static_cast<QMouseEvent*>(e);
_pressedMouseButton = mouseEvent->button();
_mousePanningActive = false;
_mouseMoveRefPos = mouseEvent->pos(); // for panning
_restoreMouseCursor = getCursorFromWidget();
if (Qt::MidButton == mouseEvent->button())
{
handled = true;
_mousePanningActive = true;
_mousePanningActiveForCenterMapMidButton = false;
// setCursorToWidget( QCursor(Qt::CursorShape::ClosedHandCursor) );
}
} break;
case QEvent::TouchBegin :
{
handled = false;
debugString = QLatin1String("Touch button press event");
QTouchEvent * mouseEvent = static_cast<QTouchEvent*>(e);
_pressedMouseButton = Qt::MouseButton::LeftButton;
_mousePanningActive = false;
if (mouseEvent->touchPoints().size() > 0)
{
const QTouchEvent::TouchPoint tp = mouseEvent->touchPoints().at(0);
_mouseMoveRefPos = tp.pos().toPoint(); // for panning
_restoreMouseCursor = getCursorFromWidget();
}
} break;
case QEvent::MouseButtonRelease :
{
debugString = QLatin1String("mouse button release event");
QMouseEvent * mouseEvent = static_cast<QMouseEvent*>(e);
if (Qt::LeftButton == mouseEvent->button())
{
if (_cursorChanged)
{
setCursorToWidget(_restoreMouseCursor);
_cursorChanged = false;
}
/*
* The ESRI::MapView is doing panning on mouse move when left mouse button is pressed.
* To prevent selection in this case check mouse move distance.
*/
if (Qt::LeftButton == _pressedMouseButton && ((mouseEvent->pos() - _mouseMoveRefPos).manhattanLength() < 3) )
{
if (Rubberband::activeRubberbands(_sitMap).isEmpty())
{
handled = false; // pass event to esri map to click buttons
selectionRequested(mouseEvent->localPos());
// do not handled = true; because some buttons in GraphicsView needs to get the event later.
}
}
else
handled = true; // may be a double click catched at higher event filter
}
if (Qt::RightButton == mouseEvent->button())
{
handled = true;
pickRequested( mouseEvent->localPos() );
}
if ((Qt::MidButton == mouseEvent->button()))
{
if (!_mousePanningActiveForCenterMapMidButton)
{
// press MidButton and Release MidButton without panning in the meantime:
// center map to current mouse position:
// set viewpoint : (perform this only in 2D - MapGraphicsView <-> MapSceneView)
// (3D had different screenToLocation...)
Esri::ArcGISRuntime::MapGraphicsView *esriMapGraphicsView = _sitMap->getEsriMapGraphicsView();
if (esriMapGraphicsView)
{
const QPoint &mousePos = mouseEvent->pos();
const Esri::ArcGISRuntime::Point & mapCoordEsri = esriMapGraphicsView->screenToLocation(mousePos.x(), mousePos.y());
const Esri::ArcGISRuntime::Viewpoint & curVp = esriMapGraphicsView->currentViewpoint(Esri::ArcGISRuntime::ViewpointType::CenterAndScale);
const Esri::ArcGISRuntime::Viewpoint newVp(mapCoordEsri, curVp.targetScale());
esriMapGraphicsView->setViewpointAndWait(newVp); // sync / andWAIT
_getEventsFrom -> update();
}
}
}
if ((_mousePanningActive) || (Qt::MidButton == mouseEvent->button()))
{
handled = (Qt::MidButton == mouseEvent->button());
setCursorToWidget( _restoreMouseCursor );
}
_mousePanningActive = false;
} break;
case QEvent::TouchEnd :
{
debugString = QLatin1String("Touch button release event");
QTouchEvent * mouseEvent = static_cast<QTouchEvent*>(e);
if (mouseEvent->touchPoints().size() > 0)
{
const QTouchEvent::TouchPoint tp = mouseEvent->touchPoints().at(0);
if (_cursorChanged)
{
setCursorToWidget(_restoreMouseCursor);
_cursorChanged = false;
}
/*
* The ESRI::MapView is doing panning on mouse move when left mouse button is pressed.
* To prevent selection in this case check mouse move distance.
*/
if (Qt::LeftButton == _pressedMouseButton && ((tp.pos() - _mouseMoveRefPos).manhattanLength() < 3) )
{
if (Rubberband::activeRubberbands(_sitMap).isEmpty())
{
handled = false; // pass event to esri map to click buttons
selectionRequested(tp.pos());
// do not handled = true; because some buttons in GraphicsView needs to get the event later.
}
}
else
handled = true; // may be a double click catched at higher event filter
}
_mousePanningActive = false;
} break;
case QEvent::MouseMove :
{
handled = false;
debugString = QLatin1String("mouse button move event");
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
if (isSignalConnected(QMetaMethod::fromSignal(&EventMouseNavigator::mouseMovedEvent)))
{
emit mouseMovedEvent(mouseEvent->pos().x(), mouseEvent->pos().y());
}
if (_mousePanningActive)
{
handled = true;
if (mouseEvent->buttons().testFlag(Qt::MidButton))
{
_mousePanningActiveForCenterMapMidButton = true;
// move viewpoint : (perform this only in 2D - MapGraphicsView <-> MapSceneView)
// (3D had different screenToLocation...)
Esri::ArcGISRuntime::MapGraphicsView *esriMapGraphicsView = _sitMap->getEsriMapGraphicsView();
if (esriMapGraphicsView)
{
QPointF deltaMove = mouseEvent->pos()-_mouseMoveRefPos;
QPointF winCenter = QPointF( qreal(_getEventsFrom->width())*0.5, qreal(_getEventsFrom->height())*0.5 );
QPointF newCenter = winCenter-deltaMove;
_mouseMoveRefPos = mouseEvent->pos();
const Esri::ArcGISRuntime::Point & mapCoordEsri = esriMapGraphicsView->screenToLocation(newCenter.x(), newCenter.y());
const Esri::ArcGISRuntime::Viewpoint & curVp = esriMapGraphicsView->currentViewpoint(Esri::ArcGISRuntime::ViewpointType::CenterAndScale);
const Esri::ArcGISRuntime::Viewpoint newVp(mapCoordEsri, curVp.targetScale());
esriMapGraphicsView->setViewpointAndWait(newVp); // sync / andWAIT
_getEventsFrom -> update();
DEBUG_LOG(_logger) << LOGFUNCTION << " Panning to " << mapCoordEsri.x() << " - " << mapCoordEsri.y()
<< " newCenter pos=" << newCenter
<< " mouse pos=" << mouseEvent->pos()
<< " delta pos=" << deltaMove;
}
}
else
{
setCursorToWidget( _restoreMouseCursor );
_mousePanningActive = false;
}
// : move viewpoint
}
} break;
case QEvent::TouchUpdate :
{
handled = false;
debugString = QLatin1String("touch button move event");
QTouchEvent *mouseEvent = static_cast<QTouchEvent*>(e);
if (mouseEvent->touchPoints().size() > 0)
{
const QTouchEvent::TouchPoint tp = mouseEvent->touchPoints().at(0);
if (isSignalConnected(QMetaMethod::fromSignal(&EventMouseNavigator::mouseMovedEvent)))
{
emit mouseMovedEvent(tp.pos().x(), tp.pos().y());
}
if (_mousePanningActive)
{
handled = true;
}
else
{
setCursorToWidget( _restoreMouseCursor );
_mousePanningActive = false;
}
}
} break;
#ifdef SITUATIONMAP_OWN_WHEEL_HANDLING
case QEvent::Wheel :
{
debugString = QLatin1String("mouse wheel event");
handled = true;
if ((!_mouseZoomTaskWatcher.isValid()) || (_mouseZoomTaskWatcher.isDone()))
{
QWheelEvent * wheelEvent = static_cast<QWheelEvent*>(e);
qreal delta = wheelEvent->angleDelta().manhattanLength();
bool zoomIn = (wheelEvent->angleDelta().x() < 0) || (wheelEvent->angleDelta().y() < 0);
qreal zoomFactor = qreal( qRound( qPow( _zoomFactorBase, (zoomIn) ? delta : -delta ) * 10 )) / 10.0;
QPointF winCenter = QPointF( qreal(_getEventsFrom->width())*0.5, qreal(_getEventsFrom->height())*0.5 );
const QPoint & cursorPosWidget = _getEventsFrom->mapFromGlobal( QCursor::pos() ); // e doesn't have a position get position from cursor here
Esri::ArcGISRuntime::MapView * esriMapView = _sitMap->getEsriMapGraphicsView();
const Esri::ArcGISRuntime::Point & mapCenter = esriMapView -> screenToLocation(winCenter.x(), winCenter.y());
const Esri::ArcGISRuntime::Point & cursorPosMap = esriMapView -> screenToLocation(cursorPosWidget.x(), cursorPosWidget.y());
double mapScale = esriMapView -> mapScale() * zoomFactor;
double mapX = (-cursorPosMap.x()+mapCenter.x())*zoomFactor + cursorPosMap.x();
double mapY = (-cursorPosMap.y()+mapCenter.y())*zoomFactor + cursorPosMap.y();
_mouseZoomTaskWatcher = esriMapView->setViewpointCenter( Esri::ArcGISRuntime::Point(mapX,mapY,esriMapView->map()->spatialReference()), mapScale );
if (isSignalConnected( QMetaMethod::fromSignal(&EventMouseNavigator::mouseWheelEvent) ))
{
emit mouseWheelEvent(zoomFactor, QPointF(cursorPosMap.x(), cursorPosMap.y()) );
}
}
} break;
#endif
case QEvent::Gesture:
{
QGestureEvent * gestureEvent = static_cast<QGestureEvent*>(e);
if (gestureEvent)
{
const QList<QGesture*> & gestureList = gestureEvent->gestures();
for (auto gesture : gestureList)
{
Qt::GestureType gestureType = gesture->gestureType();
Qt::GestureState gestureState = gesture->state();
// QTapGesture * tapGesture = nullptr;
// QTapAndHoldGesture * tapAndHoldGesture = nullptr;
QPanGesture * panGesture = nullptr;
QPinchGesture * pinchGesture = nullptr;
// QSwipeGesture * swipeGesture = nullptr;
QString typeName;
QString stateName;
switch (gestureType)
{
// case Qt::TapGesture : tapGesture = (QTapGesture *)gesture; typeName = QLatin1String("TapGesture"); break;
// case Qt::TapAndHoldGesture : tapAndHoldGesture = (QTapAndHoldGesture*)gesture; typeName = QLatin1String("TapAndHoldGesture"); break;
case Qt::PanGesture : panGesture = (QPanGesture *)gesture; typeName = QLatin1String("PanGesture"); break;
case Qt::PinchGesture : pinchGesture = (QPinchGesture *)gesture; typeName = QLatin1String("PinchGesture"); break;
// case Qt::SwipeGesture : swipeGesture = (QSwipeGesture *)gesture; typeName = QLatin1String("SwipeGesture"); break;
default: break;
}
switch (gestureState)
{
case Qt::NoGesture : stateName = QLatin1String("NoGesture"); break;
case Qt::GestureStarted : stateName = QLatin1String("GestureStarted"); break;
case Qt::GestureUpdated : stateName = QLatin1String("GestureUpdated"); break;
case Qt::GestureFinished : stateName = QLatin1String("GestureFinished"); break;
case Qt::GestureCanceled : stateName = QLatin1String("GestureCanceled"); break;
}
DEBUG_LOG(_logger) << LOGFUNCTION << " Gesture type=" << typeName << " Gesture state=" << stateName;
// tapGesture = nullptr;
panGesture = nullptr; // ToDo: check: Why this?
if (panGesture)
{
QPointF deltaMove = panGesture->delta();
QPoint winCenter = QPoint( _getEventsFrom->width() / 2, _getEventsFrom->height() / 2 );
QPoint newCenter = winCenter-QPoint((int)deltaMove.x(),(int)deltaMove.y());
const Esri::ArcGISRuntime::Point mapCoordEsri =
_sitMap->getEsriMapGraphicsView()->screenToLocation(newCenter.x(), newCenter.y());
Esri::ArcGISRuntime::Viewpoint curVp = _sitMap->getEsriMapGraphicsView()->currentViewpoint(Esri::ArcGISRuntime::ViewpointType::CenterAndScale);
Esri::ArcGISRuntime::Viewpoint newVp(mapCoordEsri, curVp.targetScale());
_sitMap->getEsriMapGraphicsView()->setViewpointAndWait(newVp);
_getEventsFrom -> update();
if (gestureState == Qt::GestureStarted) gestureEvent -> setAccepted(panGesture, true);
}
if (pinchGesture)
{
///// QPinchGesture::ChangeFlags changeFlags = pinchGesture->changeFlags();
///// if (changeFlags & QPinchGesture::RotationAngleChanged)
///// {
///// qreal deltaPhi = pinchGesture->rotationAngle() - pinchGesture->lastRotationAngle();
///// _esriMap -> setRotation( _esriMap->rotation()-deltaPhi );
///// }
///// if (changeFlags & QPinchGesture::ScaleFactorChanged) _esriMap -> zoom( 1.0/pinchGesture->scaleFactor() );
_getEventsFrom -> update();
if (gestureState == Qt::GestureStarted) gestureEvent -> setAccepted(pinchGesture, true);
}
}
}
} break;
default: break;
} // switch
if (!hasFinished()) setActiveEvent( false );
if (handled) e->accept();
DEBUG_LOG(_logger) << LOGFUNCTION
<< " Event '" << debugString << "'"
<< " event->type() '" << e->type() << "'"
<< " handled = " << handled
<< " mouse panning is active = " << _mousePanningActive;
//
// 'if (handled) return true;' lead to bad behaviour at 3D: globe is often connected to mouse, without any button pressed...
//
// if (handled) return true;
}
return AbstractEventDispatcher::eventFilter(watched,e);
} // EventMouseNavigator::eventFilter
bool EventMouseNavigator::checkRunningPickingTask()
{
if ((!_pickingTask.isCanceled()) && (_pendingRequest != RequestType::None))
{
_pickingTask.cancel();
_pendingRequest = RequestType::None;
return true;
}
return false;
} // void EventMouseNavigator::checkRunningPickingTask()
void EventMouseNavigator::selectionRequested( const QPointF & pos )
{
// do the work only in case of slot connections are installed
if (! isSignalConnected( QMetaMethod::fromSignal(&EventMouseNavigator::selectionRequest) ))
{
return;
}
if (checkRunningPickingTask())
{
qWarning() << LOGFUNCTION << " request is still pending!";
}
_pendingRequest = RequestType::Selection;
_viewPortPos = pos;
requestPicking(pos);
} // EventMouseNavigator::selectionRequested
void EventMouseNavigator::pickRequested( const QPointF &pos )
{
// do the work only in case of slot connections are installed
if (! isSignalConnected( QMetaMethod::fromSignal(&EventMouseNavigator::contextMenuRequest) ))
{
return;
}
if (checkRunningPickingTask())
{
qWarning() << LOGFUNCTION << " request is still pending!";
}
_pendingRequest = RequestType::Picking;
_viewPortPos = pos;
requestPicking(pos);
} // EventMouseNavigator::pickRequested
void EventMouseNavigator::requestPicking(const QPointF &pos)
{
_pickingTask.cancel(); // cancel old task
// store new task
bool returnPopUpsOnly = false;
int maximumResultsPerOverlay = std::numeric_limits<int>::max(); // huge number;
_pickingTask = _sitMap->getEsriGeoView()->identifyGraphicsOverlays(pos.x(), pos.y(), _pickTolerance,
returnPopUpsOnly, maximumResultsPerOverlay);
//qWarning() << " XXXXXXX" << LOGFUNCTION;
// check new task
if (!_pickingTask.isValid())
{
_pendingRequest = RequestType::None;
qWarning() << LOGFUNCTION << " _identfyGraphicsOverlayTask invalid";
}
} // EventMouseNavigator::requestPicking
void EventMouseNavigator::onGetPickingResult(const QUuid &taskId, const QList<Esri::ArcGISRuntime::IdentifyGraphicsOverlayResult*> &identifyResults)
{
// qWarning() << " YYYYYYY" << LOGFUNCTION;
if (_pickingTask.taskId() != taskId)
{
qDebug() << " taskId does not match";
return;
}
const QList<SituationMap::UniqueMapId> & selectedIdList = mapToUniqueMapId(identifyResults);
// qWarning() << " _pendingRequest="<< (int)_pendingRequest << " count= " << _selectedIdList.count();
switch (_pendingRequest)
{
case RequestType::Picking:
emit contextMenuRequest(selectedIdList, _viewPortPos);
break;
case RequestType::Selection:
emit selectionRequest(selectedIdList, _viewPortPos);
break;
case RequestType::None:
//emtpy
break;
} // switch
// reset some 'flags' to enable a new request:
_pendingRequest = RequestType::None;
_viewPortPos = QPointF(-1, -1);
} // EventMouseNavigator::onGetPickingResult
QList<UniqueMapId> EventMouseNavigator::mapToUniqueMapId(const QList<Esri::ArcGISRuntime::IdentifyGraphicsOverlayResult *> &identifyResults)
{
QList<SituationMap::UniqueMapId> idList;
for (auto iResult : identifyResults)
{
// qWarning() << " process result of layer: " << iResult->graphicsOverlay();
const QList<Esri::ArcGISRuntime::Graphic*> &gResults = iResult->graphics();
for (auto pickedGraphic : gResults)
{
// qWarning() << " process pickedGraphic: " << pickedGraphic;
if (pickedGraphic->attributes())
{
// qWarning() << " process pickedGraphic cont: " << pickedGraphic->attributes()->containsAttribute(QLatin1String(SituationMap::UniqueMapIdAttribute));
// qWarning() << " process pickedGraphic cont: " << pickedGraphic->attributes()->containsAttribute(QLatin1String(SituationMap::IsPickableAttribute));
bool ok;
SituationMap::UniqueMapId uniqueMapId = pickedGraphic->attributes()->attributeValue(QLatin1String(SituationMap::UniqueMapIdAttribute)).toUInt(&ok);
if (ok)
{
// qWarning() << " process pickedGraphic uid: " << uniqueMapId;
if (!idList.contains(uniqueMapId))
{
idList += uniqueMapId;
}
}
else
{
ERROR_LOG(_logger) << " process pickedGraphic " << pickedGraphic
<< " uid: '" << pickedGraphic->attributes()->attributeValue(QLatin1String(SituationMap::UniqueMapIdAttribute)).toString()
<< "' (has uid attribute is " << pickedGraphic->attributes()->containsAttribute(QLatin1String(SituationMap::UniqueMapIdAttribute)) << ")";
}
}
} // foreach inner
} // foreach outter
return idList;
} // EventMouseNavigator::mapToUniqueMapId
} } /* namespace SituationMap::RB */
+225
View File
@@ -0,0 +1,225 @@
/**
**
** @RDE_HEADER@
** Event Dispatcher for Qt5 to handle mouse events navigate on map
** $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 .........:
**
** 24.04.2015, JT : first edition
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
// Own
#include <Map/situation_map_types.h>
#include "abstract_event_dispatcher.h"
//Esri
#include <arcgis/TaskWatcher.h>
// Qt
#include <QtCore/QList>
// #define SITUATIONMAP_OWN_WHEEL_HANDLING
// Forward:
namespace Esri {
namespace ArcGISRuntime {
class Map;
class IdentifyGraphicsOverlayResult;
} }
namespace SituationMap {
class MapImpl;
}
namespace SituationMap { namespace RB
{
/**
@class EventMouseNavigator event_mouse_navigator.h
@brief Event filter that handles mouse events for general map operation like selecting object, zooming and paning the map window
Implements class \c AbstractEventDispatcher to manage event handling for general map operation like selecting object, zooming and
panning the map window. Monitoring the mouse position can be realized by connecting the \c mouseMovedEvent signal. If the user has
clicked to map objects the signal \c selectionRequest is emitted.
Following events are handled:
| Input-Event | Interface Function | Description |
| :--------------------------------------------- | : ----------------- | : --------------------------------------------------------------------------- |
| Mouse enter | | To show/hide some widgets |
| Mouse leave | | To show/hide some widgets |
| Mouse move without any modifier | | Move Cursor. |
| Mouse move with pressed left button | | Panning of map if more then 3 pixels moved. |
| Mouse move with pressed middle button | | Panning of map. |
| Mouse wheel | | Redirect to \c Esri map for zooming. |
| Left mouse button release | | Emits signal \c selectionRequest with list of map objects at cursor position. |
@see AbstractEventDispatcher, EventDelegater, EventDispatcher
*/
class EventMouseNavigator : public AbstractEventDispatcher
{
Q_OBJECT
public:
/**
@name Construction & Destruction
@{
*/
EventMouseNavigator(const EventMouseNavigator &) = delete;
EventMouseNavigator & operator = (const EventMouseNavigator &) = delete;
EventMouseNavigator( QWidget * getEventsFrom, SituationMap::MapImpl *sitMap );
virtual ~EventMouseNavigator() = default;
/** @} */
inline static void setPickTolerance( int value = 5 ) { _pickTolerance = value; }
inline static int pickTolerance() { return _pickTolerance; }
inline static void setZoomFactorBase(qreal value = 1.002) { if ((value > 1) && (value <= 1.1))_zoomFactorBase = value; }
inline static qreal zoomFactorBase() { return _zoomFactorBase; }
signals:
/**
Will be emitted if the mouse enters the widget.
*/
void enterEvent();
/**
Will be emitted if the mouse leaves the widget.
*/
void leaveEvent();
/**
Will be emitted if the user clicks to map objects with the left mouse button.
*/
void selectionRequest( const QList< SituationMap::UniqueMapId > & idList, const QPointF &viewPortPos );
/**
Will be emitted if the user clicks to the map with the rigth mouse button.
*/
void contextMenuRequest( const QList< SituationMap::UniqueMapId > & idList, const QPointF &viewPortPos );
/**
Signal will be emitted if a mouse move is done.
*/
void mouseMovedEvent( int x, int y );
#ifdef SITUATIONMAP_OWN_WHEEL_HANDLING
/**
Signal will be emitted if the mouse wheel has been rotated
*/
void mouseWheelEvent(qreal factor, const QPointF &cursorPositionMap);
#endif
protected slots:
void onGetPickingResult(const QUuid &taskId, const QList<Esri::ArcGISRuntime::IdentifyGraphicsOverlayResult *> &identifyResults );
protected:
QList<UniqueMapId> mapToUniqueMapId( const QList<Esri::ArcGISRuntime::IdentifyGraphicsOverlayResult*> & identifyResults);
bool eventFilter(QObject*, QEvent*) override;
enum class RequestType
{
None,
Selection,
Picking
}; // RequestType
enum SelectionMode
{
NoSelection = 0x00,
SingleSelection = 0x01,
MultiSelection = 0x02,
FrameSelection = 0x04
}; // SelectionMode
Q_DECLARE_FLAGS(SelectionModes,SelectionMode)
SituationMap::MapImpl *_sitMap;
QPoint _mouseMoveRefPos;
QCursor _restoreMouseCursor;
bool _cursorChanged;
static int _pickTolerance;
QPointF _viewPortPos;
SelectionModes _selectionMode;
RequestType _pendingRequest;
bool _mousePanningActive;
bool _mousePanningActiveForCenterMapMidButton;
#ifdef SITUATIONMAP_OWN_WHEEL_HANDLING
Esri::ArcGISRuntime::TaskWatcher _mouseZoomTaskWatcher;
#endif
Qt::MouseButton _pressedMouseButton;
static qreal _zoomFactorBase; // Base value to calculate zoom factor values from QWheelEvent
Esri::ArcGISRuntime::TaskWatcher _pickingTask;
/**
test for already running picking task.
*/
bool checkRunningPickingTask();
/**
Find out which map objects are at given mouse position and emits the signal selectionRequest
*/
void selectionRequested(const QPointF & );
/**
Find out which map objects are at given mouse position and emits the signal contextMenuRequest
*/
void pickRequested( const QPointF & );
/**
Helper function to get all map objects at a given position of all GraphicsOverlays
@param pos position in window coordinates
*/
void requestPicking(const QPointF &pos);
}; /* EventMouseNavigator */
} } /* namespace SituationMap::RB */
+106
View File
@@ -0,0 +1,106 @@
/**
* @RDE_HEADER@
* Declaration/Definition
* $Id$
* $HeadURL$
* $Author$
*/
#include "gestures.h"
#include <QtCore/QDebug>
#include <QtCore/QEvent>
#include <QtWidgets/QWidget>
namespace SituationMap { namespace RB {
// TabGestureRecognizer
ApplyGestureRecognizer::ApplyGestureRecognizer() : QGestureRecognizer()
{
}
ApplyGestureRecognizer::~ApplyGestureRecognizer()
{}
QGesture * ApplyGestureRecognizer::create( QObject * target )
{
// qDebug() << "ApplyGesture create";
if (target && target->isWidgetType())
{
((QWidget*)target)->setAttribute(Qt::WA_AcceptTouchEvents);
}
return new ApplyGesture();
} // TabGestureRecognizer::create
QGestureRecognizer::Result ApplyGestureRecognizer::recognize( QGesture * stateGesture, QObject* , QEvent * event)
{
ApplyGesture * q = static_cast<ApplyGesture*>(stateGesture);
QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture;
switch (event->type())
{
case QEvent::TouchBegin:
{
const QTouchEvent * ev = static_cast<const QTouchEvent*>(event);
// qDebug() << "ApplyGesture begin";
q->_position = ev->touchPoints().at(0).pos();
q->setHotSpot(ev->touchPoints().at(0).screenPos());
q->_tripleTouch = (ev->touchPoints().size() == 3);
if (ev->touchPoints().size() == 1 )
result = QGestureRecognizer::Ignore;
else
result = QGestureRecognizer::TriggerGesture;
} break;
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
{
const QTouchEvent * ev = static_cast<const QTouchEvent*>(event);
if (q->state() != Qt::NoGesture && ev->touchPoints().size() >= 1 && ev->touchPoints().size() <= 3)
{
if (ev->touchPoints().size() == 3) q->_tripleTouch = true;
// qDebug() << "ApplyGesture update _tripleTouch=" << q->_tripleTouch;
QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
QPoint delta = p.pos().toPoint() - p.startPos().toPoint();
enum { TapRadius = 40 };
if (delta.manhattanLength() <= TapRadius)
{
if (event->type() == QEvent::TouchEnd)
{
result = (q->_tripleTouch) ? QGestureRecognizer::FinishGesture : QGestureRecognizer::CancelGesture;
}
else result = QGestureRecognizer::TriggerGesture;
}
}
} break;
case QEvent::MouseButtonPress:
case QEvent::MouseMove:
case QEvent::MouseButtonRelease:
result = QGestureRecognizer::Ignore;
break;
default:
result = QGestureRecognizer::Ignore;
break;
}
return result;
} // TabGestureRecognizer::recognize( QGesture * stateGesture, QObject * watched, QEvent * event)
void ApplyGestureRecognizer::reset( QGesture * stateGesture )
{
ApplyGesture * q = static_cast<ApplyGesture*>(stateGesture);
q->_tripleTouch = false;
} // TabGestureRecognizer::reset( QGesture * stateGesture )
}} // namspaces
+72
View File
@@ -0,0 +1,72 @@
/**
**
** @RDE_HEADER@
** Gesture recognition
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Joerg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 09.12.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <QtCore/QObject>
#include <QtWidgets/QGesture>
#include <QtWidgets/QGestureRecognizer>
namespace SituationMap { namespace RB
{
class ApplyGestureRecognizer : public QGestureRecognizer
{
public:
ApplyGestureRecognizer();
virtual ~ApplyGestureRecognizer();
QGesture * create( QObject * target ) override;
QGestureRecognizer::Result recognize( QGesture * stateGesture, QObject * watched, QEvent * event) override;
void reset( QGesture * stateGesture ) override;
}; // ApplyGestureRecognizer
class ApplyGesture : public QGesture
{
Q_OBJECT
friend class ApplyGestureRecognizer;
public:
ApplyGesture() = default;
~ApplyGesture() = default;
ApplyGesture( const ApplyGesture & ) = delete;
ApplyGesture & operator = ( const ApplyGesture & ) = delete;
QPointF position() const { return _position; }
private:
QPointF _position;
bool _tripleTouch;
}; // ApplyGesture
}} // namespaces
+52
View File
@@ -0,0 +1,52 @@
/* XPM */
static const char * polygon_xpm[] = {
"24 24 25 1",
" c None",
". c #59BA55",
"+ c #57B953",
"@ c #56B852",
"# c #55B651",
"$ c #53B44F",
"% c #51B24D",
"& c #4FB04B",
"* c #4DAE49",
"= c #4AAC46",
"- c #48A944",
"; c #46A742",
"> c #43A53F",
", c #41A23D",
"' c #3E9F3A",
") c #3C9D38",
"! c #399B35",
"~ c #379833",
"{ c #349630",
"] c #32942E",
"^ c #30922C",
"/ c #2E902A",
"( c #2D8E28",
"_ c #2B8C27",
": c #2A8B26",
" . ",
" ++ ",
" @ @ @ ",
" # # ### ",
" $$ $ $$$ $$ ",
" % %% %%% % ",
" && & &&& & ",
" * *** * ",
" == = ",
" - - ",
" ; ;",
" > >",
" , ,,",
"'' '' ",
") )) ",
"! !! ",
"~~ ~~ ",
" {{{ {{ ",
" ]]] ]] ",
" ^^ ^^ ",
" // // ",
" (( (( ",
" __ __ ",
" :::: "};
+309
View File
@@ -0,0 +1,309 @@
/**
**
** @RDE_HEADER@
** Implementation of base class for 2D 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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband.h"
#include "rubberband_drawable.h"
#include "rubberband_handle.h"
#include "rubberband_handle_proxy.h"
#include "rubberband_point_handle.h"
#include "rubberband_internal.h"
#include "rubberband_base_internal.h"
#include "rubberband_factory.h"
#include <arcgis/MapGraphicsView.h>
// Qt
#include <QtCore/QMetaMethod>
#include <QtWidgets/QGraphicsPixmapItem>
namespace SituationMap { namespace RB
{
Rubberband::Rubberband( SituationMap::Map * map, QObject * parent, bool isActive )
: RubberbandBase(map,parent,isActive)
, _internal( new Rubberband::InternalData(map) )
, _state( RubberbandState::ConstructionState )
, _previewSidc()
, _previewCursorOffset(32,32)
, _previewSize(32)
{
_fillColor.setAlpha(100);
connect( &_previewSymbolResultWatcher
, &AdvancedSymbology::SymbolResultWatcher::resultReady
, this
, &Rubberband::onPreviewSymbolResultReady );
} /* Rubberband::Rubberband */
Rubberband::~Rubberband()
{
delete _internal;
_internal = nullptr;
} /* Rubberband::~Rubberband */
void Rubberband::connectPreviewPixmap( const QPixmap & symbolPixmap )
{
if (nullptr == _internal->_connectedPreviewPixmap)
{
_internal->_connectedPreviewPixmap = new QGraphicsPixmapItem( symbolPixmap );
_internal->_connectedPreviewPixmap -> setOffset(-qreal(symbolPixmap.width())/2,-qreal(symbolPixmap.height())/2);
_internal->_mapScene -> addItem( _internal->_connectedPreviewPixmap );
}
} /* RubberbandPointFeature::connectPreviewPixmap */
unsigned int Rubberband::coordinateCount() const { return static_cast<unsigned int>(_internal->_handleList.size()); }
void Rubberband::resetAction(AbstractEventDispatcher*, int, int)
{
disenableSelectedState();
disenableMultiSelectedState();
update();
} /* Rubberband::resetAction */
bool Rubberband::selectAction( AbstractEventDispatcher*, int x, int y )
{
if (rubberbandIsAlive())
{
QPointF scenePos = pixel2ScenePosition(x,y);
if (_baseInternal->buttonProxyActive(scenePos)) return false;
_baseInternal->_lastClickPosition = scenePos;
return true;
}
return false;
} /* Rubberband::selectAction */
bool Rubberband::multiSelectActionPress( AbstractEventDispatcher * causer, int x, int y )
{
if (rubberbandIsAlive())
{
if (isEnabledModificationState())
{
_baseInternal->_lastClickPosition = pixel2ScenePosition(x,y);
enableMultiSelectedState();
}
return selectAction( causer, x, y);
}
return false;
} /* RubberbandPointFeature::multiSelectActionPress */
bool Rubberband::multiSelectActionRelease( AbstractEventDispatcher * causer, int x, int y )
{
if (rubberbandIsAlive())
{
if (isEnabledModificationState())
{
updateButtonPosition();
activateButtons();
}
else return setCoordinateAction(causer,x,y);
}
return false;
} /* RubberbandPointFeature::multiSelectActionRelease */
void Rubberband::adjustConnectedPreviewPixmap( int x, int y )
{
if (_internal->_connectedPreviewPixmap)
{
_internal->_connectedPreviewPixmap -> setPos(pixel2ScenePosition( x+_previewCursorOffset.x(), y+_previewCursorOffset.y() ));
}
} /* Rubberband::adjustConnectedPreviewPixmap */
bool Rubberband::moveAction( AbstractEventDispatcher*, int x, int y )
{
adjustConnectedPreviewPixmap(x,y);
return rubberbandIsAlive();
} /* moveAction */
bool Rubberband::setCoordinateAction( AbstractEventDispatcher*, int x, int y )
{
if (rubberbandIsAlive())
{
QPointF scenePos = pixel2ScenePosition(x,y);
if (_baseInternal->buttonProxyActive(scenePos)) return false;
_internal->_lastClickPosition = scenePos;
return true;
}
return false;
} /* Rubberband::setCoordinateAction */
bool Rubberband::movePickedAction ( AbstractEventDispatcher*, int x, int y ) { adjustConnectedPreviewPixmap(x,y); return false; }
bool Rubberband::contextMenuAction ( AbstractEventDispatcher*, int x, int y ) { Q_UNUSED(x); Q_UNUSED(y); return rubberbandIsAlive(); }
bool Rubberband::completeStateAction ( AbstractEventDispatcher*, int x, int y ) { Q_UNUSED(x); Q_UNUSED(y); return rubberbandIsAlive(); }
bool Rubberband::deleteAction ( AbstractEventDispatcher*, int x, int y ) { Q_UNUSED(x); Q_UNUSED(y); return rubberbandIsAlive(); }
bool Rubberband::undoAction ( AbstractEventDispatcher*, int x, int y ) { Q_UNUSED(x); Q_UNUSED(y); return rubberbandIsAlive(); }
RubberbandHandle * Rubberband::pickHandle( int x, int y ) const
{
if (_internal->_mapView != nullptr)
{
QPointF scenePosition = pixel2ScenePosition(x,y);
for (auto handle : qAsConst(_internal->_handleList))
{
if (handle->isPositionInside(scenePosition))
return handle.get();
}
}
return nullptr;
} /* Rubberband::pickHandle */
void Rubberband::deSelectHandles()
{
for (auto handle : qAsConst(_internal->_handleList))
{
RubberbandHandle * handlePtr = handle.get();
if (handlePtr)
{
handlePtr->setSelection(false);
}
}
} /* Rubberband::deSelectHandles */
QRectF Rubberband::sceneBbox() const
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION;
QPointF topLeft( std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
QPointF bottomRight( std::numeric_limits<double>::min(), std::numeric_limits<double>::min() );
for (auto handle : qAsConst(_internal->_handleList))
{
RubberbandPointHandle * pointHandlePtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if (pointHandlePtr)
{
const QPointF & p = pointHandlePtr->getCoordinate()._sceneCoordinate;
if (topLeft.x() > p.x()) topLeft.setX(p.x());
if (topLeft.y() > p.y()) topLeft.setY(p.y());
if (bottomRight.x() < p.x()) bottomRight.setX(p.x());
if (bottomRight.y() < p.y()) bottomRight.setY(p.y());
}
}
return QRectF( topLeft, bottomRight );
} /* Rubberband::sceneBbox */
void Rubberband::update()
{
// Check Quartz
// if (isSignalConnected(QMetaMethod::fromSignal(&Rubberband::updatePreview)))
// {
// emit updatePreview( this );
// }
// if (_internal->_map->symbolDictionary().contains(_previewSidc))
// {
// const QImage& symbolImage = _internal->_map->symbolDictionary().symbolImageBySidc( _previewSidc, _previewSize );
// connectPreviewPixmap( QPixmap::fromImage(symbolImage) );
// }
if ((!_previewSidc.isEmpty()) && (nullptr == _internal->_connectedPreviewPixmap) && (!_previewSymbolResultWatcher.resultIsValid()))
{
_previewSymbolResultWatcher.setSymbolResult(_baseInternal->_map->symbolDictionary().findBaseSymbol(_previewSidc));
}
for (auto handle : qAsConst(_internal->_handleList))
{
handle -> setDrawColor(_handleDrawColor);
handle -> setFillColor(_handleFillColor);
handle -> setSelectionColor(_handleSelectionColor);
handle -> setPickingRatio( _pickingRatio );
}
updateButtonPosition();
if (_internal->_constructionObjectDraw != nullptr)
{
// _constructionObjectDraw -> setColors
}
externalUpdate();
} /* Rubberband::update */
void Rubberband::onPreviewSymbolResultReady()
{
QSharedPointer<AdvancedSymbology::SymbolResult> symResult = _previewSymbolResultWatcher.symbolResult();
if (!symResult) return; // should NEVER happen! (Which object should have triggered the signal???)
const QPixmap & symbolPixmap = QPixmap::fromImage(symResult->symbolImage().image()).scaled(_previewSize,_previewSize,Qt::KeepAspectRatio);
if (symbolPixmap.isNull())
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION << "Preview symbol image is empty.";
}
connectPreviewPixmap( symbolPixmap );
} /* Rubberband::onPreviewSymbolResultReady */
#include "./constrainsMarker.xpm"
void Rubberband::markFailedConstrains( const QPointF & scenePos, bool on )
{
if (on)
{
QPixmap markerPixmap(constrainsMarker_xpm);
if (nullptr == _internal->_constrainFailedMarker)
{
_internal->_constrainFailedMarker = new QGraphicsPixmapItem( markerPixmap );
_internal->_mapScene -> addItem( _internal->_constrainFailedMarker );
}
_internal->_constrainFailedMarker -> setOffset(-qreal(markerPixmap.width())/2,-qreal(markerPixmap.height())/2);
_internal->_constrainFailedMarker -> setPos(scenePos-QPointF(_previewCursorOffset));
_internal->_constrainFailedMarker->setVisible(true);
}
else if (_internal->_constrainFailedMarker) _internal->_constrainFailedMarker->setVisible(false);
} /* Rubberband::markFailedConstrains */
} } /* namespace SituationMap::RB */
+319
View File
@@ -0,0 +1,319 @@
/**
**
** @RDE_HEADER@
** Definition of base class for 2D 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 "rubberband_base.h"
#include <Map/map.h>
#include <Common/ref_pointer.h>
#include <QtCore/QFlags>
#include <QtCore/QPointer>
#include <memory>
namespace Esri {
namespace ArcGISRuntime {
class MapGraphicsView;
class Point;
} }
namespace SituationMap
{
/**
Namespace for all rubberband stuff (is part of namespace SituationMap)
*/
namespace RB
{
class RubberbandDrawable;
class RubberbandHandle;
/**
@class Rubberband rubberband.h
@brief Base class of all 2D rubberbands
Rubberbands are used to create or modifiy 2D 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 RubberbandBase, Rubberband, RubberbandPointFeature, RubberbandPointCluster, RubberbandMultiPointFeature, RubberbandRectangle, RubberbandEllipse, RubberbandCorridor, RubberbandArrow
*/
class SITUATIONMAP_EXPORT Rubberband : public RubberbandBase
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* 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:
/**
@defgroup States Internal state of the rubberband
@{
*/
enum RubberbandState : unsigned int
{
ConstructionState = 1 << 0, ///< Construction state is active when a geomtrie is been build new
ModificationState = 1 << 1, ///< Modification state is active when a existing geometrie is been modified
SelectedState = 1 << 2, ///< Selection state is active, one ore more handles are selected
MultiSelectedState = 1 << 3, ///< multiple handles can be selected
ConstructionWidthState = 1 << 4 ///< Initial define of a width e.b. for corridors
}; /* RubberbandSate */
Q_DECLARE_FLAGS(RubberbandStates,RubberbandState)
/** @} */
/**
@name Construction & Destruction
@{
*/
private:
friend class RubberbandFreeHand;
friend class RubberbandPointFeature;
friend class RubberbandMultiPointFeature;
friend class RubberbandMultiEllipseFeature;
friend class RubberbandRectangle;
friend class RubberbandStateSelect;
friend class RubberbandTransformMove;
friend class RubberbandTransformRotate;
friend class RubberbandTransformScale;
/**
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
*/
explicit Rubberband( SituationMap::Map * map, QObject * parent, bool isActive = true );
public:
Q_DISABLE_COPY(Rubberband)
virtual ~Rubberband();
/** @} */
/**
@addtogroup States Methodes to query and modify rubberband states
@{
*/
inline bool isEnabledConstructionState() const { return _state.testFlag(RubberbandState::ConstructionState); }
inline bool isEnabledModificationState() const { return _state.testFlag(RubberbandState::ModificationState); }
inline bool isEnabledSelectedState() const { return _state.testFlag(RubberbandState::SelectedState); }
inline bool isEnabledMultiSelectedState() const { return _state.testFlag(RubberbandState::MultiSelectedState); }
inline void enableConstructionState() { disenableModificationState(); }
inline void enableModificationState() { disenableConstructionState(); }
inline void enableSelectedState() { _state |= RubberbandState::SelectedState; }
inline void enableMultiSelectedState() { _state |= RubberbandState::MultiSelectedState; }
inline void disenableConstructionState() { _state &= ~QFlags<RubberbandState>(RubberbandState::ConstructionState); _state |= RubberbandState::ModificationState; }
inline void disenableModificationState() { _state &= ~QFlags<RubberbandState>(RubberbandState::ModificationState); _state |= RubberbandState::ConstructionState; }
inline void disenableSelectedState() { _state &= ~QFlags<RubberbandState>(RubberbandState::SelectedState); }
inline void disenableMultiSelectedState() { _state &= ~QFlags<RubberbandState>(RubberbandState::MultiSelectedState); }
//@}
/**
@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 selectAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool multiSelectActionPress ( AbstractEventDispatcher * causer, int x, int y ) override;
bool multiSelectActionRelease( 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;
/** @} */
/**
@name Preview Setting Methodes to define visual behaviour of rubberband preview
@{
*/
inline void setPreviewSidc (const QString & sidc ) { _previewSidc = sidc; update(); } ///< Defines tactical symbol for preview
inline void setPreviewOffset (const QPoint & off ) { _previewCursorOffset = off; update(); } ///< set offset to cursor position for preview pixmap
inline void setPreviewSize (unsigned int size ) { _previewSize = size; update(); } ///< set size of preview pixmap
inline QString getPreviewSidc() const { return _previewSidc; } ///< get code of tactical preview symbol
inline const QPoint getPreviewOffset() const { return _previewCursorOffset; } ///< get offset to cursor position for preview pixmap
inline unsigned int getPreviewSize() const { return _previewSize; } ///< get size of preview pixmap
/** @} */
/**
Returns Sidc code of preview symbol (if defined)
*/
inline QString previewSidc() const { return _previewSidc; }
/**
Sets a QPixmap to use for drawing symbol preview image
@param symbolImage a nice QPixmap
*/
void connectPreviewPixmap( const QPixmap & symbolPixmap );
/**
Returns count of coordinates
*/
virtual unsigned int coordinateCount() const override;
protected:
void deSelectHandles();
void update() override;
/**
Returns the rubberband handle at screen position (x,y) or nullptr if there isn't any handle at this
position.
*/
RubberbandHandle * pickHandle( int x, int y ) const;
/**
Moves preview image to QGraphicView position (x,y) in window coordinates.
*/
void adjustConnectedPreviewPixmap( int x, int y );
/**
Shows a icon near the cursor to mark failing constrains.
*/
void markFailedConstrains( const QPointF & scenePos, bool on );
/*
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.
*/
struct InternalData;
InternalData * _internal;
RubberbandStates _state;
QString _previewSidc;
QPoint _previewCursorOffset;
unsigned int _previewSize;
AdvancedSymbology::SymbolResultWatcher _previewSymbolResultWatcher;
QRectF sceneBbox() const override;
protected slots:
void onPreviewSymbolResultReady();
}; /* Rubberband */
} } /* namespace SituationMap::RB */
+116
View File
@@ -0,0 +1,116 @@
/**
**
** @RDE_HEADER@
** Implementation of base class for 3d 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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_3d.h"
#include <Map/map.h>
#include <QtGui/QPainter>
namespace SituationMap
{
namespace RB
{
Rubberband3D::Rubberband3D( SituationMap::Map * map, QObject * parent, bool isActive )
: RubberbandBase(map,parent,isActive), _markerPixmap(nullptr), _markerSelectionPixmap(nullptr)
{
} // Rubberband3D::Rubberband3D( SituationMap::Map * map, QObject * parent, bool isActive )
Rubberband3D::~Rubberband3D()
{
delete _markerPixmap;
delete _markerSelectionPixmap;
} // Rubberband3D::~Rubberband3D()
void Rubberband3D::resetAction( AbstractEventDispatcher*,int,int ) {;}
bool Rubberband3D::selectAction( AbstractEventDispatcher*,int,int ) { return false; }
bool Rubberband3D::multiSelectActionPress ( AbstractEventDispatcher*,int,int ) { return false; }
bool Rubberband3D::multiSelectActionRelease( AbstractEventDispatcher*,int,int ) { return false; }
bool Rubberband3D::setCoordinateAction( AbstractEventDispatcher*,int,int ) { return false; }
bool Rubberband3D::moveAction( AbstractEventDispatcher*,int,int ) { return false; }
bool Rubberband3D::movePickedAction( AbstractEventDispatcher*,int,int ) { return false; }
bool Rubberband3D::contextMenuAction( AbstractEventDispatcher*,int,int ) { return false; }
bool Rubberband3D::completeStateAction( AbstractEventDispatcher*,int,int ) { return false; }
bool Rubberband3D::deleteAction( AbstractEventDispatcher*,int,int ) { return false; }
bool Rubberband3D::undoAction( AbstractEventDispatcher*,int,int ) { return false; }
QRectF Rubberband3D::sceneBbox() const { return QRectF(); }
#include "sphere_pattern.xpm"
QImage Rubberband3D::markerSelectionImage()
{
if (nullptr == _markerSelectionPixmap)
{
_markerSelectionPixmap = new QPixmap( sphere_pattern_xpm );
QPainter painter(_markerSelectionPixmap);
QBrush brush;
brush.setStyle(Qt::BrushStyle::SolidPattern);
brush.setColor(_handleSelectionColor);
painter.setCompositionMode(QPainter::CompositionMode::CompositionMode_Multiply);
painter.setPen(_handleDrawColor);
painter.setBrush(brush);
painter.drawEllipse( 0, 0, _markerSelectionPixmap->width(), _markerSelectionPixmap->height() );
}
return _markerSelectionPixmap->toImage();
} // QImage Rubberband3D::markerSelectionImage()
QImage Rubberband3D::markerImage()
{
if (nullptr == _markerPixmap)
{
_markerPixmap = new QPixmap( sphere_pattern_xpm );
QPainter painter(_markerPixmap);
QBrush brush;
brush.setStyle(Qt::BrushStyle::SolidPattern);
brush.setColor(_handleFillColor);
painter.setCompositionMode(QPainter::CompositionMode::CompositionMode_Multiply);
painter.setPen(_handleDrawColor);
painter.setBrush(brush);
painter.drawEllipse( 0, 0, _markerPixmap->width(), _markerPixmap->height() );
}
return _markerPixmap->toImage();
} // QImage Rubberband3D::markerImage()
} } /* namespace SituationMap::RB */
+214
View File
@@ -0,0 +1,214 @@
/**
**
** @RDE_HEADER@
** Definition of base class for 3d 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 "rubberband_base.h"
#include <Map/map.h>
#include <Common/ref_pointer.h>
class QObject;
namespace Esri {
namespace ArcGISRuntime {
class MapGraphicsView;
class Point;
} }
namespace SituationMap
{
/**
Namespace for all rubberband stuff (is part of namespace SituationMap)
*/
namespace RB
{
class RubberbandDrawable;
class RubberbandHandle;
/**
@class Rubberband3D rubberband_3d.h
@brief Base class of all 3D rubberbands
Rubberbands are used to create or modifiy geometries like single points or lines in 3D views 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<RubberbandPointFeature3D>(); // the map has to be in 3D mode
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 RubberbandBase, Rubberband, RubberbandPointFeature3D, RubberbandMultiPointFeature3D
*/
class SITUATIONMAP_EXPORT Rubberband3D : public RubberbandBase
{
Q_OBJECT
public:
/**
@name Construction & Destruction
@{
*/
private:
friend class RubberbandPointFeature3D;
friend class RubberbandMultiPointFeature3D;
/**
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
*/
explicit Rubberband3D( SituationMap::Map * map, QObject * parent, bool isActive = true );
public:
~Rubberband3D();
/** @} */
/**
@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 selectAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool multiSelectActionPress ( AbstractEventDispatcher * causer, int x, int y ) override;
bool multiSelectActionRelease( 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;
/** @} */
/**
Retrieve and set 3D coordinates.
@{
*/
virtual Point3D singleCoordinate3D( unsigned int idx = 0, CoordinateSystem cs = CoordinateSystem::Geo ) const = 0;
virtual QVector<Point3D> coordinateVector3D( CoordinateSystem cs = CoordinateSystem::Geo ) const = 0;
virtual void setCoordinateVector( const QVector<Point3D> & coordinateVector, CoordinateSystem cs = CoordinateSystem::Geo ) = 0;
/** @} */
protected:
QRectF sceneBbox() const override;
QImage markerImage();
QImage markerSelectionImage();
private:
QPixmap * _markerPixmap;
QPixmap * _markerSelectionPixmap;
}; /* Rubberband3D */
} } /* namespace SituationMap::RB */
+359
View File
@@ -0,0 +1,359 @@
/**
** @RDE_HEADER@
** Implementation of rubberband class to define multi point feature geoemtry with arrow
** $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 .........:
**
** 21.08.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_arrow.h"
#include "rubberband_frame_handle.h"
#include "rubberband_line_handle.h"
#include "rubberband_point_handle.h"
#include "rubberband_drawable.h"
#include "drawable_painter_path.h"
#include "rubberband_internal.h"
#include "rubberband_base_internal.h"
namespace SituationMap { namespace RB
{
struct RubberbandArrow::InternalData
{
SituationMap::RefPointer<RubberbandPointHandle> _arrowHandle;
SituationMap::RefPointer<DrawablePainterPath> _arrowItem;
}; /* struct RubberbandArrow::InternalData */
RubberbandArrow::RubberbandArrow( SituationMap::Map * map, QObject * parent )
: RubberbandMultiPointFeature(map,parent)
, _internal(new InternalData)
, _arrowSceneHalfWidth(0)
, _arrowSceneLength(0)
{
_isClosed = false;
} /* RubberbandArrow::RubberbandArrow */
RubberbandArrow::~RubberbandArrow()
{
delete _internal;
_internal = nullptr;
} /* RubberbandArrow::~RubberbandArrow */
unsigned int RubberbandArrow::arrowHalfWidth() const { return _arrowSceneHalfWidth; }
unsigned int RubberbandArrow::arrowLength() const { return _arrowSceneLength; }
void RubberbandArrow::setCoordinateVector(const QVector<QPointF> & coordinateVec, CoordinateSystem cs )
{
setCoordinateVectorArrow( coordinateVec, 0.0, 0.0, cs );
} /* RubberbandArrow::coordinateVector */
void RubberbandArrow::setCoordinateVectorArrow(const QVector<QPointF> & coordinateVec, unsigned int arrowHalfWidth, unsigned int arrowLength, CoordinateSystem cs )
{
if (coordinateVec.size() < 2) return;
RubberbandMultiPointFeature::setCoordinateVector( coordinateVec, cs );
const QPointF & aux = pixel2ScenePosition(arrowHalfWidth,arrowLength);
_arrowSceneHalfWidth = (unsigned int) aux.x();
_arrowSceneLength = (unsigned int) aux.y();
enableModificationState();
constructArrowHandle();
_baseInternal->_applyIsPossible = true;
activateButtons();
} /* RubberbandArrow::setCoordinateVectorArrow */
QPointF RubberbandArrow::getArrowHandleScenePosition()
{
if (!_arrowSceneLength) _arrowSceneLength = 40;
if (!_arrowSceneHalfWidth) _arrowSceneHalfWidth = 20;
QPointF p0 = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._sceneCoordinate;
QPointF p1 = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate;
QPointF rv( p0.x()-p1.x(), p0.y()-p1.y() );
rv /= sqrt(rv.x()*rv.x()+rv.y()*rv.y());
return QPointF( p1.x() + rv.x()*_arrowSceneLength - rv.y()*_arrowSceneHalfWidth ,
p1.y() + rv.y()*_arrowSceneLength + rv.x()*_arrowSceneHalfWidth );
} /* RubberbandArrow::getArrowHandleScenePosition */
QPointF RubberbandArrow::getArrowHandlePosition()
{
const QPointF & handlePos = getArrowHandleScenePosition();
RubberbandDrawable::RubberbandCoordinate mapHandlePos(Rubberband::_internal->_mapView, handlePos);
return QPointF( mapHandlePos._mapCoordinate.x(), mapHandlePos._mapCoordinate.y() );
} /* RubberbandArrow::getArrowhHandlePosition */
void RubberbandArrow::constructArrowHandle()
{
if (Rubberband::_internal->_handleList.size() < 2) return;
const QPointF & p = getArrowHandlePosition();
_internal->_arrowHandle = new RubberbandPointHandle( Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, p );
// ensure thate the arrow the arrow size in pixel remain the same size
connect( _internal->_arrowHandle.get(), &RubberbandHandle::adjusted, this, [this]() {
this->_internal->_arrowHandle->updateCoordinate( this->getArrowHandleScenePosition() );
this->updateArrowPath();
} );
update();
} /* RubberbandArrow::constructArrowhHandle */
void RubberbandArrow::constructArrow( const QPointF & p )
{
qreal p0X = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._sceneCoordinate.x();
qreal p0Y = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._sceneCoordinate.y();
qreal p1X = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate.x();
qreal p1Y = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate.y();
QPointF rv10( p0X-p1X , p0Y-p1Y );
QPointF rv1p( p.x()-p1X, p.y()-p1Y );
rv10 /= sqrt(rv10.x()*rv10.x()+rv10.y()*rv10.y());
qreal scalarProduct = QPointF::dotProduct(rv1p, rv10);
if (scalarProduct > 0.0)
{
_internal->_arrowHandle->getCoordinate().updateSceneCoordinate( Rubberband::_internal->_mapView, p );
_arrowSceneLength = (unsigned int) scalarProduct;
_arrowSceneHalfWidth = (unsigned int) sqrt( rv1p.x()*rv1p.x()+rv1p.y()*rv1p.y() - scalarProduct*scalarProduct );
}
} /* RubberbandArrow::constructArrow */
void RubberbandArrow::updateHandleScenePosition()
{
if (!_internal->_arrowHandle) return;
QPointF pos = getArrowHandleScenePosition();
_internal->_arrowHandle->updateCoordinate( pos );
} /* RubberbandArrow::updateHandleScenePosition */
void RubberbandArrow::updateArrowPath()
{
if (!_internal->_arrowHandle) return;
if (Rubberband::_internal->_handleList.size() < 2) return;
const QPointF & p0 = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._sceneCoordinate;
const QPointF & p1 = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate;
const QPointF & p = _internal->_arrowHandle->getCoordinate()._sceneCoordinate;
QPointF rv( p0.x()-p1.x(), p0.y()-p1.y() );
rv /= sqrt(rv.x()*rv.x()+rv.y()*rv.y());
if (!_internal->_arrowItem)
{
_internal->_arrowItem = new DrawablePainterPath( Rubberband::_internal->_mapView );
_internal->_arrowItem -> enableClosedLine( true );
_internal->_arrowItem -> fillSolid( true );
_internal->_arrowItem -> zBufferPlane( RubberbandDrawable::ZBufferPlane::ArrowSymbol );
}
QVector<QPointF> arrowPath;
arrowPath.append( p1 );
arrowPath.append( p );
arrowPath.append( QPointF( p1.x() + rv.x()*_arrowSceneLength + rv.y()*_arrowSceneHalfWidth
, p1.y() + rv.y()*_arrowSceneLength - rv.x()*_arrowSceneHalfWidth ) );
_internal->_arrowItem -> setPath( arrowPath );
RubberbandFrameHandle * frameHandle = getFrameHandle();
if (frameHandle)
{
QVector<RubberbandHandle::RubberbandCoordinate> vertexSet;
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * pointHandlePtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
vertexSet.append(pointHandlePtr->getCoordinate() );
}
vertexSet.append( _internal->_arrowHandle->getCoordinate() );
vertexSet.append( RubberbandDrawable::RubberbandCoordinate(Rubberband::_internal->_mapView,p) );
frameHandle->updateFrameShape( vertexSet );
}
} /* RubberbandArrow::updateArrowPath */
bool RubberbandArrow::selectAction( AbstractEventDispatcher * causer, int x, int y )
{
Q_UNUSED(causer);
if (!rubberbandIsAlive()) return false;
bool eventHandled = false;
QPointF scenePos(pixel2ScenePosition(x,y));
if (_baseInternal->buttonProxyActive(scenePos)) return false;
_baseInternal->_lastClickPosition = scenePos;
if (isEnabledConstructionState()) return RubberbandMultiPointFeature::selectAction(causer,x,y);
if (_internal->_arrowHandle->isPositionInside(scenePos))
{
_internal->_arrowHandle->setSelection();
eventHandled = true;
}
else eventHandled = selectHandles( x, y, scenePos );
if (eventHandled)
{
update();
deactivateButtons();
}
return eventHandled;
} /* RubberbandArrow::selectAction */
bool RubberbandArrow::setCoordinateAction(AbstractEventDispatcher * causer, int x, int y)
{
Q_UNUSED(causer);
if (!rubberbandIsAlive()) return false;
bool eventHandled = false;
QPointF scenePos(pixel2ScenePosition(x,y));
Rubberband::_internal->_lastClickPosition = scenePos;
if (isEnabledConstructionState()) return RubberbandMultiPointFeature::setCoordinateAction(causer, x, y);
if (_internal->_arrowHandle->isSelected())
{
_internal->_arrowHandle->setSelection(false);
constructArrow(scenePos);
eventHandled = true;
}
else return RubberbandMultiPointFeature::setCoordinateAction(causer, x, y);
if (eventHandled) update();
updateButtonPosition();
activateButtons();
return eventHandled;
} /* RubberbandArrow::setCoordinateAction */
bool RubberbandArrow::movePickedAction(AbstractEventDispatcher * causer, int x, int y )
{
if (!rubberbandIsAlive()) return false;
if ((_internal->_arrowHandle) && (_internal->_arrowHandle->isSelected()))
{
QPointF scenePos(pixel2ScenePosition(x,y));
constructArrow( scenePos );
update();
return false;
}
return RubberbandMultiPointFeature::movePickedAction(causer,x,y);
} /* RubberbandArrow::movePickedAction */
bool RubberbandArrow::moveAction(AbstractEventDispatcher * causer, int x, int y)
{
QPointF scenePos(pixel2ScenePosition(x,y));
if (_internal->_arrowHandle)
{
if (_internal->_arrowHandle->isPositionInside(scenePos))
{
_internal->_arrowHandle->setSelection(true);
return false;
}
_internal->_arrowHandle->setSelection(false);
}
return RubberbandMultiPointFeature::moveAction(causer,x,y);
} /* RubberbandArrow::moveAction */
bool RubberbandArrow::completeStateAction(AbstractEventDispatcher * causer, int x, int y)
{
if ((rubberbandIsAlive()) && (Rubberband::_internal->_mapView) && (Rubberband::_internal->_mapScene))
{
if (isEnabledConstructionState())
{
if ((unsigned int)Rubberband::_internal->_handleList.size() >= _minimumPointCount)
{
constructArrowHandle();
}
update();
}
}
return RubberbandMultiPointFeature::completeStateAction(causer,x,y);;
} /* RubberbandArrow::completeStateAction */
void RubberbandArrow::update()
{
_isClosed = false;
RubberbandMultiPointFeature::update();
if (_internal->_arrowHandle)
{
_internal->_arrowHandle -> setDrawColor(_handleDrawColor );
_internal->_arrowHandle -> setFillColor(_handleFillColor );
_internal->_arrowHandle -> setSelectionColor(_handleSelectionColor );
_internal->_arrowHandle -> setPickingRatio( _pickingRatio );
updateHandleScenePosition();
updateArrowPath();
}
} /* RubberbandArrow::update */
} } /* namespace SituationMap::RB */
+130
View File
@@ -0,0 +1,130 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define multi point feature geoemtry with Arrow
** $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 .........:
**
** 21.08.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband_multi_point_feature.h"
namespace SituationMap { namespace RB
{
class RubberbandLineHandle;
class RubberbandFrameHandle;
/**
@class RubberbandArrow rubberband_arrow.h
@brief Implementation of a rubberband for lines with arrow.
@see RubberbandFactory, Rubberband, RubberbandMultiPointFeature
Implementation of rubberbands used to input corridors. There are two different modes \c InputCenterLine and \c InputBoundary. In the
InputCenterLine mode the center line of the corridor has to be defined. The rubberband displays then the border geometry.
In the InputBoundary mode one side of the border has to be defined. The \c coordinateVector methodes always working on the input geometry.
*/
class SITUATIONMAP_EXPORT RubberbandArrow : public RubberbandMultiPointFeature
{
Q_OBJECT
public:
/**
@name Construction & Destruction
@{
*/
private:
friend class RubberbandFactory;
explicit RubberbandArrow( SituationMap::Map * map, QObject * parent = nullptr );
public:
~RubberbandArrow();
/** @} */
/**
Sets coordinates to modify to internal coordinate list.
@param coordinateVec List of coordinates to modify.
@param cs Defines the coordinate system of returned coordinates.
*/
void setCoordinateVector( const QVector<QPointF> & coordinateVec, CoordinateSystem cs = CoordinateSystem::Geo ) override;
/**
Sets coordinates to modify to internal coordinate list. In \c InputCenterLine mode the coordinates will be interpreted as
center line of the corridor. In \c InputBoundary the coordinates are defining one border. Id \c corridorWidth is negative
the coordinates are the right border otherwise the left one.
@param coordinateVec List of coordinates to modify.
@param arrowHalfWidth Half width of arrow in pixel.
@param arrowLength Length of arrow in pixel.
@param cs Defines the coordinate system of returned coordinates.
*/
void setCoordinateVectorArrow(const QVector<QPointF> & coordinateVec, unsigned int arrowHalfWidth, unsigned int arrowLength, CoordinateSystem cs = CoordinateSystem::Geo );
/**
Return the width of the corridor.
*/
unsigned int arrowHalfWidth() const;
unsigned int arrowLength() const;
bool selectAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool setCoordinateAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool movePickedAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool moveAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool completeStateAction ( AbstractEventDispatcher * causer, int x, int y ) override;
protected:
/*
Forward declaration of InternalData to hold private member variables. Becareful 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;
unsigned int _arrowSceneHalfWidth;
unsigned int _arrowSceneLength;
void update() override;
void updateArrowPath();
void updateHandleScenePosition();
void constructArrow( const QPointF & p );
void constructArrowHandle();
QPointF getArrowHandleScenePosition();
QPointF getArrowHandlePosition();
}; /* RubberbandCorridor */
} } /* namespace SituationMap::RB */
+654
View File
@@ -0,0 +1,654 @@
/**
**
** @RDE_HEADER@
** Implementation 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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_base.h"
#include "rubberband_base_internal.h"
#include "rubberband_handle_proxy.h"
#include "rubberband_factory.h"
#include <Common/exception.h>
#include <Map/coord_translation_functor.h>
#include <MapImpl/map_impl.h>
// Qt
#include <QtCore/QCoreApplication>
#include <QtCore/QMetaMethod>
#include <QtWidgets/QGraphicsView>
#include <QtWidgets/QWidget>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QPushButton>
#include <QtGui/QPixmap>
#include "apply.xpm"
#include "abort.xpm"
#include "undo.xpm"
static SituationMap::Map * currentFactoryMap = nullptr;
static bool allowMultipleRubberbands = false;
namespace SituationMap { namespace RB
{
QPixmap * RubberbandBase::BaseInternalData::_applyIcon = nullptr;
QPixmap * RubberbandBase::BaseInternalData::_abortIcon = nullptr;
QPixmap * RubberbandBase::BaseInternalData::_undoIcon = nullptr;
RubberbandBase::BaseInternalData::BaseInternalData( SituationMap::Map * map, RubberbandBase * me )
: _map(map)
, _mapCtFunctor(map->coordTranslationFunctor())
, _isActive(false)
, _applyIsPossible(false)
, _undoIsPossible(false)
, _hasUndoButton(false)
, _lastClickPosition(-1,-1)
, _buttonBoxSceneAnchor()
, _buttonBoxFixPosition(-1,-1)
, _buttonProxy()
, _updateFunctorList()
, _logger(getLogger("RubberbandBase"))
{
QGraphicsView * view = map->getQGraphicsView();
if (view)
{
_restoreCursor = view->viewport()->cursor(); // workaround Qt bug. remove when fixed
}
_buttonBox = new QWidget();
_buttonBox->setObjectName(QLatin1String("RBButtonBoxWidget"));
_buttonBox->hide();
_buttonBox->setAttribute( Qt::WidgetAttribute::WA_NoSystemBackground, true );
_applyButton = new QPushButton( (_applyIcon) ? *_applyIcon : QPixmap(apply_xpm), QString(), _buttonBox );
_applyButton -> setAttribute( Qt::WidgetAttribute::WA_NoSystemBackground, true );
_applyButton -> setObjectName(QLatin1String("RBApply"));
_applyButton -> setAttribute(Qt::WA_AcceptTouchEvents);
_applyButton -> grabGesture( Qt::GestureType::TapGesture );
me->connect( _applyButton, &QPushButton::clicked, me, &RubberbandBase::onDo_applyButtonClicked );
_cancelButton = new QPushButton( (_abortIcon) ? *_abortIcon : QPixmap(abort_xpm), QString(), _buttonBox );
_cancelButton -> setAttribute( Qt::WidgetAttribute::WA_NoSystemBackground, true );
_cancelButton -> setObjectName(QLatin1String("RBCancel"));
_cancelButton -> setAttribute(Qt::WA_AcceptTouchEvents);
_cancelButton -> grabGesture( Qt::GestureType::TapGesture );
me->connect( _cancelButton, &QPushButton::clicked, me, &RubberbandBase::onDo_cancelButtonClicked );
_undoButton = new QPushButton( (_undoIcon) ? *_undoIcon : QPixmap(undo_xpm), QString(), _buttonBox );
_undoButton -> setAttribute( Qt::WidgetAttribute::WA_NoSystemBackground, true );
_undoButton -> setObjectName(QLatin1String("RBUndo"));
_undoButton -> setAttribute(Qt::WA_AcceptTouchEvents);
_undoButton -> grabGesture( Qt::GestureType::TapGesture );
_undoButton -> hide();
me->connect( _undoButton, &QPushButton::clicked, me, &RubberbandBase::onDo_undoButtonClicked );
_buttonLayout = new QHBoxLayout( _buttonBox );
_buttonLayout->setObjectName(QLatin1String("RBButtonBoxLayoutHBox"));
_buttonLayout -> addWidget( _undoButton );
_buttonLayout -> addWidget( _cancelButton );
_buttonLayout -> addWidget( _applyButton );
} /* InternalData */
Rubberband::BaseInternalData::~BaseInternalData()
{
_map = nullptr;
_mapCtFunctor = nullptr;
_buttonProxy = nullptr; // delete RefPointer
if (_buttonBox) _buttonBox -> deleteLater(); // delete all widgets of button box
_buttonBox = nullptr;
_buttonLayout = nullptr;
_applyButton = nullptr;
_cancelButton = nullptr;
_undoButton = nullptr;
} /* ~InternalData */
bool RubberbandBase::BaseInternalData::buttonProxyActive( const QPointF & pos ) const
{
if (_buttonProxy)
{
return ((_buttonProxy->isVisible()) && (_buttonProxy->isPositionInside(pos)));
}
return false;
} /* bool RubberbandBase::BaseInternalData::buttonProxyActive( const QPointF & pos ) const*/
void RubberbandBase::BaseInternalData::enableAndShowOnlyPossibleButtons()
{
_applyButton->setEnabled(_applyIsPossible);
if (_undoButton)
{
if (_hasUndoButton)
{
_undoButton -> show();
}
_undoButton -> setEnabled(_undoIsPossible);
}
} /* void RubberbandBase::InternalData::showOnlyPossibleButtons() */
static QHash<SituationMap::Map*, QList<RubberbandBase*>> &activeRubberbands()
{
static QHash<SituationMap::Map*, QList<RubberbandBase*>> hashTable;
return hashTable;
} // activeRubberbands()
void RubberbandBase::currentFactoryMap(SituationMap::Map * map) { ::currentFactoryMap = map; }
void RubberbandBase::allowMultipleRubberbands( bool ok ) { ::allowMultipleRubberbands = ok; }
void * RubberbandBase::operator new(size_t bytes)
{
QString exceptionMsg;
// be careful it is not thread safe here
if (::currentFactoryMap)
{
bool doNew( ::allowMultipleRubberbands );
if (!doNew)
{
doNew = true;
const auto rubberbands = SituationMap::RB::activeRubberbands().value(::currentFactoryMap);
for (const auto rbnd : rubberbands)
{
if (rbnd->rubberbandIsAlive())
{
doNew = false;
break;
}
}
}
if (doNew)
{
RubberbandBase::currentFactoryMap( nullptr );
RubberbandBase::allowMultipleRubberbands( false );
return ::operator new(bytes);
}
else exceptionMsg = QLatin1String("Another rubberband is already alive at moment");
RubberbandBase::currentFactoryMap( nullptr );
}
else exceptionMsg = QLatin1String("Use rubberband factory to create rubberbands. Calling new directly is forbidden!");
RubberbandBase::currentFactoryMap( nullptr );
RubberbandBase::allowMultipleRubberbands( false );
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* because "return nullptr;" is not compliante with the c++ standard
* throw exception instead
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
throw Exception( __FILE__, __LINE__, exceptionMsg );
} /* RubberbandBase::operator new */
QList<RubberbandBase*> RubberbandBase::activeRubberbands( SituationMap::Map * map )
{
QList<RubberbandBase*> ret;
const auto rubberbands = SituationMap::RB::activeRubberbands().value(map);
for (const auto rbnd : rubberbands)
{
if (rbnd && rbnd->rubberbandIsAlive())
ret += rbnd;
}
return ret;
} /* RubberbandBase::activeRubberbands */
void RubberbandBase::deleteAllActiveRubberbands(Map *map)
{
const QList<SituationMap::RB::RubberbandBase*> &rbCont = RubberbandBase::activeRubberbands(map);
qDeleteAll(rbCont);
} /* RubberbandBase::deleteAllActiveRubberbands */
bool RubberbandBase::isRubberbandActive(SituationMap::Map * map)
{
return (activeRubberbands(map).size() > 0);
} /* RubberbandBase::isRubberbandActive */
void RubberbandBase::abortActiveRubberbands( SituationMap::Map * map )
{
const QList<RubberbandBase*> & rbList = activeRubberbands(map);
for (auto rb : rbList)
{
emit rb->abort(rb);
rb->doAutoDelete();
}
} /* RubberbandBase::abortActiveRubberbands */
void RubberbandBase::deleteMySelf()
{
if (_viewPortEventDispatcher) _viewPortEventDispatcher -> onDo_kickTheBucket();
if (_viewPortEventDispatcher) _viewPortEventDispatcher -> onDo_delete();
if (_windowEventDispatcher) _windowEventDispatcher -> onDo_delete();
_viewPortEventDispatcher = nullptr;
_windowEventDispatcher = nullptr;
_baseInternal->_isActive = false;
deleteLater();
} /* RubberbandBase::deleteMySelf */
RubberbandBase::RubberbandBase( SituationMap::Map * map, QObject * parent, bool isActive )
: QObject( parent )
, EventActionInterface()
, _baseInternal( new RubberbandBase::BaseInternalData(map,this) )
, _drawColor(QColor("black"))
, _fillColor(QColor("black"))
, _handleDrawColor(QColor("black"))
, _handleFillColor(QColor("yellow"))
, _handleSelectionColor(QColor("red"))
, _frameColor(QColor("black"))
, _frameFillColor(QColor(150,150,0,50))
, _frameSelectionColor(QColor(255,0,0,50))
, _frameHandleMargin(10)
, _pickingRatio(0)
, _finishAfterConstruction(true)
, _autoDelete(false)
, _viewPortEventDispatcher(nullptr)
, _windowEventDispatcher (nullptr)
, _userData(nullptr)
{
_fillColor.setAlpha(100);
if (isActive) activate();
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* In case of multiple rubberbands can be active, it is forbidden to
* create a rubberband of the same type twice anyway.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
bool rubberbandOfSameTypeIsActive = false;
const auto rubberbands = SituationMap::RB::activeRubberbands().value(map);
for (auto rbnd : rubberbands)
{
// Just to check the class names with debugger
// const char * rbndName = typeid(*rbnd).name();
// const char * thisName = typeid(*this).name();
if (( typeid(*rbnd) == typeid(*this)) && rbnd->rubberbandIsAlive())
{
rubberbandOfSameTypeIsActive = true;
break;
}
}
if (rubberbandOfSameTypeIsActive)
{
// disable dispatcher, so the rubberband is not alive yet.
if (_viewPortEventDispatcher)
{
_viewPortEventDispatcher -> onDo_kickTheBucket();
_viewPortEventDispatcher -> onDo_delete();
}
if (_windowEventDispatcher) _windowEventDispatcher->onDo_delete();
_viewPortEventDispatcher = nullptr;
_windowEventDispatcher = nullptr;
}
else
{
SituationMap::RB::activeRubberbands()[map].append( this );
if (_windowEventDispatcher)
{
_windowEventDispatcher->setCursor(QCursor(Qt::CrossCursor));
_windowEventDispatcher->grab();
}
if (_viewPortEventDispatcher)
{
_viewPortEventDispatcher->setCursor(QCursor(Qt::CrossCursor));
_viewPortEventDispatcher->grab();
}
}
if (map)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Sending signals of RubberbandFactory to inform about rubberband creation and destroy would be
* better placed in RubberbandFactory source (rubberband_factory.cpp) but there it's a lot of
* more writing stuff ...
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
SituationMap::RB::RubberbandFactory & rbndFactory = map -> rubberbandFactory();
emit rbndFactory.rubberbandCreated();
connect( this, &QObject::destroyed, &rbndFactory, &SituationMap::RB::RubberbandFactory::rubberbandDestroyed );
}
} /* RubberbandBase::RubberbandBase */
RubberbandBase::~RubberbandBase()
{
if (_viewPortEventDispatcher) _viewPortEventDispatcher -> onDo_kickTheBucket();
if (_viewPortEventDispatcher) _viewPortEventDispatcher -> onDo_delete();
if (_windowEventDispatcher) _windowEventDispatcher -> onDo_delete();
_viewPortEventDispatcher = nullptr;
_windowEventDispatcher = nullptr;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Test if map has been already destroyed. If map exists all is nice ...
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
if (_baseInternal->_map)
{
SituationMap::RB::activeRubberbands()[_baseInternal->_map].removeOne( this );
emit finished( this );
}
else
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ... otherwise we have to search the rubberband
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
const auto rubberbands = SituationMap::RB::activeRubberbands();
for (auto rubberList : rubberbands)
rubberList.removeOne(this);
}
delete _baseInternal;
_baseInternal = nullptr;
} /* RubberbandBase::~RubberbandBase */
QPointF RubberbandBase::projectCoordinateToMap( CoordinateSystem cs, const QPointF & loc ) const
{
return (cs != CoordinateSystem::Geo || !_baseInternal->_mapCtFunctor) ? loc : _baseInternal->_mapCtFunctor->geographicToMap( loc );
} /* RubberbandBase::projectCoordinateToMap */
QPointF RubberbandBase::projectCoordinateFromMap( CoordinateSystem cs, const QPointF & loc ) const
{
return (cs != CoordinateSystem::Geo || !_baseInternal->_mapCtFunctor) ? loc : _baseInternal->_mapCtFunctor->mapToGeographic( loc );
} /* RubberbandBase::projectCoordinateFromMap */
QPointF RubberbandBase::projectCoordinateFromMap( CoordinateSystem cs, const Esri::ArcGISRuntime::Point & loc ) const
{
return (cs != CoordinateSystem::Geo || !_baseInternal->_mapCtFunctor) ? QPointF(loc.x(), loc.y()) : _baseInternal->_mapCtFunctor->mapToGeographic( loc );
} /* RubberbandBase::projectCoordinateFromMap */
void RubberbandBase::activate()
{
if (!_baseInternal->_map) return;
if (!_baseInternal->_isActive)
{
QGraphicsView * view = _baseInternal->_map->getQGraphicsView();
if (view)
{
_viewPortEventDispatcher = new EventDispatcher(view->viewport(), this);
_windowEventDispatcher = new EventDelegater(view, _viewPortEventDispatcher);
_baseInternal->_isActive = true;
MapImpl *mapImpl = static_cast<MapImpl*>(_baseInternal->_map.data());
connect(_viewPortEventDispatcher.data(), &EventDispatcher::mouseMovedEvent,
mapImpl, &MapImpl::onHandleMouseMove);
}
}
} /* RubberbandBase::activate */
bool RubberbandBase::autoSelectAction(int x, int y)
{
_viewPortEventDispatcher->_leftPressHandled = true;
return selectAction(nullptr,x,y);
} /* RubberbandBase::autoSelectAction */
void RubberbandBase::installExternalUpdate(const std::function<bool(RubberbandBase*)> & updateFunctor)
{
_baseInternal->_updateFunctorList << updateFunctor;
} // void RubberbandBase::installExternalUpdate( const std::function<bool(RubberbandBase*)> & updateFunctor)
void RubberbandBase::externalUpdate()
{
for (const auto &update : qAsConst(_baseInternal->_updateFunctorList))
{
if (!update(this))
break;
}
} // void RubberbandBase::externalUpdate()
void RubberbandBase::updateButtonPosition()
{
if ((_baseInternal->_lastClickPosition.x() < 0) || (_baseInternal->_lastClickPosition.y() < 0))
_baseInternal->_buttonBoxSceneAnchor = sceneBbox().bottomRight();
else
_baseInternal->_buttonBoxSceneAnchor = _baseInternal->_lastClickPosition;
// _internal->_mapView->update();
} /* RubberbandBase::updateButtonPosition */
void RubberbandBase::setFixedButtonBoxPosition( QPoint widgetPos )
{
_baseInternal->_buttonBoxFixPosition = widgetPos;
activateButtons();
} /* RubberbandBase::setFixedButtonBoxPosition */
void RubberbandBase::unsetFixedButtonBoxPosition()
{
_baseInternal->_buttonBoxFixPosition = QPoint(-1,-1);
if (_baseInternal->_buttonProxy)
{
_baseInternal->_buttonProxy->setPos( _baseInternal->_buttonBoxSceneAnchor );
}
} /* RubberbandBase::unsetFixedButtonBoxPosition */
bool RubberbandBase::isButtonBoxPositionFixed() { return ((_baseInternal->_buttonBoxFixPosition.x() >= 0) && (_baseInternal->_buttonBoxFixPosition.y() >= 0)); }
void RubberbandBase::onDo_updateButtonFixCoordinates()
{
if (!_baseInternal->_buttonProxy) return;
if (isButtonBoxPositionFixed())
{
// Don't use bottom right corner of rubberband bbox to place the buttons,
// rather than use fixed window position.
const QPoint & pos = _baseInternal->_buttonBoxFixPosition;
_baseInternal->_buttonProxy->setPos( pixel2ScenePosition(pos.x(),pos.y()) );
}
} /* RubberbandStateSelect::onDo_updateButtonFixCoordinates */
void RubberbandBase::activateButtons()
{
DEBUG_LOG(_baseInternal->_logger) << LOGFUNCTION;
if (!_baseInternal->_buttonProxy)
{
_baseInternal->_buttonProxy = new RubberbandHandleProxy( _baseInternal->_map->getQGraphicsView(), _baseInternal->_buttonBox );
_baseInternal->_buttonProxy->setRestoreCursor( _baseInternal->_restoreCursor ); // workaround Qt bug. remove when fixed
connect( _baseInternal->_buttonProxy.get(), &RubberbandHandleProxy::adjusted, this, [this]()
{
this->_baseInternal->_buttonBoxSceneAnchor = this->_baseInternal->_buttonProxy->getCoordinate()._sceneCoordinate;
} );
}
_baseInternal->enableAndShowOnlyPossibleButtons();
if (isButtonBoxPositionFixed())
{
const QPoint & pos = _baseInternal->_buttonBoxFixPosition;
_baseInternal->_buttonProxy->setPos( pixel2ScenePosition(pos.x(),pos.y()) );
_baseInternal->_buttonProxy->setSceneOffset( QPointF(0,0) );
}
else
{
_baseInternal->_buttonProxy->setPos( _baseInternal->_buttonBoxSceneAnchor );
_baseInternal->_buttonProxy->setSceneOffset( QPointF(_frameHandleMargin+5,_frameHandleMargin+5) );
}
_baseInternal->_buttonProxy->show();
} /* Rubberband::activateButtons */
void RubberbandBase::deactivateButtons()
{
DEBUG_LOG(_baseInternal->_logger) << LOGFUNCTION;
if (isButtonBoxPositionFixed()) return;
if (_baseInternal->_buttonProxy) _baseInternal->_buttonProxy->hide();
} /* RubberbandBase::deactivateButtons() */
void RubberbandBase::adjustButtons()
{
if (_baseInternal->_buttonProxy)
{
activateButtons();
}
} /* RubberbandBase::adjustButtons */
void RubberbandBase::applyButtonClicked()
{
completeStateAction( _viewPortEventDispatcher, 0.0, 0.0 );
} /* RubberbandBase::applyButtonClicked */
void RubberbandBase::cancelButtonClicked()
{
abortAction( _viewPortEventDispatcher, 0.0, 0.0 );
} /* RubberbandBase::cancelButtonClicked */
void RubberbandBase::undoButtonClicked()
{
undoAction( _viewPortEventDispatcher, 0.0, 0.0 );
} /* RubberbandBase::undoButtonClicked */
void RubberbandBase::resetIconsToDefault()
{
if (BaseInternalData::_applyIcon) { delete BaseInternalData::_applyIcon; BaseInternalData::_applyIcon = nullptr; }
if (BaseInternalData::_abortIcon) { delete BaseInternalData::_abortIcon; BaseInternalData::_abortIcon = nullptr; }
if (BaseInternalData::_undoIcon ) { delete BaseInternalData::_undoIcon; BaseInternalData::_undoIcon = nullptr; }
} /* RubberbandBase::resetIconsToDefault */
void RubberbandBase::setIconApply(const QPixmap & icon)
{
if (BaseInternalData::_applyIcon == nullptr) BaseInternalData::_applyIcon = new QPixmap(icon);
else *BaseInternalData::_applyIcon = icon;
} /* RubberbandBase::setIconApply */
void RubberbandBase::setIconAbort(const QPixmap & icon)
{
if (BaseInternalData::_abortIcon == nullptr) BaseInternalData::_abortIcon = new QPixmap(icon);
else *BaseInternalData::_abortIcon = icon;
} /* RubberbandBase::setIconAbort */
void RubberbandBase::setIconUndo(const QPixmap & icon)
{
if (BaseInternalData::_undoIcon == nullptr) BaseInternalData::_undoIcon = new QPixmap(icon);
else *BaseInternalData::_undoIcon = icon;
} /* RubberbandBase::setIconUndo */
QPointF RubberbandBase::pixel2ScenePosition( int x, int y ) const
{
QGraphicsView * view = _baseInternal->_map->getQGraphicsView();
return (view) ? view->mapToScene(x, y) : QPointF(x,y);
} /* RubberbandBase::pixel2ScenePosition */
bool RubberbandBase::buttonPositionAction(AbstractEventDispatcher *, int x, int y)
{
QPointF scenePos(pixel2ScenePosition(x,y));
if (!_baseInternal->buttonProxyActive(scenePos))
{
_baseInternal->_buttonBoxSceneAnchor = scenePos;
adjustButtons();
}
return false;
} /* bool RubberbandBase::buttonPositionAction(AbstractEventDispatcher * causer, int x, int y) */
void RubberbandBase::unlinkEventDispatcher( AbstractEventDispatcher* )
{
_viewPortEventDispatcher = nullptr;
_windowEventDispatcher = nullptr;
} /* RubberbandBase::unlinkEventDispatcher */
bool RubberbandBase::abortAction( AbstractEventDispatcher * causer, int, int )
{
_baseInternal->_buttonBox->hide();
if (causer) causer->onDo_kickTheBucket();
emit abort( this );
doAutoDelete();
return true;
} /* RubberbandBase::abortAction */
bool RubberbandBase::applyAndEndAction( AbstractEventDispatcher * causer, int,int )
{
_baseInternal->_buttonBox->hide();
if (causer) causer->onDo_kickTheBucket();
emit apply( this );
doAutoDelete();
return true;
} /* RubberbandBase::applyAndEndAction */
} } /* namespace SituationMap::RB */
+500
View File
@@ -0,0 +1,500 @@
/**
**
** @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 */
@@ -0,0 +1,118 @@
/**
**
** @RDE_HEADER@
** Definition of internal data 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 ...........: Joerg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 16.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <QtCore/QList>
#include <QtCore/QPointer>
#include <Common/ref_pointer.h>
#include <Common/situation_map_logging.h>
#include "rubberband_base.h"
class QHBoxLayout;
class QWidget;
class QPushButton;
class QGraphicsScene;
class QGraphicsView;
namespace Esri {
namespace ArcGISRuntime {
class MapGraphicsView;
} }
namespace SituationMap
{
class Map;
}
namespace SituationMap { namespace RB
{
class RubberbandHandleProxy;
/**
@class Rubberband::BaseInternalData rubberband_base_internal.h
@brief Definition of internal data of rubberband base class.
*/
class RubberbandBase::BaseInternalData
{
public:
static QPixmap * _applyIcon;
static QPixmap * _abortIcon;
static QPixmap * _undoIcon;
QPointer<SituationMap::Map> _map;
SituationMap::CoordTranslationFunctor * _mapCtFunctor;
bool _isActive;
bool _applyIsPossible;
bool _undoIsPossible;
bool _hasUndoButton;
QPointF _lastClickPosition;
QPointF _buttonBoxSceneAnchor;
QPoint _buttonBoxFixPosition;
SituationMap::RefPointer<RubberbandHandleProxy> _buttonProxy;
QPointer<QWidget> _buttonBox;
QHBoxLayout * _buttonLayout;
QPushButton * _undoButton;
QPushButton * _cancelButton;
QPushButton * _applyButton;
QCursor _restoreCursor; // workaround Qt bug. remove when fixed
QVector<std::function<bool(RubberbandBase*)>> _updateFunctorList;
LOGGER_T _logger;
explicit BaseInternalData( SituationMap::Map * map, RubberbandBase * me );
virtual ~BaseInternalData();
bool buttonProxyActive( const QPointF & pos ) const;
void enableAndShowOnlyPossibleButtons();
BaseInternalData( const BaseInternalData & ) = delete;
BaseInternalData & operator = ( const BaseInternalData & ) = delete;
}; /* BaseInternalData */
} } /* namespace SituationMap::RB */
+991
View File
@@ -0,0 +1,991 @@
/**
**
** @RDE_HEADER@
** Implementation of rubberband class to define multi point feature geoemtry
** $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 .........:
**
** 17.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_corridor.h"
#include "rubberband_drawable.h"
#include "rubberband_frame_handle.h"
#include "rubberband_handle_proxy.h"
#include "rubberband_line_handle.h"
#include "rubberband_point_handle.h"
#include "drawable_painter_path.h"
#include "rubberband_internal.h"
#include "rubberband_base_internal.h"
#include <MathUtils/clipper.hpp>
#include <arcgis/Map.h>
#include <arcgis/MapGraphicsView.h>
namespace SituationMap { namespace RB
{
struct RubberbandCorridor::InternalData
{
SituationMap::RefPointer<RubberbandPointHandle> _widthHandle;
qreal _corridorSceneWidth = 0.0;
SituationMap::RefPointer<RubberbandLineHandle> _widthLine;
SituationMap::RefPointer<DrawablePainterPath> _geoBufferItem;
SituationMap::RefPointer<DrawablePainterPath> _centerLineItem;
QRectF _sceneBbox;
}; /* class RubberbandCorridor::InternalData */
RubberbandCorridor::RubberbandCorridor( SituationMap::Map * map, QObject * parent ) : RubberbandCorridor( map, InputMode::InputBoundary, 0, parent ) {;}
RubberbandCorridor::RubberbandCorridor( SituationMap::Map * map, InputMode mode, qreal width, QObject * parent )
: RubberbandMultiPointFeature(map, false, parent) // Map*, bool complexGeometry, QObject* parent
, _internal(new InternalData)
, _inputMode(mode)
, _corridorWidth(width)
, _minimumCorridorWidth( 0.0 )
, _maximumCorridorWidth( std::numeric_limits<qreal>::infinity() )
, _corridorBorderColor("black")
, _corridorFillColor("yellow")
{
_corridorFillColor.setAlphaF( 0.5 );
_isClosed = false;
setCheckMaxAngle(160.0 / 180.0*M_PI); // restrict angle between line segments
} /* RubberbandCorridor::RubberbandCorridor */
RubberbandCorridor::~RubberbandCorridor()
{
delete _internal;
_internal = nullptr;
} /* RubberbandCorridor::~RubberbandCorridor */
void RubberbandCorridor::minimumCorridorWidth( qreal min )
{
min = fabs(min);
if (min < _maximumCorridorWidth)
{
_minimumCorridorWidth = min;
if ((_minimumCorridorWidth) > _corridorWidth)
{
_corridorWidth = _minimumCorridorWidth;
constructWidthHandle();
}
}
} /* RubberbandCorridor::minimumCorridorWidth */
void RubberbandCorridor::maximumCorridorWidth( qreal max )
{
max = fabs(max);
if (max > _minimumCorridorWidth)
{
_maximumCorridorWidth = max;
if ((_maximumCorridorWidth) < _corridorWidth)
{
_corridorWidth = _maximumCorridorWidth;
constructWidthHandle();
}
}
} /* RubberbandCorridor::maximumCorridorWidth */
bool RubberbandCorridor::isEnabledConstructionWidthState() const
{
return _state.testFlag( RubberbandState::ConstructionWidthState );
} /* RubberbandCorridor::isEnabledConstructionWidthState */
void RubberbandCorridor::enableConstructionWidthState()
{
_state &= ~QFlags<RubberbandState>(RubberbandState::ModificationState);
_state |= RubberbandState::ConstructionWidthState;
} /* RubberbandCorridor::enableConstructionWidthState */
void RubberbandCorridor::disenableConstructionWidthState()
{
_state &= ~QFlags<RubberbandState>(RubberbandState::ConstructionWidthState);
_state |= RubberbandState::ModificationState;
} /* RubberbandCorridor::disenableConstructionWidthState */
qreal RubberbandCorridor::corridorWidth() const
{
return _corridorWidth;
} /* RubberbandCorridor::corridorWidth */
void RubberbandCorridor::setCoordinateVector(const QVector<QPointF> & coordinateVec, CoordinateSystem cs )
{
setCoordinateVectorWidth( coordinateVec, 0.0, cs );
} /* RubberbandCorridor::setCoordinateVector */
void RubberbandCorridor::setCoordinateVectorWidth(const QVector<QPointF> & coordinateVec, qreal corridorWidth, CoordinateSystem cs )
{
if (coordinateVec.size() < 2) return;
if (corridorWidth < 0)
{
QVector<QPointF> reverseVec;
reverseVec.reserve(coordinateVec.size());
for (const auto &point : coordinateVec)
{
reverseVec.push_front(point);
}
RubberbandMultiPointFeature::setCoordinateVector(reverseVec, cs);
}
else RubberbandMultiPointFeature::setCoordinateVector( coordinateVec, cs );
_corridorWidth = fabs(corridorWidth);
enableModificationState();
constructWidthHandle();
_baseInternal->_applyIsPossible = true;
activateButtons();
update();
} /* RubberbandCorridor::setCoordinateVectorWidth */
QVector<QPointF> RubberbandCorridor::centerLine( CoordinateSystem cs )
{
if (_inputMode == InputMode::InputCenterLine)
{
return RubberbandMultiPointFeature::coordinateVector( cs );
}
QVector<QPointF> cLine;
QVector<QPointF> cLineRet;
// getCenterLineFromHandleBorder( cLine, _corridorWidth * ((_internal->_corridorSceneWidth >= 0) ? 0.5 : -0.5), true );
getCenterLineFromHandleBorder( cLine, _corridorWidth * 0.5, true );
cLineRet.reserve(cLine.size());
for (const auto &point : qAsConst(cLine))
cLineRet.push_back(projectCoordinateFromMap( cs, point ));
return cLineRet;
} /* RubberbandCorridor::centerLine */
void RubberbandCorridor::setCenterLine( const QVector<QPointF> & coordinateVec, qreal corridorWidth, CoordinateSystem cs )
{
if (_inputMode == InputMode::InputBoundary)
{
const QVector<QPointF> &borderLine = getCenterLineFromBorder( coordinateVec, corridorWidth*-0.5,cs);
setCoordinateVectorWidth( borderLine, corridorWidth, CoordinateSystem::Map);
return;
}
setCoordinateVectorWidth( coordinateVec, corridorWidth, cs );
} /* RubberbandCorridor::setCenterLine */
QVector<QPointF> RubberbandCorridor::frontLine(CoordinateSystem cs)
{
if (_inputMode == InputMode::InputBoundary)
{
const QVector<QPointF> & fLine = RubberbandMultiPointFeature::coordinateVector(cs);
if (_internal->_corridorSceneWidth >= 0) return fLine;
// reverse order of coordinates
QVector<QPointF> fLineRet;
fLineRet.reserve(fLine.size());
for (const auto & point : fLine)
{
fLineRet.push_front(point);
}
return fLineRet;
}
// In case of InputMode::InputCenterLine construct centerLine
QVector<QPointF> fLine;
getCenterLineFromHandleBorder(fLine, _corridorWidth*-1.0, true);
if (_internal->_corridorSceneWidth >= 0)
{
for (QPointF & point : fLine)
{
point = projectCoordinateFromMap(cs, point);
}
return fLine;
}
// reverse order of coordinates
QVector<QPointF> fLineRet;
fLineRet.reserve(fLine.size());
for (const auto & point : qAsConst(fLine))
{
fLineRet.push_front( projectCoordinateFromMap(cs,point) );
}
return fLineRet;
} /* RubberbandCorridor::frontLine */
void RubberbandCorridor::setFrontLine(const QVector<QPointF> & coordinateVec, qreal corridorWidth, CoordinateSystem cs)
{
if (_inputMode == InputMode::InputBoundary)
{
setCoordinateVectorWidth(coordinateVec, corridorWidth, cs);
}
// In case of InputMode::InputCenterLine construct centerLine
const QVector<QPointF> &centerLine = getCenterLineFromBorder( coordinateVec, corridorWidth*0.5, cs);
setCoordinateVectorWidth(centerLine, corridorWidth, CoordinateSystem::Map);
} /* RubberbandCorridor::setFrontLine */
void RubberbandCorridor::constructWidth( const QPointF & scenePos )
{
if (Rubberband::_internal->_handleList.size() < 2) return;
QPointF p0 = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._sceneCoordinate;
QPointF p1 = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate;
QPointF rv( p0.y()-p1.y(), p1.x()-p0.x() );
rv /= sqrt(rv.x()*rv.x()+rv.y()*rv.y());
QPointF pScene = scenePos - p1;
qreal scalarProduct = pScene.x()*rv.x() + pScene.y()*rv.y();
if (_inputMode == InputMode::InputCenterLine) scalarProduct *= 2;
_internal->_corridorSceneWidth = scalarProduct;
rv *= scalarProduct;
RubberbandHandle::RubberbandCoordinate pointW( Rubberband::_internal->_mapView, p1+rv );
rv = QPointF( pointW._mapCoordinate.x() - static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._mapCoordinate.x()
, pointW._mapCoordinate.y() - static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._mapCoordinate.y() );
// _corridorWidth = sqrt(rv.x()*rv.x()+rv.y()*rv.y());
_corridorWidth = (scalarProduct > 0 ) ? sqrt(rv.x()*rv.x()+rv.y()*rv.y()) : - sqrt(rv.x()*rv.x()+rv.y()*rv.y());
bool constrainsComplied = true;
if (_corridorWidth != 0.0)
{
qreal constraintFactor = 1.0;
if (_minimumCorridorWidth > fabs(_corridorWidth)) { constraintFactor = _minimumCorridorWidth / _corridorWidth; constrainsComplied = false; }
if (_maximumCorridorWidth < fabs(_corridorWidth)) { constraintFactor = _maximumCorridorWidth / fabs(_corridorWidth); constrainsComplied = false; }
_corridorWidth *= constraintFactor;
_internal->_corridorSceneWidth *= constraintFactor;
}
else
{
if (_minimumCorridorWidth > 0)
{
_corridorWidth = _minimumCorridorWidth;
const QPointF & whp = calcWidthHandlePosition();
Esri::ArcGISRuntime::MapGraphicsView * mapView = Rubberband::_internal->_mapView;
RubberbandDrawable::RubberbandCoordinate widthCoordinate( mapView, convert( whp, mapView->map()->spatialReference() ));
const QPointF & p0 = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate;
const QPointF & p1 = widthCoordinate._sceneCoordinate;
QPointF rv( p0.y()-p1.y(), p1.x()-p0.x() );
_internal->_corridorSceneWidth = sqrt(rv.x()*rv.x()+rv.y()*rv.y());
if (_inputMode == InputMode::InputCenterLine) _internal->_corridorSceneWidth *= 2;
}
}
markFailedConstrains( scenePos, !constrainsComplied );
} /* RubberbandCorridor::constructWidth */
QPointF RubberbandCorridor::getWidthHandleScenePosition() const
{
QPointF p0 = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._sceneCoordinate;
QPointF p1 = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate;
QPointF rv( p0.y()-p1.y(), p1.x()-p0.x() );
rv /= sqrt(rv.x()*rv.x()+rv.y()*rv.y());
if ((std::numeric_limits<qreal>::infinity() != rv.x()) && (std::numeric_limits<qreal>::infinity() != rv.y()))
{
rv *= _internal->_corridorSceneWidth;
if (_inputMode == InputMode::InputCenterLine) rv *= 0.5;
return p1 + rv;
}
return p1;
} /* RubberbandCorridor::getWidthHandleScenePosition */
QPointF RubberbandCorridor::calcWidthHandlePosition()
{
qreal p0X = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._mapCoordinate.x();
qreal p0Y = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._mapCoordinate.y();
qreal p1X = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._mapCoordinate.x();
qreal p1Y = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._mapCoordinate.y();
QPointF p( p1Y-p0Y, p1X-p0X );
qreal lp = _corridorWidth / sqrt(p.x()*p.x()+p.y()*p.y());
if (std::numeric_limits<qreal>::infinity() != lp)
{
p *= lp;
if (_inputMode == InputMode::InputCenterLine) p *= 0.5;
p = QPointF(p1X,p1Y) + p;
}
else p = QPointF(p1X,p1Y);
return p;
} /* RubberbandCorridor::calcWidthHandlePosition */
void RubberbandCorridor::constructWidthHandle()
{
if (Rubberband::_internal->_handleList.size() < 2) return;
if ((fabs(_corridorWidth) <= _minimumCorridorWidth) || (fabs(_corridorWidth) >= _maximumCorridorWidth))
{
enableConstructionWidthState();
deactivateButtons();
}
const QPointF & p = calcWidthHandlePosition();
const Esri::ArcGISRuntime::Point mapP( convert(p, Rubberband::_internal->_mapView->map()->spatialReference()) );
_internal->_widthHandle = new RubberbandPointHandle( Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, mapP );
qreal pX = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._mapCoordinate.x();
qreal pY = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._mapCoordinate.y();
_internal->_widthLine = new RubberbandLineHandle( Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, QPointF(pX,pY), p, 2, true );
pX = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate.x();
pY = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate.y();
const QPointF & pScene = _internal->_widthHandle->getCoordinate()._sceneCoordinate;
pX -= pScene.x();
pY -= pScene.y();
_internal->_corridorSceneWidth = sqrt(pX*pX+pY*pY);
if (_inputMode == InputMode::InputCenterLine) _internal->_corridorSceneWidth *= 2;
// connect signal to call updateBufferGeometry when zooming or resizing the window
// connect( _internal->_widthHandle.get(), &RubberbandHandle::adjusted, [this]() { this->updateBufferGeometry(); } );
// doesn't work because not all handles are adjusted this time ...
// but we have to ensure that coordinateSceneWidth have all ways the correct value:
connect( _internal->_widthHandle.get(), &RubberbandHandle::adjusted, this, &RubberbandCorridor::onDo_adjustCorridorSceneWidth );
} /* RubberbandCorridor::constructWidthHandle */
void RubberbandCorridor::onDo_adjustCorridorSceneWidth()
{
if (Rubberband::_internal->_handleList.size() > 1)
{
qreal pX = static_cast<RubberbandPointHandle*>(this->Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate.x();
qreal pY = static_cast<RubberbandPointHandle*>(this->Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate.y();
const QPointF & pScene = this->_internal->_widthHandle->getCoordinate()._sceneCoordinate;
pX -= pScene.x();
pY -= pScene.y();
qreal sceneWidth = sqrt(pX*pX+pY*pY);
if (_inputMode == InputMode::InputCenterLine) sceneWidth *= 2;
_internal->_corridorSceneWidth = (_internal->_corridorSceneWidth >= 0) ? sceneWidth : -sceneWidth;
}
} /* RubberbandCorridor::onDo_adjustCorridorSceneWidth */
void RubberbandCorridor::updateHandleScenePosition()
{
if (!_internal->_widthHandle) return;
QPointF pos = getWidthHandleScenePosition();
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " old handle Position = " << _internal->_widthHandle->getCoordinate()._sceneCoordinate.x()
<< " ; " << _internal->_widthHandle->getCoordinate()._sceneCoordinate.y()
<< " new handle position = " << pos.x() << " ; " << pos.y()
<< " width = " << _corridorWidth
<< " scene width = " << _internal->_corridorSceneWidth;
_internal->_widthHandle->updateCoordinate( pos );
const QPointF & lp1 = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate;
_internal->_widthLine->updateCoordinate( 0, lp1 );
_internal->_widthLine->updateCoordinate( 1, pos );
} /* RubberbandCorridor::updateHandleScenePosition */
bool RubberbandCorridor::getCenterLineFromHandleBorder( QVector<QPointF> & centerLine, qreal corridorWidth, bool mapCoordinates )
{
ClipperLib::ClipperOffset pathOffset;
ClipperLib::Path borderPath;
ClipperLib::Path offsetPath;
int precision = (mapCoordinates) ? 1000 : 10;
qreal baseX = 0.0;
qreal baseY = 0.0;
bool initBase = true;
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * pointHandlePtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
const RubberbandPointHandle::RubberbandCoordinate & pointCoordinate = pointHandlePtr->getCoordinate();
qreal x = (mapCoordinates) ? pointCoordinate._mapCoordinate.x() : pointCoordinate._sceneCoordinate.x();
qreal y = (mapCoordinates) ? pointCoordinate._mapCoordinate.y() : -pointCoordinate._sceneCoordinate.y();
if (mapCoordinates)
{
// use relative coordinates to avoid to large numbers
if (initBase)
{
baseX = x; baseY = y; x = 0.0; y = 0.0;
initBase = false;
}
else { x -= baseX; y -= baseY; }
}
borderPath << ClipperLib::IntPoint(int(x*precision),int(y*precision));
}
bool ok = pathOffset.PathOffset( borderPath, offsetPath, int(corridorWidth*precision) );
ClipperLib::Path::const_iterator it = offsetPath.begin();
if (mapCoordinates)
{
for (; it != offsetPath.end(); ++it)
{
centerLine << QPointF(qreal(it->X)/qreal(precision)+baseX, qreal(it->Y)/qreal(precision)+baseY);
}
}
else
{
for (; it != offsetPath.end(); ++it)
{
centerLine << QPointF(qreal(it->X)/qreal(precision)+baseX, qreal(-it->Y)/qreal(precision)-baseY);
}
}
return ok;
} /* RubberbandCorridor::getCenterLineFromHandleBorder */
QVector<QPointF> RubberbandCorridor::getCenterLineFromBorder(const QVector<QPointF> & borderLine, qreal corridorWidth, CoordinateSystem cs)
{
const int precision = 1000;
QVector<QPointF> centerLine;
ClipperLib::ClipperOffset pathOffset;
ClipperLib::Path borderPath;
ClipperLib::Path offsetPath;
qreal baseX = 0.0;
qreal baseY = 0.0;
bool initBase = true;
for (const auto &point : borderLine)
{
const QPointF & mapPoint = projectCoordinateToMap(cs, point);
qreal x = mapPoint.x();
qreal y = mapPoint.y();
// use relative coordinates to avoid to large numbers
if (initBase)
{
baseX = x; baseY = y; x = 0.0; y = 0.0;
initBase = false;
}
else { x -= baseX; y -= baseY; }
borderPath << ClipperLib::IntPoint(int(x*precision), int(y*precision));
}
if (pathOffset.PathOffset(borderPath, offsetPath, int(corridorWidth*precision)))
{
centerLine.reserve(100);
for (const auto &p : offsetPath)
{
centerLine << QPointF( qreal(p.X)/qreal(precision)+baseX, qreal(p.Y)/qreal(precision)+baseY );
}
}
return centerLine;
} // RubberbandCorridor::getCenterLineFromBorder
void RubberbandCorridor::updateBufferGeometry()
{
if (!_internal->_widthHandle) return;
QVector<QPointF> centerLine;
qreal corridorWidth = 0.0;
bool centerLineOk = true;
centerLine.reserve(Rubberband::_internal->_handleList.size() );
switch (_inputMode)
{
case InputMode::InputBoundary:
{
corridorWidth = _internal->_corridorSceneWidth * 0.5;
centerLineOk = getCenterLineFromHandleBorder( centerLine, corridorWidth, false );
if (_internal->_centerLineItem == nullptr)
{
_internal->_centerLineItem = new DrawablePainterPath( Rubberband::_internal->_mapView );
}
_internal -> _centerLineItem -> setDrawColor( centerLineOk ? _drawColor : QColor(255,0,0) );
_internal -> _centerLineItem -> setFillColor( QColor(0,0,0,0) ); // turn off filling
_internal -> _centerLineItem -> dottedPath( centerLineOk );
_internal -> _centerLineItem -> setVisibility( true );
_internal -> _centerLineItem -> enableClosedLine( !centerLineOk );
_internal -> _centerLineItem -> setPath( centerLine );
} break;
case InputMode::InputCenterLine:
{
corridorWidth = _internal->_corridorSceneWidth * 0.5;
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * pointHandlePtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
const RubberbandPointHandle::RubberbandCoordinate & pointCoordinate = pointHandlePtr->getCoordinate();
qreal x = pointCoordinate._sceneCoordinate.x();
qreal y = pointCoordinate._sceneCoordinate.y();
centerLine.append( QPointF(x,y) );
}
_internal -> _centerLineItem = nullptr;
} break;
}
ClipperLib::ClipperOffset pathOffset;
ClipperLib::Path borderPath;
ClipperLib::Paths offsetPathVec;
QVector<RubberbandHandle::RubberbandCoordinate> vertexSet;
for (auto point : qAsConst(centerLine))
borderPath << ClipperLib::IntPoint(int(point.x()*10),int(-point.y()*10));
pathOffset.AddPath( borderPath, ClipperLib::JoinType::jtSquare, ClipperLib::EndType::etOpenButt);
pathOffset.Execute( offsetPathVec, int(fabs(corridorWidth)*10) );
if (centerLineOk)
{
if (_internal->_geoBufferItem) _internal->_geoBufferItem->setVisibility(false);
for (auto path : offsetPathVec)
{
ClipperLib::Path::const_iterator it = path.begin();
for (; it != path.end(); ++it)
{
vertexSet.append( RubberbandHandle::RubberbandCoordinate( Rubberband::_internal->_mapView
, QPointF(qreal(it->X)/10.0,qreal(-it->Y)/10.0) ));
}
if (!vertexSet.empty())
{
if (!_internal->_geoBufferItem)
{
_internal->_geoBufferItem = new DrawablePainterPath( Rubberband::_internal->_mapView );
}
_internal -> _geoBufferItem -> setVisibility( true );
_internal -> _geoBufferItem -> enableClosedLine( true );
_internal -> _geoBufferItem -> setDrawColor( _corridorBorderColor );
_internal -> _geoBufferItem -> setFillColor( _corridorFillColor );
_internal -> _geoBufferItem -> setPath( vertexSet );
}
break;
}
}
else if (_internal->_geoBufferItem) _internal->_geoBufferItem->setVisibility(false);
RubberbandFrameHandle * frameHandle = getFrameHandle();
if (frameHandle)
{
if (vertexSet.isEmpty())
{
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * pointHandlePtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
vertexSet.append(pointHandlePtr->getCoordinate() );
}
if (_internal->_widthHandle != nullptr)
{
vertexSet.append( _internal->_widthHandle->getCoordinate() );
}
}
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " frameHandle->updateFrameShape( vertexSet );";
frameHandle->updateFrameShape( vertexSet );
}
if (!vertexSet.isEmpty())
{
qreal minX = vertexSet.first()._sceneCoordinate.x();
qreal maxX = minX;
qreal minY = vertexSet.first()._sceneCoordinate.y();
qreal maxY = minY;
for (const auto &v : qAsConst(vertexSet))
{
const QPointF & p = v._sceneCoordinate;
if (p.x() < minX) minX = p.x();
if (p.y() < minY) minY = p.y();
if (p.x() > maxX) maxX = p.x();
if (p.y() > maxY) maxY = p.y();
}
_internal->_sceneBbox.setCoords( minX, minY, maxX, maxY );
if (!isButtonBoxPositionFixed())
{
RubberbandBase::_baseInternal->_buttonBoxSceneAnchor = QPointF(maxX,maxY);
}
}
else _internal->_sceneBbox = QRectF();
} /* RubberbandCorridor::updateBufferGeometry*/
bool RubberbandCorridor::bufferPolygon( QVector<QPointF> & coordinateVec, CoordinateSystem cs )
{
coordinateVec.clear();
const QVector<QPointF> & cLine = centerLine( CoordinateSystem::Map );
if (cLine.size() < 2) return false;
ClipperLib::ClipperOffset pathOffset;
ClipperLib::Path borderPath;
ClipperLib::Paths offsetPathVec;
int precision = 1000;
const QPointF & basePoint = cLine.first();
for (const auto &point : cLine)
{
borderPath << ClipperLib::IntPoint(int((point.x()-basePoint.x())*precision),
int((point.y()-basePoint.y())*precision));
}
pathOffset.AddPath( borderPath, ClipperLib::JoinType::jtSquare, ClipperLib::EndType::etOpenButt);
pathOffset.Execute( offsetPathVec, int(fabs(_corridorWidth*0.5)*precision) );
if (offsetPathVec.empty()) return false;
const ClipperLib::Path & bufferCoordinates = offsetPathVec.front();
if (bufferCoordinates.empty()) return false;
coordinateVec.reserve(bufferCoordinates.size());
for (const ClipperLib::IntPoint & p : bufferCoordinates)
{
const QPointF & vertex = QPointF( qreal(p.X)/qreal(precision), qreal(p.Y)/qreal(precision) ) + basePoint;
coordinateVec << projectCoordinateFromMap( cs, vertex );
}
return true;
} /* RubberbandCorridor::bufferPolygon */
void RubberbandCorridor::resetAction(AbstractEventDispatcher * causer, int x, int y )
{
if (rubberbandIsAlive())
{
if (!isEnabledConstructionWidthState())
{
if (isEnabledConstructionState())
{
RubberbandMultiPointFeature::resetAction(causer,x,y);
return;
}
}
}
RubberbandMultiPointFeature::resetAction(causer,x,y);
} /* RubberbandCorridor::resetAction */
bool RubberbandCorridor::selectAction( AbstractEventDispatcher * causer, int x, int y )
{
Q_UNUSED(causer);
if (!rubberbandIsAlive()) return false;
bool eventHandled = false;
QPointF scenePos(pixel2ScenePosition(x,y));
if (_baseInternal->buttonProxyActive(scenePos)) return false;
_baseInternal->_lastClickPosition = scenePos;
if (!isEnabledConstructionWidthState())
{
if (isEnabledConstructionState()) return RubberbandMultiPointFeature::selectAction(causer,x,y);
if (_internal->_widthHandle->isPositionInside(scenePos))
{
_internal->_widthHandle->setSelection();
eventHandled = true;
}
else return RubberbandMultiPointFeature::selectAction(causer,x,y);
}
else eventHandled = true;
if (eventHandled)
{
update();
deactivateButtons();
}
return eventHandled;
} /* RubberbandCorridor::selectAction */
bool RubberbandCorridor::setCoordinateAction(AbstractEventDispatcher * causer, int x, int y)
{
Q_UNUSED(causer);
markFailedConstrains( QPointF(), false );
if (!rubberbandIsAlive()) return false;
bool eventHandled = false;
QPointF scenePos(pixel2ScenePosition(x,y));
if (isEnabledConstructionWidthState())
{
Rubberband::_internal->_lastClickPosition = scenePos;
constructWidth( scenePos );
updateHandleScenePosition();
disenableConstructionWidthState();
enableModificationState();
eventHandled = true;
markFailedConstrains( QPointF(), false );
}
else
{
if (isEnabledConstructionState())
{
bool handled = RubberbandMultiPointFeature::setCoordinateAction(causer,x,y);
if (isEnabledConstructionWidthState())
{
// guarantee that buttons are of
deactivateButtons();
}
return handled;
}
if (_internal->_widthHandle->isSelected())
{
_internal->_widthHandle->setSelection(false);
constructWidth( scenePos );
markFailedConstrains( QPointF(), false );
eventHandled = true;
RubberbandMultiPointFeature::setCoordinateAction(causer,x,y);
}
else return RubberbandMultiPointFeature::setCoordinateAction(causer,x,y);
}
if (eventHandled) update();
updateButtonPosition();
activateButtons();
return eventHandled;
} /* RubberbandCorridor::setCoordinateAction */
bool RubberbandCorridor::movePickedAction(AbstractEventDispatcher * causer, int x, int y )
{
adjustConnectedPreviewPixmap(x,y);
if (!rubberbandIsAlive()) return false;
if ((isEnabledConstructionWidthState()) || ((_internal->_widthHandle) && (_internal->_widthHandle->isSelected())))
{
QPointF scenePos(pixel2ScenePosition(x,y));
constructWidth( scenePos );
update();
return false;
}
return RubberbandMultiPointFeature::movePickedAction(causer,x,y);
} /* RubberbandCorridor::movePickedAction */
bool RubberbandCorridor::moveAction(AbstractEventDispatcher * causer, int x, int y)
{
adjustConnectedPreviewPixmap(x,y);
QPointF scenePos(pixel2ScenePosition(x,y));
if (isEnabledConstructionWidthState())
{
constructWidth( scenePos );
update();
return false;
}
if (_internal->_widthHandle)
{
if (_internal->_widthHandle->isPositionInside(scenePos))
{
_internal->_widthHandle->setSelection(true);
return true;
}
_internal->_widthHandle->setSelection(false);
}
return RubberbandMultiPointFeature::moveAction(causer,x,y);
} /* RubberbandCorridor::moveAction */
bool RubberbandCorridor::completeStateAction(AbstractEventDispatcher * causer, int x, int y)
{
if ((rubberbandIsAlive()) && (Rubberband::_internal->_mapView) && (Rubberband::_internal->_mapScene))
{
if (isEnabledConstructionWidthState())
{
if (!_finishAfterConstruction)
{
disenableSelectedState();
enableModificationState();
update();
return true;
}
}
if (isEnabledConstructionState())
{
if ((unsigned int)Rubberband::_internal->_handleList.size() >= _minimumPointCount)
{
disenableConstructionState();
if ((fabs(_corridorWidth) <= _minimumCorridorWidth) || (fabs(_corridorWidth) >= _maximumCorridorWidth))
{
enableConstructionWidthState();
deSelectHandles();
disenableSelectedState();
deactivateButtons();
updatePreviewLine(QPointF(0,0));
constructWidth( static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate );
constructWidthHandle();
if (_internal->_widthHandle)
{
_internal->_widthHandle->setSelection(true);
}
}
else
{
if (_finishAfterConstruction)
{
return applyAndEndAction(causer,x,y);
}
else
{
deSelectHandles();
constructWidthHandle();
disenableSelectedState();
enableModificationState();
}
}
}
update();
return true;
}
return applyAndEndAction(causer,x,y);
}
return false;
} /* RubberbandCorridor::completeStateAction */
void RubberbandCorridor::activateButtons()
{
if (isEnabledConstructionWidthState())
{
_baseInternal->_applyIsPossible = false;
_baseInternal->_undoIsPossible = false;
RubberbandMultiPointFeature::activateButtons();
}
else RubberbandMultiPointFeature::activateButtons();
} /* RubberbandCorridor::activateButtons */
QRectF RubberbandCorridor::sceneBbox() const
{
if (_internal->_sceneBbox.isValid()) return _internal->_sceneBbox;
else return Rubberband::sceneBbox();
} /* RubberbandCorridor::sceneBbox */
void RubberbandCorridor::update()
{
RubberbandMultiPointFeature::update();
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION;
_isClosed = false;
if (_internal->_widthHandle)
{
_internal->_widthHandle -> setDrawColor(_handleDrawColor);
_internal->_widthHandle -> setFillColor(_handleFillColor);
_internal->_widthHandle -> setSelectionColor(_handleSelectionColor);
_internal->_widthHandle -> setPickingRatio( _pickingRatio );
updateHandleScenePosition();
updateBufferGeometry();
}
} /* RubberbandCorridor::update */
} } /* namespace SituationMap::RB */
+239
View File
@@ -0,0 +1,239 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define multi point feature geoemtry
** $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 .........:
**
** 17.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband_multi_point_feature.h"
namespace SituationMap { namespace RB
{
/**
@class RubberbandCorridor rubberband_corridor.h
@brief Implementation of a rubberband for corridors.
@see RubberbandFactory, Rubberband, RubberbandMultiPointFeature
Implementation of rubberbands used to input corridors. There are two different modes \c InputCenterLine and \c InputBoundary. In the
InputCenterLine mode the center line of the corridor has to be defined. The rubberband displays then the border geometry.
In the InputBoundary mode one side of the border has to be defined. The \c coordinateVector methodes always working on the input geometry.
*/
class SITUATIONMAP_EXPORT RubberbandCorridor : public RubberbandMultiPointFeature
{
Q_OBJECT
public:
enum class InputMode
{
InputCenterLine,
InputBoundary
}; /* InputMethode */
/**
@name Construction & Destruction
@{
Construction of one instance of class RubberbandCorridor.
@param map Pointer to SituationMap class instance
@param mode Two mode are distinguished. In \c InputCenterLine mode the coordinates will be interpreted as center line of the corridor.
In \c InputBoundary the coordinates are defining one border.
@param width With of a corridor in meters. In \c InputBoundary the coordinates are defining one border. If \c corridorWidth is negative
the coordinates are the right border otherwise the left one.
*/
private:
friend class RubberbandFactory;
explicit RubberbandCorridor( SituationMap::Map * map, QObject * parent );
explicit RubberbandCorridor( SituationMap::Map * map, InputMode mode = InputMode::InputBoundary, qreal width = 0, QObject * parent = nullptr );
public:
~RubberbandCorridor();
/** @} */
/**
@addtogroup States Methodes to query and modify rubberband states
@{
*/
bool isEnabledConstructionWidthState() const;
void enableConstructionWidthState();
void disenableConstructionWidthState();
/** @} */
inline bool isEnabledInputBoundary() const { return _inputMode == InputMode::InputBoundary; }
inline void setInputBoundary() { _inputMode = InputMode::InputBoundary; }
inline void setInputCenterline() { _inputMode = InputMode::InputCenterLine; }
/**
Sets coordinates to modify to internal coordinate list.
@param coordinateVec List of coordinates to modify
@param cs Defines the coordinate system of returned coordinates.
*/
void setCoordinateVector( const QVector<QPointF> & coordinateVec, CoordinateSystem cs = CoordinateSystem::Geo ) override;
/**
Sets coordinates to modify to internal coordinate list. In \c InputCenterLine mode the coordinates will be interpreted as
center line of the corridor. In \c InputBoundary the coordinates are defining one border. If \c corridorWidth is negative
the coordinates are the right border otherwise the left one.
@param coordinateVec List of coordinates to modify
@param corridorWidth Width of corridor in meters.
@param cs Defines the coordinate system of returned coordinates.
*/
void setCoordinateVectorWidth(const QVector<QPointF> & coordinateVec, qreal corridorWidth, CoordinateSystem cs = CoordinateSystem::Geo );
/**
Returns the center line of the corridor
@param cs Defines the coordinate system of returned coordinates.
*/
QVector<QPointF> centerLine( CoordinateSystem cs = CoordinateSystem::Geo );
/**
Sets the center line of the corridor.
@param coordinateVec List of coordinates of border to modify
@param corridorWidth Width of corridor in meters
@param cs Defines the coordinate system of returned coordinates.
*/
void setCenterLine( const QVector<QPointF> & coordinateVec, qreal corridorWidth, CoordinateSystem cs = CoordinateSystem::Geo );
/**
Returns the front line of the rubberband.
@param cs Defines the coordinate system of returned coordinates.
*/
QVector<QPointF> frontLine(CoordinateSystem cs = CoordinateSystem::Geo);
/**
Sets the front line of the corridor.
@param coordinateVec List of coordinates of border to modify
@param corridorWidth Width of corridor in meters
@param cs Defines the coordinate system of returned coordinates.
*/
void setFrontLine(const QVector<QPointF> & coordinateVec, qreal corridorWidth, CoordinateSystem cs = CoordinateSystem::Geo);
/**
Provides the buffer polygon (outline) of the corridor.
@param coordinateVec Coordinate list of buffer polygon
@param cs Defines the coordinate system of returned coordinates.
@return true on success otherwise false
*/
bool bufferPolygon( QVector<QPointF> & coordinateVec, CoordinateSystem cs = CoordinateSystem::Geo );
/**
Return the width of the corridor.
*/
qreal corridorWidth() const;
/**
Set the width of the corridor.
*/
inline void setCorridorWidth(qreal width) { _corridorWidth = width;}
/**
@name Constrains for corridor width
@{
*/
void minimumCorridorWidth( qreal min );
void maximumCorridorWidth( qreal max );
qreal minimumCorridorWidth() const { return _minimumCorridorWidth; }
qreal maximumCorridorWidth() const { return _maximumCorridorWidth; }
/** @} */
bool selectAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool setCoordinateAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool movePickedAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool moveAction ( AbstractEventDispatcher * causer, int x, int y ) override;
void resetAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool completeStateAction ( AbstractEventDispatcher * causer, int x, int y ) override;
QColor getCorridorBorderColor() const { return _corridorBorderColor; }
QColor getCorridorFillColor() const { return _corridorFillColor; }
void setCorridorBorderColor( const QColor & color ) { _corridorBorderColor = color; }
void setCorridorFillColor ( const QColor & color ) { _corridorFillColor = color; }
protected:
/*
Forward declaration of InternalData to hold private member variables. Becareful 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;
InputMode _inputMode;
qreal _corridorWidth;
qreal _minimumCorridorWidth;
qreal _maximumCorridorWidth;
QColor _corridorBorderColor;
QColor _corridorFillColor;
void activateButtons() override;
QRectF sceneBbox() const override;
void update() override;
QPointF calcWidthHandlePosition();
void constructWidth( const QPointF & );
void constructWidthHandle();
QPointF getWidthHandleScenePosition() const;
bool getCenterLineFromHandleBorder(QVector<QPointF> & centerLine, qreal corridorWidth, bool mapCoordinates);
QVector<QPointF> getCenterLineFromBorder(const QVector<QPointF> & borderLine, qreal corridorWidth, CoordinateSystem cs );
void updateHandleScenePosition();
void updateBufferGeometry();
private slots:
void onDo_adjustCorridorSceneWidth();
}; /* RubberbandCorridor */
} } /* namespace SituationMap::RB */
+155
View File
@@ -0,0 +1,155 @@
/**
**
** @RDE_HEADER@
** Implementation of base class for rubberband handles
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_drawable.h"
// ESRI
#include <arcgis/Map.h>
namespace SituationMap { namespace RB
{
Esri::ArcGISRuntime::Point convert(const QPointF &point, const Esri::ArcGISRuntime::SpatialReference& spatialReference)
{
return Esri::ArcGISRuntime::Point(point.x(), point.y(), spatialReference);
} // convert
RubberbandDrawable::RubberbandDrawable( QGraphicsView * view )
: _scene((view) ? view->scene() : nullptr)
, _mapView()
, _isVisible(true)
, _lineWidth(1)
, _zBufferValue((unsigned int) ZBufferPlane::Drawables)
, _logger(getLogger("RubberbandDrawable"))
{
doConnecting();
} /* RubberbandDrawable::RubberbandDrawable */
RubberbandDrawable::RubberbandDrawable( Esri::ArcGISRuntime::MapGraphicsView * mapView )
: _scene(mapView->scene())
, _mapView(mapView)
, _isVisible(true)
, _lineWidth(1)
, _zBufferValue((unsigned int) ZBufferPlane::Drawables)
, _logger(getLogger("RubberbandDrawable"))
{
doConnecting();
} /* RubberbandDrawable::RubberbandDrawable */
RubberbandDrawable::RubberbandDrawable( Esri::ArcGISRuntime::MapGraphicsView * mapView, QGraphicsScene * scene)
: _scene(scene)
, _mapView(mapView)
, _isVisible(true)
, _lineWidth(1)
, _zBufferValue((unsigned int) ZBufferPlane::Drawables)
, _logger(getLogger("RubberbandDrawable"))
{
doConnecting();
} /* RubberbandDrawable::RubberbandDrawable */
#ifdef ADJUST_COORDINATES_EVERY_PAINT_EVENT
bool RubberbandDrawable::eventFilter( QObject*, QEvent * e )
{
if (e)
{
if (e->type() == QEvent::Paint)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Sometimes the signals extentChanges and rectChanged of Esri Map Widget are not emitted. In this case
* the position update of handles and drawabled fails and they are drawn at wrong positions on map. As
* workaround updates coordinates at every paint event.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
DEBUG_LOG(_logger) << LOGFUNCTION << " paint event";
onDo_adjustCoordinates();
}
}
return false;
} /* RubberbandDrawable::eventFilter */
#endif
void RubberbandDrawable::doConnecting()
{
if (nullptr == _mapView) return;
#ifdef ADJUST_COORDINATES_EVERY_PAINT_EVENT
_view -> installEventFilter( this );
#endif
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* It is really important to specify the connnection type as following. Because the onDo_adjustCoordinates
* should be call as soon as possible to get smooth changes of map. The connection type is DirectConnnection here.
* The rectChanged signal is some times emitted, when the calculation of screen coordinates to map coordinates
* and vice versa has not been updated to the new map window size. In this case all calculations provides wrong
* results. Using the connection type QueuedConnection defers the call of onDo_adjustWindow.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
// Check Quartz
connect( _mapView.data(), &Esri::ArcGISRuntime::MapGraphicsView::viewpointChanged,
this, &RubberbandDrawable::onDo_adjustCoordinates, Qt::ConnectionType::DirectConnection );
connect( _mapView.data(), &Esri::ArcGISRuntime::MapGraphicsView::rectChanged ,
this, &RubberbandDrawable::onDo_adjustWindow , Qt::ConnectionType::QueuedConnection );
} /* RubberbandDrawable::doConnecting */
void RubberbandDrawable::onDo_adjustCoordinates()
{
adjustCoordinates();
forceUpdateViewWidget();
} /* RubberbandDrawable::onDo_adjustCoordinates */
void RubberbandDrawable::onDo_adjustWindow( const QRectF &r )
{
adjustWindow(r);
forceUpdateViewWidget();
} /* RubberbandDrawable::onDo_adjustWindow */
void RubberbandDrawable::makeLineStyle( bool dottedLine, QPen & lineStyle )
{
lineStyle.setColor( _drawColor );
lineStyle.setWidth( int(_lineWidth) );
if (dottedLine) lineStyle.setStyle( Qt::DashDotLine );
else lineStyle.setStyle( Qt::SolidLine );
} /* DrawablePainterPathItem::makeLineStyle */
RubberbandDrawable::~RubberbandDrawable() { if (_mapView) _mapView->removeEventFilter(this); }
} } /* namespace SituationMap::RB */
+212
View File
@@ -0,0 +1,212 @@
/**
**
** @RDE_HEADER@
** Definition of base class for rubberband drawing objects
** $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 <QtCore/QObject>
#include <QtGui/QColor>
#include <arcgis/MapGraphicsView.h>
#include <arcgis/Point.h>
#include <Common/referenced.h>
#include <Common/situation_map_logging.h>
class QGraphicsScene;
namespace SituationMap { namespace RB
{
Esri::ArcGISRuntime::Point convert(const QPointF &point, const Esri::ArcGISRuntime::SpatialReference& spatialReference);
/**
@class RubberbandDrawable rubberband_drawable.h
@brief Base class of all rubberband drawables and handles for rubberband internal use.
*/
class RubberbandDrawable : public QObject, public SituationMap::Referenced
{
Q_OBJECT
public:
enum class ZBufferPlane
{
FrameHandle = 10,
Drawables = 20,
LineHandle = 30,
ArrowSymbol = 31,
PointHandle = 40,
Widget = 100
}; /* InputMethode */
/**
Manages scene and map coordinates.
*/
struct RubberbandCoordinate
{
QPointF _sceneCoordinate;
Esri::ArcGISRuntime::Point _mapCoordinate;
RubberbandCoordinate()
{}
explicit RubberbandCoordinate( const QPointF & sceneCoordinate)
{
updateSceneCoordinate( sceneCoordinate );
} /* RubberbandCoordinate */
explicit RubberbandCoordinate( Esri::ArcGISRuntime::MapGraphicsView * mapView, const QPointF & sceneCoordinate)
{
updateSceneCoordinate( mapView, sceneCoordinate );
} /* RubberbandCoordinate */
explicit RubberbandCoordinate( Esri::ArcGISRuntime::MapGraphicsView * mapView, const Esri::ArcGISRuntime::Point & mapCoordinate)
: _mapCoordinate(mapCoordinate)
{
mapToScene( mapView );
} /* RubberbandCoordinate */
inline QPointF mapToScene(Esri::ArcGISRuntime::MapGraphicsView * mapView)
{
if (!_mapCoordinate.isValid())
return QPointF();
const QPointF pixelCoordinate = mapView->locationToScreen(_mapCoordinate);
_sceneCoordinate = mapView->mapToScene( pixelCoordinate.x(), pixelCoordinate.y() );
return _sceneCoordinate;
} /* QPointF mapToScene(Esri::ArcGISRuntime::MapGraphicsView * mapView) */
inline void updateSceneCoordinate( Esri::ArcGISRuntime::MapGraphicsView * mapView, const QPointF & sceneCoordinate)
{
if (mapView)
{
_sceneCoordinate = sceneCoordinate;
QPoint pixelCoordinate = mapView->mapFromScene(sceneCoordinate);
_mapCoordinate = mapView->screenToLocation( pixelCoordinate.x(), pixelCoordinate.y() );
}
else updateSceneCoordinate( sceneCoordinate );
} /* void updateSceneCoordinate( Esri::ArcGISRuntime::MapGraphicsView * mapView, const QPointF & sceneCoordinate) */
inline void updateSceneCoordinate( const QPointF & sceneCoordinate )
{
_sceneCoordinate = sceneCoordinate;
_mapCoordinate = Esri::ArcGISRuntime::Point();
} /* void updateSceneCoordinate( const QPointF & sceneCoordinate ) */
bool isNull() const
{
return _sceneCoordinate.isNull();
}
}; /* RubberbandCoordinate */
/**
@name Construction & Destruction
@{
*/
explicit RubberbandDrawable( QGraphicsView *view );
explicit RubberbandDrawable( Esri::ArcGISRuntime::MapGraphicsView * );
explicit RubberbandDrawable( Esri::ArcGISRuntime::MapGraphicsView *, QGraphicsScene * );
~RubberbandDrawable();
/** @} */
inline bool isVisible() const { return _isVisible; }
inline void setVisibility(bool on = true) { _isVisible = on; updateGraphic(); }
inline void setDrawColor (const QColor & col) { _drawColor = col; updateGraphic(); }
inline void setFillColor (const QColor & col) { _fillColor = col; updateGraphic(); }
inline void setLineWidth(unsigned int width) { _lineWidth = width; updateGraphic(); }
inline void zBufferPlane( ZBufferPlane zPlane ) { _zBufferValue = (unsigned int) zPlane; }
inline void setZValue(qreal zValue) { _zValue = zValue; updateGraphic(); }
inline qreal zValue() const { return _zValue; }
protected:
QPointer<QGraphicsScene> _scene;
QPointer<Esri::ArcGISRuntime::MapGraphicsView> _mapView;
bool _isVisible;
QColor _drawColor;
QColor _fillColor;
unsigned int _lineWidth;
qreal _zBufferValue;
qreal _zValue{0}; // combine _zBufferValue and _zValue???
LOGGER_T _logger;
#ifdef ADJUST_COORDINATES_EVERY_PAINT_EVENT
bool eventFilter(QObject*, QEvent*) override;
#endif
virtual void updateGraphic() = 0;
void makeLineStyle( bool dottedLine, QPen & lineStyle );
inline void forceUpdateViewWidget() { _mapView->viewport()->update(); }
virtual void adjustCoordinates() = 0;
virtual void adjustWindow( const QRectF& ) = 0;
QColor transparentFillColor() const
{
QColor fillColor(_fillColor);
if (fillColor.alphaF() > 0.85)
{
fillColor.setAlphaF( fillColor.alphaF()*0.5 );
}
return fillColor;
} // QColor transparentFillColor()
protected slots:
void onDo_adjustCoordinates();
void onDo_adjustWindow(const QRectF & );
private:
void doConnecting();
}; /* RubberbandDrawable */
} } /* namespace SituationMap::RB */
+455
View File
@@ -0,0 +1,455 @@
/**
**
** @RDE_HEADER@
** Implementation of rubberband class to define point feature geoemtry
** $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 .........:
**
** 17.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_ellipse.h"
#include "drawable_ellipse.h"
#include "rubberband_point_handle.h"
#include "rubberband_internal.h"
#include "rubberband_base_internal.h"
#include <MathUtils/math_const.h>
#include <MathUtils/simple_helper.h>
#include <LtsCoordTrans/lts_coord_trans.h>
namespace SituationMap { namespace RB
{
struct RubberbandEllipse::InternalData
{
SituationMap::RefPointer<DrawableEllipse> _ellipseSymbol;
int _alphaFill = 50; // alpha value used for fill color of ellipse
QPointF _sectorOStart = QPointF(1,0);
QPointF _sectorOEnd = QPointF(1,0);
SituationMap::RefPointer<RubberbandPointHandle> _sectorStartHandle;
SituationMap::RefPointer<RubberbandPointHandle> _sectorEndHandle;
bool _sectorEnabled = false;
bool _sectorFixedAngleEnabled = false;
}; /* RubberbandEllipse::InternalData */
RubberbandEllipse::RubberbandEllipse( SituationMap::Map * map, QObject * parent )
: RubberbandRectangle(map,parent), _internal(new InternalData)
{
useDottedLineHandles(true);
} /* RubberbandEllipse::RubberbandEllipse */
RubberbandEllipse::~RubberbandEllipse()
{
delete _internal;
_internal = nullptr;
} /* RubberbandEllipse::~RubberbandEllipse */
QPointF RubberbandEllipse::getRotatedPoint(QPointF sector) const
{
qreal sinRect = 0, cosRect = 1;
getSceneRotation( sinRect, cosRect);
double angleRad = SituationMap::MathUtils::getMathAngle(QPointF(cosRect,sinRect));// angle rad
//double angleDeg = SituationMap::MathUtils::getMathAngle(QPointF(cosRect,sinRect)) * LtsCoordTrans::rad2deg();
const double clockwiseAngle = ((360*LtsCoordTrans::deg2rad()) - angleRad);// angle in rad;
// map clockwise rotation
QPointF point = sector;
point.setX( sector.x()*std::cos(clockwiseAngle) + sector.y()*std::sin(clockwiseAngle));
point.setY( -sector.x()*std::sin(clockwiseAngle) + sector.y()*std::cos(clockwiseAngle));
return point;
}
void RubberbandEllipse::setSectorStart(qreal sinPhi, qreal cosPhi)
{
_internal->_sectorOStart = QPointF( cosPhi, sinPhi );
update();
} /* RubberbandEllipse::setSectorStart */
void RubberbandEllipse::setSectorEnd(qreal sinPhi, qreal cosPhi)
{
_internal->_sectorOEnd = QPointF( cosPhi, sinPhi );
update();
} /* RubberbandEllipse::setSectorEnd */
QPointF RubberbandEllipse::sectorStart() const
{
return getRotatedPoint(_internal->_sectorOStart);
} /* RubberbandEllipse::sectorStart */
QPointF RubberbandEllipse::sectorEnd() const
{
return getRotatedPoint(_internal->_sectorOEnd);
} /* RubberbandEllipse::sectorEnd */
bool RubberbandEllipse::hasSector() const
{
auto getAngle = [](qreal sinPhi, qreal cosPhi) -> int
{
qreal phi = acos( cosPhi );
if (sinPhi < 0) phi = MathConst::pi_two - phi;
return int( (phi * 180.0 / MathConst::pi) * 16);
}; // getAngle
int phiStart = getAngle(_internal->_sectorOStart.y(),_internal->_sectorOStart.y());
int phiEnd = getAngle( _internal->_sectorOEnd.y(), _internal->_sectorOEnd.y());
return phiStart != phiEnd;
} /* RubberbandEllipse::hasSector */
void RubberbandEllipse::enableSector(bool on) { _internal -> _sectorEnabled = on; }
bool RubberbandEllipse::isSectorEnabled() const { return _internal -> _sectorEnabled; }
void RubberbandEllipse::setSectorAngleFixed(bool on)
{
_internal -> _sectorFixedAngleEnabled = on;
}
bool RubberbandEllipse::isSectorFixedAngeEnabled() const
{
return _internal->_sectorFixedAngleEnabled;
}
bool RubberbandEllipse::selectAction(AbstractEventDispatcher * causer, int x, int y)
{
if (rubberbandIsAlive())
{
QPointF scenePos(pixel2ScenePosition(x,y));
_baseInternal->_lastClickPosition = scenePos;
if (_internal -> _sectorEnabled)
{
if ((_internal->_sectorEndHandle.valid()) && (_internal->_sectorEndHandle->isPositionInside(scenePos)))
{
_internal->_sectorEndHandle->setSelection(true);
enableSelectedState();
update();
deactivateButtons();
return true;
}
if ((_internal->_sectorStartHandle.valid()) && (_internal->_sectorStartHandle->isPositionInside(scenePos)))
{
_internal->_sectorStartHandle->setSelection(true);
enableSelectedState();
update();
deactivateButtons();
return true;
}
}
}
return RubberbandRectangle::selectAction(causer,x,y);
} /* RubberbandEllipse::selectAction */
bool RubberbandEllipse::moveAction(AbstractEventDispatcher * causer, int x, int y)
{
if (rubberbandIsAlive())
{
QPointF scenePos(pixel2ScenePosition(x,y));
if (_internal -> _sectorEnabled)
{
if (_internal->_sectorEndHandle.valid())
{
if (_internal->_sectorEndHandle->isPositionInside(scenePos))
{
_internal->_sectorEndHandle->setSelection(true);
update();
return false;
}
else _internal->_sectorEndHandle->setSelection(false);
}
if (_internal->_sectorStartHandle.valid())
{
if (_internal->_sectorStartHandle->isPositionInside(scenePos))
{
_internal->_sectorStartHandle->setSelection(true);
update();
return false;
}
else _internal->_sectorStartHandle->setSelection(false);
}
}
}
return RubberbandRectangle::moveAction(causer,x,y);
} /* RubberbandEllipse::moveAction */
bool RubberbandEllipse::setCoordinateAction(AbstractEventDispatcher * causer, int x, int y)
{
if (rubberbandIsAlive())
{
if (_internal -> _sectorEnabled)
{
if ((_internal->_sectorEndHandle.valid()) && (_internal->_sectorEndHandle->isSelected()))
{
_internal->_sectorEndHandle->setSelection(false);
update();
activateButtons();
return true;
}
if ((_internal->_sectorStartHandle.valid()) && (_internal->_sectorStartHandle->isSelected()))
{
_internal->_sectorStartHandle->setSelection(false);
update();
activateButtons();
return true;
}
}
}
return RubberbandRectangle::setCoordinateAction(causer,x,y);
} /* RubberbandEllipse::setCoordinateAction */
bool RubberbandEllipse::movePickedAction(AbstractEventDispatcher * causer, int x, int y)
{
if (rubberbandIsAlive())
{
auto updateHandle = [this](RubberbandPointHandle * handle, const RubberbandHandle::RubberbandCoordinate & pos, QPointF & oVector ) -> bool
{
if (handle == nullptr) return false;
if (!handle->isSelected()) return false;
if (isSectorFixedAngeEnabled()) return false;
qreal sinRect = 0;
qreal cosRect = 1;
const QPointF & center = getCenter();
getSceneRotation( sinRect, cosRect);
qreal cosA = pos._mapCoordinate.x() - center.x();
qreal sinA = pos._mapCoordinate.y() - center.y();
qreal len = sqrt(cosA*cosA+sinA*sinA);
cosA /= len;
sinA /= len;
oVector.setX( cosA*cosRect + sinA*sinRect );
oVector.setY( sinA*cosRect - cosA*sinRect );
update();
return true;
}; // updateHandle
QPointF scenePos(pixel2ScenePosition(x,y));
RubberbandHandle::RubberbandCoordinate pos(Rubberband::_internal->_mapView, scenePos );
if (updateHandle( _internal->_sectorEndHandle.get() , pos, _internal->_sectorOEnd )) return false;
if (updateHandle( _internal->_sectorStartHandle.get(), pos, _internal->_sectorOStart )) return false;
}
return RubberbandRectangle::movePickedAction(causer,x,y);
} /* RubberbandEllipse::movePickedAction */
void RubberbandEllipse::updateSectorHandles()
{
auto ellipse = []( qreal a, qreal b, qreal sinA, qreal cosA ) -> QPointF
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Qt does not use the paramater equation of a ellipse to draw sectors. Instead of a simpler term
* is used. For simpleness we use the same of.
*
qreal e2 = 1 - (b*b) / (a*a);
qreal cos2 = cosA * cosA;
qreal f = b / sqrt(1-e2*cos2);
return QPointF( f*cosA, f*sinA );
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
return QPointF(a*cosA,b*sinA);
};
auto rotate = [] ( const QPointF & p, qreal sinA, qreal cosA ) -> QPointF { return QPointF( p.x()*cosA - p.y()*sinA, p.y()*cosA + p.x()*sinA ); };
qreal a = getWidth() * 0.5;
qreal b = getHeight() * 0.5;
QPointF startP = ellipse(a,b,_internal->_sectorOStart.y(),_internal->_sectorOStart.x() );
QPointF endP = ellipse(a,b,_internal->_sectorOEnd.y() ,_internal->_sectorOEnd.x() );
qreal sinRect = 0;
qreal cosRect = 1;
getSceneRotation( sinRect, cosRect);
startP = rotate(startP, sinRect, cosRect) + getCenter();
endP = rotate( endP, sinRect, cosRect) + getCenter();
const Esri::ArcGISRuntime::Point &mapStartP = convert( startP, Rubberband::_internal->_mapView->map()->spatialReference() );
const Esri::ArcGISRuntime::Point &mapEndP = convert( endP, Rubberband::_internal->_mapView->map()->spatialReference() );
if (!_internal->_sectorStartHandle.valid())
{
_internal->_sectorStartHandle = new RubberbandPointHandle( Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, mapStartP );
}
else _internal->_sectorStartHandle->setCoordinate( RubberbandHandle::RubberbandCoordinate(Rubberband::_internal->_mapView,mapStartP) );
_internal->_sectorStartHandle -> setVisibility((isSectorEnabled() && !isSectorFixedAngeEnabled())/*_internal->_sectorEnabled*/);
_internal->_sectorStartHandle -> setDrawColor(_handleDrawColor);
_internal->_sectorStartHandle -> setFillColor( _handleFillColor );
_internal->_sectorStartHandle -> setSelectionColor(_handleSelectionColor);
if (!_internal->_sectorEndHandle.valid())
{
_internal->_sectorEndHandle = new RubberbandPointHandle( Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, mapEndP );
}
else _internal->_sectorEndHandle->setCoordinate( RubberbandHandle::RubberbandCoordinate(Rubberband::_internal->_mapView,mapEndP) );
_internal->_sectorEndHandle -> setVisibility(isSectorEnabled() && !isSectorFixedAngeEnabled()/*_internal->_sectorEnabled*/);
_internal->_sectorEndHandle -> setDrawColor(_handleDrawColor);
_internal->_sectorEndHandle -> setFillColor( _handleFillColor );
_internal->_sectorEndHandle -> setSelectionColor(_handleSelectionColor);
} /* RubberbandEllipse::updateSectorHandles */
void RubberbandEllipse::update()
{
RubberbandRectangle::update();
if (isEnabledModificationState())
{
updateSectorHandles();
QPointF center = getCenter();
qreal width2 = getWidth()*0.5;
qreal height2 = getHeight()*0.5;
qreal sinRect = 0.0;
qreal cosRect = 1.0;
getSceneRotation( sinRect, cosRect );
if (_internal->_ellipseSymbol == nullptr)
{
_internal->_ellipseSymbol = new DrawableEllipse( Rubberband::_internal->_mapView );
}
QColor drawColor = _drawColor;
_internal->_ellipseSymbol->setDrawColor( drawColor );
drawColor.setAlpha(_internal->_alphaFill);
if (_internal -> _sectorEnabled){
_fillColor.setAlpha(_internal->_alphaFill+10);
_internal->_ellipseSymbol->setFillColor( _fillColor );
}
else
{
_fillColor.setAlpha(0);
_internal->_ellipseSymbol->setFillColor( _fillColor );
}
_internal->_ellipseSymbol->setRect( center, width2, height2, sinRect, cosRect, _internal->_sectorOStart, _internal->_sectorOEnd );
}
} /* RubberbandEllipse::update */
void RubberbandEllipse::buildTmpConstruction( SituationMap::RefPointer<RubberbandDrawable> &tmpGraphic, QPointF &start, QPointF &end )
{
if (!tmpGraphic.valid())
{
tmpGraphic = new DrawableEllipse( Rubberband::_internal->_mapView );
tmpGraphic -> setDrawColor( _drawColor );
tmpGraphic -> setFillColor( _fillColor );
tmpGraphic -> setLineWidth( 1 );
tmpGraphic -> zBufferPlane( RubberbandDrawable::ZBufferPlane::Drawables );
}
QVector<QPointF> path;
QPointF sceneCenter;
qreal sceneWidth;
qreal sceneHeight;
qreal sinMap;
qreal cosMap;
getMapRotation( sinMap, cosMap );
auto rotate = [sinMap, cosMap](qreal x, qreal y) -> QPointF
{
qreal px = x*cosMap - y*sinMap;
qreal py = y*cosMap + x*sinMap;
return QPointF(px,py);
}; // rotate
buildTmpConstructionPath( start-end + start, end, path, sceneCenter, sceneWidth, sceneHeight );
DrawableEllipse * tmpEllipse = static_cast<DrawableEllipse*>(tmpGraphic.get());
RubberbandHandle::RubberbandCoordinate mapCenter( Rubberband::_internal->_mapView, start );
RubberbandHandle::RubberbandCoordinate mapRadius( Rubberband::_internal->_mapView, start+rotate(sceneWidth*0.5,sceneHeight*0.5) );
qreal w = mapRadius._mapCoordinate.x() - mapCenter._mapCoordinate.x();
qreal h = mapRadius._mapCoordinate.y() - mapCenter._mapCoordinate.y();
tmpEllipse->setRect( QPointF(mapCenter._mapCoordinate.x(),mapCenter._mapCoordinate.y()), w, h, 0, 1 );
} /* RubberbandEllipse::buildTmpConstruction */
void RubberbandEllipse::getTmpConstructionParameter(const QPointF & start, const QPointF & end, QPointF & sceneCenter, qreal & sceneWidth, qreal & sceneHeight)
{
QVector<QPointF> path;
qreal sinMap;
qreal cosMap;
getMapRotation( sinMap, cosMap );
auto rotate = [sinMap, cosMap]( qreal x, qreal y ) -> QPointF
{
qreal px = x*cosMap - y*sinMap;
qreal py = y*cosMap + x*sinMap;
return QPointF(px,py);
}; // rotate
auto length = [](qreal x, qreal y) -> qreal { return sqrt(x*x+y*y); };
buildTmpConstructionPath( start, end, path, sceneCenter, sceneWidth, sceneHeight );
RubberbandHandle::RubberbandCoordinate mapCenter ( Rubberband::_internal->_mapView, start );
RubberbandHandle::RubberbandCoordinate mapRadiusX( Rubberband::_internal->_mapView, start+rotate(sceneWidth,0) );
RubberbandHandle::RubberbandCoordinate mapRadiusY( Rubberband::_internal->_mapView, start+rotate(0,sceneHeight) );
qreal w = length( mapRadiusX._sceneCoordinate.x()-mapCenter._sceneCoordinate.x(), mapRadiusX._sceneCoordinate.y()-mapCenter._sceneCoordinate.y() );
qreal h = length( mapRadiusY._sceneCoordinate.x()-mapCenter._sceneCoordinate.x(), mapRadiusY._sceneCoordinate.y()-mapCenter._sceneCoordinate.y() );
sceneCenter = start;
sceneWidth = 2*w;
sceneHeight = 2*h;
} /* RubberbandEllipse::getTmpConstructionParameter */
} } /* namespace SituationMap::RB */
+95
View File
@@ -0,0 +1,95 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define point feature geoemtry
** $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 .........:
**
** 17.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband_rectangle.h"
namespace SituationMap { namespace RB
{
/**
@class RubberbandEllipse rubberband_ellipse.h
@brief Implementation of a rubberband to input ellipses and circles
@see Rubberband, RubberbandRectangle
*/
class SITUATIONMAP_EXPORT RubberbandEllipse : public RubberbandRectangle
{
Q_OBJECT
/**
@name Construction & Destruction
@{
*/
friend class RubberbandFactory;
explicit RubberbandEllipse( SituationMap::Map * map, QObject * parent = nullptr );
public:
virtual ~RubberbandEllipse();
RubberbandEllipse(const RubberbandEllipse &) = delete;
RubberbandEllipse & operator = (const RubberbandEllipse &) = delete;
/** @} */
void setSectorStart( qreal sinPhi, qreal cosPhi );
void setSectorEnd( qreal sinPhi, qreal cosPhi );
QPointF getRotatedPoint(QPointF sector)const;
bool hasSector() const;
QPointF sectorStart() const;
QPointF sectorEnd() const;
void enableSector( bool on = true );
bool isSectorEnabled() const;
void setSectorAngleFixed(bool on); // true: start and end sectors positon can't be modifed
bool isSectorFixedAngeEnabled() const;
bool selectAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool setCoordinateAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool movePickedAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool moveAction ( AbstractEventDispatcher * causer, int x, int y ) override;
protected:
void updateSectorHandles();
void update() override;
struct InternalData;
InternalData * _internal;
void buildTmpConstruction( SituationMap::RefPointer<RubberbandDrawable> & tmpGraphic, QPointF & start, QPointF & end ) override;
void getTmpConstructionParameter( const QPointF & start, const QPointF & end, QPointF & sceneCenter, qreal & sceneWidth, qreal & sceneHeight ) override;
}; /* RubberbandPointFeature */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,236 @@
/**
**
** @RDE_HEADER@
** Implementation of base class for rubberband handles
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_ellipse_handle.h"
#include <MathUtils/math_const.h>
#include <arcgis/MapGraphicsView.h>
#include <arcgis/Map.h>
#include <QtWidgets/QGraphicsScene>
#include <QtWidgets/QGraphicsEllipseItem>
#include <math.h>
namespace SituationMap { namespace RB
{
RubberbandEllipseHandle::RubberbandEllipseHandle(Esri::ArcGISRuntime::MapGraphicsView * mapView, QGraphicsScene *scene)
: RubberbandHandle(mapView, scene)
{
zBufferPlane( ZBufferPlane::LineHandle );
updateGraphic();
}
RubberbandEllipseHandle::~RubberbandEllipseHandle()
{
if (!_scene)
return;
if (_ellipseSymbol)
{
_scene->removeItem(_ellipseSymbol);
delete _ellipseSymbol;
}
}
void RubberbandEllipseHandle::adjustCoordinates()
{
_center.mapToScene(_mapView);
updateGraphic();
emit adjusted();
}
void RubberbandEllipseHandle::adjustWindow( const QRectF& )
{
onDo_adjustCoordinates();
}
qreal length(const QPointF &p)
{
return sqrt(p.x()*p.x()+p.y()*p.y());
}
void RubberbandEllipseHandle::updateGraphic()
{
if (_scene)
{
if (!_ellipseSymbol)
{
_ellipseSymbol = new QGraphicsEllipseItem();
_scene->addItem(_ellipseSymbol);
_ellipseSymbol->setFlags( QGraphicsItem::ItemIgnoresTransformations );
}
_ellipseSymbol->setZValue(_zValue);
// Style
makeLineStyle( _dottedLine, _lineStyle );
if (_isSelected)
{
_lineStyle.setWidth( _lineStyle.width() + 1 );
_lineStyle.setColor( _selectionColor );
}
_ellipseSymbol->setPen(_lineStyle);
if (isSelected())
_ellipseSymbol->setBrush( QBrush(_selectionColor) );
else
_ellipseSymbol->setBrush( QBrush(_fillColor) );
_ellipseSymbol->setVisible(_isVisible);
// geometry:
{
_center.mapToScene(_mapView);
QPointF mapCenter( _center._mapCoordinate.x(), _center._mapCoordinate.y() );
qreal mapRotatePhi = _mapView->mapRotation() * MathConst::pi / 180.0;
qreal sinMap = sin(mapRotatePhi);
qreal cosMap = cos(mapRotatePhi);
qreal sinPhi = _sinRect * cosMap + _cosRect * sinMap;
qreal cosPhi = _cosRect * cosMap - _sinRect * sinMap;
RubberbandCoordinate x0y0(_mapView, convert( mapCenter+QPointF(-_radiusX,-_radiusY), _mapView->map()->spatialReference()) );
RubberbandCoordinate x1y0(_mapView, convert( mapCenter+QPointF( _radiusX,-_radiusY), _mapView->map()->spatialReference()) );
RubberbandCoordinate x0y1(_mapView, convert( mapCenter+QPointF(-_radiusX, _radiusY), _mapView->map()->spatialReference()) );
const qreal width = length(x1y0._sceneCoordinate-x0y0._sceneCoordinate);
const qreal height = length(x0y1._sceneCoordinate-x0y0._sceneCoordinate);
// honor sector??
if (_sectorStart != _sectorEnd)
{
auto getAngle = [](qreal sinPhi, qreal cosPhi) -> int
{
qreal phi = acos( cosPhi );
if (sinPhi < 0) phi = MathConst::pi_two - phi;
return int( (phi * 180.0 / MathConst::pi) * 16);
}; // getAngle
int startAngle = getAngle(_sectorStart.y(), _sectorStart.x());
int endAngle = getAngle( _sectorEnd.y(), _sectorEnd.x());
int spanAngle = (endAngle > startAngle) ? endAngle-startAngle : 5760-startAngle+endAngle;
QColor fillColor = transparentFillColor();
_ellipseSymbol->setRect(-width*0.5, -height*0.5, width, height);
_ellipseSymbol->setPen(_lineStyle );
_ellipseSymbol->setBrush( (fillColor.alpha() > 0) ? QBrush(fillColor) : QBrush() );
_ellipseSymbol->setTransform( QTransform( cosPhi, -sinPhi, sinPhi, cosPhi, _center._sceneCoordinate.x(), _center._sceneCoordinate.y() ));
_ellipseSymbol->setStartAngle(startAngle );
_ellipseSymbol->setSpanAngle(spanAngle);
_ellipseSymbol->setVisible(true);
}
_ellipseSymbol->setRect(-width*0.5, -height*0.5, width, height);
_ellipseSymbol->setTransform( QTransform( cosPhi, -sinPhi, sinPhi, cosPhi, _center._sceneCoordinate.x(), _center._sceneCoordinate.y()) );
}
}
}
QPointF RubberbandEllipseHandle::getRadius()
{
return {_radiusX, _radiusY};
}
void RubberbandEllipseHandle::setRect(const RubberbandCoordinate &center, qreal radiusX, qreal radiusY,
qreal sin, qreal cos,
const QPointF &sectorStart, const QPointF &sectorEnd)
{
// p1,p2 = corner points of unrotated ellipse in scene coordinates
_center = center;
_radiusX = radiusX;
_radiusY = radiusY;
_sinRect = sin;
_cosRect = cos;
_sectorStart = sectorStart;
_sectorEnd = sectorEnd;
updateGraphic();
}
bool RubberbandEllipseHandle::isPositionInside(const QPointF &scenePosition) const
{
if (_ellipseSymbol)
{
if (_ellipseSymbol->contains( scenePosition ))
{
return true;
}
// else
// {
// // Ok, Qt's methodes doesn't work safely
// // if it fails do some own calculations
// QPointF V0 = _coordinates[0]._sceneCoordinate;
// QPointF V1 = _coordinates[1]._sceneCoordinate;
// QPointF R = V1-V0;
// QPointF P = scenePosition-V0;
// qreal lenR = R.x() * R.x() + R.y() * R.y();
// qreal lenP = P.x() * P.x() + P.y() * P.y();
// if ((lenR == 0) || (lenP > lenR)) return false; // scene Position is to far away
// // now check the direction
// lenR = sqrt(lenR);
// lenP = sqrt(lenP);
// R /= lenR;
// P /= lenP;
// qreal cosPhi = QPointF::dotProduct(R,P);
// if (cosPhi < 0) return false;
// qreal epsilon = sqrt(1.0-cosPhi*cosPhi) * lenR;
// return (epsilon < qreal(_pickingRatio));
// }
}
return false;
}
} }
@@ -0,0 +1,96 @@
/**
**
** @RDE_HEADER@
** Definition of base class for rubberband handles
** $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 <QtCore/QPointF>
#include <QtGui/QPen>
#include "rubberband_handle.h"
class QGraphicsEllipse;
class QGraphicsScene;
namespace SituationMap
{
namespace RB
{
/**
@class RubberbandEllipseHandle rubberband_line_handle.h
@brief Implementation of a line handle for rubberband internal use.
@see RubberbandHandle
*/
class RubberbandEllipseHandle : public RubberbandHandle
{
Q_OBJECT
public:
RubberbandEllipseHandle(Esri::ArcGISRuntime::MapGraphicsView * mapView ,QGraphicsScene * scene);
~RubberbandEllipseHandle();
bool isPositionInside(const QPointF &scenePosition) const override;
// virtual void updateCoordinates(const QVector<QPointF> &scenePositionVector);
// virtual void updateCoordinate(unsigned index, const QPointF &scenePosition);
QPointF getRadius();
void setRect(const RubberbandDrawable::RubberbandCoordinate &center,
qreal radiusX, qreal radiusY,
qreal sin, qreal cos,
const QPointF & sectorStart = QPointF(), const QPointF & sectorEnd = QPointF());
void dottedLine(bool on = true) { _dottedLine = on; }
protected:
QGraphicsEllipseItem *_ellipseSymbol{nullptr};
QPen _lineStyle;
RubberbandDrawable::RubberbandCoordinate _center;
qreal _radiusX{0.0};
qreal _radiusY{0.0};
qreal _sinRect{0.0};
qreal _cosRect{0.0};
QPointF _sectorStart;
QPointF _sectorEnd;
bool _dottedLine{false};
void updateGraphic() override;
void adjustCoordinates() override;
void adjustWindow(const QRectF&) override;
}; // RubberbandEllipseHandle
}
} // namespace SituationMap::RB
+634
View File
@@ -0,0 +1,634 @@
/**
**
** @RDE_HEADER@
** Implementation 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
** 30.09.2015, JT : New create method for creating rubberbands fitting to a special sidc code
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_factory.h"
#include "rubberband_corridor.h"
#include <Symbology/sidc_builder_base.h>
#include <cmath>
#include <Map/coord_translation_functor.h>
namespace SituationMap { namespace RB
{
class RubberbandFactory::Defaults
{
public:
QColor _rubberbandDrawColor = QColor();
QColor _rubberbandFillColor = QColor();
QColor _rubberbandHandleDrawColor = QColor();
QColor _rubberbandHandleFillColor = QColor();
QColor _rubberbandSelectionColor = QColor();
QColor _rubberbandFrameColor = QColor();
QColor _rubberbandFrameFillColor = QColor();
int _rubberbandFrameHandleMargin = 0;
QPoint _rubberbandPreviewOffset = QPoint();
unsigned int _rubberbandPreviewSize = 0;
unsigned int _rubberbandPickingRatio = 0;
unsigned int _rubberbandLineHandleWidth = 0;
}; // RubberbandFactory::Defaults
RubberbandFactory::RubberbandFactory( SituationMap::Map * map )
: QObject()
, _map(map)
, _defaults(new Defaults())
, _allowMultipleRubberbands(false)
, _logger(getLogger("RubberbandFactory"))
{}
RubberbandFactory::~RubberbandFactory() { delete _defaults; }
class SymbolConstruction
{
public:
enum class Mode
{
Unknown = 0,
Point,
ArcCurve,
Triangle,
MultiPoint,
PolyLine,
PolyLineWidth,
Polygon,
Rectangle,
Circular,
Corridor
}; // Mode
Mode _mode;
unsigned int _minPoints;
unsigned int _maxPoints;
explicit SymbolConstruction( const AdvancedSymbology::GeometryType & geomType, const QString & gctString )
: _mode(Mode::Unknown), _minPoints(-1), _maxPoints(-1)
{
if (QLatin1String("gct_arrow") == gctString) { _mode = Mode::PolyLine; _minPoints = 2; _maxPoints = 0; }
if (QLatin1String("gct_arrow_with_offset") == gctString) { _mode = Mode::PolyLineWidth; _minPoints = 2; _maxPoints = 0; }
if (QLatin1String("gct_arrow_with_tail") == gctString) { _mode = Mode::Triangle; _minPoints = 3; _maxPoints = 3; }
if (QLatin1String("gct_circle") == gctString) { _mode = Mode::MultiPoint; _minPoints = 2; _maxPoints = 2; }
if (QLatin1String("gct_circular") == gctString) { _mode = Mode::Circular; _minPoints = 1; _maxPoints = 1; }
if (QLatin1String("gct_freehand_arrow") == gctString) { _mode = Mode::ArcCurve; _minPoints = 3; _maxPoints = 3; }
if (QLatin1String("gct_freehand_line") == gctString) { _mode = Mode::ArcCurve; _minPoints = 3; _maxPoints = 3; }
if (QLatin1String("gct_freehand_reverse_arrow") == gctString) { _mode = Mode::ArcCurve; _minPoints = 3; _maxPoints = 3; }
if (QLatin1String("gct_freehand_u") == gctString) { _mode = Mode::ArcCurve; _minPoints = 4; _maxPoints = 4; }
if (QLatin1String("gct_hook") == gctString) { _mode = Mode::MultiPoint; _minPoints = 3; _maxPoints = 3; }
if (QLatin1String("gct_horns") == gctString) { _mode = Mode::MultiPoint; _minPoints = 4; _maxPoints = 4; }
if (QLatin1String("gct_open_triangle") == gctString) { _mode = Mode::Triangle; _minPoints = 3; _maxPoints = 3; }
if (QLatin1String("gct_parallel_lines") == gctString) { _mode = Mode::PolyLineWidth; _minPoints = 2; _maxPoints = 2; }
if (QLatin1String("gct_parallel_lines_mid_line") == gctString) { _mode = Mode::PolyLineWidth; _minPoints = 2; _maxPoints = 2; }
if (QLatin1String("gct_parallel_lines_with_ticks") == gctString)
{
_mode = Mode::MultiPoint;
// ESRI implmentation seems to differ from symbology standard and takes always 4 input
// coordinates here to construct the symbol!
//
// if (AdvancedSymbology::GeometryType::Polygon == geomType) _minPoints = _maxPoints = 4;
// else _minPoints = _maxPoints = 3;
_minPoints = _maxPoints = 4;
}
if (QLatin1String("gct_rectangular") == gctString) { _mode = Mode::Corridor; _minPoints = 2; _maxPoints = 2; }
if (QLatin1String("gct_rectangular_1_pt") == gctString) { _mode = Mode::Rectangle; _minPoints = 1; _maxPoints = 1; }
if (QLatin1String("gct_t") == gctString) { _mode = Mode::MultiPoint; _minPoints = 3; _maxPoints = 3; }
if (QLatin1String("gct_triple_arrow") == gctString) { _mode = Mode::MultiPoint; _minPoints = 3; _maxPoints = 3; }
if (QLatin1String("gct_two_line") == gctString) { _mode = Mode::Triangle; _minPoints = 3; _maxPoints = 3; }
if (QLatin1String("gct_two_line_3_or_4_pt") == gctString) { _mode = Mode::MultiPoint; _minPoints = 3; _maxPoints = 4; }
if (QLatin1String("gct_u_or_t_shape") == gctString) { _mode = Mode::MultiPoint; _minPoints = 3; _maxPoints = 3; }
if (Mode::Unknown == _mode)
{
// gct string is empty or not supported yet
switch (geomType)
{
case AdvancedSymbology::GeometryType::Point : { _mode = Mode::Point; _minPoints = 1; _maxPoints = 1; } break;
case AdvancedSymbology::GeometryType::Polyline : { _mode = Mode::PolyLine; _minPoints = 2; _maxPoints = 0; } break;
case AdvancedSymbology::GeometryType::Polygon : { _mode = Mode::Polygon; _minPoints = 3; _maxPoints = 0; } break;
case AdvancedSymbology::GeometryType::Undefined : break;
default : break;
} // switch
}
} // SymbolConstruction( const QString & gctString )
~SymbolConstruction() = default;
Mode mode() const { return _mode; }
unsigned int minPoints() const { return _minPoints; }
unsigned int maxPoints() const { return _maxPoints; }
bool unlimitedMaxPoints() const { return (_maxPoints == 0); }
}; // SymbolConstruction
struct ActivateRubberbandInfo
{
Rubberband * _rubberband;
SymbolConstruction _symbolConstruction;
explicit ActivateRubberbandInfo( Rubberband * r, const SymbolConstruction & sc ) : _rubberband(r), _symbolConstruction(sc) {;}
~ActivateRubberbandInfo() = default;
ActivateRubberbandInfo() = delete;
}; // ActivateRubberbandInfo
QString toString( SymbolConstruction::Mode mode )
{
switch (mode)
{
case SymbolConstruction::Mode::Unknown : return QStringLiteral("Unknown Rubberband"); break;
case SymbolConstruction::Mode::Point : return QStringLiteral("Point Rubberband"); break;
case SymbolConstruction::Mode::PolyLine : return QStringLiteral("Polyline Rubberband"); break;
case SymbolConstruction::Mode::PolyLineWidth : return QStringLiteral("PolylineWidth Rubberband"); break;
case SymbolConstruction::Mode::Polygon : return QStringLiteral("Polygon Rubberband"); break;
case SymbolConstruction::Mode::Triangle : return QStringLiteral("Triangle Rubberband"); break;
case SymbolConstruction::Mode::ArcCurve : return QStringLiteral("ArcCurve Rubberband"); break;
case SymbolConstruction::Mode::Rectangle : return QStringLiteral("Rectangle Rubberband"); break;
case SymbolConstruction::Mode::Circular : return QStringLiteral("Circular Rubberband"); break;
case SymbolConstruction::Mode::Corridor : return QStringLiteral("Corridor Rubberband"); break;
case SymbolConstruction::Mode::MultiPoint : return QStringLiteral("MultiPoint Rubberband"); break;
}
return QString();
} // QString toString( SymbolConstruction::Mode mode )
static bool defaultSymbolRubberbandCoordinates( Map * map, Rubberband * rbnd, const QPointF & pixelPos, const SymbolConstruction & symbolConstruction );
Rubberband * RubberbandFactory::createSymbol(const QString & sidc, QObject * parent) const { return createSymbol(sidc,QPoint(-1,-1),parent); }
Rubberband * RubberbandFactory::createSymbol( const QString & sidc, const QPoint & winPos, QObject * parent ) const
{
if (Mode::Mode_2D != _map->mode()) return nullptr;
const QString & baseSymbolCode = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode( sidc );
const AdvancedSymbology::SymbolProperties & symbolProperties = _map->symbolDictionary().symbolProperties( baseSymbolCode );
const AdvancedSymbology::GeometryType & geomType = symbolProperties.geometryType();
SymbolConstruction symbolConstruction( geomType, symbolProperties.gctString() );
Rubberband::currentFactoryMap(_map);
Rubberband::allowMultipleRubberbands(_allowMultipleRubberbands);
Rubberband *rubberband = nullptr;
DEBUG_LOG(_logger) << LOGFUNCTION << QStringLiteral(" - %1").arg(toString(geomType), 30);
DEBUG_LOG(_logger) << LOGFUNCTION << QStringLiteral(" - %1").arg(symbolProperties.gctString(), 30);
DEBUG_LOG(_logger) << LOGFUNCTION << QStringLiteral(" - %1").arg(toString(symbolConstruction.mode()),30);
bool rubberbandConstructionMode = ((winPos.x() < 0) || (winPos.y() < 0));
try
{
switch (geomType)
{
case AdvancedSymbology::GeometryType::Point :
{
rubberband = new RubberbandPointFeature(_map, parent);
} break;
case AdvancedSymbology::GeometryType::Polyline :
{
switch (symbolConstruction.mode())
{
case SymbolConstruction::Mode::PolyLine :
{
RubberbandMultiPointFeature * r = new RubberbandMultiPointFeature(_map,false,parent);
if (r)
{
r->minimumPointCount( symbolConstruction.minPoints() );
r->maximumPointCount( symbolConstruction.maxPoints() );
r->enableFinishAfterConstruction(true);
rubberband = r;
}
} break;
case SymbolConstruction::Mode::PolyLineWidth :
{
RubberbandMultiPointFeature * r = new RubberbandPolylineWidth(_map,parent);
if (r)
{
r->minimumPointCount( symbolConstruction.minPoints() );
r->maximumPointCount( symbolConstruction.maxPoints() );
r->enableFinishAfterConstruction(true);
rubberband = r;
}
} break;
case SymbolConstruction::Mode::ArcCurve :
case SymbolConstruction::Mode::MultiPoint :
case SymbolConstruction::Mode::Triangle :
{
RubberbandPointCluster * r = new RubberbandPointCluster(_map,parent,false);
if (r)
{
r->minimumPointCount(symbolConstruction.minPoints());
r->maximumPointCount(symbolConstruction.maxPoints());
r->enableFinishAfterConstruction(true);
rubberband = r;
if ((!symbolConstruction.unlimitedMaxPoints()) && rubberbandConstructionMode)
{
// Rubberband is not active here because we need one position to initialize
// the coordinates
Rubberband::currentFactoryMap(_map);
RubberbandPointFeature * askPosition = new RubberbandPointFeature(_map, parent);
setDefaults(askPosition);
askPosition -> enableFinishAfterConstruction(true);
askPosition -> setUserData( new ActivateRubberbandInfo(rubberband, symbolConstruction) );
askPosition -> setPreviewSidc(sidc);
askPosition -> setAutoDelete(true);
connect(askPosition, &SituationMap::RB::Rubberband::apply, this, &RubberbandFactory::onActivateRubberband );
connect(askPosition, &SituationMap::RB::Rubberband::abort, this, &RubberbandFactory::onAbortRubberband );
}
else rubberband->activate();
}
} break;
default:
{
rubberband = new RubberbandPointCluster(_map,parent);
if (rubberband) rubberband->activate();
} break;
} // switch
} break;
case AdvancedSymbology::GeometryType::Polygon :
{
switch (symbolConstruction.mode())
{
case SymbolConstruction::Mode::Circular :
{
RubberbandEllipse * r = new RubberbandEllipse(_map, parent);
if (r)
{
r->enableSector(false);
r->constrainOrthogonal(true);
r->constrainQuadratic(true);
r->enableFinishAfterConstruction(true);
}
rubberband = r;
} break;
case SymbolConstruction::Mode::Rectangle :
{
RubberbandRectangle * r = new RubberbandRectangle(_map, parent);
if (r)
{
r->constrainOrthogonal(false);
r->enableFinishAfterConstruction(true);
}
rubberband = r;
} break;
case SymbolConstruction::Mode::Corridor :
{
RubberbandCorridor * r = new RubberbandCorridor(_map, RubberbandCorridor::InputMode::InputCenterLine, 0, parent);
if (r)
{
r->setCorridorBorderColor( QColor("Black") );
r->setCorridorFillColor( QColor(255,255,0,100) );
r->minimumPointCount( symbolConstruction.minPoints() );
r->maximumPointCount( symbolConstruction.maxPoints() );
r->enableFinishAfterConstruction(true);
rubberband = r;
}
} break;
case SymbolConstruction::Mode::MultiPoint :
{
RubberbandPointCluster * r = new RubberbandPointCluster(_map,parent,false);
if (r)
{
r->minimumPointCount(symbolConstruction.minPoints());
r->maximumPointCount(symbolConstruction.maxPoints());
r->enableFinishAfterConstruction(true);
rubberband = r;
if ((!symbolConstruction.unlimitedMaxPoints()) && rubberbandConstructionMode)
{
// Rubberband is not active here because we need one position to initialize
// the coordinates
Rubberband::currentFactoryMap(_map);
RubberbandPointFeature * askPosition = new RubberbandPointFeature(_map, parent);
setDefaults(askPosition);
askPosition -> enableFinishAfterConstruction(true);
askPosition -> setUserData( new ActivateRubberbandInfo(rubberband, symbolConstruction) );
askPosition -> setPreviewSidc(sidc);
askPosition -> setAutoDelete(true);
connect(askPosition, &SituationMap::RB::Rubberband::apply, this, &RubberbandFactory::onActivateRubberband );
connect(askPosition, &SituationMap::RB::Rubberband::abort, this, &RubberbandFactory::onAbortRubberband );
}
else rubberband->activate();
}
} break;
case SymbolConstruction::Mode::Polygon :
default:
{
RubberbandMultiPointFeature * rubberArea = new RubberbandMultiPointFeature( _map, parent );
if (rubberArea)
{
rubberArea -> enableClosed(true);
}
rubberband = rubberArea;
} break;
} // switch
} break;
default : break;
} //switch
}
catch (const SituationMap::Exception &) {;}
if (rubberband)
{
setDefaults( rubberband );
rubberband -> setAutoDelete(true);
rubberband -> setPreviewSidc( sidc );
if (!rubberbandConstructionMode)
{
QPointF pixelPos( winPos.x(), winPos.y() );
if (!defaultSymbolRubberbandCoordinates(_map, rubberband, pixelPos, symbolConstruction))
{
ERROR_LOG(_logger) << LOGFUNCTION << "Can't init symbol rubberband coordinate list, undefined proposal.";
rubberband->deleteMySelf();
rubberband = nullptr;
}
}
}
return rubberband;
} /* RubberbandFactory::create */
static bool defaultSymbolRubberbandCoordinates( Map * map, Rubberband * rbnd, const QPointF & pixelPos, const SymbolConstruction & symbolConstruction )
{
QVector<QPointF> pointList;
pointList.reserve( symbolConstruction.maxPoints() );
switch (symbolConstruction.mode())
{
case SymbolConstruction::Mode::ArcCurve:
{
if (4 == symbolConstruction.maxPoints())
{
pointList.append(pixelPos + QPointF(-150,-100));
pointList.append(pixelPos + QPointF(-100,-100));
pointList.append(pixelPos + QPointF(-100, 100));
pointList.append(pixelPos + QPointF(-150, 100));
}
if (3 == symbolConstruction.maxPoints())
{
pointList.append(pixelPos + QPointF(-150, 100));
pointList.append(pixelPos + QPointF(+150, -20));
pointList.append(pixelPos);
}
} break;
case SymbolConstruction::Mode::MultiPoint:
{
if (4 == symbolConstruction.maxPoints())
{
pointList.append(pixelPos + QPointF(-100, 100));
pointList.append(pixelPos + QPointF( 100, 100));
pointList.append(pixelPos + QPointF(-150,-100));
pointList.append(pixelPos + QPointF( 150,-100));
}
if (3 == symbolConstruction.maxPoints())
{
pointList.append(pixelPos + QPointF(-150, 0));
pointList.append(pixelPos + QPointF( 150, 0));
pointList.append(pixelPos + QPointF(-150,-100));
}
if (2 == symbolConstruction.maxPoints())
{
pointList.append(pixelPos);
pointList.append(pixelPos + QPointF(150, 150));
}
} break;
case SymbolConstruction::Mode::Polygon:
case SymbolConstruction::Mode::Triangle:
{
pointList.append(pixelPos);
pointList.append(pixelPos + QPointF(-150, +150));
pointList.append(pixelPos + QPointF(+150, +150));
} break;
case SymbolConstruction::Mode::Point:
{
pointList.append(pixelPos);
} break;
case SymbolConstruction::Mode::Circular:
case SymbolConstruction::Mode::Rectangle:
{
pointList.append(pixelPos + QPointF(-150, 150));
pointList.append(pixelPos + QPointF( 150, 150));
pointList.append(pixelPos + QPointF( 150,-150));
pointList.append(pixelPos + QPointF(-150,-150));
} break;
case SymbolConstruction::Mode::PolyLineWidth:
{
pointList.append(pixelPos + QPointF( 50, 0));
pointList.append(pixelPos + QPointF(-150, 0));
pointList.append(pixelPos + QPointF( 0, +50));
} break;
case SymbolConstruction::Mode::Corridor:
case SymbolConstruction::Mode::PolyLine:
{
pointList.append(pixelPos);
pointList.append(pixelPos + QPointF(150, 150));
} break;
case SymbolConstruction::Mode::Unknown:
default:
{
// empty
} break;
} // switch
if (!pointList.isEmpty())
{
for (int i = 0; i < pointList.size(); ++i) { pointList[i] = map->viewPortWindowPointToGeoCoordinate(pointList[i]); }
if (SymbolConstruction::Mode::Corridor == symbolConstruction.mode())
{
SituationMap::CoordTranslationFunctor * cf = map->coordTranslationFunctor();
QPointF p1 = pointList[0];
QPointF p2 = pointList[1];
if (cf)
{
p1 = cf->geographicToMap(p1);
p2 = cf->geographicToMap(p2);
}
p1 -= p2;
qreal wCorr = sqrt(p1.x()*p1.x()+p1.y()*p1.y()) * 0.15;
RubberbandCorridor * rbndCorr = static_cast<RubberbandCorridor*>(rbnd);
rbndCorr->setCoordinateVectorWidth(pointList,wCorr);
}
else rbnd->setCoordinateVector(pointList);
return true;
}
return false;
} /* RubberbandFactory::defaultSymbolRubberbandCoordinates */
void RubberbandFactory::onActivateRubberband( RubberbandBase * rubberband )
{
if (nullptr == rubberband) return;
ActivateRubberbandInfo * arbInfo = static_cast<ActivateRubberbandInfo*>( rubberband->userData() );
if (nullptr == arbInfo) return;
const QPointF & position = rubberband->singleCoordinate();
const QPointF & pixelPos = _map->geoCoordinateToViewPortWindowPoint(position);
if (defaultSymbolRubberbandCoordinates( _map, arbInfo->_rubberband, pixelPos, arbInfo->_symbolConstruction))
{
arbInfo->_rubberband->activate();
}
else
{
arbInfo->_rubberband->deleteMySelf();
ERROR_LOG(_logger) << LOGFUNCTION << "Can't init symbol rubberband coordinate list, undefined proposal.";
}
delete arbInfo;
rubberband->setUserData(nullptr);
} /* RubberbandFactory::onActivateRubberband */
void RubberbandFactory::onAbortRubberband( RubberbandBase * rubberband )
{
if (nullptr == rubberband) return;
ActivateRubberbandInfo * arbInfo = static_cast<ActivateRubberbandInfo*>(rubberband->userData());
if (arbInfo)
{
arbInfo->_rubberband->deleteMySelf();
delete arbInfo;
}
rubberband->setUserData(nullptr);
} /* RubberbandFactory::onAbortRubberband */
void RubberbandFactory::setRubberbandDrawColor ( const QColor & c ) { _defaults->_rubberbandDrawColor = c; }
void RubberbandFactory::setRubberbandFillColor ( const QColor & c ) { _defaults->_rubberbandFillColor = c; }
void RubberbandFactory::setRubberbandHandleDrawColor ( const QColor & c ) { _defaults->_rubberbandHandleDrawColor = c; }
void RubberbandFactory::setRubberbandHandleFillColor ( const QColor & c ) { _defaults->_rubberbandHandleFillColor = c; }
void RubberbandFactory::setRubberbandSelectionColor ( const QColor & c ) { _defaults->_rubberbandSelectionColor = c; }
void RubberbandFactory::setRubberbandFrameColor ( const QColor & c ) { _defaults->_rubberbandFrameColor = c; }
void RubberbandFactory::setRubberbandFrameFillColor ( const QColor & c ) { _defaults->_rubberbandFrameFillColor = c; }
void RubberbandFactory::setRubberbandFrameHandleMargin ( int m ) { _defaults->_rubberbandFrameHandleMargin = m; }
void RubberbandFactory::setRubberbandPreviewOffset ( const QPoint & o ) { _defaults->_rubberbandPreviewOffset = o; }
void RubberbandFactory::setRubberbandPreviewSize ( unsigned int s ) { _defaults->_rubberbandPreviewSize = s; }
void RubberbandFactory::setRubberbandPickingRatio ( unsigned int s ) { _defaults->_rubberbandPickingRatio = s; }
void RubberbandFactory::setRubberbandLineHandleWidth ( unsigned int s ) { _defaults->_rubberbandLineHandleWidth = s; }
void RubberbandFactory::setDefaults(RubberbandBase * rband) const
{
if (nullptr == rband) return;
if ( _defaults->_rubberbandDrawColor.isValid() ) rband->setDrawColor ( _defaults->_rubberbandDrawColor );
if ( _defaults->_rubberbandFillColor.isValid() ) rband->setFillColor ( _defaults->_rubberbandFillColor );
if ( _defaults->_rubberbandHandleDrawColor.isValid()) rband->setHandleDrawColor ( _defaults->_rubberbandHandleDrawColor );
if ( _defaults->_rubberbandHandleFillColor.isValid()) rband->setHandleFillColor ( _defaults->_rubberbandHandleFillColor );
if ( _defaults->_rubberbandSelectionColor.isValid() ) rband->setHandleSelectionColor( _defaults->_rubberbandSelectionColor );
if ( _defaults->_rubberbandFrameColor.isValid() ) rband->setFrameColor ( _defaults->_rubberbandFrameColor );
if ( _defaults->_rubberbandFrameFillColor.isValid() ) rband->setFrameFillColor ( _defaults->_rubberbandFrameFillColor );
rband->setFrameHandleMargin( _defaults->_rubberbandFrameHandleMargin );
} /* RubberbandFactory::setDefaults */
void RubberbandFactory::setDefaults(Rubberband * rband) const
{
if (nullptr == rband) return;
setDefaults( static_cast<RubberbandBase*>(rband) );
if (_defaults->_rubberbandPreviewSize > 0) rband->setPreviewSize ( _defaults->_rubberbandPreviewSize );
if (_defaults->_rubberbandPickingRatio > 0) rband->setPickingRatio ( _defaults->_rubberbandPickingRatio );
if (!_defaults->_rubberbandPreviewOffset.isNull()) rband->setPreviewOffset( _defaults->_rubberbandPreviewOffset );
if (_defaults->_rubberbandLineHandleWidth > 0) rband->setLineHandleWidth ( _defaults->_rubberbandLineHandleWidth );
RubberbandCorridor *rbCorridor = qobject_cast<RubberbandCorridor*>(rband);
if (rbCorridor)
{
rbCorridor->setCorridorBorderColor(rband->getDrawColor());
rbCorridor->setCorridorFillColor(rband->getFillColor());
}
} /* RubberbandFactory::setDefaults */
} } /* namespace SituationMap::RB */
+290
View File
@@ -0,0 +1,290 @@
/**
**
** @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 "rubberband_base.h"
#include "rubberband.h"
#include "rubberband_arrow.h"
#include "rubberband_corridor.h"
#include "rubberband_ellipse.h"
#include "rubberband_free_hand.h"
#include "rubberband_multi_point_feature.h"
#include "rubberband_multi_ellipse_feature.h"
#include "rubberband_point_cluster.h"
#include "rubberband_point_feature.h"
#include "rubberband_polyline_width.h"
#include "rubberband_rectangle.h"
#include "rubberband_smooth_line.h"
#include "rubberband_state_select.h"
#include "rubberband_transform.h"
#include "rubberband_transform_move.h"
#include "rubberband_transform_rotate.h"
#include "rubberband_transform_scale.h"
#include "rubberband_3d.h"
#include "rubberband_point_feature_3d.h"
#include "rubberband_multi_point_feature_3d.h"
#include <Common/exception.h>
#include <Common/situation_map_logging.h>
#include <QtCore/QObject>
namespace SituationMap { namespace RB
{
/**
@brief Factory class to create rubberbands
Rubberbands are used to create or modifiy 2D geometries like lines, circles, polygons etc. on a 2D map view
Rubberbands are used to create or modifiy 2D geometries like lines, circles, polygons etc. by processing
Qt input events like keyboard and mouse events. Following rubberbands are available:
| Class Name | Description |
| :----------------------------- | : --------------------------------------------------------------------------------------- |
| RubberbandPointFeature | Rubberband to edit a single position for a point feature. |
| RubberbandPointCluster | Rubberband to edit multiple positions to define a cluster of point features. |
| RubberbandMultiPointFeature | Rubberband to edit a polyline or polygon to define line or areal features. |
| RubberbandSmoothLine | Like RubberbandMultiPointFeature with rounded edges. |
| RubberbandPolylineWidth | Rubberband like RubberbandMultiPointFeature for symbols with additional width coordinate. |
| RubberbandArrow | Rubberband to edit a polyline with an arrow at the end. |
| RubberbandCorridor | Rubberband to edit corridors by defining a polyline and a width. |
| RubberbandRectangle | Rubberband to edit a rectangle or square. |
| RubberbandEllipse | Rubberband to edit a ellipse or circle. |
| RubberbandFreeHand | Rubberband to input a free hand line. |
| RubberbandStateSelect | Rubberband to set states to coordinates. |
| RubberbandTransform | Rubberband to manipulate moving, rotating and scaling in a single step |
| RubberbandTransformMove | Rubberband to define moving transformations |
| RubberbandTransformRotate | Rubberband to define rotating transformations |
| RubberbandTransformScale | Rubberband to define scaling transformations |
On a 3D map scene following rubberbands are available:
| Class Name | Description |
| :----------------------------- | : --------------------------------------------------------------------------------------- |
| RubberbandPointFeature3D | Rubberband to edit a single position for a point feature. |
| RubberbandMultiPointFeature3D | Rubberband to edit a polyline or polygon to define line or areal features. |
@see Rubberband, RubberbandPointFeature, RubberbandPointCluster, RubberbandMultiPointFeature, RubberbandSmoothLine, RubberbandPolylineWidth
RubberbandRectangle, RubberbandEllipse, RubberbandCorridor, RubberbandArrow, RubberbandFreeHand, RubberbandStateSelect
RubberbandTransform, RubberbandTransformMove, RubberbandTransformRotate, RubberbandTransformScale,
Rubberband3D, RubberbandPointFeature3D, RubberbandMultiPointFeature3D
*/
class SITUATIONMAP_EXPORT RubberbandFactory : public QObject
{
Q_OBJECT
public:
explicit RubberbandFactory( SituationMap::Map * map );
virtual ~RubberbandFactory();
/**
@brief template methode to create a rubberband instance
Creates with new a rubberband from type RubberbandClass. RubberbandClass must be inherited
from class SiMapRubBnd::Rubberband otherwise a nullptr will be retruned. After use the
pointer have to be freed with delete.
Expample to create a rubberband:
@code
SituationMap::Map & map = ...
const RubberbandFactory & rubberbandFactory = map.rubberbandFactory();
RubberbandPointFeature * rubberband = rubberbandFactory.create<RubberbandPointFeature>();
if (rubberband != nullptr) doSomething(rubberband);
@endcode
@param parent Parent of rubberband object. If parent is nullptr \c _map will be used as parent
@see Rubberband, RubberbandPointFeature, RubberbandPointCluster, RubberbandMultiPointFeature, RubberbandRectangle, RubberbandEllipse, RubberbandCorridor, RubberbandArrow
*/
template<class RubberbandClass> RubberbandClass * create( QObject * parent = nullptr ) const
{
RubberbandClass * rubberband = nullptr;
if ((std::is_base_of<Rubberband, RubberbandClass>::value) && (Mode::Mode_2D == _map->mode()))
{
// be careful it is not thread safe here
Rubberband::currentFactoryMap(_map);
Rubberband::allowMultipleRubberbands(_allowMultipleRubberbands);
try
{
rubberband = new RubberbandClass( _map, parent );
}
catch (const SituationMap::Exception &) {;}
setDefaults( rubberband );
}
return rubberband;
}
/**
Creates a new corridor rubberband and defines the input method of the rubberband
@param inputMethode Defines the input method of the rubberband
@param width With of a corridor in meters.
@param parent Parent of rubberband object. If parent is nullptr \c _map will be used as parent
@see RubberbandCorridor
*/
RubberbandCorridor * create( RubberbandCorridor::InputMode inputMode, qreal width = 0, QObject * parent = nullptr ) const
{
if (!_map->isReady() || (Mode::Mode_2D != _map->mode()) )
return nullptr;
Rubberband::currentFactoryMap(_map);
Rubberband::allowMultipleRubberbands(_allowMultipleRubberbands);
RubberbandCorridor * rubberband = nullptr;
try
{
rubberband = new RubberbandCorridor( _map, inputMode, width, parent );
}
catch (const SituationMap::Exception &) {;}
setDefaults( rubberband );
return rubberband;
}
/**
Creates a new rubberband fitting to the sidc code
@param sidc sidc of symbol that will be created with rubberband.
@see RubberbandPointFeature, RubberbandMultiPointFeature
*/
Rubberband * createSymbol( const QString & sidc, QObject * parent = nullptr ) const;
/**
Creates a new rubberband fitting to the sidc code
@param sidc sidc of symbol that will be created with rubberband.
@param winPos Default position of the rubberband on window
@see RubberbandPointFeature, RubberbandMultiPointFeature
*/
Rubberband * createSymbol( const QString & sidc, const QPoint & winPos, QObject * parent = nullptr ) const;
/**
@brief template methode to create a rubberband instance in 3D maps
Creates with new a rubberband from type RubberbandClass. RubberbandClass must be inherited
from class SiMapRubBnd::Rubberband otherwise a nullptr will be retruned. After use the
pointer have to be freed with delete.
Expample to create a rubberband:
@code
SituationMap::Map & map = ...
const RubberbandFactory & rubberbandFactory = map.rubberbandFactory();
RubberbandPointFeature * rubberband = rubberbandFactory.create<RubberbandPointFeature>();
if (rubberband != nullptr) doSomething(rubberband);
@endcode
@param parent Parent of rubberband object. If parent is nullptr \c _map will be used as parent
@see Rubberband, RubberbandPointFeature, RubberbandPointCluster, RubberbandMultiPointFeature, RubberbandRectangle, RubberbandEllipse, RubberbandCorridor, RubberbandArrow
*/
template<class RubberbandClass> RubberbandClass * create3D( QObject * parent = nullptr ) const
{
RubberbandClass * rubberband = nullptr;
if ((std::is_base_of<Rubberband3D, RubberbandClass>::value) && (Mode::Mode_3D == _map->mode()))
{
// be careful it is not thread safe here
RubberbandBase::currentFactoryMap(_map);
RubberbandBase::allowMultipleRubberbands(_allowMultipleRubberbands);
try
{
rubberband = new RubberbandClass( _map, parent );
}
catch (const SituationMap::Exception &) {;}
setDefaults( rubberband );
}
return rubberband;
};
/**
If pass \c true multiple rubberbands per time can be created per map. Creating a rubberbad of the same type twice per time will return one
rubberband that is not alive. Default is \c false. In this case creating a second rubberband before the first has finsihed (rubberband is not alive)
will retrun \c nullptr.
*/
void allowMultipleRubberbands(bool on) { _allowMultipleRubberbands = on; }
bool allowMultipleRubberbands() const { return _allowMultipleRubberbands; }
void setRubberbandDrawColor( const QColor & );
void setRubberbandFillColor( const QColor & );
void setRubberbandHandleDrawColor( const QColor & );
void setRubberbandHandleFillColor( const QColor & );
void setRubberbandSelectionColor( const QColor & );
void setRubberbandFrameColor( const QColor & );
void setRubberbandFrameFillColor( const QColor & );
void setRubberbandFrameHandleMargin( int );
void setRubberbandPreviewOffset( const QPoint & );
void setRubberbandPreviewSize( unsigned int );
void setRubberbandPickingRatio( unsigned int );
void setRubberbandLineHandleWidth( unsigned int );
signals:
void rubberbandCreated();
void rubberbandDestroyed();
private:
class Defaults;
SituationMap::Map * _map;
Defaults * _defaults;
bool _allowMultipleRubberbands;
LOGGER_T _logger;
void setDefaults( RubberbandBase * ) const;
void setDefaults( Rubberband * ) const;
private slots:
void onActivateRubberband( RubberbandBase * rubberband );
void onAbortRubberband ( RubberbandBase * rubberband );
}; /* RubberbandFactory */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,314 @@
/**
**
** @RDE_HEADER@
** Implementation of base class for rubberband frame handles
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_frame_handle.h"
#include <MathUtils/math_const.h>
#include <arcgis/Map.h>
#include <arcgis/MapGraphicsView.h>
#include <QtWidgets/QGraphicsScene>
namespace SituationMap { namespace RB
{
static QGraphicsPolygonItem * createFrameGraphic( QGraphicsScene * mapScene, qreal zBufferValue )
{
if (mapScene != nullptr)
{
QGraphicsPolygonItem * frameSymbol = new QGraphicsPolygonItem();
frameSymbol -> setZValue( zBufferValue );
frameSymbol -> setFlags( QGraphicsItem::ItemIgnoresTransformations );
mapScene -> addItem( frameSymbol );
return frameSymbol;
}
return nullptr;
} /* createFrameGraphic */
class FramePoint : public QPointF
{
public:
Q_DECL_CONSTEXPR FramePoint(const QPointF &p) : QPointF(p) {}
Q_DECL_CONSTEXPR FramePoint(qreal x, qreal y) : QPointF(x, y) {}
FramePoint rotate(const QPointF &center, qreal sinA, qreal cosA) const
{
qreal cx = x() - center.x();
qreal cy = y() - center.y();
qreal px = cx*cosA - cy*sinA + center.x();
qreal py = cy*cosA + cx*sinA + center.y();
return FramePoint(px, py);
} // rotate( const QPointF & center, qreal sin qreal cosA )
FramePoint rotate(const RubberbandHandle::RubberbandCoordinate & center, qreal sinA, qreal cosA) const
{
return rotate(QPointF(center._mapCoordinate.x(), center._mapCoordinate.y()), sinA, cosA);
} /* rotate */
FramePoint rotate(qreal sinA, qreal cosA) const
{
return rotate(QPointF(), sinA, cosA);
} // rotate( const QPointF & center, qreal sin qreal cosA )
}; /* FramePoint */
RubberbandFrameHandle::RubberbandFrameHandle( Esri::ArcGISRuntime::MapGraphicsView * mapView
, QGraphicsScene * scene
, qreal sceneMargin )
: RubberbandHandle(mapView,scene)
, _frameSymbol(nullptr)
, _frameSceneMargin(sceneMargin)
, _frameRotationSin(0)
, _frameRotationCos(1)
, _frameWidth(0)
, _frameHeight(0)
, _frameCenterCoordinate()
, _mapRotateSin(0)
, _mapRotateCos(1)
, _drawDisabled(false)
, _frameLineHandleList()
{
qreal mapRotatePhi = _mapView->mapRotation() * MathConst::pi / 180.0;
_mapRotateSin = sin(mapRotatePhi);
_mapRotateCos = cos(mapRotatePhi);
zBufferPlane( ZBufferPlane::FrameHandle );
_frameSymbol = createFrameGraphic( _scene, _zBufferValue );
if (_drawDisabled) _frameSymbol->hide();
updateGraphic();
} /* RubberbandFrameHandle::RubberbandFrameHandle */
RubberbandFrameHandle::~RubberbandFrameHandle()
{
if (_scene)
{
if (_frameSymbol)
{
_scene->removeItem(_frameSymbol);
delete _frameSymbol;
}
}
_frameSymbol = nullptr;
} /* RubberbandFrameHandle::~RubberbandFrameHandle */
void RubberbandFrameHandle::buildFrameVertexCoordinates()
{
auto length = [](qreal x, qreal y) -> qreal { return sqrt(x*x+y*y); };
QPointF center( _frameCenterCoordinate._mapCoordinate.x(), _frameCenterCoordinate._mapCoordinate.y());
RubberbandCoordinate marginP( _mapView, _frameCenterCoordinate._sceneCoordinate+QPointF(_frameSceneMargin,0) );
qreal margin = length( marginP._mapCoordinate.x()-center.x(), marginP._mapCoordinate.y()-center.y() );
QPointF vertex[4];
qreal frameWidth2 = _frameWidth * 0.5;
qreal frameHeight2 = _frameHeight * 0.5;
vertex[0] = QPointF( center.x() - frameWidth2 - margin, center.y() - frameHeight2 - margin );
vertex[1] = QPointF( center.x() + frameWidth2 + margin, center.y() - frameHeight2 - margin );
vertex[2] = QPointF( center.x() + frameWidth2 + margin, center.y() + frameHeight2 + margin );
vertex[3] = QPointF( center.x() - frameWidth2 - margin, center.y() + frameHeight2 + margin );
for (int i = 0; i < 4; ++i)
{
const FramePoint & v = FramePoint(vertex[i]).rotate(_frameCenterCoordinate, -_frameRotationSin, _frameRotationCos );
_frameVertexCoordinate[i] = RubberbandCoordinate(_mapView, convert(v, _mapView->map()->spatialReference()));
}
// Now we have the vertex coordinates in map coordinate system
} /* RubberbandFrameHandle::buildFrameVertexCoordinates */
void RubberbandFrameHandle::adjustCoordinates()
{
qreal mapRotatePhi = _mapView->mapRotation() * MathConst::pi / 180.0;
_mapRotateSin = sin(mapRotatePhi);
_mapRotateCos = cos(mapRotatePhi);
_frameCenterCoordinate.mapToScene(_mapView);
buildFrameVertexCoordinates();
updateFramePolygonItem();
emit adjusted();
} /* RubberbandFrameHandle::adjustCoordinates */
void RubberbandFrameHandle::adjustWindow( const QRectF& )
{
onDo_adjustCoordinates();
} /* RubberbandFrameHandle::adjustWindow */
void RubberbandFrameHandle::updateFrameShape( const QVector<RubberbandCoordinate> & vertexList, qreal sinA, qreal cosA )
{
DEBUG_LOG(_logger) << LOGFUNCTION << "( const QVector<RubberbandCoordinate> & vertexList, qreal sinA, qreal cosA )";
qreal sinPhi = sinA * _mapRotateCos - cosA * _mapRotateSin; // Addition-Theorem get rotation of the frame without map rotation
qreal cosPhi = cosA * _mapRotateCos + sinA * _mapRotateSin;
qreal minX = std::numeric_limits<qreal>::infinity();
qreal maxX = -std::numeric_limits<qreal>::infinity();
qreal minY = std::numeric_limits<qreal>::infinity();
qreal maxY = -std::numeric_limits<qreal>::infinity();
for (const RubberbandCoordinate & vertex : vertexList)
{
// eliminate rotation from vertex scene coordinate
FramePoint xy = FramePoint(vertex._sceneCoordinate.x(),vertex._sceneCoordinate.y()).rotate( -sinPhi, cosPhi );
qreal x = xy.x();
qreal y = xy.y();
if (minX > x) minX = x;
if (minY > y) minY = y;
if (maxX < x) maxX = x;
if (maxY < y) maxY = y;
}
_frameRotationSin = sinA;
_frameRotationCos = cosA;
// calculate rotated coordinates (map rotation) of (minX,minY), (maxX,maxY) and frame scene center
FramePoint frameSceneV0 = FramePoint( minX , minY ).rotate( sinPhi, cosPhi );
FramePoint frameSceneVW = FramePoint( maxX , minY ).rotate( sinPhi, cosPhi );
FramePoint frameSceneVH = FramePoint( minX , maxY ).rotate( sinPhi, cosPhi );
FramePoint frameSceneCenter = FramePoint( (minX+maxX)*0.5, (minY+maxY)*0.5 ).rotate( sinPhi, cosPhi );
_frameCenterCoordinate.updateSceneCoordinate( _mapView, frameSceneCenter );
// Calculate map coordinates of bounding rectangle
RubberbandCoordinate frameV0( _mapView, QPointF(frameSceneV0.x(),frameSceneV0.y()) );
RubberbandCoordinate frameVW( _mapView, QPointF(frameSceneVW.x(),frameSceneVW.y()) );
RubberbandCoordinate frameVH( _mapView, QPointF(frameSceneVH.x(),frameSceneVH.y()) );
auto length = []( qreal x1, qreal y1, qreal x2, qreal y2 ) -> qreal
{
qreal dx = x2-x1;
qreal dy = y2-y1;
return sqrt(dx*dx+dy*dy);
};
// get frame width and height in map coordinates
_frameWidth = length( frameV0._mapCoordinate.x(), frameV0._mapCoordinate.y(), frameVW._mapCoordinate.x(), frameVW._mapCoordinate.y() );
_frameHeight = length( frameV0._mapCoordinate.x(), frameV0._mapCoordinate.y(), frameVH._mapCoordinate.x(), frameVH._mapCoordinate.y() );
buildFrameVertexCoordinates();
updateFramePolygonItem();
} /* RubberbandFrameHandle::updateFrameShape */
void RubberbandFrameHandle::updateFrameShape()
{
DEBUG_LOG(_logger) << LOGFUNCTION;
buildFrameVertexCoordinates();
updateFramePolygonItem();
} /* RubberbandFrameHandle::updateFrameShape */
void RubberbandFrameHandle::updateFramePolygonItem()
{
QPolygonF framePolygon;
framePolygon.reserve( 4 );
for (auto vertex : _frameVertexCoordinate)
{
framePolygon.append(vertex.mapToScene(_mapView));
}
framePolygon.append(_frameVertexCoordinate[0]._sceneCoordinate);
_frameSymbol->setPolygon(framePolygon);
} /* RubberbandFrameHandle::updateFramePolygonItem */
void RubberbandFrameHandle::updateGraphic()
{
if (_frameSymbol)
{
_frameSymbol -> setPen( QPen(QColor("black"),1,Qt::PenStyle::DashDotLine) );
_frameSymbol -> setVisible( _isVisible );
if (isSelected())
_frameSymbol -> setBrush( QBrush(_selectionColor) );
else
_frameSymbol -> setBrush( QBrush(_fillColor) );
}
} /* RubberbandFrameHandle::updateGraphic */
void RubberbandFrameHandle::updateCoordinate(const QPointF & scenePosition)
{
_frameCenterCoordinate.updateSceneCoordinate( _mapView, scenePosition );
updateFrameShape();
} /* RubberbandFrameHandle::updateCoordinate */
void RubberbandFrameHandle::moveCoordinate(const QPointF & sceneDelta)
{
_frameCenterCoordinate.updateSceneCoordinate( _mapView, _frameCenterCoordinate._sceneCoordinate+sceneDelta );
updateFrameShape();
} /* RubberbandFrameHandle::moveCoordinate */
RubberbandHandle::RubberbandCoordinate RubberbandFrameHandle::getCoordinate() const { return _frameCenterCoordinate; }
bool RubberbandFrameHandle::isPositionInside( const QPointF & scenePosition ) const
{
if (_frameSymbol)
{
return _frameSymbol->contains( scenePosition );
}
return false;
} /* RubberbandFrameHandle::isPositionInside */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,153 @@
/**
**
** @RDE_HEADER@
** Definition of base class for rubberband frame handles
** $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 <QtCore/QPointF>
#include <QtWidgets/QGraphicsPolygonItem>
#include <cmath>
#include <Common/ref_pointer.h>
#include "rubberband_handle.h"
#include "rubberband_line_handle.h"
class QGraphicsScene;
namespace SituationMap { namespace RB
{
/**
@class RubberbandFrameHandle rubberband_frame_handle.h
@brief Implementation of a frame handle for rubberband internal use.
@see RubberbandHandle
*/
class RubberbandFrameHandle : public RubberbandHandle
{
Q_OBJECT
public:
RubberbandFrameHandle( Esri::ArcGISRuntime::MapGraphicsView * mapView
, QGraphicsScene * scene
, qreal sceneMargin );
~RubberbandFrameHandle();
inline void updateFrameShape(const QVector<RubberbandCoordinate> & vertexList)
{
updateFrameShape( vertexList, 0.0, 1.0 );
} /* updateFrameShape */
void updateFrameShape( const QVector<RubberbandCoordinate> & vertexList, qreal sinA, qreal cosA );
bool isPositionInside( const QPointF & scenePosition ) const override;
virtual void updateCoordinate( const QPointF & scenePosition );
virtual void moveCoordinate ( const QPointF & sceneDelta );
virtual RubberbandCoordinate getCoordinate() const;
inline qreal frameRotationAngle() const
{
qreal phi = acos(_frameRotationCos);
return (_frameRotationSin < 0.0) ? -phi : phi;
} /* frameRotationAngle */
inline void frameRotationAngle( qreal & sinA, qreal & cosA )
{
sinA = _frameRotationSin;
cosA = _frameRotationCos;
} /* frameRotationAngle */
inline qreal frameSceneMargin() const { return _frameSceneMargin; }
inline void updateFrameRotationAngle( qreal sinA, qreal cosA )
{
_frameRotationSin = sinA;
_frameRotationCos = cosA;
updateFrameShape();
} /* updateFrameRotationAngle */
inline void updateFrameRotationAngle( qreal x )
{
_frameRotationSin = sin(x);
_frameRotationCos = cos(x);
updateFrameShape();
} /* updateFrameRotationAngle */
inline void updateFrameSceneMargin(qreal x) { _frameSceneMargin = x; updateFrameShape(); }
inline void drawDisabled(bool v)
{
_drawDisabled = v;
if (_drawDisabled) _frameSymbol->hide();
else _frameSymbol->show();
} /* drawDisabled */
inline bool drawDisabled() const { return _drawDisabled; }
protected:
QGraphicsPolygonItem * _frameSymbol;
qreal _frameSceneMargin;
qreal _frameRotationSin;
qreal _frameRotationCos;
qreal _frameWidth;
qreal _frameHeight;
RubberbandCoordinate _frameCenterCoordinate;
RubberbandCoordinate _frameVertexCoordinate[4];
qreal _mapRotateSin;
qreal _mapRotateCos;
bool _drawDisabled;
QList<SituationMap::RefPointer<RubberbandLineHandle>> _frameLineHandleList;
void updateGraphic() override;
void updateFrameShape();
void updateFramePolygonItem();
void buildFrameVertexCoordinates();
void adjustCoordinates() override;
void adjustWindow( const QRectF& ) override;
QPointF getMapRotation() { return QPointF( _mapRotateCos, _mapRotateSin ); }
}; /* RubberbandFrameHandle */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,267 @@
/**
**
** @RDE_HEADER@
** Implementation of rubberband class to define point feature geoemtry
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_free_hand.h"
#include "rubberband_point_handle.h"
#include "rubberband_drawable.h"
#include "drawable_line.h"
#include "drawable_painter_path.h"
#include "rubberband_handle_proxy.h"
#include "rubberband_internal.h"
#include "rubberband_base_internal.h"
#include <arcgis/MapGraphicsView.h>
namespace SituationMap { namespace RB
{
struct RubberbandFreeHand::InternalData
{
QVector<RubberbandDrawable::RubberbandCoordinate> _coordinateList;
QVector<unsigned int> _inOneGoIndex;
QPoint _lastWindowPos;
bool _coordinateRecordingActive = false;
SituationMap::RefPointer<DrawableLine> _cursorPreviewLine;
SituationMap::RefPointer<DrawableLine> _cursorPreviewCloseLine;
SituationMap::RefPointer<DrawablePainterPath> _pathItem;
}; /* RubberbandFreeHand::InternalData */
RubberbandFreeHand::RubberbandFreeHand( SituationMap::Map * map, QObject * parent )
: Rubberband(map,parent)
, _internal(new RubberbandFreeHand::InternalData)
, _isClosed(false)
{
} /* RubberbandFreeHand::RubberbandFreeHand */
RubberbandFreeHand::~RubberbandFreeHand()
{
delete _internal;
_internal = nullptr;
} /* RubberbandFreeHand::~RubberbandFreeHand */
bool RubberbandFreeHand::selectAction( AbstractEventDispatcher * causer, int x, int y )
{
if (Rubberband::selectAction(causer, x, y))
{
deactivateButtons();
_internal->_coordinateRecordingActive = true;
_internal->_inOneGoIndex << _internal->_coordinateList.size();
return movePickedAction(causer,x,y);
}
return false;
} /* RubberbandFreeHand::selectAction */
bool RubberbandFreeHand::movePickedAction( AbstractEventDispatcher *, int x, int y )
{
if (_internal->_coordinateRecordingActive)
{
QPointF scenePos(pixel2ScenePosition(x,y));
if (_internal->_coordinateList.isEmpty())
{
_internal->_lastWindowPos.setX(x);
_internal->_lastWindowPos.setY(y);
_internal->_coordinateList.append(RubberbandDrawable::RubberbandCoordinate(Rubberband::_internal->_mapView,scenePos));
return true;
}
if ((std::abs(_internal->_lastWindowPos.x() - x) > 2) || (std::abs(_internal->_lastWindowPos.y() - y) > 2))
{
_internal->_lastWindowPos.setX(x);
_internal->_lastWindowPos.setY(y);
_internal->_coordinateList.append(RubberbandDrawable::RubberbandCoordinate(Rubberband::_internal->_mapView,scenePos));
}
update();
return true;
}
return false;
} /* RubberbandFreeHand::movePickedAction */
bool RubberbandFreeHand::moveAction( AbstractEventDispatcher *, int x, int y )
{
if (!_internal->_coordinateList.isEmpty())
{
const RubberbandDrawable::RubberbandCoordinate & firstPos = _internal->_coordinateList.first();
const RubberbandDrawable::RubberbandCoordinate & lastPos = _internal->_coordinateList.last();
QPointF scenePos(pixel2ScenePosition(x,y));
if (!_internal->_cursorPreviewLine) _internal->_cursorPreviewLine = new DrawableLine( Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene );
if ((isClosedEnabled()) && (!_internal->_cursorPreviewCloseLine))
{
_internal->_cursorPreviewCloseLine = new DrawableLine( Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene );
}
_internal -> _cursorPreviewLine -> setVisibility( true );
_internal -> _cursorPreviewLine -> setDrawColor( _handleSelectionColor );
_internal -> _cursorPreviewLine -> setLine( lastPos, RubberbandDrawable::RubberbandCoordinate( Rubberband::_internal->_mapView, scenePos ));
if (_internal->_cursorPreviewCloseLine)
{
_internal -> _cursorPreviewCloseLine -> setVisibility( true );
_internal -> _cursorPreviewCloseLine -> setDrawColor( _handleSelectionColor );
_internal -> _cursorPreviewCloseLine -> setLine( firstPos, RubberbandDrawable::RubberbandCoordinate( Rubberband::_internal->_mapView, scenePos ));
}
}
return false;
} /* RubberbandFreeHand::moveAction */
bool RubberbandFreeHand::setCoordinateAction( AbstractEventDispatcher * causer, int x, int y )
{
_internal->_coordinateRecordingActive = false;
if (Rubberband::setCoordinateAction(causer,x,y))
{
QPointF scenePos(pixel2ScenePosition(x,y));
activateButtons();
_baseInternal->buttonProxyActive( scenePos );
}
return false;
} /* RubberbandFreeHand::setCoordinateAction */
void RubberbandFreeHand::activateButtons()
{
_baseInternal->_hasUndoButton = true;
_baseInternal->_applyIsPossible = true;
_baseInternal->_undoIsPossible = !_internal->_inOneGoIndex.isEmpty();
Rubberband::activateButtons();
} /* RubberbandFreeHand::activateButtons */
bool RubberbandFreeHand::undoAction( AbstractEventDispatcher*, int, int )
{
if (!_internal->_inOneGoIndex.isEmpty())
{
unsigned int coordinateIdx = _internal->_inOneGoIndex.takeLast();
while (coordinateIdx < (unsigned int)_internal->_coordinateList.size())
{
_internal->_coordinateList.removeLast();
}
update();
activateButtons();
}
return true;
} /* RubberbandFreeHand::undoAction */
bool RubberbandFreeHand::completeStateAction( AbstractEventDispatcher * causer, int x, int y )
{
if (rubberbandIsAlive())
{
return applyAndEndAction(causer,x,y);
}
return false;
} /* RubberbandFreeHand::completeStateAction */
unsigned int RubberbandFreeHand::coordinateCount() const
{
return _internal->_coordinateList.size();
} /* RubberbandFreeHand::coordinateCount */
QVector<QPointF> RubberbandFreeHand::coordinateVector( CoordinateSystem cs ) const
{
QVector<QPointF> coordinateVector;
coordinateVector.reserve(_internal->_coordinateList.size());
for (const RubberbandDrawable::RubberbandCoordinate &pos : qAsConst(_internal->_coordinateList))
coordinateVector.push_back(projectCoordinateFromMap( cs, pos._mapCoordinate ));
return coordinateVector;
} /* RubberbandFreeHand::coordinateVector */
QPointF RubberbandFreeHand::singleCoordinate(unsigned int idx, CoordinateSystem cs ) const
{
if (idx >= (unsigned int)_internal->_coordinateList.size()) return QPointF();
const Esri::ArcGISRuntime::Point & pos = _internal->_coordinateList.at(idx)._mapCoordinate;
return projectCoordinateFromMap( cs, pos );
} /* RubberbandFreeHand::singleCoordinate */
void RubberbandFreeHand::update()
{
if (_internal->_coordinateList.size() > 1)
{
if (!_internal->_pathItem)
{
_internal->_pathItem = new DrawablePainterPath( Rubberband::_internal->_mapView );
}
_internal -> _pathItem -> setVisibility(true);
_internal -> _pathItem -> setLineWidth( 2 );
_internal -> _pathItem -> enableClosedLine( _isClosed );
_internal -> _pathItem -> setDrawColor( _drawColor );
_internal -> _pathItem -> setFillColor( _fillColor );
_internal -> _pathItem -> setPath( _internal->_coordinateList );
}
else
{
if (_internal -> _pathItem) _internal->_pathItem->setVisibility(false);
if (_internal->_coordinateList.isEmpty())
{
if (_internal -> _cursorPreviewLine ) _internal -> _cursorPreviewLine -> setVisibility(false);
if (_internal -> _cursorPreviewCloseLine) _internal -> _cursorPreviewCloseLine -> setVisibility(false);
}
}
if (!_internal->_coordinateList.isEmpty())
{
QPointF bottomRight( std::numeric_limits<double>::min(), std::numeric_limits<double>::min() );
for (const RubberbandDrawable::RubberbandCoordinate &coordinate : qAsConst(_internal->_coordinateList))
{
const QPointF & p = coordinate._sceneCoordinate;
if (bottomRight.x() < p.x()) bottomRight.setX(p.x());
if (bottomRight.y() < p.y()) bottomRight.setY(p.y());
}
if (isButtonBoxPositionFixed())
{
RubberbandBase::_baseInternal->_buttonBoxSceneAnchor = bottomRight;
}
}
} /* RubberbandFreeHand::update */
} } /* namespace SituationMap::RB */
+102
View File
@@ -0,0 +1,102 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class for free hand drawing
** $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 .........:
**
** 06.10.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband.h"
namespace SituationMap { namespace RB
{
/**
@class RubberbandPointCluster rubberband_point_cluster.h
@brief Implementation of a rubberband to input single coodinates for building point feature clusters
@see Rubberband, RubberbandPointFeature
*/
class SITUATIONMAP_EXPORT RubberbandFreeHand : public Rubberband
{
Q_OBJECT
/**
@name Construction & Destruction
@{
*/
friend class RubberbandFactory;
explicit RubberbandFreeHand( SituationMap::Map * map, QObject * parent = nullptr );
public:
~RubberbandFreeHand();
/** @} */
bool selectAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool movePickedAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool moveAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool setCoordinateAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool completeStateAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool undoAction ( AbstractEventDispatcher * causer, int x, int y ) override;
unsigned int coordinateCount() const override;
virtual QVector<QPointF> coordinateVector( CoordinateSystem cs = CoordinateSystem::Geo ) const override;
virtual QPointF singleCoordinate( unsigned int idx = 0, CoordinateSystem cs = CoordinateSystem::Geo ) const override;
/**
If set to true a polygon the rubberband draws a polygon otherwise a polyline.
*/
inline void enableClosed( bool flag ) { _isClosed = flag; }
/**
Gets the value of the close flag
*/
inline bool isClosedEnabled() const { return _isClosed; }
private:
virtual void setCoordinateVector( const QVector<QPointF> & /*pntList*/, CoordinateSystem /*cs*/ = CoordinateSystem::Geo ) override {}
protected:
/*
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.
*/
struct InternalData;
InternalData * _internal;
bool _isClosed;
void activateButtons() override;
void update() override;
}; /* RubberbandFreeHand */
} } /* namespace SituationMap::RB */
+70
View File
@@ -0,0 +1,70 @@
/**
**
** @RDE_HEADER@
** Implementation of base class for rubberband handles
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_handle.h"
namespace SituationMap { namespace RB
{
RubberbandHandle::RubberbandHandle( QGraphicsView *view )
: RubberbandDrawable(view)
, _pickingRatio(5)
, _isSelected(false)
, _isSelectable(true)
, _userData(nullptr)
{
} /* RubberbandHandle::RubberbandHandle */
RubberbandHandle::RubberbandHandle( Esri::ArcGISRuntime::MapGraphicsView * mapView )
: RubberbandDrawable( mapView )
, _pickingRatio(5)
, _isSelected(false)
, _isSelectable(true)
, _userData(nullptr)
{
} /* RubberbandHandle::RubberbandHandle */
RubberbandHandle::RubberbandHandle( Esri::ArcGISRuntime::MapGraphicsView * mapView, QGraphicsScene * scene)
: RubberbandDrawable( mapView, scene )
, _pickingRatio(5)
, _isSelected(false)
, _isSelectable(true)
, _userData(nullptr)
{
} /* RubberbandHandle::RubberbandHandle */
RubberbandHandle::~RubberbandHandle()
{
} /* RubberbandHandle::~Rubberbandhandle */
} } /* namespace SituationMap::RB */
+100
View File
@@ -0,0 +1,100 @@
/**
**
** @RDE_HEADER@
** Definition of base class for rubberband handles
** $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 "rubberband_drawable.h"
namespace SituationMap { namespace RB
{
/**
@class RubberbandHandle rubberband_handle.h
@brief Base class of all rubberband handles for rubberband internal use.
*/
class RubberbandHandle : public RubberbandDrawable
{
Q_OBJECT
public:
/**
@name Construction & Destruction
@{
*/
explicit RubberbandHandle( QGraphicsView * );
explicit RubberbandHandle( Esri::ArcGISRuntime::MapGraphicsView * );
explicit RubberbandHandle( Esri::ArcGISRuntime::MapGraphicsView *, QGraphicsScene * );
~RubberbandHandle();
/** @} */
virtual bool isPositionInside( const QPointF & scenePosition ) const = 0;
inline bool isSelected() const { return _isSelected; }
inline void setSelection( bool on = true ) { _isSelected = _isSelectable && on; updateGraphic(); }
inline bool isSelectable() const { return _isSelectable; }
inline void setSelectable(bool on = true) { _isSelectable = on; if (!on) { _isSelected = false; updateGraphic(); } }
inline void setSelectionColor( const QColor & col ) { _selectionColor = col; updateGraphic(); }
inline void setUserData( void * ptr ) { _userData = ptr; }
inline void* userData() { return _userData; }
inline unsigned int pickingRatio() const { return _pickingRatio; }
inline void setPickingRatio(unsigned int value) { if (value > 5) _pickingRatio = value; }
inline bool isFirst() const { return _is_first; }
inline void setIsFirst(bool on = true) { _is_first = on; }
protected:
void updateGraphic() override = 0;
void adjustCoordinates() override = 0;
void adjustWindow( const QRectF& ) override = 0;
unsigned int _pickingRatio;
bool _isSelected;
bool _isSelectable;
QColor _selectionColor;
bool _is_first{false};
private:
void * _userData;
signals:
void adjusted();
}; /* RubberbandHandle */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,167 @@
/**
**
** @RDE_HEADER@
** Implementation of class RubberbandHandleProxy to forward adjust signals from view
** $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 .........:
**
** 10.07.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_handle_proxy.h"
#include <MathUtils/math_const.h>
#include <QtCore/QRectF>
#define BUG_iOSQz_000005
namespace SituationMap { namespace RB
{
void RubberbandHandleProxy::init( QWidget * widget )
{
zBufferPlane( ZBufferPlane::Widget );
_widgetsProxy = new QGraphicsProxyWidget();
_widgetsProxy -> setWidget( widget );
_widgetsProxy -> setZValue( _zBufferValue );
#ifdef BUG_iOSQz_000005
// Bug iOSQz-000005 'QGraphicsProxyWidget will crash'
// Adding a widget will let the application crash
// Workaround: 'proxy->setOpacity(0.99);'
_widgetsProxy->setOpacity(0.99);
#endif
_scene->addItem( _widgetsProxy );
} /* RubberbandHandleProxy::init */
RubberbandHandleProxy::RubberbandHandleProxy( QGraphicsView * view, QWidget * widget )
: RubberbandHandle(view)
, _coordinate()
, _sceneOffset(0, 0)
, _rotateSceneOffset(true)
, _restoreView(view)
{
init( widget );
} /* RubberbandHandleProxy::RubberbandHandleProxy */
RubberbandHandleProxy::RubberbandHandleProxy( Esri::ArcGISRuntime::MapGraphicsView * view, QWidget * widget )
: RubberbandHandle(view)
, _coordinate()
, _sceneOffset(0, 0)
, _rotateSceneOffset(true)
, _restoreView(view)
{
init( widget );
} /* RubberbandHandleProxy::RubberbandHandleProxy */
RubberbandHandleProxy::RubberbandHandleProxy( Esri::ArcGISRuntime::MapGraphicsView * view, QGraphicsScene * scene, QWidget * widget )
: RubberbandHandle(view, scene)
, _coordinate()
, _sceneOffset(0, 0)
, _rotateSceneOffset(true)
, _restoreView(view)
{
init( widget );
} /* RubberbandHandleProxy::RubberbandHandleProxy */
RubberbandHandleProxy::~RubberbandHandleProxy()
{
if (_scene)
{
if (_widgetsProxy)
{
_widgetsProxy->setWidget(nullptr);
_scene->removeItem(_widgetsProxy);
delete _widgetsProxy;
}
}
_widgetsProxy = nullptr;
if (_restoreView && _restoreView->viewport())
_restoreView->viewport()->setCursor(_restoreCursor); // workaround Qt bug. remove when fixed
} /* RubberbandHandleProxy::~RubberbandHandleProxy */
QPointF RubberbandHandleProxy::getRotatedSceneOffset() const
{
if ((_mapView) && (_rotateSceneOffset))
{
auto rotate = [](const QPointF & p, qreal sinA, qreal cosA) -> QPointF { return QPointF(p.x()*cosA+p.y()*sinA,p.y()*cosA-p.x()*sinA); };
qreal mapRotatePhi = _mapView->mapRotation() * MathConst::pi / 180.0;
qreal sinMap = sin(mapRotatePhi);
qreal cosMap = cos(mapRotatePhi);
return rotate( _sceneOffset, sinMap, cosMap );
}
else return _sceneOffset;
} /* RubberbandHandleProxy::getRotatedSceneOffset */
void RubberbandHandleProxy::setPos(const QPointF & pos)
{
_coordinate.updateSceneCoordinate( _mapView, pos );
if (_widgetsProxy)
{
_widgetsProxy -> setPos(pos+getRotatedSceneOffset());
_widgetsProxy -> setZValue( _zBufferValue );
}
} /* RubberbandHandleProxy::setPos */
bool RubberbandHandleProxy::isPositionInside( const QPointF & scenePosition ) const
{
const QRectF & bbox = _widgetsProxy->windowFrameGeometry();
return bbox.contains(scenePosition);
} /* RubberbandHandleProxy::isPositionInside */
void RubberbandHandleProxy::adjustCoordinates()
{
const QPointF & scenePosition = _coordinate.mapToScene(_mapView);
if (_widgetsProxy)
{
_widgetsProxy -> setZValue( _zBufferValue );
_widgetsProxy -> setPos(scenePosition+getRotatedSceneOffset());
}
emit adjusted();
} /* RubberbandHandleProxy::adjustCoordinates */
void RubberbandHandleProxy::adjustWindow( const QRectF & )
{
onDo_adjustCoordinates();
} /* RubberbandHandleProxy::adjustWindow */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,104 @@
/**
**
** @RDE_HEADER@
** Definition of class RubberbandHandleProxy to forward adjust signals from View
** $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 .........:
**
** 10.07.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband_handle.h"
#include <QtWidgets/QGraphicsProxyWidget>
class QGraphicsView;
class QGraphicsScene;
namespace SituationMap { namespace RB
{
/**
@class RubberbandHandleProxy rubberband_handle_proxy.h
@brief Implementation of a procx to handle small menues and other widgets like buttons
@see RubberbandHandle
*/
class RubberbandHandleProxy : public RubberbandHandle
{
Q_OBJECT
public:
/**
@name Construction & Destruction
@{
*/
RubberbandHandleProxy( QGraphicsView *view, QWidget * widget );
RubberbandHandleProxy( Esri::ArcGISRuntime::MapGraphicsView * view, QWidget * widget );
RubberbandHandleProxy( Esri::ArcGISRuntime::MapGraphicsView * view, QGraphicsScene * scene, QWidget * widget );
~RubberbandHandleProxy();
/** @} */
bool isPositionInside( const QPointF & scenePosition ) const override;
void setPos(const QPointF & pos);
const RubberbandCoordinate & getCoordinate() const { return _coordinate; }
inline void setSceneOffset(const QPointF & offset) { _sceneOffset = offset; }
inline void show() { setVisibility(false); if (_widgetsProxy) { _widgetsProxy->show(); setVisibility(true); } }
inline void hide() { setVisibility(false); if (_widgetsProxy) { _widgetsProxy->hide(); setVisibility(false); } }
inline void setRotateSceneOffset(bool on = true) { _rotateSceneOffset = on; }
inline void setRestoreCursor( const QCursor & cursor ) { _restoreCursor = cursor; } // workaround Qt bug. remove when fixed
protected:
RubberbandCoordinate _coordinate;
QGraphicsProxyWidget * _widgetsProxy = nullptr;
QPointF _sceneOffset;
bool _rotateSceneOffset;
QPointer<QGraphicsView> _restoreView;
QCursor _restoreCursor; // workaround Qt bug. remove when fixed
void updateGraphic() override {}
void adjustCoordinates() override;
void adjustWindow( const QRectF& ) override;
private:
QPointF getRotatedSceneOffset() const;
private:
void init( QWidget * widget );
}; /* RubberbandHandleProxy */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,98 @@
/**
**
** @RDE_HEADER@
** Definition of internal data 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 ...........: Joerg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 16.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_internal.h"
#include "rubberband.h"
#include "rubberband_drawable.h"
#include "rubberband_handle.h"
#include "rubberband_handle_proxy.h"
#include <Map/map.h>
#include <MapImpl/map_impl.h>
namespace SituationMap { namespace RB
{
Rubberband::InternalData::InternalData( SituationMap::Map * map )
: _mapView(nullptr)
, _mapScene(nullptr)
, _handleList()
, _constructionObjectDraw(nullptr)
, _connectedPreviewPixmap(nullptr)
, _lastClickPosition(-1,-1)
, _constrainFailedMarker(nullptr)
, _logger(getLogger("Rubberband"))
{
SituationMap::MapImpl * mapImpl = dynamic_cast<SituationMap::MapImpl*>(map);
if (mapImpl)
{
_mapView = mapImpl -> getEsriMapGraphicsView();
if (_mapView != nullptr)
{
_mapScene = _mapView -> scene();
}
}
} /* InternalData */
Rubberband::InternalData::~InternalData()
{
/* Because of using shared RefPointer we don't need to call delete for every handle,
* just clear the handle-list.
for (auto handle : _handleList)
{
handle = nullptr;;
}
*/
_handleList.clear();
delete _constructionObjectDraw;
_constructionObjectDraw = nullptr;
if (_mapScene)
{
if (nullptr != _connectedPreviewPixmap)
{
_mapScene->removeItem( _connectedPreviewPixmap );
delete _connectedPreviewPixmap;
_connectedPreviewPixmap = nullptr;
}
delete _constrainFailedMarker;
}
_mapView = nullptr;
_mapScene = nullptr;
} /* ~InternalData */
} } /* namespace SituationMap::RB */
+98
View File
@@ -0,0 +1,98 @@
/**
**
** @RDE_HEADER@
** Definition of internal data 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 ...........: Joerg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 16.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <QtCore/QList>
#include <QtCore/QPointer>
#include <Common/ref_pointer.h>
#include <Common/situation_map_logging.h>
#include "rubberband.h"
#include "rubberband_handle.h"
#include "rubberband_drawable.h"
class QHBoxLayout;
class QWidget;
class QPushButton;
class QGraphicsScene;
namespace Esri {
namespace ArcGISRuntime {
class MapGraphicsView;
} }
namespace SituationMap
{
class Map;
class CoordTranslationFunctor;
}
namespace SituationMap { namespace RB
{
class RubberbandHandleProxy;
/**
@class Rubberband::InternalData rubberband_internal.h
@brief Definition of internal data of rubberband base class.
*/
struct Rubberband::InternalData
{
Q_DISABLE_COPY(InternalData)
QPointer<Esri::ArcGISRuntime::MapGraphicsView> _mapView;
QPointer<QGraphicsScene> _mapScene;
QList<SituationMap::RefPointer<RubberbandHandle>> _handleList;
RubberbandDrawable * _constructionObjectDraw;
QGraphicsPixmapItem * _connectedPreviewPixmap;
QPointF _lastClickPosition;
QGraphicsPixmapItem * _constrainFailedMarker;
LOGGER_T _logger;
explicit InternalData( SituationMap::Map * map );
~InternalData();
void markFailedConstrains( QPoint pos, bool on );
}; /* InternalData */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,231 @@
/**
**
** @RDE_HEADER@
** Implementation of base class for rubberband handles
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_line_handle.h"
#include <arcgis/MapGraphicsView.h>
#include <QtWidgets/QGraphicsScene>
#include <QtWidgets/QGraphicsLineItem>
#include <math.h>
namespace SituationMap { namespace RB
{
RubberbandLineHandle::RubberbandLineHandle( Esri::ArcGISRuntime::MapGraphicsView * mapView
, QGraphicsScene * scene
, const QPointF & p1
, const QPointF & p2
, unsigned int lineWidth
, bool dottedLine )
: RubberbandHandle(mapView,scene)
, _lineSymbol(nullptr)
, _lineStyle()
, _coordinates()
, _dottedLine(dottedLine)
{
_lineWidth = lineWidth;
zBufferPlane( ZBufferPlane::LineHandle );
_lineStyle.setWidth(_lineWidth);
if (_scene != nullptr)
{
QGraphicsLineItem * line = new QGraphicsLineItem();
_lineSymbol = line;
_coordinates.resize(2);
_coordinates[0].updateSceneCoordinate(mapView,p1);
_coordinates[1].updateSceneCoordinate(mapView,p2);
if (_lineSymbol != nullptr)
{
_scene -> addItem( _lineSymbol );
line->setLine( _coordinates[0]._sceneCoordinate.x(), _coordinates[0]._sceneCoordinate.y()
, _coordinates[1]._sceneCoordinate.x(), _coordinates[1]._sceneCoordinate.y() );
line -> setZValue(10);
line -> setFlags( QGraphicsItem::ItemIgnoresTransformations );
makeLineStyle( _dottedLine, _lineStyle );
line -> setPen( _lineStyle );
}
}
} /* RubberbandLineHandle::RubberbandLineHandle */
RubberbandLineHandle::~RubberbandLineHandle()
{
if (_scene)
{
if (_lineSymbol)
{
_scene->removeItem(_lineSymbol);
delete _lineSymbol;
}
}
_coordinates.clear();
} /* RubberbandHandle::~Rubberbandhandle */
void RubberbandLineHandle::adjustCoordinates()
{
if (_coordinates.size() >= 2)
{
_coordinates[0].mapToScene( _mapView );
_coordinates[1].mapToScene( _mapView );
static_cast<QGraphicsLineItem*>(_lineSymbol)->setLine( _coordinates[0]._sceneCoordinate.x(), _coordinates[0]._sceneCoordinate.y()
, _coordinates[1]._sceneCoordinate.x(), _coordinates[1]._sceneCoordinate.y() );
}
DEBUG_LOG(_logger) << LOGFUNCTION << " map-coordinate = " << QString::number(_coordinates[0]._mapCoordinate.x(),'f',15)
<< " ; " << QString::number(_coordinates[0]._mapCoordinate.y(),'f',15)
<< " scene-coordinate = " << _coordinates[1]._sceneCoordinate.x() << " ; " << _coordinates[1]._sceneCoordinate.y();
emit adjusted();
} /* RubberbandLineHandle::adjustCoordinates */
void RubberbandLineHandle::adjustWindow( const QRectF& )
{
onDo_adjustCoordinates();
} /* RubberbandLineHandle::adjustWindow */
void RubberbandLineHandle::updateGraphic()
{
if (_lineSymbol)
{
QGraphicsLineItem * line = static_cast<QGraphicsLineItem*>( _lineSymbol);
makeLineStyle( _dottedLine, _lineStyle );
if (_isSelected)
{
_lineStyle.setWidth( _lineStyle.width() + 1 );
_lineStyle.setColor( _selectionColor );
}
line -> setPen( _lineStyle );
line -> setVisible( _isVisible );
}
} /* RubberbandLineHandle::updateGraphic */
void RubberbandLineHandle::updateCoordinates(const QVector<QPointF> & scenePositionVector)
{
if (scenePositionVector.size() == 2)
{
if (_coordinates.isEmpty()) _coordinates.resize(2);
_coordinates[0].updateSceneCoordinate(_mapView,scenePositionVector[0]);
_coordinates[1].updateSceneCoordinate(_mapView,scenePositionVector[1]);
if (_lineSymbol != nullptr)
{
QGraphicsLineItem * line = static_cast<QGraphicsLineItem*>( _lineSymbol);
line->setLine( _coordinates[0]._sceneCoordinate.x(), _coordinates[0]._sceneCoordinate.y()
, _coordinates[1]._sceneCoordinate.x(), _coordinates[1]._sceneCoordinate.y() );
}
}
} /* RubberbandLineHandle::updateCoordinates */
void RubberbandLineHandle::updateCoordinate( unsigned index, const QPointF & scenePosition )
{
if (index < 2)
{
_coordinates[index].updateSceneCoordinate(_mapView,scenePosition);
QGraphicsLineItem * line = static_cast<QGraphicsLineItem*>( _lineSymbol);
line->setLine( _coordinates[0]._sceneCoordinate.x(), _coordinates[0]._sceneCoordinate.y()
, _coordinates[1]._sceneCoordinate.x(), _coordinates[1]._sceneCoordinate.y() );
}
} /* RubberbandLineHandle::updateCoordinate */
QVector<RubberbandHandle::RubberbandCoordinate> RubberbandLineHandle::getCoordinates() const
{
return _coordinates;
} /* RubberbandLineHandle::getCoordinates */
RubberbandHandle::RubberbandCoordinate RubberbandLineHandle::getCoordinate( unsigned index ) const
{
if (index < 2)
{
return _coordinates[index];
}
return RubberbandCoordinate();
} /* RubberbandLineHandle::getCoordinate */
bool RubberbandLineHandle::isPositionInside( const QPointF & scenePosition ) const
{
if (_lineSymbol)
{
if (_lineSymbol->contains( scenePosition ))
{
return true;
}
else
{
// Ok, Qt's methodes doesn't work safely
// if it fails do some own calculations
QPointF V0 = _coordinates[0]._sceneCoordinate;
QPointF V1 = _coordinates[1]._sceneCoordinate;
QPointF R = V1-V0;
QPointF P = scenePosition-V0;
qreal lenR = R.x() * R.x() + R.y() * R.y();
qreal lenP = P.x() * P.x() + P.y() * P.y();
if ((lenR == 0) || (lenP > lenR)) return false; // scene Position is to far away
// now check the direction
lenR = sqrt(lenR);
lenP = sqrt(lenP);
R /= lenR;
P /= lenP;
qreal cosPhi = QPointF::dotProduct(R,P);
if (cosPhi < 0) return false;
qreal epsilon = sqrt(1.0-cosPhi*cosPhi) * lenR;
return (epsilon < qreal(_pickingRatio));
}
}
return false;
} /* RubberbandLineHandle::isPositionInside */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,81 @@
/**
**
** @RDE_HEADER@
** Definition of base class for rubberband handles
** $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 <QtCore/QPointF>
#include <QtGui/QPen>
#include "rubberband_handle.h"
class QGraphicsItem;
class QGraphicsScene;
namespace SituationMap { namespace RB
{
/**
@class RubberbandLineHandle rubberband_line_handle.h
@brief Implementation of a line handle for rubberband internal use.
@see RubberbandHandle
*/
class RubberbandLineHandle : public RubberbandHandle
{
Q_OBJECT
public:
RubberbandLineHandle( Esri::ArcGISRuntime::MapGraphicsView * mapView ,QGraphicsScene * scene , const QPointF & p1, const QPointF & p2, unsigned int lineWidth = 2, bool dottedLine = false );
~RubberbandLineHandle();
bool isPositionInside( const QPointF & scenePosition ) const override;
virtual void updateCoordinates( const QVector<QPointF> & scenePositionVector );
virtual void updateCoordinate( unsigned index, const QPointF & scenePosition );
virtual QVector<RubberbandCoordinate> getCoordinates() const;
virtual RubberbandCoordinate getCoordinate( unsigned index ) const;
void dottedLine(bool on = true) { _dottedLine = on; }
protected:
QGraphicsItem * _lineSymbol;
QPen _lineStyle;
QVector<RubberbandCoordinate> _coordinates;
bool _dottedLine;
void updateGraphic() override;
void adjustCoordinates() override;
void adjustWindow( const QRectF& ) override;
}; /* RubberbandLineHandle */
} } /* namespace SituationMap::RB */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,254 @@
/**
* @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<QPointF> 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 &center, CoordinateSystem cs, const QVector<QPointF> &radii); // no constraints
bool setCenterAndRadii2(const QPointF &center, CoordinateSystem cs,
const QVector<RubberbandMultiEllipseFeature::RadiusWithContraints> &radiiWithConstraints);
void prepareFixedNumberOfRadiiWithConstraints(const QVector<RubberbandMultiEllipseFeature::RadiusWithContraints> &radiiContraints);
// get SectorStartEnd
QPointF getRotatedPoint(const QPointF &sector)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<QPointF> 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<QPointF> &, 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 */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,209 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define multi point feature geoemtry
** $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 .........:
**
** 10.04.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband.h"
namespace SituationMap { namespace RB
{
class RubberbandHandle;
class RubberbandFrameHandle;
/**
@class RubberbandMultiPointFeature rubberband_multi_point_feature.h
@brief Implementation of a rubberband to input multi point features, like areals or linears
@see Rubberband
*/
class SITUATIONMAP_EXPORT RubberbandMultiPointFeature : 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 RubberbandMultiPointFeature( SituationMap::Map * map );
explicit RubberbandMultiPointFeature( SituationMap::Map * map, bool complexGeometry );
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
Construction of RubberbandMultiPointFeature in most common cases. The parameter parent is
optional.
*/
explicit RubberbandMultiPointFeature( SituationMap::Map * map, QObject * parent = nullptr );
/**
Construction of RubberbandMultiPointFeature in case of controlling complex geometry objects, like
splines or multi point symbols. In this case set complexGeometry true.
*/
explicit RubberbandMultiPointFeature( SituationMap::Map * map, bool complexGeometry, QObject * parent = nullptr );
public:
~RubberbandMultiPointFeature();
/** @} */
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;
/**
If set to true a polygon the rubberband draws a polygon otherwise a polyline.
*/
inline void enableClosed( bool flag )
{
_isClosed = flag;
if (( _isClosed) && (_minimumPointCount < 3)) _minimumPointCount = 3;
if ((!_isClosed) && (_minimumPointCount < 2)) _minimumPointCount = 2;
} /* enableClosed */
/**
Gets the value of the close flag
*/
inline bool isClosedEnabled() const { return _isClosed; }
/**
@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 0.
*/
inline void minimumPointCount( unsigned int x )
{
if (( _isClosed) && (x < 3)) x = 3;
if ((!_isClosed) && (x < 2)) x = 2;
_minimumPointCount = x;
} /* minimumPointCount */
/**
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 maximumPointCount( unsigned int x )
{
if (x > 0)
{
if (( _isClosed) && (x < 3)) x = 3;
if ((!_isClosed) && (x < 2)) x = 2;
}
_maximumPointCount = x;
} /* maximumPointCount */
/**
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; }
virtual QVector<QPointF> 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<QPointF> &, 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. Becareful 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;
unsigned int _minimumPointCount;
unsigned int _maximumPointCount;
qreal _maximumSegmentLength;
qreal _maximumLength;
void activateButtons() override;
void update() override;
// some helper methodes
RubberbandHandle * constructPoint( QPointF scenePos );
void constructPoint(const QPointF &point, CoordinateSystem cs );
bool selectHandles( int x, int y, const QPointF & scenePos );
bool checkLengthConstrains( unsigned int checkHandleIdx, QPointF & scenePos );
bool checkLengthConstrains( const QPointF & scenePos, const QPointF & deltaScenePos );
void updatePreviewLine( const QPointF & scenePosition );
RubberbandFrameHandle * getFrameHandle() const;
void setCheckMaxAngle( double phi );
}; /* RubberbandMultiPointFeature */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,660 @@
/**
**
** @RDE_HEADER@
** Implementation of rubberband class to define point feature geometry in 3d
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include <limits>
#include "rubberband_multi_point_feature_3d.h"
#include "rubberband_base_internal.h"
#include "event_mouse_navigator.h"
#include <Map/map.h>
#include <Map/layer_factory.h>
#include <MapImpl/map_impl.h>
#include <MapImpl/coordinate_translation.h>
#include <MapImpl/screen_to_location_helper.h>
#include <MapImpl/location_to_elevation_helper.h>
#include <MathUtils/math_const.h>
#include <GraphicalObjects/graphical_object_picture_marker.h>
#include <GraphicalObjects/graphical_object_path.h>
#include <QtGui/QGuiApplication>
#include <arcgis/IdentifyGraphicsOverlayResult.h>
namespace SituationMap { namespace RB
{
class RubberbandMultiPointFeature3D::InternalData
{
public:
QVector<GraphicalObjectPictureMarker*> m_marker;
GraphicalObjectPath *m_path;
QVector<QPointF> m_coordinates;
int m_currentIndex;
int m_selectionIndex;
Esri::ArcGISRuntime::TaskWatcher m_pickingTask;
Esri::ArcGISRuntime::TaskWatcher m_selectionTask;
QPoint m_pickingPoint;
QPointF * m_startMove;
ScreenToLocationHelper * m_screenToMap;
QPointer<LocationToElevationHelper> m_toElevation;
PositionCont m_positionList3D;
bool m_doCompleteAction;
InternalData()
: m_marker()
, m_path(nullptr)
, m_coordinates()
, m_currentIndex(-1)
, m_selectionIndex(-1)
, m_pickingTask()
, m_selectionTask()
, m_pickingPoint()
, m_startMove(nullptr)
, m_screenToMap()
, m_toElevation(nullptr)
, m_positionList3D()
, m_doCompleteAction(false)
{
m_marker.reserve(100);
m_coordinates.reserve(100);
} // InternalData()
~InternalData()
{
delete m_startMove;
for (auto marker : qAsConst(m_marker))
delete marker;
delete m_path;
delete m_screenToMap;
} // ~InternalData()
}; // RubberbandPointFeature3D::InternalData
RubberbandMultiPointFeature3D::RubberbandMultiPointFeature3D( SituationMap::Map * map, QObject * parent, bool isActive )
: Rubberband3D(map,parent,isActive)
, _internal( new RubberbandMultiPointFeature3D::InternalData() )
, _isClosed(false)
, _isCircular(false)
{
MapImpl *mapImpl = static_cast<MapImpl*>(_baseInternal->_map.data());
Esri::ArcGISRuntime::SceneGraphicsView *view = mapImpl->getEsriSceneGraphicsView();
connect( view, &Esri::ArcGISRuntime::SceneGraphicsView::identifyGraphicsOverlaysCompleted, this, &RubberbandMultiPointFeature3D::onGetPickingResult );
_internal->m_screenToMap = new ScreenToLocationHelper(view);
connect( _internal->m_screenToMap, &ScreenToLocationHelper::mouseScenePositionChanged, this, &RubberbandMultiPointFeature3D::onMapPosition ); // ToDO
} // RubberbandMultiPointFeature3D::RubberbandMultiPointFeature3D( SituationMap::Map * map, QObject * parent = nullptr, bool isActive )
RubberbandMultiPointFeature3D::~RubberbandMultiPointFeature3D()
{
delete _internal;
_internal = nullptr;
} // RubberbandMultiPointFeature3D::~RubberbandMultiPointFeature3D()
void RubberbandMultiPointFeature3D::activateButtons()
{
_baseInternal->_hasUndoButton = false;
_baseInternal->_undoIsPossible = false;
_baseInternal->_applyIsPossible = (_internal->m_coordinates.size() > ((_isClosed && !_isCircular) ? 2 : 1));
RubberbandBase::activateButtons();
} /* RubberbandMultiPointFeature3D::activateButtons */
void circleShape( GraphicalObjectPath *pathObj, const PositionCont &positionList )
{
if (positionList.size() < 2) return;
PositionCont circleShape;
double cx = positionList[0].x();
double cy = positionList[0].y();
double rx = positionList[1].x()-cx;
double ry = positionList[1].y()-cy;
double corrLon = cos(cy / 57.2957795147); // correct factor from nautic simulation to get a real circle
double dPhi = MathConst::pi / 50; // delta angle to rasterize the circle to a polyline
auto sqr = [](double x) -> double { return x * x; };
double r = sqrt(sqr(rx*corrLon) + sqr(ry) );
double phi = 0.0;
while (phi < MathConst::pi_two)
{
double sinPhi = sin(phi);
double cosPhi = cos(phi);
double px = cx + r * cosPhi / corrLon;
double py = cy + r*sinPhi;
circleShape.append(Point3D(px, py, 0.0));
phi += dPhi;
}
pathObj->setPositions(circleShape);
} // circleShape
void RubberbandMultiPointFeature3D::onMapPosition(const Point3D &mapCoordinate)
{
if (_internal->m_currentIndex < 0) return;
if (qIsNaN(mapCoordinate.x())) return; // illegal map position
if (qIsNaN(mapCoordinate.y())) return;
if ((!_internal->m_toElevation) && (RubberbandBase::_baseInternal->_map->layerFactory().elevationAvailable()))
{
_internal->m_toElevation = RubberbandBase::_baseInternal->_map->layerFactory().locationToElevation(); // layerFactory has ownership
}
if ((std::numeric_limits<int>::max()) == _internal->m_currentIndex)
{
// move all coordinates
if (_internal->m_startMove)
{
QPointF deltaMove = mapCoordinate.toPointF() - *(_internal->m_startMove);
_internal->m_positionList3D.clear();
_internal->m_positionList3D.reserve(_internal->m_coordinates.size());
for (int i = 0; i < _internal->m_coordinates.size(); ++i)
{
const QPointF & pos = _internal->m_coordinates[i] += deltaMove;
_internal->m_marker[i]->setOrigin( pos );
if (_internal->m_toElevation)
{
QMetaObject::Connection conn;
conn = connect(_internal->m_toElevation.data(), &SituationMap::LocationToElevationHelper::elevationCompleted, this, [this,pos,conn](double elevation)
{
disconnect(conn);
_internal->m_positionList3D << Point3D(pos.x(),pos.y(),elevation);
if (_internal->m_positionList3D.size() == _internal->m_coordinates.size())
{
if (_internal->m_path) _internal->m_path->setPositions( _internal->m_positionList3D );
update();
}
// qCritical() << "elevation at (" << pos.x() << " , " << pos.y() << ") : " << elevation;
});
_internal->m_toElevation->locationToElevation(pos);
}
else
{
_internal->m_positionList3D << Point3D::fromQPointF(pos);
}
}
if (_internal->m_toElevation)
{
if (_internal->m_path) _internal->m_path->setPositions( _internal->m_positionList3D );
update();
}
}
else _internal->m_startMove = new QPointF(mapCoordinate.toPointF());
return;
}
if (_internal->m_currentIndex >= _internal->m_coordinates.size()) return;
MapImpl *mapImpl = static_cast<MapImpl*>(_baseInternal->_map.data());
Esri::ArcGISRuntime::SceneGraphicsView *view = mapImpl->getEsriSceneGraphicsView();
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer = mapImpl->getGraphicsLayer(mapImpl->layerFactory().rubberbandLayer());
if (nullptr == view) return;
for (int idx = _internal->m_positionList3D.size(); idx <= _internal->m_currentIndex; ++idx)
{
_internal->m_positionList3D << mapCoordinate;
}
_internal->m_coordinates[_internal->m_currentIndex] = mapCoordinate.toPointF();
_internal->m_positionList3D[_internal->m_currentIndex] = mapCoordinate;
// qCritical() << "elevation idx=" << _internal->m_currentIndex <<" at (" << mapCoordinate.x() << " , " << mapCoordinate.y() << ") : " << mapCoordinate.z();
GraphicalObjectPictureMarker *&marker = _internal->m_marker[_internal->m_currentIndex];
if (nullptr == marker)
{
marker = new GraphicalObjectPictureMarker( view, graphicsLayer, QStringLiteral("RubberbandMultiPointFeature3D"), INVALID_MAP_ID );
marker->setImage(markerImage());
marker->setOrigin( mapCoordinate );
marker->updateView();
marker->setPickable(true);
Esri::ArcGISRuntime::Graphic *graphic = marker->graphic();
if (graphic)
{
Esri::ArcGISRuntime::AttributeListModel *attLisModel = graphic->attributes();
if (attLisModel)
{
// qCritical() << "Rubberband3D-Item =" << _internal->m_currentIndex;
attLisModel->insertAttribute(QStringLiteral("Rubberband3D-Item"),_internal->m_currentIndex);
}
}
}
else marker->setOrigin( mapCoordinate );
if (_internal->m_coordinates.size() > ((_isClosed && !_isCircular) ? 2 : 1))
{
if (nullptr == _internal->m_path)
{
bool isPolygon = (_isClosed || _isCircular);
_internal->m_path = new GraphicalObjectPath(isPolygon ? GraphicalObjectPathType::Polygon : GraphicalObjectPathType::Polyline, view, graphicsLayer, QStringLiteral("RubberbandMultiPointFeature3D"), INVALID_MAP_ID);
_internal->m_path->rLineStyle().setLineColor(_handleDrawColor);
_internal->m_path->rLineStyle().setLinePattern(LinePattern::Solid);
_internal->m_path->rLineStyle().setLineWidth(3);
_internal->m_path->setPickable(false);
if (isPolygon)
{
_internal->m_path->rFillStyle().setFillColor(_frameFillColor);
}
if (_isCircular)
{
circleShape(_internal->m_path, _internal->m_positionList3D);
}
else _internal->m_path->setPositions(_internal->m_positionList3D);
_internal->m_path->updateView();
}
else
{
if (_isCircular)
{
circleShape(_internal->m_path, _internal->m_positionList3D);
}
else _internal->m_path->setPositions(_internal->m_positionList3D);
}
}
if (_isCircular && (0 == _internal->m_currentIndex) && (1 == _internal->m_coordinates.size()))
{
_internal->m_coordinates << _internal->m_coordinates.first();
_internal->m_positionList3D << _internal->m_positionList3D.first();
_internal->m_marker << nullptr;
_internal->m_currentIndex++;
// qCritical() << QCursor::pos() << " != " << view->viewport()->mapToGlobal(_internal->m_pickingPoint);
_internal->m_doCompleteAction = (QCursor::pos() != view->viewport()->mapToGlobal(_internal->m_pickingPoint));
if (!_internal->m_doCompleteAction)
{
// Click with out moving the mouse, set a default size of the circle and let the user do some editing
// The rubberband doesn't complete automatically in this case.
_internal->m_screenToMap->screenToLocation(_internal->m_pickingPoint.x()+100, _internal->m_pickingPoint.y());
}
}
update();
if (!QGuiApplication::mouseButtons().testFlag(Qt::MouseButton::LeftButton))
{
if (_isCircular && _internal->m_doCompleteAction && (1 == _internal->m_currentIndex))
{
completeStateAction(nullptr, 0, 0);
}
else
{
updateButtonPosition();
activateButtons();
}
}
} // void RubberbandMultiPointFeature3D::onMapPosition(const QPointF &mapCoordinate)
void RubberbandMultiPointFeature3D::onGetPickingResult(const QUuid &taskId, const QList<Esri::ArcGISRuntime::IdentifyGraphicsOverlayResult*> &identifyResults)
{
if (_internal->m_pickingTask.taskId() == taskId)
{
for (auto iResult : identifyResults)
{
const QList<Esri::ArcGISRuntime::Graphic*> &gResults = iResult->graphics();
for (auto pickedGraphic : gResults)
{
if (pickedGraphic->attributes())
{
bool ok = false;
int pickedIndex = pickedGraphic->attributes()->attributeValue(QStringLiteral("Rubberband3D-Item")).toInt(&ok);
if (ok)
{
qCritical() << "Picking index " << pickedIndex;
_internal->m_currentIndex = pickedIndex;
_internal->m_screenToMap->screenToLocation(_internal->m_pickingPoint.x(), _internal->m_pickingPoint.y());
if (pickedIndex < _internal->m_marker.size())
{
GraphicalObjectPictureMarker *&marker = _internal->m_marker[pickedIndex];
if (marker)
{
marker->setImage(markerSelectionImage());
marker->updateView();
}
}
return;
}
}
} // foreach pickedGraphic
} // foreach iResult
if ((!_isCircular) || (_internal->m_coordinates.size() < 2))
{
// add new coordinate and calculate map location
_internal->m_currentIndex = _internal->m_marker.size();
_internal->m_marker << nullptr;
_internal->m_coordinates << QPointF();
_internal->m_screenToMap->screenToLocation(_internal->m_pickingPoint.x(), _internal->m_pickingPoint.y());
}
}
if (_internal->m_selectionTask.taskId() == taskId)
{
for (auto iResult : identifyResults)
{
const QList<Esri::ArcGISRuntime::Graphic*> &gResults = iResult->graphics();
for (auto pickedGraphic : gResults)
{
if (pickedGraphic->attributes())
{
bool ok = false;
int pickedIndex = pickedGraphic->attributes()->attributeValue(QStringLiteral("Rubberband3D-Item")).toInt(&ok);
if ((ok) && (pickedIndex < _internal->m_marker.size()))
{
GraphicalObjectPictureMarker *&marker = _internal->m_marker[pickedIndex];
if (marker)
{
_internal->m_selectionIndex = pickedIndex;
marker->setImage(markerSelectionImage());
marker->updateView();
return;
}
}
}
}
}
}
if ((_internal->m_selectionIndex >= 0) && (_internal->m_selectionIndex < _internal->m_marker.size()))
{
GraphicalObjectPictureMarker *&marker = _internal->m_marker[_internal->m_selectionIndex];
if (marker)
{
marker->setImage(markerImage());
marker->updateView();
}
_internal->m_selectionIndex = -1;
}
} // void RubberbandMultiPointFeature3D::onGetPickingResult(const QUuid &taskId, const QList<Esri::ArcGISRuntime::IdentifyGraphicsOverlayResult*> &identifyResults)
bool RubberbandMultiPointFeature3D::selectAction(AbstractEventDispatcher *, int x, int y)
{
delete _internal->m_startMove;
_internal->m_startMove = nullptr;
if (rubberbandIsAlive())
{
if (_baseInternal->buttonProxyActive(QPointF(x,y))) return false;
MapImpl *mapImpl = static_cast<MapImpl*>(_baseInternal->_map.data());
_internal->m_pickingTask.cancel(); // cancel old task
_internal->m_pickingPoint = QPoint(x,y);
_internal->m_pickingTask = mapImpl->getEsriGeoView()->identifyGraphicsOverlays(x,y,EventMouseNavigator::pickTolerance(),false,std::numeric_limits<int>::max());
_internal->m_currentIndex = -1;
return true;
}
return false;
} // bool RubberbandMultiPointFeature3D::selectAction(AbstractEventDispatcher *, int x, int y)
bool RubberbandMultiPointFeature3D::setCoordinateAction(AbstractEventDispatcher *, int x, int y)
{
delete _internal->m_startMove;
_internal->m_startMove = nullptr;
if (rubberbandIsAlive())
{
_baseInternal->_lastClickPosition = QPointF(x,y);
if (_baseInternal->buttonProxyActive(_baseInternal->_lastClickPosition)) return false;
_internal->m_screenToMap->screenToLocation(x,y);
if ((_internal->m_currentIndex >= 0) && (_internal->m_currentIndex < _internal->m_marker.size()))
{
GraphicalObjectPictureMarker *&marker = _internal->m_marker[_internal->m_currentIndex];
if (marker)
{
marker->setImage(markerImage());
marker->updateView();
}
}
return true;
}
return false;
} // bool RubberbandMultiPointFeature3D::setCoordinateAction(AbstractEventDispatcher *, int x, int y)
bool RubberbandMultiPointFeature3D::movePickedAction(AbstractEventDispatcher *, int x, int y)
{
if (rubberbandIsAlive())
{
_internal->m_screenToMap->screenToLocation(x,y);
return true;
}
return false;
} // bool RubberbandMultiPointFeature3D::movePickedAction(AbstractEventDispatcher *, int x, int y)
bool RubberbandMultiPointFeature3D::moveAction( AbstractEventDispatcher*, int x, int y )
{
if (rubberbandIsAlive())
{
if (_baseInternal->buttonProxyActive(QPointF(x,y))) return false;
MapImpl *mapImpl = static_cast<MapImpl*>(_baseInternal->_map.data());
_internal->m_selectionTask.cancel(); // cancel old task
_internal->m_selectionTask = mapImpl->getEsriGeoView()->identifyGraphicsOverlays(x,y,EventMouseNavigator::pickTolerance(),false,std::numeric_limits<int>::max());
if ((_internal->m_selectionIndex >= 0) && (_internal->m_selectionIndex < _internal->m_marker.size()))
{
GraphicalObjectPictureMarker *&marker = _internal->m_marker[_internal->m_selectionIndex];
if (marker)
{
marker->setImage(markerImage());
marker->updateView();
}
}
_internal->m_selectionIndex = -1;
}
return false;
} // bool RubberbandMultiPointFeature3D::moveAction(AbstractEventDispatcher*,int,int)
bool RubberbandMultiPointFeature3D::completeStateAction ( AbstractEventDispatcher * causer, int x, int y )
{
if (_internal->m_coordinates.size() > ((_isClosed && !_isCircular) ? 2 : 1))
{
return applyAndEndAction(causer,x,y);
}
return false;
} // bool RubberbandMultiPointFeature3D::completeStateAction ( AbstractEventDispatcher * causer, int x, int y )
bool RubberbandMultiPointFeature3D::contextMenuAction ( AbstractEventDispatcher*,int,int ) { return rubberbandIsAlive(); }
bool RubberbandMultiPointFeature3D::deleteAction ( AbstractEventDispatcher*,int,int ) { return rubberbandIsAlive(); }
bool RubberbandMultiPointFeature3D::undoAction ( AbstractEventDispatcher*,int,int ) { return rubberbandIsAlive(); }
unsigned int RubberbandMultiPointFeature3D::coordinateCount() const
{
return (_internal->m_coordinates.size());
} // unsigned int RubberbandMultiPointFeature3D::coordinateCount() const
void RubberbandMultiPointFeature3D::update()
{
for (auto marker : qAsConst(_internal->m_marker))
if (marker) marker->updateView();
if (_internal->m_path)
_internal->m_path->updateView();
externalUpdate();
} // RubberbandMultiPointFeature3D::update()
QVector<QPointF> RubberbandMultiPointFeature3D::coordinateVector( CoordinateSystem cs ) const
{
QVector<QPointF> coordinateVector;
coordinateVector.reserve(_internal->m_coordinates.size());
for (const auto &mapCoordinate : qAsConst(_internal->m_coordinates))
coordinateVector << projectCoordinateFromMap( cs, mapCoordinate );
return coordinateVector;
} // QVector<QPointF> RubberbandMultiPointFeature3D::coordinateVector( CoordinateSystem cs ) const
QPointF RubberbandMultiPointFeature3D::singleCoordinate( unsigned int idx, CoordinateSystem cs ) const
{
if (coordinateCount() > idx)
return coordinateVector(cs).at(idx);
return QPointF();
} // QPointF RubberbandMultiPointFeature3D::singleCoordinate( unsigned int idx, CoordinateSystem cs ) const
void RubberbandMultiPointFeature3D::setCoordinateVector( const QVector<QPointF> & coordinateVector, CoordinateSystem cs )
{
_internal->m_coordinates.clear();
for (const auto &geoCoordinate : coordinateVector)
_internal->m_coordinates << projectCoordinateToMap( cs, geoCoordinate );
if ((!_internal->m_toElevation) && (_baseInternal->_map->layerFactory().elevationAvailable()))
{
_internal->m_toElevation = _baseInternal->_map->layerFactory().locationToElevation(); // layerFactory has ownership
}
// now get elevations
_internal->m_positionList3D.clear();
for (const auto &pos : qAsConst(_internal->m_coordinates))
{
if (_internal->m_toElevation)
{
QMetaObject::Connection conn;
conn = connect(_internal->m_toElevation.data(), &SituationMap::LocationToElevationHelper::elevationCompleted, this, [this,pos,conn](double elevation)
{
disconnect(conn);
_internal->m_positionList3D << Point3D(pos.x(),pos.y(),elevation);
if (_internal->m_positionList3D.size() == _internal->m_coordinates.size())
{
if (_internal->m_path) _internal->m_path->setPositions( _internal->m_positionList3D );
update();
}
});
_internal->m_toElevation->locationToElevation(pos);
}
else _internal->m_positionList3D << Point3D::fromQPointF(pos);
}
} // void RubberbandMultiPointFeature3D::setCoordinateVector( const QVector<QPointF> & coordinateVector, CoordinateSystem cs )
void RubberbandMultiPointFeature3D::setCoordinateVector(const QVector<Point3D> & coordinateVector, CoordinateSystem cs)
{
_internal->m_coordinates.clear();
_internal->m_positionList3D.clear();
for (const auto &geoCoordinate : coordinateVector)
{
const QPointF & projCoordinate = projectCoordinateToMap( cs, geoCoordinate.toPointF() );
_internal->m_coordinates << projCoordinate;
_internal->m_positionList3D << Point3D(projCoordinate.x(),projCoordinate.y(),geoCoordinate.z());
}
} // void RubberbandMultiPointFeature3D::setCoordinateVector(const QVector<Point3D> & coordinateVector, CoordinateSystem cs)
QVector<Point3D> RubberbandMultiPointFeature3D::coordinateVector3D(CoordinateSystem cs) const
{
QVector<Point3D> coordinateVector;
coordinateVector.reserve(_internal->m_coordinates.size());
for (const auto &mapCoordinate : qAsConst(_internal->m_coordinates))
coordinateVector << Point3D::fromQPointF( projectCoordinateFromMap(cs,mapCoordinate) );
return coordinateVector;
} // QVector<Point3D> RubberbandMultiPointFeature3D::coordinateVector3D(CoordinateSystem cs) const
Point3D RubberbandMultiPointFeature3D::singleCoordinate3D(unsigned int idx, CoordinateSystem cs) const
{
if (coordinateCount() > idx)
{
return coordinateVector3D(cs).at(idx);
}
return Point3D();
} // Point3D RubberbandMultiPointFeature3D::singleCoordinate3D(unsigned int idx, CoordinateSystem cs) const
} } /* namespace SituationMap::RB */
@@ -0,0 +1,136 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define multipoint feature geometry in 3d
** $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 "rubberband_3d.h"
namespace Esri
{
namespace ArcGISRuntime
{
class IdentifyGraphicsOverlayResult;
}
}
namespace SituationMap { namespace RB
{
/**
@class RubberbandPointFeature rubberband_point_feature.h
@brief Implementation of a rubberband to input single coodinates for building point features
@see Rubberband3D
*/
class SITUATIONMAP_EXPORT RubberbandMultiPointFeature3D : public Rubberband3D
{
Q_OBJECT
/**
@name Construction & Destruction
@{
*/
friend class RubberbandFactory;
explicit RubberbandMultiPointFeature3D( SituationMap::Map * map, QObject * parent = nullptr, bool isActive = true );
public:
virtual ~RubberbandMultiPointFeature3D();
RubberbandMultiPointFeature3D(const RubberbandMultiPointFeature3D &) = delete;
RubberbandMultiPointFeature3D & operator = (const RubberbandMultiPointFeature3D &) = delete;
/** @} */
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;
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;
inline void enableClosed( bool flag )
{
_isClosed = flag;
} /* enableClosed */
/**
Gets the value of the close flag
*/
inline bool isClosedEnabled() const { return _isClosed; }
unsigned int coordinateCount() const override;
QVector<QPointF> coordinateVector( CoordinateSystem cs = CoordinateSystem::Geo ) const override;
QPointF singleCoordinate( unsigned int idx = 0, CoordinateSystem cs = CoordinateSystem::Geo ) const override;
void setCoordinateVector( const QVector<QPointF> & coordinateVector, CoordinateSystem cs = CoordinateSystem::Geo ) override;
Point3D singleCoordinate3D( unsigned int idx = 0, CoordinateSystem cs = CoordinateSystem::Geo ) const override;
QVector<Point3D> coordinateVector3D( CoordinateSystem cs = CoordinateSystem::Geo ) const override;
void setCoordinateVector( const QVector<Point3D> & coordinateVector, CoordinateSystem cs = CoordinateSystem::Geo ) override;
inline void enableCircular(bool flag)
{
_isCircular = flag;
} // enableCircular
inline bool isCircularEnabled() const { return _isCircular; }
protected:
virtual bool buttonProxyActive( const QPointF & scenePos) const { Q_UNUSED(scenePos); return false; }
void activateButtons() override;
void update() override;
/*
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 InternalData;
InternalData * _internal;
bool _isClosed;
bool _isCircular;
protected slots:
void onGetPickingResult(const QUuid &taskId, const QList<Esri::ArcGISRuntime::IdentifyGraphicsOverlayResult*> &identifyResults);
void onMapPosition( const Point3D &mapCoordinate );
}; /* RubberbandMultiPointFeature3D */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,133 @@
/**
**
** @RDE_HEADER@
** Implementation of rubberband class to define point feature geoemtry
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_point_cluster.h"
#include "rubberband_point_handle.h"
#include "rubberband_drawable.h"
#include "rubberband_handle_proxy.h"
#include "transient_tactical_symbol.h"
#include "rubberband_internal.h"
#include "rubberband_base_internal.h"
namespace SituationMap { namespace RB
{
struct RubberbandPointCluster::InternalData
{
Q_DISABLE_COPY(InternalData)
InternalData() = default;
SituationMap::RefPointer<TransientTacticalSymbol> _previewSymbol;
}; /* RubberbandMultiPointFeature::InternalData */
RubberbandPointCluster::RubberbandPointCluster( SituationMap::Map * map, QObject * parent, bool isActive ) : RubberbandPointCluster( map, INT_MAX, parent, isActive ) {;}
RubberbandPointCluster::RubberbandPointCluster( SituationMap::Map * map, unsigned int maxCoordinates, QObject * parent, bool isActive )
: RubberbandPointFeature(map,parent,isActive), _internal(new InternalData()), _minimalPointCount(1)
{
_maximalPointCount = maxCoordinates;
} /* RubberbandPointCluster::RubberbandPointCluster */
RubberbandPointCluster::~RubberbandPointCluster()
{
delete _internal;
} /* RubberbandPointCluster::~RubberbandPointCluster */
void RubberbandPointCluster::activateButtons()
{
_baseInternal->_hasUndoButton = isEnabledConstructionState();
_baseInternal->_applyIsPossible = (static_cast<unsigned int>(Rubberband::_internal->_handleList.size()) >= _minimalPointCount);
_baseInternal->_undoIsPossible = (isEnabledConstructionState() && (static_cast<unsigned int>(Rubberband::_internal->_handleList.size()) > _minimalPointCount));
Rubberband::activateButtons();
} /* RubberbandMultiPointFeature::activateButton */
void RubberbandPointCluster::setCoordinateVector(const QVector<QPointF> & coordinateVector, CoordinateSystem cs )
{
RubberbandPointFeature::setCoordinateVector( coordinateVector, cs );
enableModificationState();
activateButtons();
} /* RubberbandPointCluster::setCoordinateVector */
bool RubberbandPointCluster::setCoordinateAction( AbstractEventDispatcher * causer, int x, int y )
{
bool ok = false;
if (rubberbandIsAlive())
{
ok = RubberbandPointFeature::setCoordinateAction(causer,x,y);
if (ok) activateButtons();
}
return ok;
} /* RubberbandPointCluster::setCoordinateAction */
void RubberbandPointCluster::update()
{
RubberbandPointFeature::update();
if (!_previewSidc.isEmpty())
{
if (!_internal->_previewSymbol)
{
_internal->_previewSymbol = new TransientTacticalSymbol( static_cast<MapImpl*>(_baseInternal->_map.data()), _previewSidc );
}
QVector<RubberbandHandle::RubberbandCoordinate> coordinateList;
coordinateList.reserve( Rubberband::_internal->_handleList.size() );
for (auto handlePoint : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handlePoint.get());
if (handlePointPtr)
{
coordinateList.append( handlePointPtr->getCoordinate() );
}
}
_internal->_previewSymbol->update( coordinateList );
}
else _internal->_previewSymbol = nullptr;
} /* RubberbandPointCluster::update */
bool RubberbandPointCluster::deleteAction(AbstractEventDispatcher * causer, int x, int y)
{
if (rubberbandIsAlive())
{
if (static_cast<unsigned int>(RubberbandPointFeature::_internal->_handleList.size()) <= _minimalPointCount) return true;
return RubberbandPointFeature::deleteAction(causer,x,y);
}
return false;
} /* RubberbandPointCluster::deleteAction */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,102 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define multiple point feature geoemtry
** $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 .........:
**
** 18.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include <limits>
#include "rubberband_point_feature.h"
namespace SituationMap { namespace RB
{
/**
@class RubberbandPointCluster rubberband_point_cluster.h
@brief Implementation of a rubberband to input single coodinates for building point feature clusters
@see Rubberband, RubberbandPointFeature
*/
class SITUATIONMAP_EXPORT RubberbandPointCluster : public RubberbandPointFeature
{
Q_OBJECT
/**
@name Construction & Destruction
@{
*/
friend class RubberbandFactory;
RubberbandPointCluster( SituationMap::Map * map, QObject * parent, bool isActive = true );
RubberbandPointCluster( SituationMap::Map * map
, unsigned int maxCoordinates = std::numeric_limits<unsigned int>::max()
, QObject * parent = nullptr
, bool isActive = true );
public:
virtual ~RubberbandPointCluster();
RubberbandPointCluster(const RubberbandPointCluster &) = delete;
RubberbandPointCluster & operator = (const RubberbandPointCluster &) = delete;
/** @} */
bool setCoordinateAction( AbstractEventDispatcher * causer, int x, int y ) override;
bool deleteAction ( AbstractEventDispatcher * causer, int x, int y ) override;
/**
Defines the minimum number of coordinates to input. Default is 1
*/
inline void minimumPointCount(unsigned int n) { _minimalPointCount = (n > 0) ? n : 1; }
/**
Returns the setting for minimum number of coordinates to input.
*/
inline unsigned int getMinimumPointCount() { return _minimalPointCount; }
void setCoordinateVector(const QVector<QPointF> & coordinateVector, CoordinateSystem cs = CoordinateSystem::Geo ) override;
protected:
/*
Forward declaration of InternalData to hold private member variables. Becareful 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;
unsigned int _minimalPointCount;
void activateButtons() override;
void update() override;
}; /* RubberbandPointCluster */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,311 @@
/**
**
** @RDE_HEADER@
** Implementationof rubberband class to define point feature geoemtry
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_point_feature.h"
#include "rubberband_point_handle.h"
#include "rubberband_drawable.h"
#include "rubberband_internal.h"
#include "rubberband_base_internal.h"
#include <arcgis/Map.h>
#include <arcgis/MapGraphicsView.h>
namespace SituationMap { namespace RB
{
RubberbandPointFeature::RubberbandPointFeature( SituationMap::Map * map, QObject * parent, bool isActive )
: Rubberband(map,parent,isActive), _maximalPointCount(1)
{
} /* RubberbandPointFeature::RubberbandPointFeature */
RubberbandPointFeature::~RubberbandPointFeature()
{
} /* RubberbandPointFeature::~RubberbandPointFeature */
QVector<QPointF> RubberbandPointFeature::coordinateVector( CoordinateSystem cs ) const
{
QVector<QPointF> coordinateVector;
coordinateVector.reserve(_internal->_handleList.size());
for (auto handle : qAsConst(_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
coordinateVector.push_back(projectCoordinateFromMap( cs, handlePointPtr->getCoordinate()._mapCoordinate ));
}
return coordinateVector;
} /* RubberbandPointFeature::coordinateVector */
QVector<QPointF> RubberbandPointFeature::coordinateVectorPixel() const
{
QVector<QPointF> coordinateVector;
coordinateVector.reserve(_internal->_handleList.size());
for (auto handle : qAsConst(_internal->_handleList))
{
RubberbandPointHandle *handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
coordinateVector.push_back(handlePointPtr->getPixelCoordinate());
}
return coordinateVector;
}
QPointF RubberbandPointFeature::singleCoordinate(unsigned int idx, CoordinateSystem cs ) const
{
if (idx < (unsigned int) _internal->_handleList.size())
{
const RubberbandPointHandle * handle = dynamic_cast<const RubberbandPointHandle*>(_internal->_handleList[idx].get());
return projectCoordinateFromMap( cs, handle->getCoordinate()._mapCoordinate );
}
return QPointF();
} /* RubberbandPointFeature::singleCoordinate */
void RubberbandPointFeature::setCoordinateVector(const QVector<QPointF> & coordinateVector, CoordinateSystem cs )
{
_internal->_handleList.clear();
for (auto p : coordinateVector)
{
const QPointF &mapPos = projectCoordinateToMap( cs, p );
RubberbandPointHandle * handlePointPtr = new RubberbandPointHandle( _internal->_mapView
, _internal->_mapScene
, Esri::ArcGISRuntime::Point(mapPos.x(),mapPos.y(),Rubberband::_internal->_mapView->map()->spatialReference()) );
_internal->_handleList.append( SituationMap::RefPointer<RubberbandHandle>(handlePointPtr) );
}
update();
} /* RubberbandPointFeature::setCoordinateVector */
bool RubberbandPointFeature::selectAction( AbstractEventDispatcher * , int x, int y )
{
if (rubberbandIsAlive())
{
bool eventHandled = false;
QPointF scenePos(pixel2ScenePosition(x,y));
if (_baseInternal->buttonProxyActive(scenePos)) return false;
_baseInternal->_lastClickPosition = scenePos;
RubberbandHandle * handlePtr = pickHandle(x,y);
if (handlePtr)
{
handlePtr->setSelection();
enableSelectedState();
eventHandled = true;
}
if (!isEnabledSelectedState())
{
if (isEnabledConstructionState())
{
if (!buttonProxyActive(scenePos))
{
RubberbandPointHandle * handlePtr = new RubberbandPointHandle( _internal->_mapView, _internal->_mapScene, scenePos );
_internal->_handleList.append( SituationMap::RefPointer<RubberbandHandle>(handlePtr) );
handlePtr->setSelection();
enableSelectedState();
eventHandled = true;
}
}
}
if (eventHandled)
{
update();
deactivateButtons();
}
return eventHandled;
}
return false;
} /* RubberbandPointFeature::selectAction */
bool RubberbandPointFeature::setCoordinateAction( AbstractEventDispatcher * causer, int x, int y )
{
if ((rubberbandIsAlive()) && (_internal->_mapView) && (_internal->_mapScene))
{
bool eventHandled = false;
QPointF scenePos(pixel2ScenePosition(x,y));
Rubberband::_internal->_lastClickPosition = scenePos;
if (isEnabledSelectedState())
{
if (_baseInternal->buttonProxyActive(scenePos)) return false;
for (auto handle : qAsConst(_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if ((handlePointPtr) && (handlePointPtr->isSelected()))
{
handlePointPtr->setSelection(false);
handlePointPtr->moveCoordinate( scenePos - _baseInternal->_lastClickPosition );
eventHandled = true;
}
}
disenableSelectedState();
disenableMultiSelectedState();
}
else if (_baseInternal->buttonProxyActive(scenePos)) return false;
if (eventHandled) update();
if ((isEnabledConstructionState()) && (_internal->_handleList.size() >= static_cast<int>(_maximalPointCount)))
{
completeStateAction( causer, x, y );
eventHandled = true;
}
return eventHandled;
}
return false;
} /* RubberbandPointFeature::setCoordinateAction */
bool RubberbandPointFeature::moveAction( AbstractEventDispatcher*, int x, int y )
{
adjustConnectedPreviewPixmap(x,y);
if (rubberbandIsAlive())
{
if (!isEnabledMultiSelectedState()) deSelectHandles();
RubberbandHandle * handlePtr = pickHandle(x,y);
if (handlePtr)
{
handlePtr->setSelection();
return false;
}
}
return false;
} /* RubberbandPointFeature::moveAction */
bool RubberbandPointFeature::movePickedAction( AbstractEventDispatcher*, int x, int y )
{
adjustConnectedPreviewPixmap(x,y);
if ((rubberbandIsAlive()) && (_internal->_mapView) && (_internal->_mapScene))
{
if (isEnabledSelectedState())
{
QPointF scenePos(pixel2ScenePosition(x,y));
QPointF deltaMove(scenePos-_baseInternal->_lastClickPosition);
_baseInternal->_lastClickPosition = scenePos;
bool eventHandled = false;
for (auto handle : qAsConst(_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if ((handlePointPtr) && (handlePointPtr->isSelected()))
{
handlePointPtr->moveCoordinate( deltaMove );
eventHandled = true;
}
}
if (eventHandled) update();
}
return false;
}
return false;
} /* RubberbandPointFeature::movePickedAction */
bool RubberbandPointFeature::contextMenuAction( AbstractEventDispatcher*, int , int )
{
return rubberbandIsAlive();
} /* RubberbandPointFeature::contextMenuAction */
bool RubberbandPointFeature::completeStateAction( AbstractEventDispatcher * causer, int x, int y )
{
if (!_internal->_handleList.empty())
{
return applyAndEndAction(causer,x,y);
}
return false;
} /* RubberbandPointFeature::completeStateAction */
bool RubberbandPointFeature::undoAction( AbstractEventDispatcher*, int , int )
{
if (rubberbandIsAlive())
{
if (!_internal->_handleList.empty())
{
_internal->_handleList.pop_back();
update();
activateButtons();
}
return true;
}
return false;
} /* RubberbandPointFeature::undoAction */
bool RubberbandPointFeature::deleteAction(AbstractEventDispatcher*, int x, int y)
{
if ((rubberbandIsAlive()) && (_internal->_mapView) && (_internal->_mapScene))
{
if ((_internal->_handleList.size() > 1) && (isEnabledSelectedState()))
{
QPointF scenePosition = pixel2ScenePosition(x,y);
QList<SituationMap::RefPointer<RubberbandHandle>>::iterator handleIter = _internal->_handleList.begin();
while (handleIter != _internal->_handleList.end())
{
if (handleIter->get()->isPositionInside(scenePosition))
{
handleIter = _internal->_handleList.erase(handleIter);
continue;
}
++handleIter;
}
update();
activateButtons();
}
return true;
}
return false;
} /* RubberbandPointFeature::deleteAction */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,99 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define point feature geoemtry
** $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 <limits>
#include "rubberband.h"
namespace SituationMap { namespace RB
{
/**
@class RubberbandPointFeature rubberband_point_feature.h
@brief Implementation of a rubberband to input single coodinates for building point features
@see Rubberband
*/
class SITUATIONMAP_EXPORT RubberbandPointFeature : public Rubberband
{
Q_OBJECT
/**
@name Construction & Destruction
@{
*/
friend class RubberbandFactory;
friend class RubberbandPointCluster;
explicit RubberbandPointFeature( SituationMap::Map * map, QObject * parent = nullptr, bool isActive = true );
public:
~RubberbandPointFeature();
/** @} */
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;
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;
/**
Defines the maximum number of coordinates to input. Default is 1
*/
inline void maximumPointCount(unsigned int n) { _maximalPointCount = (n > 0) ? n : std::numeric_limits<unsigned int>::max(); }
/**
Returns the setting for maximum number of coordinates to input.
*/
inline unsigned int getMaximumPointCount() { return _maximalPointCount; }
QVector<QPointF> coordinateVector( CoordinateSystem cs = CoordinateSystem::Geo ) const override;
QVector<QPointF> coordinateVectorPixel() const;
QPointF singleCoordinate( unsigned int idx = 0, CoordinateSystem cs = CoordinateSystem::Geo ) const override;
void setCoordinateVector( const QVector<QPointF> & coordinateVector, CoordinateSystem cs = CoordinateSystem::Geo ) override;
protected:
virtual bool buttonProxyActive( const QPointF & scenePos) const { Q_UNUSED(scenePos); return false; }
unsigned int _maximalPointCount;
}; /* RubberbandPointFeature */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,272 @@
/**
**
** @RDE_HEADER@
** Implementation of rubberband class to define point feature geometry in 3d
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include <limits>
#include "rubberband_point_feature_3d.h"
#include "rubberband_base_internal.h"
#include <Map/map.h>
#include <Map/layer_factory.h>
#include <MapImpl/map_impl.h>
#include <MapImpl/coordinate_translation.h>
#include <MapImpl/screen_to_location_helper.h>
#include <GraphicalObjects/graphical_object_picture_marker.h>
#include <QtCore/QPoint>
namespace SituationMap { namespace RB
{
struct RubberbandPointFeature3D::InternalData
{
QPoint m_screenCordinate = QPoint(std::numeric_limits<int>::min(),std::numeric_limits<int>::min());
Point3D m_position;
GraphicalObjectPictureMarker * m_marker = nullptr;
ScreenToLocationHelper * m_screenToMap = nullptr;
AbstractEventDispatcher * m_causer = nullptr;
bool m_modifyPosition = false;
bool m_positionReady = false;
InternalData() = default;
~InternalData()
{
delete m_marker;
delete m_screenToMap;
}
}; // RubberbandPointFeature3D::InternalData
RubberbandPointFeature3D::RubberbandPointFeature3D( SituationMap::Map * map, QObject * parent, bool isActive )
: Rubberband3D(map,parent,isActive)
, _internal( new RubberbandPointFeature3D::InternalData() )
{
MapImpl *mapImpl = static_cast<MapImpl*>(_baseInternal->_map.data());
Esri::ArcGISRuntime::SceneGraphicsView *view = mapImpl->getEsriSceneGraphicsView();
_internal->m_screenToMap = new ScreenToLocationHelper(view);
connect( _internal->m_screenToMap, &ScreenToLocationHelper::mouseScenePositionChanged, this, &RubberbandPointFeature3D::onMapPosition );
} // RubberbandPointFeature3D::RubberbandPointFeature3D( SituationMap::Map * map, QObject * parent = nullptr, bool isActive )
RubberbandPointFeature3D::~RubberbandPointFeature3D()
{
delete _internal;
_internal = nullptr;
} // RubberbandPointFeature3D::~RubberbandPointFeature3D()
void RubberbandPointFeature3D::enableModificationState()
{
_internal->m_modifyPosition = true;
_internal->m_positionReady = true;
} // void RubberbandPointFeature3D::enableModificationState()
void RubberbandPointFeature3D::onMapPosition(const Point3D &mapCoordinate)
{
if (qIsNaN(mapCoordinate.x())) return; // illegal map position
if (qIsNaN(mapCoordinate.y())) return;
_internal->m_position = mapCoordinate;
if (nullptr == _internal->m_marker)
{
MapImpl *mapImpl = static_cast<MapImpl*>(_baseInternal->_map.data());
Esri::ArcGISRuntime::SceneGraphicsView *view = mapImpl->getEsriSceneGraphicsView();
Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer = mapImpl->getGraphicsLayer(mapImpl->layerFactory().rubberbandLayer());
if (nullptr == view) return;
_internal->m_marker = new GraphicalObjectPictureMarker( view, graphicsLayer, QStringLiteral("RubberbandPointFeature3D"), INVALID_MAP_ID );
_internal->m_marker->setImage(markerImage());
}
_internal->m_marker->setOrigin( mapCoordinate );
update();
if (_internal->m_causer)
{
_internal->m_positionReady = true;
completeStateAction(_internal->m_causer,_internal->m_screenCordinate.x(), _internal->m_screenCordinate.y());
}
} // void RubberbandPointFeature3D::onMapPosition(const QPointF &mapCoordinate)
bool RubberbandPointFeature3D::selectAction(AbstractEventDispatcher *, int x, int y)
{
if (rubberbandIsAlive())
{
if (nullptr ==_internal->m_causer)
{
_internal->m_screenCordinate = QPoint(x,y);
_internal->m_screenToMap->screenToLocation(x,y);
}
return true;
}
return false;
} // bool RubberbandPointFeature3D::selectAction(AbstractEventDispatcher *, int x, int y)
bool RubberbandPointFeature3D::setCoordinateAction(AbstractEventDispatcher * causer, int x, int y)
{
if (rubberbandIsAlive())
{
_internal->m_causer = (_internal->m_modifyPosition) ? nullptr : causer;
_internal->m_screenCordinate = QPoint(x,y);
_internal->m_screenToMap->screenToLocation(x,y);
return true;
}
return false;
} // bool RubberbandPointFeature3D::setCoordinateAction(AbstractEventDispatcher * causer, int x, int y)
bool RubberbandPointFeature3D::movePickedAction(AbstractEventDispatcher *, int x, int y)
{
if (rubberbandIsAlive())
{
if (nullptr == _internal->m_causer)
{
_internal->m_screenCordinate = QPoint(x,y);
_internal->m_screenToMap->screenToLocation(x,y);
}
return true;
}
return false;
} // bool RubberbandPointFeature3D::movePickedAction(AbstractEventDispatcher *, int x, int y)
bool RubberbandPointFeature3D::moveAction(AbstractEventDispatcher*,int,int)
{
if (rubberbandIsAlive())
{
}
return false;
} // bool RubberbandPointFeature3D::moveAction(AbstractEventDispatcher*,int,int)
bool RubberbandPointFeature3D::completeStateAction ( AbstractEventDispatcher * causer, int x, int y )
{
if (coordinateCount() > 0)
{
return applyAndEndAction(causer,x,y);
}
return false;
} // bool RubberbandPointFeature3D::completeStateAction ( AbstractEventDispatcher * causer, int x, int y )
bool RubberbandPointFeature3D::contextMenuAction ( AbstractEventDispatcher*,int,int ) { return rubberbandIsAlive(); }
bool RubberbandPointFeature3D::deleteAction ( AbstractEventDispatcher*,int,int ) { return rubberbandIsAlive(); }
bool RubberbandPointFeature3D::undoAction ( AbstractEventDispatcher*,int,int ) { return rubberbandIsAlive(); }
unsigned int RubberbandPointFeature3D::coordinateCount() const
{
return (_internal->m_positionReady) ? 1 : 0;
} // unsigned int RubberbandPointFeature3D::coordinateCount() const
void RubberbandPointFeature3D::update()
{
if (_internal->m_marker) _internal->m_marker->updateView();
externalUpdate();
} // RubberbandPointFeature3D::update()
QVector<QPointF> RubberbandPointFeature3D::coordinateVector( CoordinateSystem cs ) const
{
if (coordinateCount() > 0)
{
const QPointF &geoPos = projectCoordinateFromMap( cs, _internal->m_position.toPointF() );
return QVector<QPointF>() << geoPos;
}
return QVector<QPointF>();
} // QVector<QPointF> RubberbandPointFeature3D::coordinateVector( CoordinateSystem cs ) const
QPointF RubberbandPointFeature3D::singleCoordinate( unsigned int idx, CoordinateSystem cs ) const
{
Q_UNUSED(idx);
if (coordinateCount() > 0)
{
return coordinateVector(cs).value(0);
}
return QPointF();
} // QPointF RubberbandPointFeature3D::singleCoordinate( unsigned int idx, CoordinateSystem cs ) const
void RubberbandPointFeature3D::setCoordinateVector( const QVector<QPointF> & coordinateVector, CoordinateSystem cs )
{
if (coordinateVector.size() > 0)
{
const QPointF &mapPos = projectCoordinateToMap(cs,coordinateVector[0]);
onMapPosition( Point3D::fromQPointF(mapPos) );
}
} // void RubberbandPointFeature3D::setCoordinateVector( const QVector<QPointF> & coordinateVector, CoordinateSystem cs )
void RubberbandPointFeature3D::setCoordinateVector(const QVector<Point3D> & coordinateVector, CoordinateSystem cs )
{
if (coordinateVector.size() > 0)
{
const QPointF &mapPos = projectCoordinateToMap(cs,coordinateVector[0].toPointF());
_internal->m_position = Point3D(mapPos.x(),mapPos.y(),coordinateVector[0].z());
}
} // void RubberbandPointFeature3D::setCoordinateVector(const QVector<Point3D> & coordinateVector, CoordinateSystem cs )
QVector<Point3D> RubberbandPointFeature3D::coordinateVector3D( CoordinateSystem cs ) const
{
if (coordinateCount() > 0)
{
const QPointF &geoPos = projectCoordinateFromMap( cs, _internal->m_position.toPointF() );
return QVector<Point3D>() << Point3D(geoPos.x(),geoPos.y(),_internal->m_position.z());
}
return QVector<Point3D>();
} // QVector<Point3D> RubberbandPointFeature3D::coordinateVector3D( CoordinateSystem cs ) const
Point3D RubberbandPointFeature3D::singleCoordinate3D(unsigned int idx , CoordinateSystem cs) const
{
Q_UNUSED(idx);
if (coordinateCount() > 0)
{
return coordinateVector3D(cs).value(0);
}
return Point3D();
} // Point3D RubberbandPointFeature3D::singleCoordinate3D(unsigned int idx, CoordinateSystem cs) const
} } /* namespace SituationMap::RB */
@@ -0,0 +1,104 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define point feature geometry in 3d
** $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 "rubberband_3d.h"
namespace SituationMap { namespace RB
{
/**
@class RubberbandPointFeature rubberband_point_feature.h
@brief Implementation of a rubberband to input single coodinates for building point features
@see Rubberband
*/
class SITUATIONMAP_EXPORT RubberbandPointFeature3D : public Rubberband3D
{
Q_OBJECT
/**
@name Construction & Destruction
@{
*/
friend class RubberbandFactory;
explicit RubberbandPointFeature3D( SituationMap::Map * map, QObject * parent = nullptr, bool isActive = true );
public:
~RubberbandPointFeature3D();
/** @} */
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;
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;
unsigned int coordinateCount() const override;
QVector<QPointF> coordinateVector( CoordinateSystem cs = CoordinateSystem::Geo ) const override;
QPointF singleCoordinate( unsigned int idx = 0, CoordinateSystem cs = CoordinateSystem::Geo ) const override;
void setCoordinateVector( const QVector<QPointF> & coordinateVector, CoordinateSystem cs = CoordinateSystem::Geo ) override;
Point3D singleCoordinate3D( unsigned int idx = 0, CoordinateSystem cs = CoordinateSystem::Geo ) const override;
QVector<Point3D> coordinateVector3D( CoordinateSystem cs = CoordinateSystem::Geo ) const override;
void setCoordinateVector( const QVector<Point3D> & coordinateVector, CoordinateSystem cs = CoordinateSystem::Geo ) override;
void enableModificationState();
protected:
virtual bool buttonProxyActive( const QPointF & scenePos) const { Q_UNUSED(scenePos); return false; }
void update() override;
/*
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.
*/
struct InternalData;
InternalData * _internal;
protected slots:
void onMapPosition( const Point3D &mapCoordinate );
}; /* RubberbandPointFeature3D */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,390 @@
/**
**
** @RDE_HEADER@
** Implementation of base class for rubberband handles
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_point_handle.h"
#include <MathUtils/math_const.h>
#include <arcgis/MapGraphicsView.h>
#include <QtWidgets/QGraphicsScene>
#include <QtWidgets/QGraphicsEllipseItem>
namespace SituationMap { namespace RB
{
RubberbandPointHandle::RubberbandPointHandle( Esri::ArcGISRuntime::MapGraphicsView * mapView
, QGraphicsScene * scene
, const QPointF & scenePosition )
: RubberbandHandle(mapView,scene)
, _pointSymbol(nullptr)
, _coordinate( mapView, scenePosition )
, _sceneOffset(0,0)
, _iconPixmap(nullptr)
, _boundingRect(nullptr)
{
zBufferPlane( ZBufferPlane::PointHandle );
buildHandle( scenePosition );
} /* RubberbandPointHandle::RubberbandPointHandle */
RubberbandPointHandle::RubberbandPointHandle( Esri::ArcGISRuntime::MapGraphicsView * mapView
, QGraphicsScene * scene
, const Esri::ArcGISRuntime::Point & mapCoordinate )
: RubberbandHandle(mapView,scene)
, _pointSymbol(nullptr)
, _coordinate( mapView, mapCoordinate )
, _sceneOffset(0,0)
, _iconPixmap(nullptr)
, _boundingRect(nullptr)
{
zBufferPlane( ZBufferPlane::PointHandle );
buildHandle( _coordinate._sceneCoordinate );
} /* RubberbandPointHandle::RubberbandPointHandle */
RubberbandPointHandle::RubberbandPointHandle( Esri::ArcGISRuntime::MapGraphicsView * mapView
, QGraphicsScene * scene
, const QPointF & scenePosition
, const QPixmap & icon )
: RubberbandHandle(mapView,scene)
, _pointSymbol(nullptr)
, _coordinate( mapView, scenePosition )
, _sceneOffset(0,0)
, _iconPixmap( new QPixmap(icon) )
, _boundingRect(nullptr)
{
zBufferPlane( ZBufferPlane::PointHandle );
buildHandle( scenePosition );
} /* RubberbandPointHandle::RubberbandPointHandle */
RubberbandPointHandle::RubberbandPointHandle( Esri::ArcGISRuntime::MapGraphicsView * mapView
, QGraphicsScene * scene
, const Esri::ArcGISRuntime::Point & mapCoordinate
, const QPixmap & icon )
: RubberbandHandle(mapView,scene)
, _pointSymbol(nullptr)
, _coordinate( mapView, mapCoordinate )
, _sceneOffset(0,0)
, _iconPixmap( new QPixmap(icon) )
, _boundingRect(nullptr)
{
zBufferPlane( ZBufferPlane::PointHandle );
buildHandle( _coordinate._sceneCoordinate );
} /* RubberbandPointHandle::RubberbandPointHandle */
void RubberbandPointHandle::setIcon( const QPixmap & icon )
{
if (_iconPixmap == nullptr)
{
_iconPixmap = new QPixmap(icon);
if (_pointSymbol)
{
_scene->removeItem(_pointSymbol);
delete _pointSymbol;
_pointSymbol = nullptr;
}
buildHandle( _coordinate._sceneCoordinate );
return;
}
*_iconPixmap = icon;
QGraphicsPixmapItem * iconItem = static_cast<QGraphicsPixmapItem*>( _pointSymbol);
if (iconItem)
{
iconItem->setPixmap( *_iconPixmap );
QRectF bbox = iconItem->boundingRect();
bbox.moveCenter( _coordinate._sceneCoordinate );
if (_boundingRect) _boundingRect->setRect(bbox);
}
else buildHandle( _coordinate._sceneCoordinate );
} /* RubberbandPointHandle::setIcon */
void RubberbandPointHandle::buildHandle( const QPointF & scenePosition )
{
if (_scene != nullptr)
{
if (_iconPixmap != nullptr)
{
if (_iconPixmap->isNull())
{
delete _iconPixmap;
_iconPixmap = nullptr;
}
}
if (_iconPixmap == nullptr)
{
QGraphicsEllipseItem * kuller = new QGraphicsEllipseItem();
_pointSymbol = kuller;
if (_pointSymbol != nullptr)
{
_scene -> addItem( _pointSymbol );
kuller -> setPos( scenePosition+_sceneOffset );
kuller -> setRect( -qreal(_pickingRatio), -qreal(_pickingRatio), qreal(2*_pickingRatio), qreal(2*_pickingRatio) );
kuller -> setZValue( _zBufferValue );
kuller -> setCacheMode(QGraphicsItem::CacheMode::NoCache, QSize(_pickingRatio*2,_pickingRatio*2) );
kuller -> setFlags( QGraphicsItem::ItemIgnoresTransformations );
kuller -> setVisible( _isVisible );
}
}
else
{
QGraphicsPixmapItem * icon = new QGraphicsPixmapItem(*_iconPixmap);
_pointSymbol = icon;
if (_pointSymbol != nullptr)
{
_scene -> addItem( _pointSymbol );
qreal xOff = -(_iconPixmap->width() * 0.5);
qreal yOff = -(_iconPixmap->height() * 0.5);
icon -> setPos( scenePosition+_sceneOffset );
icon -> setZValue( _zBufferValue );
icon -> setFlags( QGraphicsItem::ItemIgnoresTransformations );
icon -> setVisible( _isVisible );
icon -> setOffset( xOff, yOff );
icon -> setShapeMode( QGraphicsPixmapItem::BoundingRectShape );
QRectF bbox = icon->boundingRect();
bbox.moveCenter( scenePosition );
_boundingRect = new QGraphicsRectItem( bbox );
_boundingRect -> setZValue(_zBufferValue-1);
_boundingRect -> setVisible( _isVisible );
_scene -> addItem( _boundingRect );
}
}
}
} /* RubberbandPointHandle::buildHandle */
RubberbandPointHandle::~RubberbandPointHandle()
{
delete _iconPixmap;
if (_scene)
{
if (nullptr != _boundingRect)
{
_scene->removeItem(_boundingRect);
delete _boundingRect;
}
if (nullptr != _pointSymbol)
{
_scene->removeItem(_pointSymbol);
delete _pointSymbol;
}
}
_pointSymbol = nullptr;
_iconPixmap = nullptr;
_boundingRect = nullptr;
} /* RubberbandHandle::~Rubberbandhandle */
QPointF RubberbandPointHandle::getRotatedSceneOffset() const
{
auto rotate = [](const QPointF & p, qreal sinA, qreal cosA) -> QPointF { return QPointF(p.x()*cosA+p.y()*sinA,p.y()*cosA-p.x()*sinA); };
qreal mapRotatePhi = _mapView->mapRotation() * MathConst::pi / 180.0;
qreal sinMap = sin(mapRotatePhi);
qreal cosMap = cos(mapRotatePhi);
return rotate( _sceneOffset, sinMap, cosMap );
} /* RubberbandPointHandle::getRotatedSceneOffset */
void RubberbandPointHandle::adjustCoordinates()
{
const QPointF & rotatedSceneOffset = getRotatedSceneOffset();
if (_iconPixmap == nullptr)
{
static_cast<QGraphicsEllipseItem*>(_pointSymbol)->setPos(_coordinate.mapToScene(_mapView)+rotatedSceneOffset);
}
else
{
QGraphicsPixmapItem * icon = static_cast<QGraphicsPixmapItem*>( _pointSymbol);
const QPointF & scenePosition = _coordinate.mapToScene(_mapView);
icon -> setPos( scenePosition+rotatedSceneOffset );
QRectF bbox = icon->boundingRect();
bbox.moveCenter( scenePosition+rotatedSceneOffset );
_boundingRect->setRect(bbox);
}
DEBUG_LOG(_logger) << LOGFUNCTION << " map-coordinate = " << QString::number(_coordinate._mapCoordinate.x(),'f',15)
<< " ; " << QString::number(_coordinate._mapCoordinate.y(),'f',15)
<< " scene-coordinate = " << _coordinate._sceneCoordinate.x() << " ; " << _coordinate._sceneCoordinate.y();
emit adjusted();
} /* RubberbandPointHandle::onDo_adjustCoordinates */
void RubberbandPointHandle::adjustWindow( const QRectF& )
{
onDo_adjustCoordinates();
} /* RubberbandPointHandle::onDo_adjustWindow */
void RubberbandPointHandle::updateGraphic()
{
if (_pointSymbol)
{
if (_pointSymbol != nullptr)
{
if (_iconPixmap == nullptr)
{
QGraphicsEllipseItem * kuller = static_cast<QGraphicsEllipseItem*>( _pointSymbol);
kuller -> setPen( QPen(_drawColor) );
QRadialGradient gradient(0, 0, _pickingRatio, 0, 0);
QColor gradientColor = (_isSelected) ? _selectionColor : _fillColor;
gradient.setColorAt( 0, gradientColor);
gradient.setColorAt( 1, QColor(gradientColor.red(), gradientColor.green(), gradientColor.blue(), 0) );
kuller -> setBrush( QBrush(gradient) );
kuller -> setVisible( _isVisible );
}
else
{
QGraphicsPixmapItem * icon = static_cast<QGraphicsPixmapItem*>( _pointSymbol);
_boundingRect -> setPen( QPen(_drawColor) );
const QColor &backColor = (_isSelected) ? _selectionColor : _fillColor;
_boundingRect -> setBrush( QBrush(backColor) );
_boundingRect -> setVisible( _isVisible );
icon -> setVisible( _isVisible );
}
}
}
} /* RubberbandPointHandle::updateGraphic */
void RubberbandPointHandle::updateCoordinate(const QPointF & scenePosition)
{
const QPointF & rotatedSceneOffset = getRotatedSceneOffset();
_coordinate.updateSceneCoordinate( _mapView, scenePosition );
if (_pointSymbol != nullptr)
{
if (_iconPixmap == nullptr)
{
QGraphicsEllipseItem * kuller = static_cast<QGraphicsEllipseItem*>( _pointSymbol);
kuller -> setPos( scenePosition+rotatedSceneOffset );
}
else
{
QGraphicsPixmapItem * icon = static_cast<QGraphicsPixmapItem*>( _pointSymbol);
icon -> setPos( scenePosition+rotatedSceneOffset );
QRectF bbox = icon->boundingRect();
bbox.moveCenter( scenePosition+rotatedSceneOffset );
_boundingRect->setRect(bbox);
}
}
} /* RubberbandPointHandle::updateCoordinate */
void RubberbandPointHandle::updateCoordinate()
{
const QPointF & rotatedSceneOffset = getRotatedSceneOffset();
if (_pointSymbol != nullptr)
{
if (_iconPixmap == nullptr)
{
QGraphicsEllipseItem * kuller = static_cast<QGraphicsEllipseItem*>( _pointSymbol);
kuller -> setPos( _coordinate._sceneCoordinate+rotatedSceneOffset );
}
else
{
QGraphicsPixmapItem * icon = static_cast<QGraphicsPixmapItem*>( _pointSymbol);
icon -> setPos( _coordinate._sceneCoordinate+rotatedSceneOffset );
QRectF bbox = icon->boundingRect();
bbox.moveCenter( _coordinate._sceneCoordinate+rotatedSceneOffset );
_boundingRect->setRect(bbox);
}
}
} /* RubberbandPointHandle::updateCoordinate */
void RubberbandPointHandle::moveCoordinate(const QPointF & sceneDelta)
{
_coordinate.updateSceneCoordinate( _mapView, _coordinate._sceneCoordinate+sceneDelta );
updateCoordinate();
} /* RubberbandPointHandle::moveCoordinate */
void RubberbandPointHandle::setCoordinate(const RubberbandHandle::RubberbandCoordinate & p)
{
_coordinate = p;
updateCoordinate();
} /* RubberbandPointHandle::setCoordinate */
RubberbandHandle::RubberbandCoordinate RubberbandPointHandle::getCoordinate() const { return _coordinate; }
QPointF RubberbandPointHandle::getPixelCoordinate() const
{
return _coordinate._sceneCoordinate;
}
bool RubberbandPointHandle::isPositionInside( const QPointF & scenePosition ) const
{
if (_pointSymbol)
{
return _pointSymbol->contains( _coordinate._sceneCoordinate+getRotatedSceneOffset() - scenePosition );
}
return false;
} /* RubberbandPointHandle::isPositionInside */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,114 @@
/**
**
** @RDE_HEADER@
** Definition of base class for rubberband handles
** $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 <QtCore/QPointF>
#include "rubberband_handle.h"
class QGraphicsItem;
class QGraphicsScene;
namespace SituationMap { namespace RB
{
/**
@class RubberbandPointHandle rubberband_point_handle.h
@brief Implementation of a point handle for rubberband internal use.
@see RubberbandHandle
*/
class RubberbandPointHandle : public RubberbandHandle
{
Q_OBJECT
public:
/**
@name Construction & Destruction
@{
*/
RubberbandPointHandle( Esri::ArcGISRuntime::MapGraphicsView*
, QGraphicsScene*
, const QPointF & scenePosition );
RubberbandPointHandle( Esri::ArcGISRuntime::MapGraphicsView*
, QGraphicsScene*
, const Esri::ArcGISRuntime::Point & mapCoordinate );
RubberbandPointHandle( Esri::ArcGISRuntime::MapGraphicsView*
, QGraphicsScene*
, const QPointF & scenePosition
, const QPixmap & icon );
RubberbandPointHandle( Esri::ArcGISRuntime::MapGraphicsView*
, QGraphicsScene*
, const Esri::ArcGISRuntime::Point & mapCoordinate
, const QPixmap & icon );
~RubberbandPointHandle();
/** @} */
void setIcon( const QPixmap & icon );
bool isPositionInside( const QPointF & scenePosition ) const override;
virtual void updateCoordinate( const QPointF & scenePosition );
virtual void moveCoordinate( const QPointF & sceneDelta );
virtual void setCoordinate( const RubberbandCoordinate & );
virtual RubberbandCoordinate getCoordinate() const;
QPointF getPixelCoordinate() const;
inline void setSceneOffset(const QPointF & offset) { _sceneOffset = offset; }
protected:
QGraphicsItem * _pointSymbol;
RubberbandCoordinate _coordinate;
QPointF _sceneOffset;
QPixmap * _iconPixmap;
QGraphicsRectItem * _boundingRect;
void updateGraphic() override;
virtual void updateCoordinate();
void adjustCoordinates() override;
void adjustWindow( const QRectF & ) override;
private:
QPointF getRotatedSceneOffset() const;
void buildHandle( const QPointF & scenePosition );
}; /* RubberbandPointHandle */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,318 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define multi point feature geometry with an additional width coordinate
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Linux, Windows 7, Qt 5.7. ArcGISRuntimeQt 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 7.12.2016, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_polyline_width.h"
#include "rubberband_point_handle.h"
#include "rubberband_internal.h"
#include "rubberband_base_internal.h"
#include <cmath>
#include <arcgis/Map.h>
namespace SituationMap { namespace RB
{
struct RubberbandPolylineWidth::InternalData
{
SituationMap::RefPointer<RubberbandPointHandle> _widthItem;
}; /* RubberbandPolylineWidth::InternalData*/
RubberbandPolylineWidth::RubberbandPolylineWidth( SituationMap::Map * map, QObject * parent )
: RubberbandMultiPointFeature(map,true,parent), _internal( new InternalData() )
{
} /* RubberbandPolylineWidth::RubberbandPolylineWidth */
RubberbandPolylineWidth::~RubberbandPolylineWidth()
{
delete _internal;
} /* RubberbandPolylineWidth::~RubberbandPolylineWidth */
void RubberbandPolylineWidth::buildWidthItem(const QPointF & mapPos1, const QPointF & mapPos2) const
{
double dx = mapPos2.x() - mapPos1.x();
double dy = mapPos2.y() - mapPos1.y();
QPointF handleMapPos = mapPos1 + QPointF(dx,dy)*0.35 + QPointF(dy,dx)*0.35;
setUpWidthItem(handleMapPos);
} /* RubberbandPolylineWidth::buildWidthItem */
void RubberbandPolylineWidth::setUpWidthItem(const QPointF & mapPos) const
{
RubberbandHandle::RubberbandCoordinate coordinate( Rubberband::_internal->_mapView, convert(mapPos,Rubberband::_internal->_mapView->map()->spatialReference()) );
_internal->_widthItem = new RubberbandPointHandle(Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, coordinate._sceneCoordinate);
} /* RubberbandPolylineWidth::setUpWidthItem */
QVector<QPointF> RubberbandPolylineWidth::coordinateVector( CoordinateSystem cs ) const
{
QVector<QPointF> polylineCoords = RubberbandMultiPointFeature::coordinateVector(cs);
if (polylineCoords.size() > 1)
{
if (_internal->_widthItem == nullptr)
{
RubberbandPointHandle * pointHandle1Ptr = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[0].get());
RubberbandPointHandle * pointHandle2Ptr = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[1].get());
Esri::ArcGISRuntime::Point p1 = pointHandle1Ptr->getCoordinate()._mapCoordinate;
Esri::ArcGISRuntime::Point p2 = pointHandle2Ptr->getCoordinate()._mapCoordinate;
buildWidthItem( QPointF(p1.x(),p1.y()), QPointF(p2.x(),p2.y()) );
}
polylineCoords += projectCoordinateFromMap(cs, _internal->_widthItem->getCoordinate()._mapCoordinate);
}
return polylineCoords;
} /* RubberbandPolylineWidth::coordinateVector */
QPointF RubberbandPolylineWidth::singleCoordinate( unsigned int idx, CoordinateSystem cs ) const
{
if (static_cast<unsigned int>(Rubberband::_internal->_handleList.size()) == idx)
{
return projectCoordinateFromMap(cs, _internal->_widthItem->getCoordinate()._mapCoordinate);
}
return RubberbandMultiPointFeature::singleCoordinate(idx, cs);
} /* RubberbandPolylineWidth::singleCoordinate */
void RubberbandPolylineWidth::setCoordinateVector( const QVector<QPointF> & coordinateVector, CoordinateSystem cs )
{
if (coordinateVector.size() > 2)
{
QVector<QPointF> lineCoords = coordinateVector;
setUpWidthItem( projectCoordinateToMap(cs, lineCoords.last()) );
lineCoords.removeLast();
RubberbandMultiPointFeature::setCoordinateVector(lineCoords, cs);
return;
}
if (coordinateVector.size() == 2)
{
const QPointF & mapP1 = projectCoordinateToMap(cs, coordinateVector[0]);
const QPointF & mapP2 = projectCoordinateToMap(cs, coordinateVector[1]);
buildWidthItem(mapP1, mapP2);
}
RubberbandMultiPointFeature::setCoordinateVector(coordinateVector,cs);
} /* RubberbandPolylineWidth::setCoordinateVector */
bool RubberbandPolylineWidth::selectAction( AbstractEventDispatcher * causer, int x, int y )
{
if (rubberbandIsAlive() && (nullptr != _internal->_widthItem.get()))
{
_internal->_widthItem->setSelection(false);
QPointF scenePos(pixel2ScenePosition(x, y));
if (_baseInternal->buttonProxyActive(scenePos)) return false;
if (_internal->_widthItem->isPositionInside(scenePos))
{
_internal->_widthItem->setSelection();
_baseInternal->_lastClickPosition = scenePos;
update();
return true;
}
}
return RubberbandMultiPointFeature::selectAction(causer,x,y);
} /* RubberbandPolylineWidth::selectAction */
bool RubberbandPolylineWidth::setCoordinateAction( AbstractEventDispatcher * causer, int x, int y )
{
if (rubberbandIsAlive() && (nullptr != _internal->_widthItem.get()))
{
if (_internal->_widthItem->isSelected())
{
QPointF scenePos(pixel2ScenePosition(x, y));
QPointF deltaMove = scenePos - _baseInternal->_lastClickPosition;
_internal->_widthItem->setSelection(false);
_internal->_widthItem->moveCoordinate(deltaMove);
update();
return true;
}
}
return RubberbandMultiPointFeature::setCoordinateAction(causer, x, y);
} /* RubberbandPolylineWidth::setCoordinateAction */
bool RubberbandPolylineWidth::movePickedAction( AbstractEventDispatcher * causer, int x, int y )
{
if (rubberbandIsAlive() && (nullptr != _internal->_widthItem.get()))
{
if (_internal->_widthItem->isSelected())
{
adjustConnectedPreviewPixmap(x, y);
QPointF scenePos(pixel2ScenePosition(x, y));
QPointF deltaMove = scenePos - _baseInternal->_lastClickPosition;
_baseInternal->_lastClickPosition = scenePos;
_internal->_widthItem->moveCoordinate(deltaMove);
update();
return false;
}
else
{
RubberbandPointHandle * handlePoint1Ptr = dynamic_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[0].get());
RubberbandPointHandle * handlePoint2Ptr = dynamic_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[1].get());
if (handlePoint1Ptr && handlePoint2Ptr)
{
const RubberbandDrawable::RubberbandCoordinate & loc1Start = handlePoint1Ptr->getCoordinate();
const RubberbandDrawable::RubberbandCoordinate & loc2Start = handlePoint2Ptr->getCoordinate();
bool ret = RubberbandMultiPointFeature::movePickedAction(causer, x, y);
const RubberbandDrawable::RubberbandCoordinate & loc1End = handlePoint1Ptr->getCoordinate();
const RubberbandDrawable::RubberbandCoordinate & loc2End = handlePoint2Ptr->getCoordinate();
QPointF deltaMove1 = loc1End._sceneCoordinate - loc1Start._sceneCoordinate;
QPointF deltaMove2 = loc2End._sceneCoordinate - loc2Start._sceneCoordinate;
if ((fabs(deltaMove1.x()) >= 1) || (fabs(deltaMove1.y()) >= 1) || (fabs(deltaMove2.x()) >= 1) || (fabs(deltaMove2.y()) >= 1))
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* First or second point have been moved. Now recalculate the coordinate of the width handle point as follows:
* The width handle "C" and the first two coordinates ("A","B") are providing a triangle:
* B
* / \
* / \
* /sinB \
* / cosB \
* / \
* / \
* c / \ a
* / \
* / \
* / \
* / \
* / sinA sinC \
* / cosA cosC \
* A ------------------------- C
* b
* If the coordinates of "A" or "B" are changed, try to keep the ratio of angles and sides of the triangle constant. For this
* use some trigonometric identities.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
auto rotate = []( const QPointF & p, qreal sinPhi, qreal cosPhi ) -> QPointF
{
return QPointF( p.x()*cosPhi - p.y()*sinPhi, p.y()*cosPhi + p.x()*sinPhi );
};
QPointF A = loc2Start._sceneCoordinate;
QPointF B = loc1Start._sceneCoordinate;
QPointF C = _internal->_widthItem->getCoordinate()._sceneCoordinate;
qreal a = QLineF(B,C).length(); // side length of triangle
qreal b = QLineF(A,C).length();
qreal c = QLineF(A,B).length();
qreal cosA = (b*b+c*c-a*a)/(b*c*2); // cosin rule
qreal cosB = (a*a+c*c-b*b)/(a*c*2);
qreal cosC = (a*a+b*b-c*c)/(a*b*2);
qreal sinA = sqrt(1-cosA*cosA); // pythagorean trigonometric identity
qreal sinB = sqrt(1-cosB*cosB);
qreal sinC = sqrt(1-cosC*cosC);
// now we have all angle of the triangle, set A and B to the new coordinates ...
A = loc2End._sceneCoordinate;
B = loc1End._sceneCoordinate;
// ... and calculate the coordinate of C with the same ratio of angles as before ...
QPointF AB = B-A;
// c = QLineF(QPointF(0,0),AB).length();
if (sinC != 0.0)
{
// ... rotate AB and scale it to the right length
C = A + rotate(AB,sinA,cosA) * sinB / sinC;
// the RubberbandPointHandle dosn't has a set to set scene coordinate. Using the moveCoordinate methode instead.
_internal->_widthItem->moveCoordinate( C - _internal->_widthItem->getCoordinate()._sceneCoordinate );
}
// else could only happen when the triangle is degenrated to a line
update();
}
return ret;
}
}
}
return RubberbandMultiPointFeature::movePickedAction(causer, x, y);
} /* RubberbandPolylineWidth::movePickedAction */
bool RubberbandPolylineWidth::moveAction( AbstractEventDispatcher * causer, int x, int y )
{
if (rubberbandIsAlive() && (nullptr != _internal->_widthItem.get()))
{
QPointF scenePos(pixel2ScenePosition(x, y));
_internal->_widthItem->setSelection( _internal->_widthItem->isPositionInside(scenePos) );
}
return RubberbandMultiPointFeature::moveAction( causer, x, y);
} /* RubberbandPolylineWidth::moveAction */
void RubberbandPolylineWidth::update()
{
if ((_internal->_widthItem.get() == nullptr) && (Rubberband::_internal->_handleList.size() > 1))
{
RubberbandPointHandle * pointHandle1Ptr = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[0].get());
RubberbandPointHandle * pointHandle2Ptr = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[1].get());
Esri::ArcGISRuntime::Point p1 = pointHandle1Ptr->getCoordinate()._mapCoordinate;
Esri::ArcGISRuntime::Point p2 = pointHandle2Ptr->getCoordinate()._mapCoordinate;
buildWidthItem(QPointF(p1.x(), p1.y()), QPointF(p2.x(), p2.y()));
}
if (_internal->_widthItem)
{
Rubberband::_internal->_handleList += static_cast<SituationMap::RefPointer<RubberbandHandle>>(_internal->_widthItem);
RubberbandMultiPointFeature::update();
Rubberband::_internal->_handleList.removeLast();
}
else RubberbandMultiPointFeature::update();
} /* RubberbandPolylineWidth::update */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,88 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define multi point feature geometry with an additional width coordinate
** $Id$
** $HeadURL$
** $Author$
**
** -----------------------------------------------------------------------------------------------
**
** Hardware-Environment: Intel-PC
** Software-Environment: Linux, Windows 7, Qt 5.7. ArcGISRuntimeQt 100
**
** Language ........: C++ 11
**
** -----------------------------------------------------------------------------------------------
**
** Author ...........: Jörg Turla, SPD G, Tel. 3132
**
** -----------------------------------------------------------------------------------------------
**
** Notes .........:
**
** 7.12.2016, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband_multi_point_feature.h"
namespace SituationMap { namespace RB
{
class RubberbandLineHandle;
class RubberbandFrameHandle;
/**
@class RubberbandPolylineWidth rubberband_smooth_line.h
@brief Implementation of a multi point feature rubberband with rounded edges.
@see RubberbandFactory, Rubberband, RubberbandMultiPointFeature
*/
class SITUATIONMAP_EXPORT RubberbandPolylineWidth : public RubberbandMultiPointFeature
{
Q_OBJECT
/**
@name Construction & Destruction
@{
*/
friend class RubberbandFactory;
explicit RubberbandPolylineWidth( SituationMap::Map * map, QObject * parent = nullptr );
public:
virtual ~RubberbandPolylineWidth();
/** @} */
virtual QVector<QPointF> 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<QPointF> &, CoordinateSystem cs = CoordinateSystem::Geo ) override;
bool selectAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool setCoordinateAction( AbstractEventDispatcher * causer, int x, int y ) override;
bool movePickedAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool moveAction ( AbstractEventDispatcher * causer, int x, int y ) override;
protected:
/*
Forward declaration of InternalData to hold private member variables. Becareful 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;
void update() override;
void buildWidthItem(const QPointF & mapPos1, const QPointF & mapPos2) const;
void setUpWidthItem(const QPointF & mapPos) const;
}; /* RubberbandSmoothLine */
} } /* namespace SituationMap::RB */
File diff suppressed because it is too large. Load diff
+274
View File
@@ -0,0 +1,274 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define point feature geoemtry
** $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 .........:
**
** 17.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband.h"
#include <MathUtils/matrix2d.h>
namespace SituationMap { namespace RB
{
class RubberbandPointHandle;
/**
@class RubberbandRectangle rubberband_rectangle.h
@brief Implementation of a rectangle rubberband
@see Rubberband
*/
class SITUATIONMAP_EXPORT RubberbandRectangle : public Rubberband
{
Q_OBJECT
/**
@name Construction & Destruction
@}
*/
friend class RubberbandFactory;
friend class RubberbandEllipse;
friend class RubberbandTransform;
explicit RubberbandRectangle( SituationMap::Map * map, QObject * parent = nullptr );
public:
~RubberbandRectangle();
/** @} */
bool selectAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool multiSelectActionPress ( AbstractEventDispatcher * causer, int x, int y ) override;
bool multiSelectActionRelease( 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;
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;
/**
@see rectangleVerticies
*/
bool coordinatesAreValid() const override { return rectangleIsValid(); }
/**
* @brief Get 4 verticies of rectangle
*/
QVector<QPointF> coordinateVector( CoordinateSystem cs = CoordinateSystem::Geo ) const override;
/**
* @brief Get center point of rectangle, see methode centerPoint
*/
QPointF singleCoordinate( unsigned int idx = 0, CoordinateSystem cs = CoordinateSystem::Geo ) const override;
/**
* @brief Set 4 verticies of rectangle
*/
void setCoordinateVector( const QVector<QPointF> &, CoordinateSystem cs = CoordinateSystem::Geo ) override;
/**
* @brief Returns center point of rectangle
*/
QPointF centerPoint( CoordinateSystem cs = CoordinateSystem::Geo ) const;
/**
* @brief Sets center point of rectangle
*/
void centerPoint(const QPointF &centerPoint, CoordinateSystem cs = CoordinateSystem::Geo );
/**
* @brief Get 4 verticies of rectangle
*/
QVector<QPointF> rectangleVerticies( CoordinateSystem cs = CoordinateSystem::Geo ) const;
/**
* @brief Set 4 verticies of rectangle
*/
void rectangleVerticies( const QVector<QPointF> &, CoordinateSystem cs = CoordinateSystem::Geo );
/**
* @brief Returns true if a valid rectangle has been set with method \c rectangleVerticies
* The rectangle rubberband is expecting input coordinates defining a rectangle in map coordinate system. Otherwise
* a similar as possible rectangle is used for rubberbanding and the coordinates returned by \c coordinateVector()
* will be different from input coordinates.
*/
bool rectangleIsValid() const;
/**
* @brief Pass back the rectangle parameter
* For convenience some times it would be an asset to get the parameter like center, width, height and rotation. This
* function pass back these parameter. A coordinate transformation or projection will \b not be done. All values are related to
* the coordinate system of the map.
* <b>Warning, if the map coordinate system doesn't use the same geographical projection as the simulation coordinate system
* the returned parameter may be all wrong.</b>
*
* @param center Center point of the rectangle in map coordinates.
* @param width Width of the rectangle.
* @param height Height of the rectangle.
* @param direction Normalized direction vector related to width axis.
*/
void rectangleParameter( QPointF & center, qreal & width, qreal & height, QPointF & direction, CoordinateSystem cs = CoordinateSystem::Geo );
/**
* @brief Build rectangle from rectangle parameter
* For convenience some times it would be an asset to initialize a rectangle rubberband from rectangle the parameter like width, height and rotation.
* A coordinate transformation or projection will \b not be done. All values are related to the coordinate system of the map.
* <b>Warning, if the map coordinate system doesn't use the same geographical projection as the simulation coordinate system all parameter may be wrong.</b>
*
* @param center Center of the rectangle in \b cs coordinate.
* @param width Width of the rectangle.
* @param height Height of the rectangle.
* @param direction Normalized direction vector related to width axis.
* @param cs Coordinate System.
*/
void buildFromRectangleParamter( const QPointF & center, qreal width, qreal height, const QPointF & direction, CoordinateSystem cs = CoordinateSystem::Geo );
/**
* @brief Build rectangle relative to the bottom left corner
* For convenience some times it would be an asset to initialize a rectangle rubberband from rectangle the parameter like width, height and rotation.
* A coordinate transformation or projection will \b not be done. All values are related to the coordinate system of the map.
* <b>Warning, if the map coordinate system doesn't use the same geographical projection as the simulation coordinate system all parameter may be wrong.</b>
*
* @param bottomLeft Bottom left corner of the rectangle in \b cs coordinates.
* @param width Width of the rectangle.
* @param height Height of the rectangle.
* @param direction Normalized direction vector related to width axis.
* @param cs Coordinate System.
*/
void buildRectangleRelativeToBottomLeftCorner( const QPointF & bottomLeft, qreal width, qreal height, const QPointF & direction, CoordinateSystem cs = CoordinateSystem::Geo );
/**
* @brief If set to true only quadratic rectangles can be created.
*/
void constrainQuadratic( bool on );
/**
* @brief Returns the setting for quadratic constrain.
*/
bool constrainQuadratic() const;
/**
* @brief If set to true the rectangle can not be rotated.
*/
void constrainOrthogonal( bool on );
/**
* @brief Returns the setting fpr orthogonsl constrain.
*/
bool constrainOrthogonal() const;
/**
@name Setting Constrains for Width and Height
To define a constrain value a postive values has to be assigned. Negative values will reset the constrain setting to undefined state.
@{
*/
void minWidth ( qreal x );
void maxWidth ( qreal x );
void minHeight( qreal x );
void maxHeight( qreal x );
/** @} */
protected:
/*
Forward declaration of InternalData to hold private member variables. Becareful 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 _rectangleIsValid;
/*
Coordinate matrix to describe the change of coordinates of the last user input
*/
MathUtils::Matrix2D _lastCoordinateChange;
/*
ModificationMode is used internally to restrict input for special purposes. It will be defined
by derived class
*/
enum class ModificationMode
{
NoneRestriction,
NoneRotation,
TranslationOnly,
ScalingOnly,
RotationOnly
};
void setModificationMode( ModificationMode );
void activateButtons() override;
void constructHandles();
void updateHandles( const QPointF & scenePos, QPointF deltaMove );
bool adjustLine( QPointF & deltaMove, bool & constrainsComplied );
void adjustNeighbouringPoints( RubberbandPointHandle * handlePointPtr, unsigned int handleIdx, QPointF deltaMove );
bool checkMinMaxConstrains(const QPointF & vertexScene, QPointF & deltaMovePtr );
bool checkMinMaxConstrains(const QPointF & vertexScene, bool isVertical );
bool constrainsSatisfied( RubberbandPointHandle * handlePointPtr, unsigned int handleIdx, QPointF & deltaMove, bool & constrainsComplied );
void useDottedLineHandles( bool on = true );
void update() override;
QPointF getSceneCenter() const;
qreal getSceneWidth() const;
qreal getSceneHeight() const;
QPointF getCenter() const;
qreal getWidth() const;
qreal getHeight() const;
void getSceneRotation( qreal & sinA, qreal & cosA ) const;
void getMapRotation ( qreal & sinA, qreal & cosA ) const;
void buildTmpConstructionPath(const QPointF & start, const QPointF & end, QVector<QPointF> & path, QPointF & sceneCenter, qreal & sceneWidth, qreal & sceneHeight );
virtual void buildTmpConstruction( SituationMap::RefPointer<RubberbandDrawable> & tmpGraphic, QPointF & start, QPointF & end );
virtual void getTmpConstructionParameter( const QPointF & start, const QPointF & end, QPointF & sceneCenter, qreal & sceneWidth, qreal & sceneHeight );
private:
void setButtonPosition();
}; /* RubberbandRectangle */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,93 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define multi point feature geometry
** $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 .........:
**
** 17.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_smooth_line.h"
#include "rubberband_point_handle.h"
#include "drawable_smooth_path.h"
#include "rubberband_internal.h"
namespace SituationMap { namespace RB
{
struct RubberbandSmoothLine::InternalData
{
SituationMap::RefPointer<DrawableSmoothPath> _smoothLineItem;
}; /* RubberbandSmoothLine::InternalData*/
RubberbandSmoothLine::RubberbandSmoothLine( SituationMap::Map * map, QObject * parent )
: RubberbandMultiPointFeature(map,true,parent), _internal( new InternalData() )
{
} /* RubberbandSmoothLine::RubberbandSmoothLine */
RubberbandSmoothLine::~RubberbandSmoothLine()
{
delete _internal;
} /* RubberbandSmoothLine::~RubberbandSmoothLine */
void RubberbandSmoothLine::update()
{
QVector<RubberbandDrawable::RubberbandCoordinate> vertexVector;
vertexVector.reserve( Rubberband::_internal->_handleList.size() );
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * pointHandlePtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if (pointHandlePtr)
{
vertexVector.append( pointHandlePtr -> getCoordinate() );
}
}
if (vertexVector.size() > 2)
{
if (!_internal->_smoothLineItem)
{
_internal->_smoothLineItem = new DrawableSmoothPath( Rubberband::_internal->_mapView );
}
_internal->_smoothLineItem -> enableClosedLine( isClosedEnabled() );
_internal->_smoothLineItem -> setDrawColor( _drawColor );
_internal->_smoothLineItem -> setFillColor( _fillColor );
_internal->_smoothLineItem -> setVisibility( true );
_internal->_smoothLineItem -> setPath( vertexVector );
}
else if (_internal->_smoothLineItem) _internal->_smoothLineItem->setVisibility( false );
RubberbandMultiPointFeature::update();
} /* RubberbandSmoothLine::update */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,72 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define multi point feature geoemtry with rounded edges
** $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 .........:
**
** 17.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband_multi_point_feature.h"
namespace SituationMap { namespace RB
{
/**
@class RubberbandSmoothLine rubberband_smooth_line.h
@brief Implementation of a multi point feature rubberband with rounded edges.
@see RubberbandFactory, Rubberband, RubberbandMultiPointFeature
*/
class SITUATIONMAP_EXPORT RubberbandSmoothLine : public RubberbandMultiPointFeature
{
Q_OBJECT
/**
@name Construction & Destruction
@{
*/
friend class RubberbandFactory;
explicit RubberbandSmoothLine( SituationMap::Map * map, QObject * parent = nullptr );
public:
~RubberbandSmoothLine();
/** @} */
protected:
/*
Forward declaration of InternalData to hold private member variables. Becareful 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;
void update() override;
}; /* RubberbandSmoothLine */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,572 @@
/**
**
** @RDE_HEADER@
** Implementation of rubberband class to edit states of point objects
** $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 .........:
**
** 19.10.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_state_select.h"
#include "rubberband_point_handle.h"
#include "rubberband_drawable.h"
#include "rubberband_handle_proxy.h"
#include "rubberband_factory.h"
#include "rubberband_internal.h"
#include "rubberband_base_internal.h"
#include <arcgis/Map.h>
#include <arcgis/MapGraphicsView.h>
#include <QtGui/QCursor>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QMenu>
#include "polygon.xpm"
namespace SituationMap { namespace RB
{
struct RubberbandStateSelect::InternalData
{
Q_DISABLE_COPY(InternalData)
InternalData() : _logger(getLogger("RubberbandStateSelect"))
{}
~InternalData()
{
delete _stateMenu;
}
QVector<State> _states;
QVector<StateItem> _items;
QList<SituationMap::RefPointer<RubberbandHandle>> _stateMenuSelectedHandleList;
LOGGER_T _logger;
const State * getStateFromValue( int stateValue ) const
{
for (const State &state : _states)
{
if (state.value() == stateValue) return &state;
}
return nullptr;
} /* getStateFromValue */
const State * getStateFromItem( const StateItem & item ) const { return getStateFromValue(item.stateValue()); }
static QPixmap * _polygonIcon;
QPushButton * _polygonButton = nullptr;
QMenu * _stateMenu = nullptr;
bool _stateMenuIsActive = false;
}; /* RubberbandMultiPointFeature::InternalData */
QPixmap * RubberbandStateSelect::InternalData::_polygonIcon = nullptr;
void RubberbandStateSelect::setIconPolygon(const QPixmap & icon)
{
if (InternalData::_polygonIcon == nullptr) InternalData::_polygonIcon = new QPixmap(icon);
else *InternalData::_polygonIcon = icon;
} /* RubberbandStateSelect::setIconPolygon */
RubberbandStateSelect::RubberbandStateSelect( SituationMap::Map * map, QObject * parent )
: Rubberband(map,parent), _internal(new InternalData())
{
delete RubberbandBase::_baseInternal->_undoButton;
RubberbandBase::_baseInternal->_undoButton = nullptr;
_internal->_polygonButton = new QPushButton( (InternalData::_polygonIcon) ? *InternalData::_polygonIcon : QPixmap(polygon_xpm), QString(), RubberbandBase::_baseInternal->_buttonBox );
RubberbandBase::_baseInternal->_buttonLayout->insertWidget( 0, _internal->_polygonButton );
connect( _internal->_polygonButton, &QPushButton::clicked, this, &RubberbandStateSelect::onDo_areaSelectionBegin );
// Check Quartz
connect( Rubberband::_internal->_mapView.data(), &Esri::ArcGISRuntime::MapGraphicsView::viewpointChanged,
this, &RubberbandStateSelect::onDo_updateButtonFixCoordinates );
connect( Rubberband::_internal->_mapView.data(), &Esri::ArcGISRuntime::MapGraphicsView::rectChanged ,
this, &RubberbandStateSelect::onDo_updateButtonFixCoordinates );
setFixedButtonBoxPosition(QPoint(5,5));
} /* RubberbandStateSelect::RubberbandStateSelect */
bool RubberbandStateSelect::setStateItems( const QVector<State> & stateVector
, const QVector<StateItem> & itemVector
, CoordinateSystem cs )
{
if (stateVector.size() < 2) return false;
if (itemVector.isEmpty()) return false;
// check for all states are valid
for (const State & state : qAsConst(_internal->_states))
{
if (!state.isValid())
return false;
}
bool ok = true;
_internal -> _states = stateVector;
_internal -> _items = itemVector;
for (QVector<StateItem>::iterator it = _internal->_items.begin(); it != _internal->_items.end(); ++it)
{
if (it->isValid())
{
const State * statePtr = _internal->getStateFromItem( *it );
if (statePtr == nullptr)
{
ok = false;
statePtr = & _internal->_states.first();
}
const QPointF &mapPos = projectCoordinateToMap( cs, it->coordinate() );
Esri::ArcGISRuntime::Point mapCoordinate( mapPos.x(), mapPos.y(), Rubberband::_internal->_mapView->map()->spatialReference() );
RubberbandPointHandle * handlePtr = new RubberbandPointHandle( Rubberband::_internal->_mapView
, Rubberband::_internal->_mapScene
, mapCoordinate
, statePtr->icon() );
if (handlePtr)
{
handlePtr->setSelection(false);
handlePtr->setUserData( &(*it) );
Rubberband::_internal->_handleList.append( SituationMap::RefPointer<RubberbandHandle>(handlePtr) );
}
}
else ok = false;
}
update();
activateButtons();
buildStateMenu();
return ok;
} /* RubberbandStateSelect::setStateItems */
const QVector<RubberbandStateSelect::StateItem> & RubberbandStateSelect::stateItems() const
{
return _internal->_items;
} /* RubberbandStateSelect::stateItems */
void RubberbandStateSelect::activateButtons()
{
_baseInternal->_hasUndoButton = false;
_baseInternal->_applyIsPossible = (!Rubberband::_internal->_handleList.isEmpty());
_baseInternal->_undoIsPossible = false;
Rubberband::activateButtons();
} /* RubberbandStateSelect::activateButton */
void RubberbandStateSelect::toggleState( RubberbandPointHandle * handlePtr )
{
if (_internal->_states.size() < 2) return;
if (handlePtr == nullptr) return;
StateItem * itemPtr = static_cast<StateItem*>(handlePtr->userData());
if (itemPtr == nullptr) return;
if (_internal->_states.size() == 2)
{
const State * statePtr = _internal -> getStateFromItem( *itemPtr );
if (statePtr != nullptr)
{
if (statePtr == &_internal->_states.first()) statePtr = &_internal->_states.last();
else statePtr = &_internal->_states.first();
}
else statePtr = &_internal->_states.first();
itemPtr->_stateValue = statePtr->value();
handlePtr->setIcon( statePtr->icon() );
}
} /* RubberbandStateSelect::toggleState */
void RubberbandStateSelect::setState( RubberbandPointHandle * handlePtr, int stateValue )
{
if (handlePtr == nullptr) return;
const State * statePtr = _internal -> getStateFromValue(stateValue);
StateItem * itemPtr = static_cast<StateItem*>(handlePtr->userData());
if (itemPtr == nullptr) return;
if (statePtr == nullptr) return;
itemPtr->_stateValue = stateValue;
handlePtr->setIcon( statePtr->icon() );
} /* RubberbandStateSelect::setState */
void RubberbandStateSelect::buildStateMenu()
{
if (_internal->_states.isEmpty()) return;
_internal->_stateMenu = new QMenu();
for (const State & state : qAsConst(_internal->_states))
{
QAction * action = _internal->_stateMenu->addAction( state.icon(), state.description() );
action -> setData( state.value() );
connect( action, &QAction::triggered, this, &RubberbandStateSelect::onDo_setState );
}
connect( _internal->_stateMenu, &QMenu::aboutToShow, this, [this]()
{
this->_internal->_stateMenuSelectedHandleList.clear();
_baseInternal->_buttonBox->setDisabled(true);
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
if (handle->isSelected())
{
this->_internal->_stateMenuSelectedHandleList << handle;
}
}
} );
connect( _internal->_stateMenu, &QMenu::aboutToHide, this, [this]()
{
_baseInternal->_buttonBox->setEnabled(true);
deSelectHandles();
} );
} /* RubberbandStateSelect::buildStateMenu */
void RubberbandStateSelect::onDo_setState(bool)
{
QAction * action = (QAction*) sender();
if (action == nullptr) return;
int stateValue = action->data().toInt();
for (auto handle : qAsConst(_internal->_stateMenuSelectedHandleList))
setState( dynamic_cast<RubberbandPointHandle*>(handle.get()), stateValue );
_internal -> _stateMenuSelectedHandleList.clear();
_internal -> _stateMenuIsActive = false;
update();
} /* RubberbandStateSelect::onDo_setState */
void RubberbandStateSelect::chooseStateMenu()
{
// popup a window with states the user can choose
_internal->_stateMenu->popup( QCursor::pos() );
_internal -> _stateMenuIsActive = true;
} /* RubberbandStateSelect::chooseStateMenu */
bool RubberbandStateSelect::selectAction( AbstractEventDispatcher*, int x, int y )
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION << x << " ; " << y;
_internal->_stateMenuSelectedHandleList.clear();
if (rubberbandIsAlive())
{
if (_internal->_stateMenuIsActive) return true;
QPointF scenePos(pixel2ScenePosition(x,y));
if (_baseInternal->buttonProxyActive(scenePos)) return false;
RubberbandHandle * handlePtr = pickHandle(x,y);
if (handlePtr)
{
handlePtr->setSelection();
enableSelectedState();
update();
deactivateButtons();
return true;
}
}
return false;
} /* RubberbandStateSelect::selectAction */
bool RubberbandStateSelect::multiSelectActionPress(AbstractEventDispatcher*, int x, int y)
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION << x << " ; " << y;
if (rubberbandIsAlive())
{
if (_internal -> _stateMenuIsActive) return true;
RubberbandHandle * handlePtr = pickHandle(x,y);
if (handlePtr)
{
handlePtr->setSelection();
enableSelectedState();
enableMultiSelectedState();
update();
deactivateButtons();
return true;
}
}
return false;
} /* RubberbandStateSelect::multiSelectActionPress */
bool RubberbandStateSelect::multiSelectActionRelease( AbstractEventDispatcher*, int, int )
{
return false;
} /* RubberbandStateSelect::multiSelectActionRelease */
bool RubberbandStateSelect::setCoordinateAction( AbstractEventDispatcher * causer, int x, int y )
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION << x << " ; " << y;
if (rubberbandIsAlive())
{
Rubberband::_internal->_lastClickPosition = pixel2ScenePosition(x,y);
if (_internal->_stateMenuIsActive)
{
_internal -> _stateMenuIsActive = false;
disenableSelectedState();
disenableMultiSelectedState();
activateButtons();
return true;
}
if (isEnabledSelectedState())
{
bool handlePicked = (pickHandle(x,y) != nullptr);
bool toggleMode = (_internal->_states.size() == 2);
bool eventHandled = false;
if (!toggleMode)
{
disenableSelectedState();
disenableMultiSelectedState();
chooseStateMenu();
return true;
}
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if ((handlePointPtr) && (handlePointPtr->isSelected()))
{
handlePointPtr->setSelection(false);
if ((handlePicked) && (toggleMode)) toggleState( handlePointPtr );
eventHandled = true;
}
}
disenableSelectedState();
disenableMultiSelectedState();
activateButtons();
return eventHandled;
}
else Rubberband::setCoordinateAction(causer,x,y);
}
return false;
} /* RubberbandStateSelect::setCoordinateAction */
bool RubberbandStateSelect::moveAction(AbstractEventDispatcher*, int x, int y)
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION << x << " ; " << y;
if (rubberbandIsAlive())
{
if (_internal -> _stateMenuIsActive) return false;
bool eventHandled = false;
QPointF scenePosition(pixel2ScenePosition(x,y));
if (_baseInternal->buttonProxyActive(scenePosition)) return false;
if (Rubberband::_internal->_mapView != nullptr)
{
if (!isEnabledMultiSelectedState()) deSelectHandles();
RubberbandHandle * handlePtr = pickHandle(x,y);
if (handlePtr != nullptr)
{
handlePtr->setSelection();
eventHandled = true;
}
}
if (eventHandled) update();
}
return false;
} /* RubberbandStateSelect::moveAction */
bool RubberbandStateSelect::movePickedAction(AbstractEventDispatcher * causer, int x, int y )
{
DEBUG_LOG(_internal->_logger) << LOGFUNCTION << x << " ; " << y;
Rubberband::movePickedAction(causer,x,y);
return false; // isEnabledSelectedState() || _internal->_stateMenuIsActive;
} /* RubberbandStateSelect::movePickedAction */
bool RubberbandStateSelect::contextMenuAction( AbstractEventDispatcher*, int, int )
{
if (!_internal -> _stateMenuIsActive) chooseStateMenu();
return true;
} /* RubberbandStateSelect::contextMenuAction */
void RubberbandStateSelect::onDo_areaSelectionBegin()
{
bool mRbands = _baseInternal->_map->rubberbandFactory().allowMultipleRubberbands();
_baseInternal->_map->rubberbandFactory().allowMultipleRubberbands(true);
{
RB::RubberbandMultiPointFeature * selectionRB = _baseInternal->_map->rubberbandFactory().create<RB::RubberbandMultiPointFeature>(this);
if (selectionRB == nullptr)
{
qWarning() << LOGFUNCTION << "Creating rubberband multi points feature failed";
}
else
{
selectionRB->setAutoDelete(true); // when finished rubberband will commit suicide
selectionRB->setDrawColor( QColor(255,0,0,255) );
selectionRB->setFillColor( QColor( 0,0,0,100) );
selectionRB -> enableClosed( true );
selectionRB -> enableFinishAfterConstruction( true );
selectionRB -> setFixedButtonBoxPosition(QPoint(15,15));
QObject::connect( selectionRB, &RB::Rubberband::apply, this, &RubberbandStateSelect::onDo_areaSelectionApply );
QObject::connect( selectionRB, &RB::Rubberband::abort, this, &RubberbandStateSelect::onDo_areaSelectionAbort );
RubberbandBase::_baseInternal->_buttonBox->setDisabled(true);
}
}
_baseInternal->_map->rubberbandFactory().allowMultipleRubberbands( mRbands );
} /* RubberbandStateSelect::onDo_areaSelectionBegin */
void RubberbandStateSelect::onDo_areaSelectionApply( RubberbandBase * selectionRB )
{
RubberbandBase::_baseInternal->_buttonBox->setEnabled(true);
if (selectionRB)
{
QVector<QPointF> polygonVertexList = selectionRB->coordinateVector( CoordinateSystem::Map );
// Looking for all handle which are inside polygon and select
unsigned int hitCounter = 0;
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if (handlePointPtr)
{
const Esri::ArcGISRuntime::Point &v = handlePointPtr->getCoordinate()._mapCoordinate;
bool inside = false;
int nvert = polygonVertexList.size();
for (int i = 0, j = nvert-1; i < nvert; j = i++)
{
const QPointF & vertex_i = polygonVertexList[i];
const QPointF & vertex_j = polygonVertexList[j];
if ((vertex_i.y()>v.y()) != (vertex_j.y()>v.y()))
{
if (v.x() < (vertex_j.x() - vertex_i.x()) * (v.y() - vertex_i.y()) / (vertex_j.y() - vertex_i.y()) + vertex_i.x())
{
inside = !inside;
}
}
}
if (inside)
{
hitCounter++;
handlePointPtr->setSelection();
}
}
}
if (hitCounter > 0)
{
if (_internal->_states.size() == 2)
{
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
if (!handle->isSelected()) continue;
handle->setSelection(false);
toggleState( dynamic_cast<RubberbandPointHandle*>(handle.get()) );
}
}
else
{
chooseStateMenu();
// ????? enableMultiSelectedState();
}
}
}
} /* RubberbandStateSelect::onDo_areaSelectionApply */
void RubberbandStateSelect::onDo_areaSelectionAbort( RubberbandBase * )
{
_baseInternal->_buttonBox->setEnabled(true);
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Really nothing else to do here?
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
} /* RubberbandStateSelect::onDo_areaSelectionAbort */
void RubberbandStateSelect::update()
{
Rubberband::update();
onDo_updateButtonFixCoordinates();
} /* RubberbandPointCluster::update */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,180 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to edit states of point objects
** $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 .........:
**
** 18.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband.h"
namespace SituationMap { namespace RB
{
class RubberbandPointHandle;
/**
@class RubberbandPointCluster rubberband_point_cluster.h
@brief Implementation of a rubberband to input single coodinates for building point feature clusters
@see Rubberband, RubberbandPointFeature
*/
class SITUATIONMAP_EXPORT RubberbandStateSelect : public Rubberband
{
Q_OBJECT
/**
@name Construction & Destruction
@{
*/
friend class RubberbandFactory;
explicit RubberbandStateSelect( SituationMap::Map * map, QObject * parent = nullptr );
public:
class State
{
public:
State() = default;
State(int value, const QString & description, const QPixmap & icon)
: _description(description), _icon(icon), _value(value), _valid(true)
{
}
inline bool isValid() const { return _valid; }
inline int value() const { return _value; }
inline const QString & description() const { return _description; }
inline const QPixmap & icon() const { return _icon; }
protected:
QString _description;
QPixmap _icon;
int _value = 0;
bool _valid = false;
}; /* State */
class StateItem
{
friend class RubberbandStateSelect;
public:
StateItem() : _valid(false), _id(0), _description(), _coordinate(), _stateValue(0) {;}
StateItem( quint32 id, const QString &description, const QPointF & coordinate, int stateValue )
: _valid(true), _id(id), _description(description), _coordinate(coordinate), _stateValue(stateValue)
{
} /* StateItem */
~StateItem() = default;
StateItem(const StateItem &) = default;
StateItem & operator = (const StateItem &) = default;
inline bool isValid() const { return _valid; }
inline quint32 id() const { return _id; }
inline const QPointF & coordinate() const { return _coordinate; }
inline int stateValue() const { return _stateValue; }
protected:
bool _valid;
quint32 _id;
QString _description;
QPointF _coordinate;
int _stateValue;
}; /* StateItem */
virtual ~RubberbandStateSelect() = default;
RubberbandStateSelect(const RubberbandStateSelect &) = delete;
RubberbandStateSelect & operator = (const RubberbandStateSelect &) = delete;
/** @} */
bool selectAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool multiSelectActionPress ( AbstractEventDispatcher * causer, int x, int y ) override;
bool multiSelectActionRelease( 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;
bool contextMenuAction ( AbstractEventDispatcher * causer, int x, int y ) override;
bool undoAction ( AbstractEventDispatcher * causer, int x, int y ) override { return contextMenuAction(causer,x,y); }
bool setStateItems( const QVector<State> & stateVector,
const QVector<StateItem> & itemVector,
CoordinateSystem cs = CoordinateSystem::Geo );
const QVector<StateItem> & stateItems() const;
static void setIconPolygon( const QPixmap & );
protected:
/*
Forward declaration of InternalData to hold private member variables. Becareful 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;
void activateButtons() override;
void update() override;
void applyButtonClicked() override { applyAndEndAction( _windowEventDispatcher, 0.0, 0.0 ); }
void buildStateMenu();
void chooseStateMenu();
void toggleState( RubberbandPointHandle * handlePtr );
void setState( RubberbandPointHandle * handlePtr, int stateValue );
protected slots:
void onDo_areaSelectionBegin();
void onDo_areaSelectionApply( RubberbandBase* );
void onDo_areaSelectionAbort( RubberbandBase* );
void onDo_setState( bool );
private:
void setCoordinateVector(const QVector<QPointF> &, CoordinateSystem ) override {}
QVector<QPointF> coordinateVector( CoordinateSystem ) const override { return QVector<QPointF>(); }
QPointF singleCoordinate( unsigned int, CoordinateSystem ) const override { return QPointF(); }
}; /* RubberbandStateSelect */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,92 @@
/**
**
** @RDE_HEADER@
** Implementation of rubberband class to define moving transforms
** $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 .........:
**
** 07.04.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_transform.h"
#include "rubberband_internal.h"
#include <MathUtils/math_const.h>
namespace SituationMap { namespace RB
{
struct RubberbandTransform::InternalData
{
Q_DISABLE_COPY(InternalData)
MathUtils::Matrix2D _transformCoordinates;
LOGGER_T _logger;
InternalData()
: _transformCoordinates()
, _logger(getLogger("RubberbandTransform"))
{
} /* InternalData */
}; /* RubberbandTransform::InternalData */
RubberbandTransform::RubberbandTransform( SituationMap::Map * map, QObject * parent )
: RubberbandRectangle(map,parent)
, _internal(new InternalData())
{
} /* RubberbandTransform::RubberbandTransform */
RubberbandTransform::~RubberbandTransform()
{
delete _internal;
_internal = nullptr;
} /* RubberbandTransform::~RubberbandTransform */
const MathUtils::Matrix2D & RubberbandTransform::transformMatrix() const { return _internal->_transformCoordinates; }
void RubberbandTransform::update()
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* It is importent here to call RubberbandRectangle::update(); first to do an update, because
* in other case the RubberbandRectangle::_lastCoordinateChange variable will have wrong values.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
RubberbandRectangle::update();
if (!_lastCoordinateChange.isIdentity())
{
_internal->_transformCoordinates = _lastCoordinateChange * _internal->_transformCoordinates;
}
emit updatePreview( this, _lastCoordinateChange );
_lastCoordinateChange.setToIdentity(); // reset matrix
} /* RubberbandTransform::update */
} } /* namespace SituationMap::RB */
+99
View File
@@ -0,0 +1,99 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define moving, scale and rotating transforms
** $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 .........:
**
** 22.06.2016, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband_rectangle.h"
namespace SituationMap { namespace RB
{
/**
@class RubberbandTransform rubberband_transform.h
@brief Implementation of a rubberband to move, scale and rotate features
@see Rubberband
*/
class SITUATIONMAP_EXPORT RubberbandTransform : public RubberbandRectangle
{
Q_OBJECT
friend class RubberbandFactory;
friend class RubberbandTransformMove;
friend class RubberbandTransformRotate;
friend class RubberbandTransformScale;
/**
@name Construction & Destruction
@}
*/
explicit RubberbandTransform( SituationMap::Map * map, QObject * parent = nullptr );
public:
~RubberbandTransform();
/** @} */
/**
Provides the transformation matrix
*/
const MathUtils::Matrix2D & transformMatrix() const;
signals:
/**
The updatePreview signal is emitted before the rubbberband itself will be redrawn. Connecting this signal can be
used to draw an preview e.g in case of transform rubberbands.
@param rbnd pointer to this Rubberband
@param mat transformation matrix to transform features for preview
@see Rubberband
*/
void updatePreview( Rubberband * rbnd, const MathUtils::Matrix2D & mat );
protected:
/*
Forward declaration of InternalData to hold private member variables. Becareful 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;
void update() override;
private:
void setButtonPosition();
}; /* RubberbandTransform */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,48 @@
/**
**
** @RDE_HEADER@
** Implementation of rubberband class to define moving transforms
** $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 .........:
**
** 07.04.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_transform_move.h"
namespace SituationMap { namespace RB
{
RubberbandTransformMove::RubberbandTransformMove( SituationMap::Map * map, QObject * parent )
: RubberbandTransform(map,parent)
{
setModificationMode( ModificationMode::TranslationOnly );
} /* RubberbandTransformMove::RubberbandTransformMove */
QPointF RubberbandTransformMove::translationVector() const
{
const MathUtils::Matrix2D & M = transformMatrix();
return QPointF(M(0,2),M(1,2));
} /* RubberbandTransformMove::translationVector() const */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,67 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define moving transforms
** $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 .........:
**
** 17.06.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband_transform.h"
namespace SituationMap { namespace RB
{
class RubberbandPointHandle;
/**
@class RubberbandTransformMove rubberband_transform_move.h
@brief Implementation of a rubberband to move features
@see Rubberband, RubberbandRectangle, RubberbandTransform
*/
class SITUATIONMAP_EXPORT RubberbandTransformMove : public RubberbandTransform
{
Q_OBJECT
friend class RubberbandFactory;
/**
@name Construction & Destruction
@}
*/
explicit RubberbandTransformMove( SituationMap::Map * map, QObject * parent = nullptr );
/**
Returns vector of translation
*/
QPointF translationVector() const;
public:
/** @} */
}; /* RubberbandTransformMove */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,62 @@
/**
**
** @RDE_HEADER@
** Implementation of rubberband class to define rotating transforms
** $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 .........:
**
** 07.04.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_transform_rotate.h"
#include <MathUtils/simple_helper.h>
namespace SituationMap { namespace RB
{
RubberbandTransformRotate::RubberbandTransformRotate( SituationMap::Map * map, QObject * parent )
: RubberbandTransform(map,parent)
{
setModificationMode( ModificationMode::RotationOnly );
} /* RubberbandTransformRotate::RubberbandTransformRotate */
qreal RubberbandTransformRotate::rotationSin() const
{
return transformMatrix()(0,1);
} // RubberbandTransformRotate::rotationSin
qreal RubberbandTransformRotate::rotationCos() const
{
return transformMatrix()(0,0);
} // RubberbandTransformRotate::rotationCos
qreal RubberbandTransformRotate::rotationAngle() const
{
return MathUtils::getMathAngle(rotationSin(),rotationCos());
} // RubberbandTransformRotate::rotationAngle
} } /* namespace SituationMap::RB */
@@ -0,0 +1,77 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define moving transformation
** $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 .........:
**
** 07.04.2016, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband_transform.h"
namespace SituationMap { namespace RB
{
class RubberbandPointHandle;
/**
@class RubberbandTransformRotate rubberband_transform_rotate.h
@brief Implementation of a rubberband to rotate features
@see Rubberband
*/
class SITUATIONMAP_EXPORT RubberbandTransformRotate : public RubberbandTransform
{
Q_OBJECT
friend class RubberbandFactory;
/**
@name Construction & Destruction
@}
*/
explicit RubberbandTransformRotate( SituationMap::Map * map, QObject * parent );
public:
/** @} */
/**
Returns sinus of rotation angle
*/
qreal rotationSin() const;
/**
Return cosinus of roation angle
*/
qreal rotationCos() const;
/**
Return rotation angle (math.) in radians
*/
qreal rotationAngle() const;
}; /* RubberbandTransformRotate */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,47 @@
/**
**
** @RDE_HEADER@
** Implementation of rubberband class to define scaling transforms
** $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 .........:
**
** 07.04.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_transform_scale.h"
namespace SituationMap { namespace RB
{
RubberbandTransformScale::RubberbandTransformScale( SituationMap::Map * map, QObject * parent )
: RubberbandTransform(map,parent)
{
setModificationMode( ModificationMode::ScalingOnly );
} /* RubberbandTransformScale::RubberbandTransformScale */
qreal RubberbandTransformScale::scaleX() const { return transformMatrix()(0,0); }
qreal RubberbandTransformScale::scaleY() const { return transformMatrix()(1,1); }
} } /* namespace SituationMap::RB */
@@ -0,0 +1,64 @@
/**
**
** @RDE_HEADER@
** Definition of rubberband class to define scaling transformation
** $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 .........:
**
** 07.04.2016, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband_transform.h"
namespace SituationMap { namespace RB
{
/**
@class RubberbandTransformScale rubberband_transform_scale.h
@brief Implementation of a rubberband to scale features
@see Rubberband
*/
class SITUATIONMAP_EXPORT RubberbandTransformScale : public RubberbandTransform
{
Q_OBJECT
friend class RubberbandFactory;
/**
@name Construction & Destruction
@}
*/
explicit RubberbandTransformScale( SituationMap::Map * map, QObject * parent = nullptr );
public:
/** @} */
qreal scaleX() const; /**< Returns scaling factor in x direction */
qreal scaleY() const; /**< Returns scaling factor in y direction */
}; /* RubberbandTransformRotate */
} } /* namespace SituationMap::RB */
+32
View File
@@ -0,0 +1,32 @@
/* XPM */
static const char *sphere_pattern_xpm[] = {
"16 16 13 1",
" c None",
". c #FFFFFF",
"+ c #F8F8F8",
"@ c #DCDCDC",
"# c #BFBFBF",
"$ c #E3E3E3",
"% c #929292",
"& c #6C6C6C",
"* c #484848",
"= c #393939",
"- c #F3F3F3",
"; c #B5B5B5",
"> c #0A0A0A",
" ...... ",
" .....+.... ",
" ..@++++++... ",
" ..#$++....++.. ",
" .%#$+.......+. ",
"..%#$........+..",
".&%#@........+..",
".*%%#$........+.",
".=&%##@-.....+-.",
".=*&%##@$--++-@.",
".;=*&%##@@$$@@#.",
" .>==&%%######. ",
" ..>>==&&%%%%.. ",
" ..>>>>==*=.. ",
" ..;>>>>;.. ",
" ...... "};
@@ -0,0 +1,88 @@
/**
**
** @RDE_HEADER@
** Implementation of preview for tactical symbols
** $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
**
** -----------------------------------------------------------------------------------------------
*/
#include "transient_tactical_symbol.h"
#include <Map/situation_map_types.h>
#include <MapImpl/sidc_symbol_impl.h>
#include <MapImpl/layer_factory_impl.h>
namespace SituationMap { namespace RB
{
TransientTacticalSymbol::TransientTacticalSymbol( MapImpl * mapImpl, const QString & sidc )
{
QString layerIdent;
if (mapImpl)
{
layerIdent = mapImpl->layerFactoryImpl().rubberbandLayer();
}
if (layerIdent.isEmpty())
{
qWarning() << LOGFUNCTION << "not layername found";
}
_tacticalRubberbandObj = new SidcSymbolImpl( sidc, QStringLiteral("TransientTacticalSymbol:sidc=%1").arg(sidc) );
_tacticalRubberbandObj -> init( mapImpl, layerIdent );
//_tacticalRubberbandObj -> setDrawOrder( 2000 );
} /* PreviewTaticalSymbol::PreviewTaticalSymbol */
TransientTacticalSymbol::~TransientTacticalSymbol()
{
delete _tacticalRubberbandObj;
} /* TransientTacticalSymbol::~TransientTacticalSymbol */
void TransientTacticalSymbol::update(const QVector<RubberbandDrawable::RubberbandCoordinate> & coordinateVector)
{
PositionCont controlPoints;
controlPoints.reserve(coordinateVector.size());
for (const RubberbandDrawable::RubberbandCoordinate &pos : coordinateVector)
{
const Esri::ArcGISRuntime::Point & p = pos._mapCoordinate;
controlPoints.append(Point3D(p.x(), p.y(), p.z()));
}
_tacticalRubberbandObj -> setPositionsTranslated( controlPoints );
try
{
_tacticalRubberbandObj -> updateView();
}
catch (...)
{
qWarning() << LOGFUNCTION << "Exception from TacticalAppearance::updateView() catched!!!!";
}
} /* TransientTacticalSymbol::update */
} } /* namespace SituationMap::RB */
@@ -0,0 +1,79 @@
/**
**
** @RDE_HEADER@
** Definition of tansient tactical symbols while rubberband input is done.
** $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 .........:
**
** 01.09.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#pragma once
#include "rubberband_drawable.h"
#include <MapImpl/map_impl.h>
#include <Common/referenced.h>
#include <QtCore/QObject>
namespace SituationMap { class SidcSymbolImpl; }
namespace SituationMap { namespace RB
{
/**
@class TransientTacticalSymbol transient_tactical_symbol.h
The class \c TransientTacticalSymbol a map object of type RubberbandObjectImpl to display a tactical symbol
transiently while rubberband input is done. The tactical symbol is defined by a \a sidc code which is passed
to the ctor as second parameter.
@see RubberbandObjectImpl
*/
class TransientTacticalSymbol : public QObject, public SituationMap::Referenced
{
Q_OBJECT
public:
/**
@name Construction & Destruction
@{
*/
explicit TransientTacticalSymbol( MapImpl *, const QString & sidc );
virtual ~TransientTacticalSymbol();
TransientTacticalSymbol(const TransientTacticalSymbol &) = delete;
TransientTacticalSymbol & operator = (const TransientTacticalSymbol &) = delete;
/** @} */
virtual void update( const QVector<RubberbandDrawable::RubberbandCoordinate> & coordinateVector );
protected:
SidcSymbolImpl * _tacticalRubberbandObj;
protected slots:
}; /* TransientTacticalSymbol */
} } /* namespace SituationMap::RB */
+134
View File
@@ -0,0 +1,134 @@
/* XPM */
static const char * undo_xpm[] = {
"24 24 107 2",
" c None",
". c #BEAD52",
"+ c #D4C15C",
"@ c #CCBA59",
"# c #A49546",
"$ c #F7E16A",
"% c #FEE65E",
"& c #FEE350",
"* c #FEE248",
"= c #FEE34C",
"- c #FEE662",
"; c #DAC75E",
"> c #CBBA57",
", c #FDE456",
"' c #FCDE32",
") c #FCDD2D",
"! c #FCE143",
"~ c #E5D15F",
"{ c #C1B152",
"] c #FBE047",
"^ c #FADB2B",
"/ c #FADE3C",
"( c #BBAB4F",
"_ c #94873F",
": c #F9DF49",
"< c #F8D929",
"[ c #F5DC4B",
"} c #EFD751",
"| c #F6D627",
"1 c #EACC25",
"2 c #E3C524",
"3 c #F1D226",
"4 c #F6D72A",
"5 c #AA9A46",
"6 c #BAAA4B",
"7 c #F3D52B",
"8 c #F3D424",
"9 c #E1C421",
"0 c #C0A81C",
"a c #D3BD43",
"b c #EBD242",
"c c #F1D122",
"d c #D3B71E",
"e c #B29B19",
"f c #E7CB37",
"g c #97893C",
"h c #EECF25",
"i c #EECE1F",
"j c #E7C81E",
"k c #D8BB1C",
"l c #ECCE28",
"m c #CDB741",
"n c #EBCC1C",
"o c #EBCD1F",
"p c #CBB84D",
"q c #DCC857",
"r c #B5A447",
"s c #E6CA31",
"t c #E8C919",
"u c #D0B416",
"v c #DFC118",
"w c #E8CA26",
"x c #EACF3B",
"y c #ECD552",
"z c #E3CE59",
"A c #CAB74F",
"B c #E6C71C",
"C c #E6C617",
"D c #BEA51A",
"E c #D3B513",
"F c #E3C314",
"G c #E4C51D",
"H c #E6CA2E",
"I c #DBBC13",
"J c #917F20",
"K c #917E15",
"L c #E0C011",
"M c #DDBF17",
"N c #C0AE49",
"O c #D8BA0E",
"P c #DDBE0E",
"Q c #DEBF12",
"R c #E1C62C",
"S c #E5CE4A",
"T c #D3BF4F",
"U c #928436",
"V c #AC930E",
"W c #DBBB0C",
"X c #DEC01D",
"Y c #E2C93D",
"Z c #CCB84B",
"` c #D7B809",
" . c #D8B909",
".. c #CCAF09",
"+. c #BDA107",
"@. c #D6B607",
"#. c #CFB007",
"$. c #897504",
"%. c #D4B405",
"&. c #D0B105",
"*. c #978004",
"=. c #C9AA03",
"-. c #D2B203",
";. c #D0B003",
">. c #A48B03",
",. c #968109",
"'. c #AD9301",
" ",
" ",
" . + @ ",
" # $ % & * = - ; ",
" > , ' ) ) ) ) ) ! ~ ",
" { ] ^ ^ ^ ^ ^ ^ ^ ^ / ( ",
" _ : < < < < < < < < < < [ ",
" } | | | | | | 1 2 3 | | 4 5 ",
" 6 7 8 8 8 8 9 0 8 8 a ",
" b c c c c d e c f ",
" g h i i i j k l ",
" m n n n n o ",
" p q r s t t t u v ",
" w x y z A B C C C D ",
" E F F G H F F F I J ",
" K L L L L L L L M N ",
" O P P P P P P Q R S T U ",
" V W W W W W W W W W X Y Z ",
" ` . . . . . . . ... ",
" +.@.@.@.@.@.@.#.$. ",
" %.%.%.%.&.*. ",
" =.-.;.>. ",
" ,.'. ",
" "};
+84
View File
@@ -0,0 +1,84 @@
/* XPM */
static const char * winkelIcon_xpm[] = {
"40 40 41 1",
" c None",
". c #250075",
"+ c #250074",
"@ c #260074",
"# c #250073",
"$ c #240072",
"% c #250071",
"& c #22006F",
"* c #24006E",
"= c #280078",
"- c #290076",
"; c #270076",
"> c #240073",
", c #250072",
"' c #240071",
") c #240070",
"! c #23006E",
"~ c #23006D",
"{ c #22006D",
"] c #23006C",
"^ c #21006D",
"/ c #270075",
"( c #230073",
"_ c #24006F",
": c #22006E",
"< c #22006C",
"[ c #240075",
"} c #260075",
"| c #230070",
"1 c #24006C",
"2 c #230072",
"3 c #260073",
"4 c #23006F",
"5 c #230071",
"6 c #24006D",
"7 c #210064",
"8 c #210066",
"9 c #200065",
"0 c #210065",
"a c #200063",
"b c #1D0062",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" .++ ",
" @+#+$%&* ",
" =-;#>,')!~{]^ ",
" .;/>(>)_:~~~<~< ",
" [}###'|&:~<<~~1!* ",
" .2$3'')4::{~~~~~^ ",
" $%'5' 4{6<~~~~_ ",
" 4)| <~~~~! ",
" :~~~!~ ",
" 4{~~~< ",
" ~~~~{_ ",
" ~~~6~ ",
" ~~~~: ",
" ]~~{~! ",
" ~~~{~ ",
" ~~~]! ",
" ~~~~:| ",
" {<~~~! ",
" ~~~~!~ ",
" <~~~~! ",
" :{{<~~~*] ",
" !::]1!{{{{<~{~~~~]! ",
" ^64~~]!~~~<~~~~~*6{ ",
" {!&!]~~~~~~~<]~*~ ",
" :*]~~~~~~~<_< ",
" 7890009ab ",
" ",
" ",
" ",
" ",
" ",
" ",
" "};