Files
qt5-legatus-legacy/Lts/Viewer/SituationMap/Rubberbands/rubberband_multi_point_feature.cpp
T
2026-08-13 18:33:10 +02:00

1138 lines
44 KiB
C++
Executable File

/**
**
** @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 .........:
**
** 27.03.2015, JT : First edition for use with Qt5
**
** -----------------------------------------------------------------------------------------------
*/
#include "rubberband_multi_point_feature.h"
#include "rubberband_frame_handle.h"
#include "rubberband_line_handle.h"
#include "rubberband_point_handle.h"
#include "rubberband_drawable.h"
#include "rubberband_handle_proxy.h"
#include "drawable_line.h"
#include "drawable_painter_path.h"
#include "transient_tactical_symbol.h"
#include "rubberband_internal.h"
#include "rubberband_base_internal.h"
#include <arcgis/Map.h>
#include <QtCore/QMetaMethod>
namespace SituationMap { namespace RB
{
struct RubberbandMultiPointFeature::InternalData
{
Q_DISABLE_COPY(InternalData)
QList<SituationMap::RefPointer<RubberbandLineHandle>> _lineHandleList;
SituationMap::RefPointer<RubberbandFrameHandle> _frameHandle;
SituationMap::RefPointer<DrawablePainterPath> _fillPath;
SituationMap::RefPointer<DrawableLine> _cursorPreviewLine;
SituationMap::RefPointer<DrawableLine> _cursorPreviewCloseLine;
SituationMap::RefPointer<TransientTacticalSymbol> _previewSymbol;
bool _complexGeometry;
bool _addVertexAtEnd;
bool _showCursorPreviewLine;
double _checkMaxAngle;
InternalData( QGraphicsScene * scene, bool complexGeometry )
: _lineHandleList()
, _frameHandle()
, _fillPath()
, _cursorPreviewLine()
, _cursorPreviewCloseLine()
, _previewSymbol()
, _complexGeometry(complexGeometry)
, _addVertexAtEnd(false)
, _showCursorPreviewLine(false)
, _checkMaxAngle(0.0)
{
Q_UNUSED(scene);
} /* InternalData */
}; /* RubberbandMultiPointFeature::InternalData */
RubberbandMultiPointFeature::RubberbandMultiPointFeature( SituationMap::Map * map, QObject * parent )
: RubberbandMultiPointFeature(map, false, parent)
{
} /* RubberbandMultiPointFeature::RubberbandMultiPointFeature */
RubberbandMultiPointFeature::RubberbandMultiPointFeature( SituationMap::Map * map, bool complexGeometry, QObject * parent )
: Rubberband(map,parent)
, _internal(new InternalData(Rubberband::_internal->_mapScene, complexGeometry))
, _isClosed(false)
, _minimumPointCount(2)
, _maximumPointCount(0)
, _maximumSegmentLength(0.0)
, _maximumLength(0.0)
{
} /* RubberbandMultiPointFeature::RubberbandMultiPointFeature */
RubberbandMultiPointFeature::~RubberbandMultiPointFeature()
{
delete _internal;
} /* RubberbandMultiPointFeature::~RubberbandMultiPointFeature */
void RubberbandMultiPointFeature::setCheckMaxAngle(double phi)
{
_internal->_checkMaxAngle = ((phi > 0.0) && (phi < M_PI)) ? phi : 0.0;
} // RubberbandMultiPointFeature::setCheckMaxAngle
RubberbandFrameHandle * RubberbandMultiPointFeature::getFrameHandle() const { return _internal->_frameHandle.get(); }
QVector<QPointF> RubberbandMultiPointFeature::coordinateVector( CoordinateSystem cs ) const
{
QVector<QPointF> coordinateVector;
coordinateVector.reserve(Rubberband::_internal->_handleList.size());
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
coordinateVector.push_back(projectCoordinateFromMap( cs, handlePointPtr->getCoordinate()._mapCoordinate ));
}
return coordinateVector;
} /* RubberbandMultiPointFeature::coordinateVector */
QPointF RubberbandMultiPointFeature::singleCoordinate(unsigned int idx, CoordinateSystem cs ) const
{
if (idx < (unsigned int)Rubberband::_internal->_handleList.size())
{
const RubberbandPointHandle * handle = dynamic_cast<const RubberbandPointHandle*>(Rubberband::_internal->_handleList[idx].get());
return projectCoordinateFromMap( cs, handle->getCoordinate()._mapCoordinate );
}
return QPointF();
} /* RubberbandMultiPointFeature::singleCoordinate */
void RubberbandMultiPointFeature::setCoordinateVector(const QVector<QPointF> & coordinateVector, CoordinateSystem cs )
{
Rubberband::_internal->_handleList.clear();
for (const auto &p : coordinateVector)
{
constructPoint( p, cs );
}
enableModificationState();
update();
activateButtons();
} /* RubberbandMultiPointFeature::setCoordinateVector */
void RubberbandMultiPointFeature::constructPoint( const QPointF &point, CoordinateSystem cs )
{
const QPointF &mapPos = projectCoordinateToMap( cs, point );
RubberbandHandle::RubberbandCoordinate coordinate( Rubberband::_internal->_mapView, convert(mapPos, Rubberband::_internal->_mapView->map()->spatialReference()) );
RubberbandHandle * handlePtr = constructPoint( coordinate._sceneCoordinate );
if (handlePtr)
{
static_cast<RubberbandPointHandle*>(handlePtr)->setCoordinate( coordinate );
handlePtr->setSelection(false);
}
} /* RubberbandMultiPointFeature::constructPoint */
RubberbandHandle * RubberbandMultiPointFeature::constructPoint( QPointF scenePos )
{
RubberbandHandle * handlePtr;
if (!Rubberband::_internal->_handleList.empty())
{
handlePtr = Rubberband::_internal->_handleList.last().get();
if (handlePtr)
{
const RubberbandHandle::RubberbandCoordinate && lastPos = static_cast<RubberbandPointHandle*>(handlePtr)->getCoordinate();
if (isClosedEnabled())
{
handlePtr = Rubberband::_internal->_handleList.first().get(); // get pointer to first point
if ((unsigned int)Rubberband::_internal->_handleList.size() == 2)
{
const RubberbandHandle::RubberbandCoordinate && firstPos = static_cast<RubberbandPointHandle*>(handlePtr)->getCoordinate();
// create line from first point of polyline to new point to close the polyline
handlePtr = new RubberbandLineHandle( Rubberband::_internal->_mapView
, Rubberband::_internal->_mapScene
, scenePos
, firstPos._sceneCoordinate
, _lineHandleWidth
, _internal->_complexGeometry );
_internal->_lineHandleList.insert( 0, SituationMap::RefPointer<RubberbandLineHandle>(static_cast<RubberbandLineHandle*>(handlePtr)) );
}
else if ((unsigned int)Rubberband::_internal->_handleList.size() > 2)
{
// update coordinates
handlePtr = _internal->_lineHandleList.first().get(); // get pointer to first line handle
static_cast<RubberbandLineHandle*>(handlePtr)->updateCoordinate(0,scenePos);
}
}
// create line from last point to new point
handlePtr = new RubberbandLineHandle( Rubberband::_internal->_mapView
, Rubberband::_internal->_mapScene
, lastPos._sceneCoordinate
, scenePos
, _lineHandleWidth
, _internal->_complexGeometry );
_internal->_lineHandleList.append( SituationMap::RefPointer<RubberbandLineHandle>(static_cast<RubberbandLineHandle*>(handlePtr)) );
}
}
handlePtr = new RubberbandPointHandle( Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, scenePos );
handlePtr -> setSelection();
Rubberband::_internal->_handleList.append( SituationMap::RefPointer<RubberbandHandle>(handlePtr) );
if ((unsigned int)Rubberband::_internal->_handleList.size() >= _minimumPointCount)
{
activateButtons();
}
if ((!_maximumPointCount) || ((unsigned int)Rubberband::_internal->_handleList.size() < _maximumPointCount))
{
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 );
if (_internal->_cursorPreviewCloseLine) _internal -> _cursorPreviewCloseLine -> setVisibility( true );
}
else
{
_internal->_cursorPreviewLine = nullptr;
_internal->_cursorPreviewCloseLine = nullptr;
}
return handlePtr;
} /* RubberbandMultiPointFeature::constructPoint */
bool RubberbandMultiPointFeature::checkLengthConstrains( const QPointF & scenePos, const QPointF & deltaScenePos )
{
if (_internal->_complexGeometry)
{
markFailedConstrains( QPointF(), false );
return true;
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Checking constrains for moving selected coordinates (handles)
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
bool allHandlesSelected = true;
QVector<RubberbandHandle::RubberbandCoordinate> coordinateVector;
coordinateVector.reserve( Rubberband::_internal->_handleList.size() );
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if (handlePointPtr)
{
coordinateVector.append(handlePointPtr->getCoordinate());
if (handlePointPtr->isSelected())
{
RubberbandHandle::RubberbandCoordinate & coordinate = coordinateVector.back();
coordinate.updateSceneCoordinate( Rubberband::_internal->_mapView , coordinate._sceneCoordinate + deltaScenePos );
}
else allHandlesSelected = false;
}
}
if ((allHandlesSelected) || ((_internal->_frameHandle) && (_internal->_frameHandle->isSelected())))
{
markFailedConstrains( QPointF(), false );
return true;
}
if (_internal->_checkMaxAngle > 0.0)
{
// Check angle of line segments first
for (int i = 2; i < coordinateVector.size(); ++i)
{
const RubberbandHandle::RubberbandCoordinate & p1 = coordinateVector[i - 2];
const RubberbandHandle::RubberbandCoordinate & p2 = coordinateVector[i - 1];
const RubberbandHandle::RubberbandCoordinate & p3 = coordinateVector[i];
// build tangent vectors
QPointF t1 = QPointF(p2._mapCoordinate.x() - p1._mapCoordinate.x(), p2._mapCoordinate.y() - p1._mapCoordinate.y());
QPointF t2 = QPointF(p3._mapCoordinate.x() - p2._mapCoordinate.x(), p3._mapCoordinate.y() - p2._mapCoordinate.y());
double l1 = sqrt(t1.x()*t1.x() + t1.y()*t1.y());
double l2 = sqrt(t2.x()*t2.x() + t2.y()*t2.y());
if (qFuzzyIsNull(l1) || qFuzzyIsNull(l2))
{
continue;
}
t1 /= l1;
t2 /= l2;
double phi = acos(t1.x()*t2.x() + t1.y()*t2.y());
if (phi > _internal->_checkMaxAngle)
{
markFailedConstrains(scenePos, true);
return false;
}
}
}
if ((!isClosedEnabled()) && (_maximumLength > 0.0))
{
qreal totalLength = 0.0;
const Esri::ArcGISRuntime::Point * mapPointPtr = nullptr; // Check Quartz
for (int i = 0; i < coordinateVector.size(); ++i)
{
const RubberbandHandle::RubberbandCoordinate & coordinate = coordinateVector[i];
if (mapPointPtr)
{
qreal x = coordinate._mapCoordinate.x() - mapPointPtr->x();
qreal y = coordinate._mapCoordinate.y() - mapPointPtr->y();
totalLength += sqrt(x*x+y*y);
}
mapPointPtr = &coordinateVector.at(i)._mapCoordinate;
}
if (totalLength > _maximumLength)
{
markFailedConstrains( scenePos, true );
return false;
}
}
const RubberbandHandle::RubberbandCoordinate * mapPointPtr = nullptr;
bool lastSelected = false;
auto handleIter = Rubberband::_internal->_handleList.constBegin();
for (int i = 0; i < coordinateVector.size(); ++i)
{
const RubberbandHandle::RubberbandCoordinate & coordinate = coordinateVector[i];
bool isSelected = (*handleIter)->isSelected();
if ((isSelected || lastSelected) && (mapPointPtr))
{
if ((!isClosedEnabled()) && (_maximumSegmentLength > 0.0))
{
qreal x = coordinate._mapCoordinate.x() - mapPointPtr->_mapCoordinate.x();
qreal y = coordinate._mapCoordinate.y() - mapPointPtr->_mapCoordinate.y();
if (sqrt(x*x+y*y) > _maximumSegmentLength)
{
markFailedConstrains( scenePos, true );
return false;
}
}
// looking for identical coordinate with last point
qreal x = coordinate._sceneCoordinate.x() - mapPointPtr->_sceneCoordinate.x();
qreal y = coordinate._sceneCoordinate.y() - mapPointPtr->_sceneCoordinate.y();
if ((x*x + y*y) <= 1)
{
markFailedConstrains( scenePos, true );
return false;
}
}
++handleIter;
mapPointPtr = &coordinateVector.at(i);
lastSelected = isSelected;
} // for
markFailedConstrains( QPointF(), false );
return true;
} /* RubberbandMultiPointFeature::checkLengthConstrains */
bool RubberbandMultiPointFeature::checkLengthConstrains( unsigned int checkHandleIdx, QPointF & scenePos )
{
if (_internal->_complexGeometry)
{
markFailedConstrains( QPointF(), false );
return true;
}
bool markFailedConstrainsFlag = false;
// calculate pixel size for later use
RubberbandDrawable::RubberbandCoordinate pi1( Rubberband::_internal->_mapView,scenePos );
RubberbandDrawable::RubberbandCoordinate pi2( Rubberband::_internal->_mapView,scenePos+QPointF(1,1) );
qreal piX = pi2._mapCoordinate.x() - pi1._mapCoordinate.x();
qreal piY = pi2._mapCoordinate.y() - pi1._mapCoordinate.y();
qreal pixelSize = sqrt(piX*piX+piY*piY);
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Checking constrains for adding single coordinate at end of polyline
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
RubberbandHandle::RubberbandCoordinate mapPos( Rubberband::_internal->_mapView, scenePos );
if ((!Rubberband::_internal->_handleList.empty()) && (_maximumLength > 0.0) && (!isClosedEnabled()))
{
qreal totalLength = 0.0;
RubberbandHandle::RubberbandCoordinate mapPoint;
QList<SituationMap::RefPointer<RubberbandHandle>>::iterator it = Rubberband::_internal->_handleList.begin();
for (; it != Rubberband::_internal->_handleList.end(); ++it)
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(it->get());
if (handlePointPtr)
{
if (it != Rubberband::_internal->_handleList.begin())
{
qreal x = handlePointPtr->getCoordinate()._mapCoordinate.x() - mapPoint._mapCoordinate.x();
qreal y = handlePointPtr->getCoordinate()._mapCoordinate.y() - mapPoint._mapCoordinate.y();
totalLength += sqrt(x*x+y*y);
}
mapPoint = handlePointPtr->getCoordinate();
}
}
if (totalLength >= _maximumLength)
{
markFailedConstrains( scenePos, true );
return false;
}
qreal x = mapPos._mapCoordinate.x() - mapPoint._mapCoordinate.x();
qreal y = mapPos._mapCoordinate.y() - mapPoint._mapCoordinate.y();
qreal l = sqrt(x*x+y*y);
qreal d = _maximumLength - totalLength - l - pixelSize;
if (d < 0.0)
{
qreal scale = (1.0 + d/l);
const Esri::ArcGISRuntime::Point newMapCoordinate(mapPoint._mapCoordinate.x() + x * scale,
mapPoint._mapCoordinate.y() + y * scale,
mapPos._mapCoordinate.spatialReference());
mapPos._mapCoordinate = newMapCoordinate;
markFailedConstrainsFlag = true;
scenePos = mapPos.mapToScene( Rubberband::_internal->_mapView );
}
}
if (checkHandleIdx <= (unsigned int)Rubberband::_internal->_handleList.size())
{
unsigned int handleListIdx = Rubberband::_internal->_handleList.size()-checkHandleIdx;
const RubberbandPointHandle * handlePointPtr = dynamic_cast<const RubberbandPointHandle*>(Rubberband::_internal->_handleList.at(handleListIdx).get());
if ((!isClosedEnabled()) && (_maximumSegmentLength > 0.0))
{
qreal x = mapPos._mapCoordinate.x() - handlePointPtr->getCoordinate()._mapCoordinate.x();
qreal y = mapPos._mapCoordinate.y() - handlePointPtr->getCoordinate()._mapCoordinate.y();
qreal l = sqrt(x*x+y*y);
qreal d = _maximumSegmentLength - l - pixelSize;
if (d < 0.0)
{
qreal scale = (1.0 + d/l);
const Esri::ArcGISRuntime::Point newMapCoordinate(handlePointPtr->getCoordinate()._mapCoordinate.x() + x * scale,
handlePointPtr->getCoordinate()._mapCoordinate.y() + y * scale,
mapPos._mapCoordinate.spatialReference());
mapPos._mapCoordinate = newMapCoordinate;
markFailedConstrainsFlag = true;
scenePos = mapPos.mapToScene( Rubberband::_internal->_mapView );
}
}
// looking for identical coordinate with last point
qreal x = handlePointPtr->getCoordinate()._sceneCoordinate.x() - scenePos.x();
qreal y = handlePointPtr->getCoordinate()._sceneCoordinate.y() - scenePos.y();
if ((x*x+y*y) <= 1)
{
markFailedConstrains( scenePos, true );
return false;
}
}
markFailedConstrains( scenePos, markFailedConstrainsFlag );
return true;
} /* RubberbandMultiPointFeature::checkLengthConstrains */
bool RubberbandMultiPointFeature::selectHandles(int x, int y, const QPointF & scenePos)
{
bool eventHandled = false;
RubberbandHandle * handlePtr = pickHandle(x,y);
_internal -> _addVertexAtEnd = false;
if (handlePtr)
{
handlePtr->setSelection();
enableSelectedState();
eventHandled = true;
}
else
{
if ((_maximumPointCount < 1) || ((unsigned int)Rubberband::_internal->_handleList.size() < _maximumPointCount))
{
unsigned int lineCounter = 0;
for (auto lineHandle : qAsConst(_internal->_lineHandleList))
{
if (lineHandle->isSelected())
{
lineHandle->setSelection(false);
handlePtr = new RubberbandLineHandle( Rubberband::_internal->_mapView
, Rubberband::_internal->_mapScene
, lineHandle->getCoordinate(0)._sceneCoordinate
, scenePos
, _lineHandleWidth
, _internal->_complexGeometry );
_internal->_lineHandleList.insert( lineCounter, SituationMap::RefPointer<RubberbandLineHandle>(static_cast<RubberbandLineHandle*>(handlePtr)) );
lineHandle->updateCoordinate( 0, scenePos );
handlePtr = new RubberbandPointHandle( Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, scenePos );
handlePtr -> setSelection();
unsigned int insertHandleIndex = lineCounter;
if (!isClosedEnabled()) insertHandleIndex += 1;
Rubberband::_internal->_handleList.insert( insertHandleIndex, SituationMap::RefPointer<RubberbandHandle>(handlePtr) );
enableSelectedState();
eventHandled = true;
break;
}
++lineCounter;
}
}
}
if (!isEnabledSelectedState())
{
// ok doesn't hit any point or line handle now looking to frame handle
if (_internal->_frameHandle != nullptr)
{
if (_internal->_frameHandle->isPositionInside(scenePos))
{
_internal->_frameHandle->setSelection(true);
enableSelectedState();
eventHandled = true;
}
}
}
return eventHandled;
} /* RubberbandMultiPointFeature::selectHandles */
void RubberbandMultiPointFeature::resetAction(AbstractEventDispatcher * causer, int x, int y )
{
if (rubberbandIsAlive())
{
if (isEnabledConstructionState())
{
if (_internal->_addVertexAtEnd)
{
Rubberband::_internal->_handleList.removeLast();
_internal->_lineHandleList.removeLast();
}
}
}
Rubberband::resetAction(causer,x,y);
} /* RubberbandMultiPointFeature::resetAction */
bool RubberbandMultiPointFeature::selectAction( AbstractEventDispatcher* , int x, int y )
{
if (rubberbandIsAlive())
{
QPointF scenePos(pixel2ScenePosition(x,y));
if (_baseInternal->buttonProxyActive(scenePos)) return false;
if (isEnabledConstructionState()) disenableMultiSelectedState();
_baseInternal->_lastClickPosition = scenePos;
bool eventHandled = selectHandles( x, y, scenePos );
if ((!eventHandled) && (isEnabledConstructionState()))
{
_internal -> _addVertexAtEnd = true;
_internal -> _showCursorPreviewLine = true;
deSelectHandles();
if (checkLengthConstrains(1,scenePos))
{
constructPoint( scenePos );
enableSelectedState();
_baseInternal->_lastClickPosition = scenePos;
}
eventHandled = true;
}
else _internal->_addVertexAtEnd = false;
if (eventHandled)
{
update();
deactivateButtons();
}
return eventHandled;
}
return false;
} /* RubberbandMultiPointFeature::selectAction */
bool RubberbandMultiPointFeature::setCoordinateAction( AbstractEventDispatcher * causer, int x, int y )
{
markFailedConstrains( QPointF(), false );
if ((rubberbandIsAlive()) && (Rubberband::_internal->_mapView) && (Rubberband::_internal->_mapScene))
{
bool eventHandled = false;
QPointF scenePos(pixel2ScenePosition(x,y));
Rubberband::_internal->_lastClickPosition = scenePos;
if (_internal->_addVertexAtEnd) // isEnabledConstructionState())
{
if (Rubberband::_internal->_handleList.isEmpty())
{
disenableSelectedState();
disenableMultiSelectedState();
return false;
}
if ((!isEnabledSelectedState()) && (_baseInternal->buttonProxyActive(scenePos)))
{
deSelectHandles();
return false;
}
if (checkLengthConstrains(2, scenePos))
{
QPointF deltaMove = scenePos - _baseInternal->_lastClickPosition;
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if ((handlePointPtr) && ((handlePointPtr->isSelected())))
{
handlePointPtr->setSelection(false);
handlePointPtr->moveCoordinate( deltaMove );
eventHandled = true;
}
}
}
markFailedConstrains( QPointF(), false );
if ((_maximumPointCount >0) && ((unsigned int)Rubberband::_internal->_handleList.size() >= _maximumPointCount))
{
completeStateAction(causer,x,y);
}
if (eventHandled) update();
if (_baseInternal->buttonProxyActive(scenePos)) return false;
updateButtonPosition();
activateButtons();
}
else
{
if (isEnabledSelectedState())
{
bool frameIsSelected( ((_internal->_frameHandle != nullptr) && (_internal->_frameHandle->isSelected())) );
QPointF deltaMove = scenePos - _baseInternal->_lastClickPosition;
if (!checkLengthConstrains(scenePos, deltaMove))
{
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if (handlePointPtr) handlePointPtr->setSelection(false);
}
if (_internal->_frameHandle) _internal->_frameHandle->setSelection(false);
updateButtonPosition();
activateButtons();
disenableSelectedState();
disenableMultiSelectedState();
markFailedConstrains( QPointF(), false );
return true;
}
markFailedConstrains( QPointF(), false );
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if ((handlePointPtr) && ((handlePointPtr->isSelected()) || (frameIsSelected)))
{
handlePointPtr->setSelection(false);
handlePointPtr->moveCoordinate( deltaMove );
eventHandled = true;
}
}
if (frameIsSelected)
{
_internal->_frameHandle->setSelection(false);
eventHandled = true;
}
disenableSelectedState();
disenableMultiSelectedState();
}
if (isEnabledConstructionState())
{
_internal->_addVertexAtEnd = true;
_internal->_showCursorPreviewLine = true;
updatePreviewLine( scenePos );
}
else if (_baseInternal->buttonProxyActive(scenePos)) return false;
if (eventHandled) update();
updateButtonPosition();
activateButtons();
}
return eventHandled;
}
return false;
} /* RubberbandMultiPointFeature::setCoordinateAction */
void RubberbandMultiPointFeature::updatePreviewLine( const QPointF & scenePosition )
{
if (isEnabledConstructionState() && (!Rubberband::_internal->_handleList.isEmpty()) && (_internal->_cursorPreviewLine))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.last().get());
if ((handlePointPtr) && (_internal->_addVertexAtEnd))
{
RubberbandDrawable::RubberbandCoordinate rbCoordinate( Rubberband::_internal->_mapView, scenePosition );
_internal->_cursorPreviewLine -> setVisibility( _internal->_showCursorPreviewLine );
_internal->_cursorPreviewLine -> setDrawColor( _handleSelectionColor );
_internal->_cursorPreviewLine->setLine( handlePointPtr->getCoordinate(), rbCoordinate );
if (_internal->_cursorPreviewCloseLine)
{
_internal->_cursorPreviewCloseLine -> setVisibility( _internal->_showCursorPreviewLine );
_internal->_cursorPreviewCloseLine -> setDrawColor( _handleSelectionColor );
handlePointPtr = dynamic_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList.front().get());
if (handlePointPtr)
{
_internal->_cursorPreviewCloseLine->setLine( handlePointPtr->getCoordinate(), rbCoordinate );
}
}
}
else
{
_internal->_cursorPreviewLine -> setVisibility( false );
if (_internal->_cursorPreviewCloseLine) _internal->_cursorPreviewCloseLine -> setVisibility( false );
}
return;
}
_internal->_cursorPreviewLine = nullptr;
_internal->_cursorPreviewCloseLine = nullptr;
} /* RubberbandMultiPointFeature::updatePreviewLine */
bool RubberbandMultiPointFeature::moveAction( AbstractEventDispatcher*, int x, int y )
{
adjustConnectedPreviewPixmap(x,y);
if (rubberbandIsAlive())
{
QPointF scenePosition(pixel2ScenePosition(x,y));
if (_baseInternal->buttonProxyActive(scenePosition)) return false;
if (Rubberband::_internal->_mapView == nullptr) return false;
if (!isEnabledMultiSelectedState()) deSelectHandles();
RubberbandHandle * handlePtr = pickHandle(x,y);
if (handlePtr == nullptr)
{
_internal->_showCursorPreviewLine = isEnabledConstructionState();
for (auto handle : qAsConst(_internal->_lineHandleList))
{
handle->setSelection(false);
if (handle->isPositionInside(scenePosition))
handle->setSelection();
}
}
else
{
_internal->_showCursorPreviewLine = false;
handlePtr->setSelection();
}
if (isEnabledConstructionState())
{
if (checkLengthConstrains(1,scenePosition))
{
updatePreviewLine( scenePosition );
if (isSignalConnected(QMetaMethod::fromSignal(&RubberbandMultiPointFeature::currentCursorPositionChanged)))
{
RubberbandDrawable::RubberbandCoordinate mapCoord(Rubberband::_internal->_mapView, scenePosition);
emit currentCursorPositionChanged( Point3D(mapCoord._mapCoordinate.x(),mapCoord._mapCoordinate.y(),0.0) );
}
}
}
return false;
}
return false;
} /* RubberbandMultiPointFeature::moveAction */
bool RubberbandMultiPointFeature::movePickedAction( AbstractEventDispatcher*, int x, int y )
{
adjustConnectedPreviewPixmap(x,y);
if ((rubberbandIsAlive()) && (Rubberband::_internal->_mapView) && (Rubberband::_internal->_mapScene))
{
if (isEnabledSelectedState())
{
QPointF scenePos( pixel2ScenePosition(x,y) );
QPointF deltaMove( scenePos-_baseInternal->_lastClickPosition );
if (checkLengthConstrains(scenePos, deltaMove))
{
bool frameIsSelected( ((_internal->_frameHandle != nullptr) && (_internal->_frameHandle->isSelected())) );
_baseInternal->_lastClickPosition = scenePos;
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
{
RubberbandPointHandle * handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
if ((handlePointPtr) && ((handlePointPtr->isSelected()) || (frameIsSelected)))
{
handlePointPtr->moveCoordinate( deltaMove );
}
}
updatePreviewLine(scenePos);
update();
}
return true;
}
}
return false;
} /* RubberbandMultiPointFeature::movePickedAction */
bool RubberbandMultiPointFeature::deleteAction(AbstractEventDispatcher*, int x, int y)
{
if ((rubberbandIsAlive()) && (Rubberband::_internal->_mapView) && (Rubberband::_internal->_mapScene))
{
if (((unsigned int)Rubberband::_internal->_handleList.size() > _minimumPointCount) && (isEnabledSelectedState()))
{
QList<SituationMap::RefPointer<RubberbandHandle>> savedHandleList = Rubberband::_internal->_handleList;
QList<SituationMap::RefPointer<RubberbandLineHandle>> savedLineHandleList = _internal->_lineHandleList;
QPointF scenePosition = pixel2ScenePosition(x,y);
QList<SituationMap::RefPointer<RubberbandHandle>>::iterator handleIter = Rubberband::_internal->_handleList.begin();
QList<SituationMap::RefPointer<RubberbandLineHandle>>::iterator lineHandleIter = _internal->_lineHandleList.begin();
while (handleIter != Rubberband::_internal->_handleList.end())
{
if (handleIter->get()->isPositionInside(scenePosition))
{
handleIter = Rubberband::_internal->_handleList.erase(handleIter);
lineHandleIter = _internal->_lineHandleList.erase(lineHandleIter);
if (lineHandleIter != _internal->_lineHandleList.end())
{
if (lineHandleIter != _internal->_lineHandleList.begin())
{
lineHandleIter->get()->updateCoordinate( 0, (lineHandleIter-1)->get()->getCoordinate(1)._sceneCoordinate );
}
}
continue;
}
++handleIter;
if ((lineHandleIter != _internal->_lineHandleList.end())
&& (lineHandleIter+1 != _internal->_lineHandleList.end()))
{
++lineHandleIter;
}
} /* while handleIter */
if (!checkLengthConstrains(scenePosition, QPointF(0,0)))
{
// constrain failed, do not delete yet
Rubberband::_internal->_handleList = savedHandleList;
_internal->_lineHandleList = savedLineHandleList;
}
update();
activateButtons();
disenableSelectedState();
disenableMultiSelectedState();
}
return true;
}
return false;
} /* RubberbandMultiPointFeature::deleteAction */
bool RubberbandMultiPointFeature::contextMenuAction( AbstractEventDispatcher*, int,int )
{
return false;
} /* RubberbandMultiPointFeature::contextMenuAction */
bool RubberbandMultiPointFeature::completeStateAction ( AbstractEventDispatcher * causer, int x, int y )
{
markFailedConstrains( QPointF(), false );
if ((rubberbandIsAlive()) && (Rubberband::_internal->_mapView) && (Rubberband::_internal->_mapScene))
{
if (isEnabledConstructionState())
{
if (!_finishAfterConstruction)
{
if ((unsigned int)Rubberband::_internal->_handleList.size() >= _minimumPointCount)
{
enableModificationState();
_internal->_cursorPreviewLine = nullptr; // remove preview lines
_internal->_cursorPreviewCloseLine = nullptr;
}
update();
return true;
}
}
if ((unsigned int)Rubberband::_internal->_handleList.size() >= _minimumPointCount)
{
return applyAndEndAction(causer,x,y);
}
}
return false;
} /* RubberbandMultiPointFeature::completeStateAction */
bool RubberbandMultiPointFeature::undoAction( AbstractEventDispatcher * /*causer*/, int,int )
{
if (rubberbandIsAlive())
{
if (!Rubberband::_internal->_handleList.empty())
{
if (isEnabledConstructionState())
{
Rubberband::_internal->_handleList.pop_back();
if (!_internal->_lineHandleList.empty()) _internal->_lineHandleList.pop_back();
if (_internal->_cursorPreviewLine) _internal->_cursorPreviewLine -> setVisibility( false );
if (_internal -> _cursorPreviewCloseLine) _internal -> _cursorPreviewCloseLine -> setVisibility( false );
update();
activateButtons();
}
}
return true;
}
return false;
} /* RubberbandMultiPointFeature::undoAction */
bool RubberbandMultiPointFeature::applyAndEndAction( AbstractEventDispatcher * causer, int x, int y)
{
if ((unsigned int)Rubberband::_internal->_handleList.size() >= _minimumPointCount) Rubberband::applyAndEndAction( causer,x,y );
else abortAction(causer,x,y);
return true;
} /* RubberbandMultiPointFeature::applyAndEndAction */
void RubberbandMultiPointFeature::activateButtons()
{
_baseInternal->_hasUndoButton = isEnabledConstructionState();
_baseInternal->_applyIsPossible = ((unsigned int)Rubberband::_internal->_handleList.size() >= _minimumPointCount);
_baseInternal->_undoIsPossible = (isEnabledConstructionState() && ((unsigned int)Rubberband::_internal->_handleList.size() > _minimumPointCount));
Rubberband::activateButtons();
} /* RubberbandMultiPointFeature::activateButtons */
void RubberbandMultiPointFeature::update()
{
Rubberband::update();
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION;
auto handleLine = _internal->_lineHandleList.begin();
bool closePolygon = ((unsigned int)Rubberband::_internal->_handleList.size() > 2) && (isClosedEnabled());
bool firstLoop = !closePolygon;
QColor lineHandleDrawColor = _drawColor;
QColor lineHandleFillColor = _drawColor;
if (_internal->_complexGeometry)
{
lineHandleDrawColor.setAlphaF( lineHandleDrawColor.alphaF()*0.5 );
lineHandleFillColor.setAlphaF( lineHandleFillColor.alphaF()*0.5 );
}
else
{
if (!_previewSidc.isEmpty())
{
lineHandleDrawColor.setAlphaF( 0.0 );
lineHandleFillColor.setAlphaF( 0.0 );
}
}
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)
{
if (handleLine != _internal->_lineHandleList.end())
{
RubberbandHandle::RubberbandCoordinate && pos = handlePointPtr->getCoordinate();
RubberbandLineHandle * handleLinePtr = dynamic_cast<RubberbandLineHandle*>(handleLine->get());
if (!firstLoop)
{
if (handleLinePtr)
{
handleLinePtr -> updateCoordinate( 1, pos._sceneCoordinate );
handleLinePtr -> setDrawColor(lineHandleDrawColor);
handleLinePtr -> setFillColor(lineHandleFillColor);
handleLinePtr -> setSelectionColor(_handleSelectionColor);
handleLinePtr -> setPickingRatio( _pickingRatio );
}
++handleLine;
if (handleLine != _internal->_lineHandleList.end())
{
handleLinePtr = dynamic_cast<RubberbandLineHandle*>(handleLine->get());
}
else handleLinePtr = nullptr;
}
else firstLoop = false;
if (handleLinePtr) handleLinePtr->updateCoordinate( 0, pos._sceneCoordinate );
}
coordinateList.append( handlePointPtr->getCoordinate() );
}
} /* for handlePoint */
// remove superfluous line handles
while (handleLine != _internal->_lineHandleList.end())
{
handleLine = _internal->_lineHandleList.erase( handleLine );
}
if (closePolygon)
{
SituationMap::RefPointer<RubberbandLineHandle> & handleLinePtr = _internal->_lineHandleList.first();
SituationMap::RefPointer<RubberbandHandle> & handlePointPtr = Rubberband::_internal->_handleList.last();
RubberbandHandle::RubberbandCoordinate && pos = dynamic_cast<RubberbandPointHandle*>(handlePointPtr.get())->getCoordinate();
handleLinePtr->updateCoordinate( 0, pos._sceneCoordinate );
if (_fillColor.alpha())
{
if (!_internal->_fillPath)
{
_internal->_fillPath = new DrawablePainterPath( Rubberband::_internal->_mapView );
_internal->_fillPath -> setDrawColor( QColor() );
}
_internal -> _fillPath -> setVisibility( true );
_internal -> _fillPath -> setFillColor(_fillColor );
_internal -> _fillPath -> setPath( coordinateList );
}
else _internal->_fillPath = nullptr;
}
else if (_internal->_fillPath) _internal->_fillPath->setVisibility( false );
if ((isEnabledModificationState()) && (coordinateList.size() >= 2) && (_internal->_frameHandle == nullptr))
{
_internal->_frameHandle = SituationMap::RefPointer<RubberbandFrameHandle>( new RubberbandFrameHandle( Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, _frameHandleMargin ));
}
if (_internal->_frameHandle != nullptr)
{
if (coordinateList.size() >= 2)
{
_internal->_frameHandle -> setDrawColor(_frameColor);
_internal->_frameHandle -> setFillColor(_frameFillColor);
_internal->_frameHandle -> setSelectionColor(_frameSelectionColor);
_internal->_frameHandle -> updateFrameSceneMargin( _frameHandleMargin );
_internal->_frameHandle -> updateFrameShape( coordinateList );
_internal->_frameHandle -> drawDisabled( (_frameHandleMargin < 0) );
}
else _internal->_frameHandle = nullptr;
}
if (!_previewSidc.isEmpty())
{
if (!_internal->_previewSymbol)
{
_internal->_previewSymbol = new TransientTacticalSymbol( static_cast<MapImpl*>(_baseInternal->_map.data()), _previewSidc );
}
_internal->_previewSymbol->update( coordinateList );
}
else _internal->_previewSymbol = nullptr;
} /* RubberbandMultiPointFeature::update */
} } /* namespace SituationMap::RB */