1748 lines
61 KiB
C++
Executable File
1748 lines
61 KiB
C++
Executable File
/**
|
||
* @RDE_HEADER@
|
||
* Rubberband class to define multiple ellipse/circle
|
||
* $Id$
|
||
* $HeadURL$
|
||
* $Author$
|
||
*/
|
||
|
||
#include "rubberband_multi_ellipse_feature.h"
|
||
#include "rubberband_frame_handle.h"
|
||
#include "rubberband_line_handle.h"
|
||
//#include "rubberband_ellipse.h"
|
||
#include "rubberband_ellipse_handle.h"
|
||
#include "rubberband_point_handle.h"
|
||
#include "rubberband_drawable.h"
|
||
#include "rubberband_handle_proxy.h"
|
||
#include "drawable_line.h"
|
||
#include "drawable_ellipse.h"
|
||
#include "drawable_painter_path.h"
|
||
#include "transient_tactical_symbol.h"
|
||
|
||
#include "rubberband_internal.h"
|
||
#include "rubberband_base_internal.h"
|
||
|
||
#include "winkel_icon.xpm"
|
||
|
||
//#include <MathUtils/math_const.h>
|
||
#include <MathUtils/simple_helper.h>
|
||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||
#include <MathUtils/matrix2d.h>
|
||
|
||
#include <arcgis/Map.h>
|
||
|
||
#include <QtCore/QMetaMethod>
|
||
|
||
namespace SituationMap
|
||
{
|
||
namespace RB
|
||
{
|
||
|
||
struct RubberbandMultiEllipseFeature::InternalData
|
||
{
|
||
Q_DISABLE_COPY(InternalData)
|
||
|
||
QList<SituationMap::RefPointer<RubberbandEllipseHandle>> _ellipseHandleList;
|
||
SituationMap::RefPointer<RubberbandFrameHandle> _frameHandle;
|
||
|
||
// sector :
|
||
QPointF _sectorOStart{1, 0};
|
||
QPointF _sectorOEnd{0, 1};
|
||
SituationMap::RefPointer<RubberbandPointHandle> _sectorStartHandle;
|
||
SituationMap::RefPointer<RubberbandPointHandle> _sectorEndHandle;
|
||
bool _sectorEnabled = false;
|
||
bool _sectorFixedAngleEnabled{false};
|
||
|
||
QPointF _oVec{1,0}; // rb: // normalized orientation vector according to scene coordinate system
|
||
// : sector
|
||
|
||
// rotationHandle :
|
||
SituationMap::RefPointer<RubberbandPointHandle> _rotationHandle;
|
||
unsigned int _rotationHandleSize{0};
|
||
// : rotationHandle
|
||
|
||
|
||
// Coordinate matrix to describe the change of coordinates of the last user input
|
||
MathUtils::Matrix2D _lastCoordinateChange;
|
||
|
||
|
||
SituationMap::RefPointer<DrawableEllipse> _previewEllipse;
|
||
SituationMap::RefPointer<TransientTacticalSymbol> _previewSymbol;
|
||
|
||
QVector<RubberbandMultiEllipseFeature::RadiusWithContraints> _preparedRadiiConstraints;
|
||
|
||
bool _complexGeometry;
|
||
bool _addVertexAtEnd;
|
||
bool _showCursorPreviewEllipse;
|
||
bool _constrainQuadratic{true};
|
||
|
||
|
||
InternalData(QGraphicsScene *scene, bool complexGeometry)
|
||
: _complexGeometry(complexGeometry)
|
||
, _addVertexAtEnd(false)
|
||
, _showCursorPreviewEllipse(false)
|
||
{
|
||
Q_UNUSED(scene);
|
||
} // InternalData
|
||
}; // RubberbandMultiEllipseFeature::InternalData
|
||
|
||
QPointF rotateVertex(const QPointF ¢er, qreal x, qreal y, qreal sinA, qreal cosA)
|
||
{
|
||
return QPointF(x*cosA-y*sinA,y*cosA+x*sinA) + center;
|
||
}
|
||
|
||
|
||
RubberbandMultiEllipseFeature::RubberbandMultiEllipseFeature(SituationMap::Map *map, QObject *parent)
|
||
: RubberbandMultiEllipseFeature(map, false, parent)
|
||
{
|
||
}
|
||
|
||
|
||
RubberbandMultiEllipseFeature::RubberbandMultiEllipseFeature(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)
|
||
{
|
||
}
|
||
|
||
|
||
RubberbandMultiEllipseFeature::~RubberbandMultiEllipseFeature()
|
||
{
|
||
delete _internal;
|
||
}
|
||
|
||
RubberbandFrameHandle *RubberbandMultiEllipseFeature::getFrameHandle() const
|
||
{
|
||
return _internal->_frameHandle.get();
|
||
}
|
||
|
||
QPointF RubberbandMultiEllipseFeature::centerCoordinate(CoordinateSystem cs) const
|
||
{
|
||
if (Rubberband::_internal->_handleList.isEmpty())
|
||
return {};
|
||
RubberbandPointHandle *handlePointCenter = dynamic_cast<RubberbandPointHandle *>(Rubberband::_internal->_handleList.first().get());
|
||
|
||
if (!handlePointCenter)
|
||
return {};
|
||
|
||
return projectCoordinateFromMap(cs, handlePointCenter->getCoordinate()._mapCoordinate);
|
||
}
|
||
|
||
QVector<QPointF> RubberbandMultiEllipseFeature::radii() const
|
||
{
|
||
QPointF center = centerCoordinate(CoordinateSystem::Map);
|
||
if (center.isNull())
|
||
return {};
|
||
if (_internal->_ellipseHandleList.isEmpty())
|
||
return {};
|
||
|
||
QVector<QPointF> ret;
|
||
ret.reserve(_internal->_ellipseHandleList.size());
|
||
|
||
for (SituationMap::RefPointer<RubberbandEllipseHandle> handle : qAsConst(_internal->_ellipseHandleList))
|
||
{
|
||
if (!handle)
|
||
continue;
|
||
ret.append(handle->getRadius());
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
QPointF RubberbandMultiEllipseFeature::getBiggestRadius() const
|
||
{
|
||
QPointF max(0,0);
|
||
const QVector<QPointF> &radiiCont = radii();
|
||
|
||
for (const QPointF &item : qAsConst(radiiCont))
|
||
{
|
||
max.setX( std::max(max.x(), item.x()) );
|
||
max.setY( std::max(max.y(), item.y()) );
|
||
}
|
||
return max;
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::setCenterAndRadii(const QPointF ¢er, CoordinateSystem cs,
|
||
const QVector<QPointF> &radii)
|
||
{
|
||
if (center.isNull() || radii.isEmpty())
|
||
return false;
|
||
|
||
const QPointF &myCenter = projectCoordinateToMap(cs, center);
|
||
|
||
QVector<QPointF> coordinateVector;
|
||
coordinateVector.reserve(radii.size()+1);
|
||
|
||
// Center:
|
||
coordinateVector.append(myCenter);
|
||
|
||
// radii:
|
||
for (const QPointF& radius : qAsConst(radii))
|
||
coordinateVector.append(myCenter + radius);
|
||
|
||
setCoordinateVector(coordinateVector, CoordinateSystem::Map);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::setCenterAndRadii2(const QPointF ¢er, CoordinateSystem cs,
|
||
const QVector<RubberbandMultiEllipseFeature::RadiusWithContraints> &radiiWithConstraints)
|
||
{
|
||
if (center.isNull() || radiiWithConstraints.isEmpty())
|
||
return false;
|
||
|
||
const QPointF &myCenter = projectCoordinateToMap(cs, center);
|
||
|
||
QVector<QPointF> coordinateVector;
|
||
coordinateVector.reserve(radiiWithConstraints.size()+1);
|
||
|
||
// Center:
|
||
coordinateVector.append(myCenter);
|
||
|
||
// Center with the radii:
|
||
for (const RubberbandMultiEllipseFeature::RadiusWithContraints& radiusItem : qAsConst(radiiWithConstraints))
|
||
if (radiusItem.m_radius > 0)
|
||
coordinateVector.append(myCenter + QPointF(radiusItem.m_radius, radiusItem.m_radius));
|
||
|
||
|
||
Rubberband::_internal->_handleList.clear();
|
||
for (const auto &p : coordinateVector)
|
||
constructPoint(p, CoordinateSystem::Map);
|
||
|
||
// are we still in construction or in modification?
|
||
// from scratch: constraints are provided, but no radius
|
||
// predefined: radius is provided, maybe constraints
|
||
if (coordinateVector.size() > 1)
|
||
enableModificationState();
|
||
update();
|
||
activateButtons();
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
void RubberbandMultiEllipseFeature::prepareFixedNumberOfRadiiWithConstraints(const QVector<RubberbandMultiEllipseFeature::RadiusWithContraints> &radiiContraints)
|
||
{
|
||
// for creation from scratch, just min/max should be prepared.
|
||
// for creation with predefined values, the m_radius is relevant.
|
||
_internal->_preparedRadiiConstraints = radiiContraints;
|
||
}
|
||
|
||
|
||
QPointF RubberbandMultiEllipseFeature::getRotatedPoint(const QPointF §or) const
|
||
{
|
||
// Rotation of entire Rubberband
|
||
qreal sinRect = 0, cosRect = 1;
|
||
getSceneRotation(sinRect, cosRect);
|
||
const double angleRad = SituationMap::MathUtils::getMathAngle(QPointF(cosRect, sinRect)); // angle rad
|
||
const double clockwiseAngleRad = ((2*LtsCoordTrans::pi()) - angleRad); // angle in rad;
|
||
|
||
// map clockwise rotation
|
||
QPointF point;
|
||
point.setX( sector.x()*std::cos(clockwiseAngleRad) + sector.y()*std::sin(clockwiseAngleRad));
|
||
point.setY( -sector.x()*std::sin(clockwiseAngleRad) + sector.y()*std::cos(clockwiseAngleRad));
|
||
|
||
return point;
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::enableSector(bool on)
|
||
{
|
||
_internal->_sectorEnabled = on;
|
||
}
|
||
bool RubberbandMultiEllipseFeature::isSectorEnabled() const
|
||
{
|
||
return _internal->_sectorEnabled;
|
||
}
|
||
|
||
QPointF RubberbandMultiEllipseFeature::sectorStart() const
|
||
{
|
||
return getRotatedPoint(_internal->_sectorOStart);
|
||
}
|
||
|
||
qreal RubberbandMultiEllipseFeature::sectorStartDegMath() const
|
||
{
|
||
const QPointF &point = sectorStart();
|
||
return MathUtils::getMathAngle(point) * LtsCoordTrans::rad2deg();
|
||
}
|
||
|
||
QPointF RubberbandMultiEllipseFeature::sectorEnd() const
|
||
{
|
||
return getRotatedPoint(_internal->_sectorOEnd);
|
||
}
|
||
|
||
qreal RubberbandMultiEllipseFeature::sectorEndDegMath() const
|
||
{
|
||
const QPointF &point = sectorEnd();
|
||
return MathUtils::getMathAngle(point) * LtsCoordTrans::rad2deg();
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::setSectorStart(qreal sinPhi, qreal cosPhi)
|
||
{
|
||
_internal->_sectorOStart = QPointF(cosPhi, sinPhi);
|
||
enableSelectedState();
|
||
update();
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::setSectorEnd(qreal sinPhi, qreal cosPhi)
|
||
{
|
||
_internal->_sectorOEnd = QPointF(cosPhi, sinPhi);
|
||
enableSelectedState();
|
||
update();
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::setSectorAngleFixed(bool on)
|
||
{
|
||
_internal->_sectorFixedAngleEnabled = on;
|
||
update();
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::isSectorFixedAngeEnabled() const
|
||
{
|
||
return _internal->_sectorFixedAngleEnabled;
|
||
}
|
||
|
||
QVector<QPointF> RubberbandMultiEllipseFeature::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;
|
||
}
|
||
|
||
QPointF RubberbandMultiEllipseFeature::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();
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::setCoordinateVector(const QVector<QPointF> &coordinateVector, CoordinateSystem cs)
|
||
{
|
||
Rubberband::_internal->_handleList.clear();
|
||
|
||
for (const auto &p : coordinateVector)
|
||
constructPoint(p, cs);
|
||
enableModificationState();
|
||
update();
|
||
activateButtons();
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::getRadiusXY(const QPointF &scenePos, qreal &radiusX_out, qreal &radiusY_out)
|
||
{
|
||
if (Rubberband::_internal->_handleList.isEmpty())
|
||
return false;
|
||
|
||
RubberbandPointHandle *handlePointCenter = dynamic_cast<RubberbandPointHandle *>(Rubberband::_internal->_handleList.first().get());
|
||
if (!handlePointCenter)
|
||
return false;
|
||
|
||
const RubberbandHandle::RubberbandCoordinate &mapCenter = handlePointCenter->getCoordinate();
|
||
RubberbandHandle::RubberbandCoordinate currentMapPos(Rubberband::_internal->_mapView, scenePos);
|
||
|
||
radiusX_out = fabs(mapCenter._mapCoordinate.x() - currentMapPos._mapCoordinate.x());
|
||
radiusY_out = fabs(mapCenter._mapCoordinate.y() - currentMapPos._mapCoordinate.y());
|
||
return true;
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::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);
|
||
}
|
||
}
|
||
|
||
RubberbandHandle *RubberbandMultiEllipseFeature::constructPoint(const QPointF &scenePos)
|
||
{
|
||
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION
|
||
<< " RubberbandMultiEllipseFeature::constructPoint, _handleList.size " << Rubberband::_internal->_handleList.size();
|
||
RubberbandHandle *handlePtr{nullptr};
|
||
|
||
if ((_maximumPointCount>0) && ((unsigned int)Rubberband::_internal->_handleList.size() >= _maximumPointCount))
|
||
{
|
||
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " skip due to _maximumPointCount (_sectorInputIsRunning)";
|
||
return nullptr;
|
||
}
|
||
|
||
|
||
if (!Rubberband::_internal->_handleList.empty())
|
||
{
|
||
handlePtr = Rubberband::_internal->_handleList.first().get();
|
||
if (handlePtr)
|
||
{
|
||
// center == first
|
||
const RubberbandHandle::RubberbandCoordinate &firstPosCenterPos = static_cast<RubberbandPointHandle *>(handlePtr)->getCoordinate();
|
||
|
||
qreal radiusX_out, radiusY_out;
|
||
if (getRadiusXY(scenePos, radiusX_out, radiusY_out))
|
||
{
|
||
bool minMaxOk = checkMinMaxRadiusConstraint(radiusX_out, radiusY_out);
|
||
if (minMaxOk)
|
||
{
|
||
RubberbandEllipseHandle *temp = new RubberbandEllipseHandle(Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene);
|
||
|
||
if (_internal->_constrainQuadratic)
|
||
radiusX_out = radiusY_out = std::max(radiusX_out, radiusY_out);
|
||
|
||
temp->setRect(firstPosCenterPos, radiusX_out, radiusY_out, 0, 1);
|
||
|
||
QColor fillColor = _fillColor;
|
||
fillColor.setAlphaF(_fillColor.alphaF()*0.5);
|
||
temp->setFillColor(fillColor);
|
||
|
||
QColor selectionColor = _handleSelectionColor;
|
||
selectionColor.setAlphaF(_handleSelectionColor.alphaF()*0.5);
|
||
temp->setSelectionColor(selectionColor);
|
||
|
||
_internal->_ellipseHandleList.append(RefPointer<RubberbandEllipseHandle>(static_cast<RubberbandEllipseHandle *>(temp)));
|
||
} else {
|
||
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION
|
||
<< " SKIP RubberbandMultiEllipseFeature::constructPoint, "
|
||
<< ", radiusX_out" << radiusX_out << ", radiusY_out" << radiusY_out;
|
||
return nullptr;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// RubberbandPointHandle einfügen
|
||
//
|
||
handlePtr = new RubberbandPointHandle(Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, scenePos);
|
||
handlePtr->setSelection();
|
||
handlePtr->setIsFirst(Rubberband::_internal->_handleList.empty()); // mark centerPoint with 'isFirst' to simplify later recognation
|
||
Rubberband::_internal->_handleList.append(SituationMap::RefPointer<RubberbandHandle>(handlePtr));
|
||
|
||
// activateButtons?
|
||
if ((unsigned int)Rubberband::_internal->_handleList.size() >= _minimumPointCount)
|
||
activateButtons();
|
||
|
||
if ((!_maximumPointCount) || ((unsigned int)Rubberband::_internal->_handleList.size() < _maximumPointCount))
|
||
{
|
||
if (!_internal->_previewEllipse)
|
||
_internal->_previewEllipse = new DrawableEllipse(Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene);
|
||
_internal->_previewEllipse->setVisibility(true);
|
||
}
|
||
else
|
||
{
|
||
_internal->_previewEllipse = nullptr;
|
||
}
|
||
return handlePtr;
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::checkLengthConstrains(const QPointF &scenePos, const QPointF &deltaScenePos)
|
||
{
|
||
Q_UNUSED(scenePos);
|
||
Q_UNUSED(deltaScenePos);
|
||
return true;
|
||
|
||
/*
|
||
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;
|
||
}
|
||
|
||
//
|
||
// check totalLength
|
||
//
|
||
if (_maximumLength > 0.0)
|
||
{
|
||
qreal totalLength = 0.0;
|
||
const Esri::ArcGISRuntime::Point *lastMapCoord = nullptr; // Check Quartz
|
||
for (int i = 0; i < coordinateVector.size(); ++i)
|
||
{
|
||
const RubberbandHandle::RubberbandCoordinate &coordinate = coordinateVector[i];
|
||
if (lastMapCoord)
|
||
{
|
||
qreal x = coordinate._mapCoordinate.x() - lastMapCoord->x();
|
||
qreal y = coordinate._mapCoordinate.y() - lastMapCoord->y();
|
||
|
||
totalLength += sqrt(x * x + y * y);
|
||
}
|
||
lastMapCoord = &coordinateVector.at(i)._mapCoordinate;
|
||
}
|
||
if (totalLength > _maximumLength)
|
||
{
|
||
markFailedConstrains(scenePos, true);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
//
|
||
// check maximumSegmentLength
|
||
//
|
||
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 (_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;
|
||
*/
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::checkMinMaxRadiusConstraint(const QPointF &curScenePos)
|
||
{
|
||
qreal radiusX_out, radiusY_out;
|
||
if (!getRadiusXY(curScenePos, radiusX_out, radiusY_out))
|
||
return true;
|
||
|
||
if (_internal->_constrainQuadratic)
|
||
radiusX_out = radiusY_out = std::max(radiusX_out, radiusY_out);
|
||
|
||
return checkMinMaxRadiusConstraint(radiusX_out, radiusY_out);
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::checkMinMaxRadiusConstraint(qreal radiusX, qreal radiusY, int idxOfConstraint)
|
||
{
|
||
// Which radius is relevant?
|
||
if (idxOfConstraint < 0)
|
||
idxOfConstraint = Rubberband::_internal->_handleList.size() - 1; // '-1' - keep handle for center (isFirst) in mind
|
||
|
||
if ((idxOfConstraint < 0) || (idxOfConstraint >= _internal->_preparedRadiiConstraints.size()))
|
||
return true;
|
||
|
||
const RadiusWithContraints &curConstraints = _internal->_preparedRadiiConstraints[idxOfConstraint];
|
||
|
||
// qCritical() << " radiusX = " << radiusX;
|
||
// qCritical() << " radiusY = " << radiusY;
|
||
|
||
bool bMinOk = true;
|
||
double minRadius = curConstraints.m_minRadius;
|
||
if (minRadius > 0)
|
||
bMinOk = ((radiusX >= minRadius) && (radiusY >= minRadius));
|
||
|
||
bool bMaxOk = true;
|
||
double maxRadius = curConstraints.m_maxRadius;
|
||
if (maxRadius > 0)
|
||
bMaxOk = ((radiusX <= maxRadius) && (radiusY <= maxRadius));
|
||
|
||
if (!bMinOk)
|
||
INFO_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " checkMinMaxRadiusConstraintNew false by bMinOk"
|
||
<< ", idxOfConstraint=" << idxOfConstraint
|
||
<< ", radiusX=" << radiusX << ", radiusY=" << radiusY
|
||
<< ", minRadius=" << minRadius << ", maxRadius=" << maxRadius;
|
||
if (!bMaxOk)
|
||
INFO_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " checkMinMaxRadiusConstraintNew false by bMaxOk"
|
||
<< ", idxOfConstraint=" << idxOfConstraint
|
||
<< ", radiusX=" << radiusX << ", radiusY=" << radiusY
|
||
<< ", minRadius=" << minRadius << ", maxRadius=" << maxRadius;
|
||
return bMinOk && bMaxOk;
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::checkLengthConstrains(unsigned int checkHandleIdx, const QPointF &scenePos)
|
||
{
|
||
Q_UNUSED(checkHandleIdx);
|
||
|
||
if (!checkMinMaxRadiusConstraint(scenePos))
|
||
{
|
||
markFailedConstrains(scenePos, true);
|
||
return false;
|
||
}
|
||
markFailedConstrains(QPoint(), true);
|
||
|
||
return true;
|
||
|
||
// return true -> construct point
|
||
// return false -> don not construct point
|
||
|
||
/*
|
||
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))
|
||
{
|
||
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);
|
||
}
|
||
}
|
||
|
||
// check radius
|
||
if (!checkMinMaxRadiusConstraint(scenePos))
|
||
{
|
||
markFailedConstrains(scenePos, true);
|
||
return false;
|
||
|
||
// markFailedConstrainsFlag = true;
|
||
// return true;
|
||
}
|
||
|
||
markFailedConstrains(scenePos, markFailedConstrainsFlag);
|
||
|
||
return true;
|
||
*/
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::selectHandles(int x, int y, const QPointF &scenePos)
|
||
{
|
||
bool eventHandled = false;
|
||
RubberbandHandle *handlePtr = pickHandle(x, y);
|
||
|
||
_internal->_addVertexAtEnd = false;
|
||
|
||
if (handlePtr && handlePtr->isVisible())
|
||
{
|
||
handlePtr->setSelection();
|
||
enableSelectedState();
|
||
eventHandled = true;
|
||
}
|
||
|
||
if (!isEnabledSelectedState())
|
||
{
|
||
// ok doesn't hit any point or line handle now looking to frame handle
|
||
if (_internal->_frameHandle && _internal->_frameHandle->isPositionInside(scenePos))
|
||
{
|
||
_internal->_frameHandle->setSelection(true);
|
||
enableSelectedState();
|
||
eventHandled = true;
|
||
}
|
||
|
||
if (_internal->_rotationHandle && _internal->_rotationHandle->isPositionInside(scenePos))
|
||
{
|
||
_internal->_rotationHandle->setSelection(true);
|
||
enableSelectedState();
|
||
eventHandled = true;
|
||
}
|
||
}
|
||
return eventHandled;
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::updateHandles(const QPointF &scenePos, const QPointF &deltaMove)
|
||
{
|
||
Q_UNUSED(deltaMove);
|
||
bool constrainsComplied = true;
|
||
|
||
if (Rubberband::_internal->_handleList.size() < 2)
|
||
return;
|
||
|
||
if ((_internal->_rotationHandle.valid()) && _internal->_rotationHandle->isSelected())
|
||
{
|
||
const RubberbandPointHandle *handlePointPtr = dynamic_cast<RubberbandPointHandle *>(Rubberband::_internal->_handleList.first().get());
|
||
if (!handlePointPtr)
|
||
return;
|
||
const RubberbandHandle::RubberbandCoordinate &mapCenter = handlePointPtr->getCoordinate();
|
||
|
||
|
||
// _internal->_centerScene --> centerScene
|
||
const QPointF ¢erScene = mapCenter._sceneCoordinate;
|
||
const Esri::ArcGISRuntime::Point ¢erMapCoords = mapCenter._mapCoordinate;
|
||
const QPointF centerMapCoordsAsPointF(centerMapCoords.x(), centerMapCoords.y());
|
||
|
||
qreal sinA = scenePos.x() - centerScene.x(); // _internal->_centerScene.x();
|
||
qreal cosA = - scenePos.y() + centerScene.y();
|
||
qreal len = sqrt(cosA*cosA+sinA*sinA);
|
||
|
||
cosA /= len;
|
||
sinA /= len;
|
||
|
||
// for circle it´s not really helpfull to rotate the handles -> skip here
|
||
// for (auto handle : qAsConst(Rubberband::_internal->_handleList))
|
||
// {
|
||
// RubberbandPointHandle *handlePointPtr = dynamic_cast<RubberbandPointHandle*>(handle.get());
|
||
// if (!handlePointPtr)
|
||
// continue;
|
||
|
||
// QPointF p = MathUtils::rotate( handlePointPtr->getCoordinate()._sceneCoordinate, centerScene, -_internal->_oVec.y(), _internal->_oVec.x() );
|
||
// p = MathUtils::rotate( p, centerScene, sinA, cosA );
|
||
// handlePointPtr->updateCoordinate( p );
|
||
|
||
// p.setX( handlePointPtr->getCoordinate()._mapCoordinate.x() );
|
||
// p.setY( handlePointPtr->getCoordinate()._mapCoordinate.y() );
|
||
// } // for
|
||
|
||
qreal dSin = sinA*_internal->_oVec.x() - cosA*_internal->_oVec.y(); // addition theorem
|
||
qreal dCos = cosA*_internal->_oVec.x() + sinA*_internal->_oVec.y();
|
||
|
||
_internal->_lastCoordinateChange.setToIdentity(); // clear matrix
|
||
_internal->_lastCoordinateChange.putTranslation( -centerMapCoordsAsPointF ); // move center to (0,0)
|
||
_internal->_lastCoordinateChange.putRotate( QPointF(dCos, dSin) ); // do rotation
|
||
_internal->_lastCoordinateChange.putTranslation( centerMapCoordsAsPointF ); // move center back
|
||
|
||
_internal->_oVec.setX(cosA);
|
||
_internal->_oVec.setY(sinA);
|
||
|
||
_baseInternal->_lastClickPosition = scenePos;
|
||
}
|
||
|
||
markFailedConstrains( scenePos, !constrainsComplied );
|
||
|
||
update();
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::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);
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::selectAction(AbstractEventDispatcher *, int x, int y)
|
||
{
|
||
if (rubberbandIsAlive())
|
||
{
|
||
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " selectAction";
|
||
|
||
QPointF scenePos(pixel2ScenePosition(x, y));
|
||
|
||
// starting a rubberband with radii prepared but without center?
|
||
if (!_internal->_preparedRadiiConstraints.isEmpty() && Rubberband::_internal->_handleList.isEmpty())
|
||
{
|
||
RubberbandDrawable::RubberbandCoordinate rbC(Rubberband::_internal->_mapView, scenePos);
|
||
setCenterAndRadii2(QPointF(rbC._mapCoordinate.x(), rbC._mapCoordinate.y()), CoordinateSystem::Map,
|
||
_internal->_preparedRadiiConstraints);
|
||
enableSelectedState();
|
||
|
||
_internal->_addVertexAtEnd = true;
|
||
_internal->_showCursorPreviewEllipse = true;
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
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->_showCursorPreviewEllipse = 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;
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::setCoordinateAction(AbstractEventDispatcher *causer, int x, int y)
|
||
{
|
||
Q_UNUSED(causer);
|
||
|
||
if ((rubberbandIsAlive()) && (Rubberband::_internal->_mapView) && (Rubberband::_internal->_mapScene))
|
||
{
|
||
QPointF scenePos(pixel2ScenePosition(x, y));
|
||
Rubberband::_internal->_lastClickPosition = scenePos;
|
||
|
||
if (Rubberband::_internal->_handleList.isEmpty())
|
||
{
|
||
disenableSelectedState();
|
||
disenableMultiSelectedState();
|
||
return false;
|
||
}
|
||
}
|
||
return false;
|
||
|
||
|
||
// -----------------------------------
|
||
/*
|
||
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))
|
||
{
|
||
INFO_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " do Sector now...";
|
||
|
||
_internal->_showCursorPreviewEllipse = false;
|
||
// continue contructionState, so we are able to move the whole object by moving the first handle (center)
|
||
|
||
// reset _lastClickPosition to improve ButtonPosition
|
||
_baseInternal->_lastClickPosition = QPointF(-1,-1);
|
||
|
||
// remove former selection:
|
||
for (SituationMap::RefPointer<RubberbandEllipseHandle> handle : qAsConst(_internal->_ellipseHandleList))
|
||
if (handle)
|
||
handle->setSelection(false);
|
||
deSelectHandles();
|
||
|
||
update();
|
||
|
||
// do not complete
|
||
// return false;
|
||
// 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->_showCursorPreviewEllipse = true;
|
||
|
||
updatePreviewEllipse(scenePos);
|
||
}
|
||
else if (_baseInternal->buttonProxyActive(scenePos))
|
||
return false;
|
||
|
||
if (eventHandled)
|
||
update();
|
||
updateButtonPosition();
|
||
activateButtons();
|
||
|
||
}
|
||
return eventHandled;
|
||
}
|
||
return false;
|
||
*/
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::updatePreviewEllipse(const QPointF &scenePosition)
|
||
{
|
||
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " START";
|
||
// qCritical() << " RubberbandMultiEllipseFeature::updatePreviewEllipse"
|
||
// << ", scenePosition " << scenePosition
|
||
// << ", _addVertexAtEnd " << _internal->_addVertexAtEnd
|
||
// << ", isEnabledConstructionState " << isEnabledConstructionState()
|
||
// << " _internal->_handleList.size() " <<Rubberband::_internal->_handleList.size()
|
||
// << " _ellipseHandleList.size() " <<_internal->_ellipseHandleList.size();
|
||
|
||
if (isEnabledConstructionState() && (!Rubberband::_internal->_handleList.isEmpty()) && (_internal->_previewEllipse))
|
||
{
|
||
// center / first point
|
||
RubberbandPointHandle *handlePointPtr = dynamic_cast<RubberbandPointHandle *>(Rubberband::_internal->_handleList.first().get());
|
||
if ((handlePointPtr) && (_internal->_addVertexAtEnd))
|
||
{
|
||
RubberbandHandle::RubberbandCoordinate mapCenter = handlePointPtr->getCoordinate();
|
||
RubberbandDrawable::RubberbandCoordinate rbCoordinate(Rubberband::_internal->_mapView, scenePosition);
|
||
|
||
_internal->_previewEllipse->setVisibility(_internal->_showCursorPreviewEllipse);
|
||
_internal->_previewEllipse->setDrawColor(_handleSelectionColor);
|
||
|
||
int distX = fabs(mapCenter._mapCoordinate.x() - rbCoordinate._mapCoordinate.x());
|
||
int distY = fabs(mapCenter._mapCoordinate.y() - rbCoordinate._mapCoordinate.y());
|
||
if (_internal->_constrainQuadratic)
|
||
distX = distY = std::max(distX, distY);
|
||
_internal->_previewEllipse->setRect(QPointF(mapCenter._mapCoordinate.x(), mapCenter._mapCoordinate.y()),
|
||
distX, distY, 0, 1);
|
||
|
||
// sync FrameHandle:
|
||
updateFrameHandle(scenePosition);
|
||
}
|
||
else
|
||
{
|
||
_internal->_previewEllipse->setVisibility(false);
|
||
}
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
_internal->_previewEllipse = nullptr;
|
||
}
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::moveAction(AbstractEventDispatcher *, int x, int y)
|
||
{
|
||
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " START";
|
||
|
||
adjustConnectedPreviewPixmap(x, y);
|
||
|
||
if (rubberbandIsAlive())
|
||
{
|
||
QPointF scenePosition(pixel2ScenePosition(x, y));
|
||
|
||
//------------------------------
|
||
// sectorStartHand, _sectorEndHandle
|
||
{
|
||
if (_internal->_sectorStartHandle.valid())
|
||
{
|
||
if (_internal->_sectorStartHandle->isPositionInside(scenePosition))
|
||
{
|
||
_internal->_sectorStartHandle->setSelection(true);
|
||
_internal->_frameHandle = nullptr;
|
||
update();
|
||
return false;
|
||
}
|
||
else
|
||
_internal->_sectorStartHandle->setSelection(false);
|
||
}
|
||
if (_internal->_sectorEndHandle.valid())
|
||
{
|
||
if (_internal->_sectorEndHandle->isPositionInside(scenePosition))
|
||
{
|
||
_internal->_sectorEndHandle->setSelection(true);
|
||
_internal->_frameHandle = nullptr;
|
||
update();
|
||
return false;
|
||
}
|
||
else
|
||
_internal->_sectorEndHandle->setSelection(false);
|
||
}
|
||
}
|
||
//------------------------------
|
||
//------------------------------
|
||
//------------------------------
|
||
|
||
//------------------------------
|
||
if (_internal->_rotationHandle.valid())
|
||
_internal->_rotationHandle->setSelection(_internal->_rotationHandle->isPositionInside(scenePosition));
|
||
|
||
|
||
if (_baseInternal->buttonProxyActive(scenePosition))
|
||
return false;
|
||
if (!Rubberband::_internal->_mapView)
|
||
return false;
|
||
|
||
if (!isEnabledMultiSelectedState())
|
||
deSelectHandles();
|
||
|
||
RubberbandHandle *handlePtr = pickHandle(x, y);
|
||
if (!handlePtr)
|
||
{
|
||
_internal->_showCursorPreviewEllipse = isEnabledConstructionState();
|
||
}
|
||
else
|
||
{
|
||
_internal->_showCursorPreviewEllipse = false;
|
||
|
||
// set handlePtr selected...
|
||
handlePtr->setSelection();
|
||
|
||
// and updateFrameHandle if not first handle:
|
||
RubberbandPointHandle *handlePointPtr = dynamic_cast<RubberbandPointHandle *>(handlePtr);
|
||
if (handlePointPtr)
|
||
{
|
||
if (handlePointPtr->isFirst())
|
||
updateFrameHandle({});
|
||
else
|
||
updateFrameHandle(handlePointPtr->getCoordinate()._sceneCoordinate);
|
||
}
|
||
}
|
||
|
||
if (isEnabledConstructionState())
|
||
{
|
||
if (checkLengthConstrains(1, scenePosition))
|
||
{
|
||
updatePreviewEllipse(scenePosition);
|
||
|
||
if (isSignalConnected(QMetaMethod::fromSignal(&RubberbandMultiEllipseFeature::currentCursorPositionChanged)))
|
||
{
|
||
RubberbandDrawable::RubberbandCoordinate mapCoord(Rubberband::_internal->_mapView, scenePosition);
|
||
emit currentCursorPositionChanged(Point3D(mapCoord._mapCoordinate.x(), mapCoord._mapCoordinate.y(), 0.0));
|
||
}
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::movePickedAction(AbstractEventDispatcher *, int x, int y)
|
||
{
|
||
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " START"
|
||
<< ", isEnabledSelectedState " << isEnabledSelectedState();
|
||
|
||
adjustConnectedPreviewPixmap(x, y);
|
||
|
||
if ((rubberbandIsAlive()) && (Rubberband::_internal->_mapView) && (Rubberband::_internal->_mapScene))
|
||
{
|
||
QPointF scenePos(pixel2ScenePosition(x,y));
|
||
|
||
updateHandles(scenePos, scenePos-_baseInternal->_lastClickPosition);
|
||
|
||
|
||
if (isEnabledSelectedState())
|
||
{
|
||
// sectorHandles:
|
||
if (!isSectorFixedAngeEnabled())
|
||
{
|
||
auto updateHandle = [this](RubberbandPointHandle * handle, const RubberbandHandle::RubberbandCoordinate & pos, QPointF & oVector ) -> bool
|
||
{
|
||
if (!handle)
|
||
return false;
|
||
if (!handle->isSelected())
|
||
return false;
|
||
|
||
RubberbandPointHandle *handlePointCenter = dynamic_cast<RubberbandPointHandle *>(Rubberband::_internal->_handleList.first().get());
|
||
if (!handlePointCenter)
|
||
return false;
|
||
const RubberbandHandle::RubberbandCoordinate &mapCenter = handlePointCenter->getCoordinate();
|
||
|
||
qreal sinRect = 0;
|
||
qreal cosRect = 1;
|
||
getSceneRotation( sinRect, cosRect);
|
||
|
||
qreal cosA = pos._mapCoordinate.x() - mapCenter._mapCoordinate.x();
|
||
qreal sinA = pos._mapCoordinate.y() - mapCenter._mapCoordinate.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
|
||
|
||
RubberbandHandle::RubberbandCoordinate pos(Rubberband::_internal->_mapView, scenePos);
|
||
updateHandle( _internal->_sectorStartHandle.get(), pos, _internal->_sectorOStart);
|
||
updateHandle( _internal->_sectorEndHandle.get() , pos, _internal->_sectorOEnd );
|
||
}
|
||
// // return true;
|
||
//------------------------------
|
||
//------------------------------
|
||
//------------------------------
|
||
|
||
// look for (first) selected PointHandle:
|
||
RubberbandPointHandle *selectedPointHandlePtr{nullptr};
|
||
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
|
||
{
|
||
RubberbandPointHandle *handlePointPtr = dynamic_cast<RubberbandPointHandle *>(handle.get());
|
||
if (!handlePointPtr)
|
||
continue;
|
||
if (handlePointPtr->isSelected())
|
||
selectedPointHandlePtr = handlePointPtr;
|
||
} // for
|
||
const bool bFirstHandlePointSelected = (selectedPointHandlePtr && selectedPointHandlePtr->isFirst());
|
||
|
||
|
||
RubberbandHandle::RubberbandCoordinate rcNewCorner;
|
||
|
||
// nur wenn _constrainQuadratic UND nicht der 'isFirst'/centerPoint
|
||
if (_internal->_constrainQuadratic && !bFirstHandlePointSelected)
|
||
{
|
||
RubberbandPointHandle *handlePointPtr = dynamic_cast<RubberbandPointHandle *>(Rubberband::_internal->_handleList.first().get());
|
||
if (!handlePointPtr)
|
||
return false;
|
||
|
||
const RubberbandHandle::RubberbandCoordinate &mapCenter = handlePointPtr->getCoordinate();
|
||
|
||
qreal radiusX, radiusY;
|
||
if (getRadiusXY(scenePos, radiusX, radiusY))
|
||
radiusX = radiusY = std::max(radiusX, radiusY);
|
||
|
||
|
||
RefPointer<RubberbandHandle> refPtr(selectedPointHandlePtr);
|
||
int idx = Rubberband::_internal->_handleList.indexOf(refPtr);
|
||
if (idx > 0)
|
||
{
|
||
if (!checkMinMaxRadiusConstraint(radiusX, radiusY, idx-1))
|
||
{
|
||
update(); // show/create preview!?
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// adjusted coord: (prefer topRight)
|
||
Esri::ArcGISRuntime::Point newCorner(mapCenter._mapCoordinate.x()+radiusX,
|
||
mapCenter._mapCoordinate.y()+radiusY,
|
||
mapCenter._mapCoordinate.spatialReference());
|
||
|
||
rcNewCorner = RubberbandHandle::RubberbandCoordinate(Rubberband::_internal->_mapView, newCorner);
|
||
}
|
||
|
||
|
||
QPointF deltaMove(scenePos - _baseInternal->_lastClickPosition);
|
||
if (checkLengthConstrains(scenePos, deltaMove))
|
||
{
|
||
const bool frameIsSelected(((_internal->_frameHandle) && (_internal->_frameHandle->isSelected())));
|
||
const bool moveAll = bFirstHandlePointSelected;
|
||
|
||
_baseInternal->_lastClickPosition = scenePos;
|
||
|
||
for (auto handle : qAsConst(Rubberband::_internal->_handleList))
|
||
{
|
||
RubberbandPointHandle *handlePointPtr = dynamic_cast<RubberbandPointHandle *>(handle.get());
|
||
if ((handlePointPtr) && ((handlePointPtr->isSelected()) || (frameIsSelected||moveAll)))
|
||
{
|
||
if (rcNewCorner.isNull())
|
||
handlePointPtr->moveCoordinate(deltaMove);
|
||
else
|
||
handlePointPtr->setCoordinate(rcNewCorner);
|
||
}
|
||
}
|
||
updatePreviewEllipse(scenePos);
|
||
update();
|
||
}
|
||
return true;
|
||
}
|
||
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::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;
|
||
|
||
QPointF scenePosition = pixel2ScenePosition(x, y);
|
||
QList<SituationMap::RefPointer<RubberbandHandle>>::iterator handleIter = Rubberband::_internal->_handleList.begin();
|
||
|
||
while (handleIter != Rubberband::_internal->_handleList.end())
|
||
{
|
||
if (handleIter->get()->isPositionInside(scenePosition))
|
||
{
|
||
handleIter = Rubberband::_internal->_handleList.erase(handleIter);
|
||
updateFrameHandle({});
|
||
continue;
|
||
}
|
||
++handleIter;
|
||
} // while handleIter
|
||
|
||
if (!checkLengthConstrains(scenePosition, QPointF(0, 0)))
|
||
{
|
||
// constrain failed, do not delete yet
|
||
Rubberband::_internal->_handleList = savedHandleList;
|
||
}
|
||
update();
|
||
activateButtons();
|
||
|
||
disenableSelectedState();
|
||
disenableMultiSelectedState();
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::contextMenuAction(AbstractEventDispatcher *, int, int)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
|
||
bool RubberbandMultiEllipseFeature::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->_previewEllipse = nullptr; // remove preview
|
||
}
|
||
update();
|
||
return true;
|
||
}
|
||
}
|
||
|
||
if ((unsigned int)Rubberband::_internal->_handleList.size() >= _minimumPointCount)
|
||
return applyAndEndAction(causer, x, y);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::undoAction(AbstractEventDispatcher * /*causer*/, int, int)
|
||
{
|
||
if (rubberbandIsAlive())
|
||
{
|
||
if (!Rubberband::_internal->_handleList.empty())
|
||
{
|
||
if (isEnabledConstructionState())
|
||
{
|
||
Rubberband::_internal->_handleList.pop_back();
|
||
if (!_internal->_ellipseHandleList.empty())
|
||
_internal->_ellipseHandleList.pop_back();
|
||
|
||
if (_internal->_previewEllipse)
|
||
_internal->_previewEllipse->setVisibility(false);
|
||
|
||
update();
|
||
activateButtons();
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool RubberbandMultiEllipseFeature::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;
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::constrainQuadratic(bool on)
|
||
{
|
||
_internal->_constrainQuadratic = on;
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::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();
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::update()
|
||
{
|
||
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " START";
|
||
|
||
Rubberband::update();
|
||
|
||
// update _ellipseHandleList according _handleList: (context modification)
|
||
|
||
RubberbandHandle::RubberbandCoordinate centerCoord;
|
||
if (!Rubberband::_internal->_handleList.isEmpty())
|
||
{
|
||
RubberbandPointHandle *handlePointPtr = dynamic_cast<RubberbandPointHandle *>(Rubberband::_internal->_handleList.first().get());
|
||
centerCoord = handlePointPtr->getCoordinate();
|
||
}
|
||
|
||
//
|
||
// adjust EllipseHandles according size, selection, zOrder:
|
||
//
|
||
RubberbandPointHandle *selectedHandlePointPtrNotCenter{nullptr};
|
||
int handleIdxMax = 0;
|
||
const int handleListSize = Rubberband::_internal->_handleList.size();
|
||
for (int handleIdx=0; handleIdx < handleListSize; ++handleIdx)
|
||
{
|
||
if (handleIdx >= Rubberband::_internal->_handleList.size())
|
||
continue;
|
||
|
||
handleIdxMax = handleIdx;
|
||
|
||
RubberbandPointHandle *pointHandle = dynamic_cast<RubberbandPointHandle *>(Rubberband::_internal->_handleList[handleIdx].get());
|
||
if (!pointHandle)
|
||
continue;
|
||
|
||
if (pointHandle->isSelected() && handleIdx>0)
|
||
selectedHandlePointPtrNotCenter = pointHandle;
|
||
|
||
if (handleIdx==0)
|
||
continue;
|
||
|
||
// --- now we have finished the first iteration ---
|
||
|
||
// 2 pointHandles are required for an elli:
|
||
SituationMap::RefPointer<RubberbandEllipseHandle> ellipseHandle = _internal->_ellipseHandleList[handleIdx-1];
|
||
if (!ellipseHandle)
|
||
continue;
|
||
|
||
const RubberbandHandle::RubberbandCoordinate &curCoord = pointHandle->getCoordinate();
|
||
qreal distX = fabs(curCoord._mapCoordinate.x() - centerCoord._mapCoordinate.x());
|
||
qreal distY = fabs(curCoord._mapCoordinate.y() - centerCoord._mapCoordinate.y());
|
||
if (_internal->_constrainQuadratic)
|
||
distX = distY = std::max(distX, distY);
|
||
|
||
if (isSectorEnabled())
|
||
{
|
||
// _internal->_sectorOStart + _internal->_oVec
|
||
QPointF sectorStartRotated = getRotatedPoint(_internal->_sectorOStart);
|
||
QPointF sectorEndRotated = getRotatedPoint(_internal->_sectorOEnd);
|
||
|
||
ellipseHandle->setRect(centerCoord, distX, distY, 0, 1, sectorStartRotated, sectorEndRotated);
|
||
}
|
||
else
|
||
ellipseHandle->setRect(centerCoord, distX, distY, 0, 1);
|
||
|
||
// transfer selection:
|
||
ellipseHandle->setSelection(pointHandle->isSelected());
|
||
|
||
// update zOrder
|
||
ellipseHandle->setZValue(handleListSize-handleIdx);
|
||
|
||
} // for
|
||
|
||
// Maybe there has ist one RubberbandPointHandle deleted (deleteAction)
|
||
// remove superfluous ellipse handles
|
||
// like: 2 RubberbandPointHandle (handleIdxMax==1) -> 1 RubberbandEllipseHandle
|
||
while (_internal->_ellipseHandleList.size() > handleIdxMax)
|
||
_internal->_ellipseHandleList.removeLast();
|
||
|
||
if (selectedHandlePointPtrNotCenter)
|
||
updateFrameHandle(selectedHandlePointPtrNotCenter->getCoordinate()._sceneCoordinate);
|
||
|
||
// transfer selection:
|
||
if (_internal->_frameHandle && selectedHandlePointPtrNotCenter)
|
||
_internal->_frameHandle->setSelection( selectedHandlePointPtrNotCenter->isSelected() );
|
||
|
||
updateSectorHandles();
|
||
updateRotationHandle();
|
||
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
|
||
void RubberbandMultiEllipseFeature::updateFrameHandle(const QPointF &sceneCoordinate)
|
||
{
|
||
const RubberbandDrawable::RubberbandCoordinate vertex(Rubberband::_internal->_mapView, sceneCoordinate);
|
||
|
||
if (//isEnabledModificationState() &&
|
||
(!vertex.isNull()) &&
|
||
!Rubberband::_internal->_handleList.isEmpty()
|
||
)
|
||
{
|
||
if (!_internal->_frameHandle)
|
||
{
|
||
_internal->_frameHandle = SituationMap::RefPointer<RubberbandFrameHandle>(new RubberbandFrameHandle(Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, _frameHandleMargin));
|
||
_internal->_frameHandle->setSelectable(false);
|
||
|
||
_internal->_frameHandle->setDrawColor(_frameColor);
|
||
_internal->_frameHandle->setFillColor(_frameFillColor);
|
||
_internal->_frameHandle->setSelectionColor(_frameSelectionColor);
|
||
_internal->_frameHandle->updateFrameSceneMargin(_frameHandleMargin);
|
||
_internal->_frameHandle->drawDisabled((_frameHandleMargin < 0));
|
||
}
|
||
} else {
|
||
_internal->_frameHandle = nullptr;
|
||
}
|
||
|
||
if (_internal->_frameHandle)
|
||
{
|
||
const RubberbandPointHandle *handlePointPtr = dynamic_cast<RubberbandPointHandle *>(Rubberband::_internal->_handleList.first().get());
|
||
if (!handlePointPtr)
|
||
return;
|
||
|
||
const RubberbandHandle::RubberbandCoordinate &mapCenter = handlePointPtr->getCoordinate();
|
||
qreal radiusX, radiusY;
|
||
if (!getRadiusXY(sceneCoordinate, radiusX, radiusY))
|
||
return;
|
||
|
||
if (_internal->_constrainQuadratic)
|
||
radiusX = radiusY = std::max(radiusX, radiusY);
|
||
|
||
RubberbandHandle::RubberbandCoordinate rcNewCorner1(Rubberband::_internal->_mapView,
|
||
Esri::ArcGISRuntime::Point(mapCenter._mapCoordinate.x()+(radiusX),
|
||
mapCenter._mapCoordinate.y()+(radiusY),
|
||
mapCenter._mapCoordinate.spatialReference()));
|
||
|
||
RubberbandHandle::RubberbandCoordinate rcNewCorner2(Rubberband::_internal->_mapView,
|
||
Esri::ArcGISRuntime::Point(mapCenter._mapCoordinate.x()-(radiusX),
|
||
mapCenter._mapCoordinate.y()-(radiusY),
|
||
mapCenter._mapCoordinate.spatialReference()));
|
||
|
||
_internal->_frameHandle->updateFrameShape({rcNewCorner1, rcNewCorner2});
|
||
}
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::getSceneRotation(qreal &sinA, qreal &cosA) const
|
||
{
|
||
sinA = -_internal->_oVec.y();
|
||
cosA = _internal->_oVec.x();
|
||
}
|
||
|
||
Esri::ArcGISRuntime::Point addOffsetToMapCoordinate(const Esri::ArcGISRuntime::Point &mapCoordinate,
|
||
const QPointF &offset)
|
||
{
|
||
return Esri::ArcGISRuntime::Point(mapCoordinate.x() + offset.x(),
|
||
mapCoordinate.y() + offset.y(),
|
||
mapCoordinate.spatialReference());
|
||
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::updateSectorHandles()
|
||
{
|
||
if (Rubberband::_internal->_handleList.isEmpty())
|
||
return;
|
||
|
||
if ((unsigned int)Rubberband::_internal->_handleList.size() < _minimumPointCount)
|
||
return;
|
||
|
||
if (!isSectorEnabled())
|
||
return;
|
||
|
||
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 ); };
|
||
|
||
|
||
const QPointF &biggestRadius = getBiggestRadius();
|
||
|
||
qreal a = biggestRadius.x(); // getWidth() * 0.5;
|
||
qreal b = biggestRadius.y(); // 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();
|
||
|
||
RubberbandPointHandle *handlePointCenter = dynamic_cast<RubberbandPointHandle *>(Rubberband::_internal->_handleList.first().get());
|
||
if (!handlePointCenter)
|
||
return;
|
||
const RubberbandHandle::RubberbandCoordinate &mapCenter = handlePointCenter->getCoordinate();
|
||
|
||
// const Esri::ArcGISRuntime::Point &mapStartP = convert( startP, Rubberband::_internal->_mapView->map()->spatialReference() );
|
||
// const Esri::ArcGISRuntime::Point &mapEndP = convert( endP, Rubberband::_internal->_mapView->map()->spatialReference() );
|
||
const Esri::ArcGISRuntime::Point &mapStartP = addOffsetToMapCoordinate(mapCenter._mapCoordinate, startP);
|
||
const Esri::ArcGISRuntime::Point &mapEndP = addOffsetToMapCoordinate(mapCenter._mapCoordinate, endP);
|
||
|
||
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((!isSectorFixedAngeEnabled())/*_internal->_sectorEnabled*/);
|
||
_internal->_sectorStartHandle->setDrawColor(Qt::red);
|
||
_internal->_sectorStartHandle->setFillColor( _handleFillColor );
|
||
_internal->_sectorStartHandle->setSelectionColor(_handleSelectionColor);
|
||
_internal->_sectorStartHandle->setSelectable(true);
|
||
|
||
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(!isSectorFixedAngeEnabled()/*_internal->_sectorEnabled*/);
|
||
_internal->_sectorEndHandle->setDrawColor(Qt::red);
|
||
_internal->_sectorEndHandle->setFillColor( _handleFillColor );
|
||
_internal->_sectorEndHandle->setSelectionColor(_handleSelectionColor);
|
||
_internal->_sectorEndHandle->setSelectable(true);
|
||
}
|
||
|
||
void RubberbandMultiEllipseFeature::updateRotationHandle()
|
||
{
|
||
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " START"
|
||
<< ", isSectorFixedAngeEnabled()=" << isSectorFixedAngeEnabled()
|
||
<< ", _handleList.size=" << Rubberband::_internal->_handleList.size();
|
||
|
||
if (!isSectorEnabled() || !isSectorFixedAngeEnabled() || (Rubberband::_internal->_handleList.size()<2))
|
||
{
|
||
_internal->_rotationHandle = nullptr; // destroy
|
||
}
|
||
else
|
||
{
|
||
static QPixmap *s_icon = nullptr;
|
||
if (!s_icon)
|
||
s_icon = new QPixmap( QPixmap( winkelIcon_xpm ).transformed(QTransform::fromScale(0.5,0.5)) );
|
||
|
||
if (!_internal->_rotationHandle)
|
||
{
|
||
_internal->_rotationHandleSize = std::max( s_icon->width(), s_icon->height() ) * 0.5;
|
||
|
||
_internal->_rotationHandle = new RubberbandPointHandle(Rubberband::_internal->_mapView
|
||
, Rubberband::_internal->_mapScene
|
||
, QPointF(100, 100) // , _internal->getScenePositionRotationHandle(),
|
||
, *s_icon );
|
||
|
||
_internal->_rotationHandle->setDrawColor(_handleDrawColor);
|
||
_internal->_rotationHandle->setFillColor(_handleFillColor);
|
||
_internal->_rotationHandle->setSelectionColor(_handleSelectionColor);
|
||
}
|
||
|
||
_internal -> _rotationHandle->setSceneOffset(getSceneOffsetRotationHandle( (_frameHandleMargin > 0) ? _frameHandleMargin : 0 ) );
|
||
_internal -> _rotationHandle->updateCoordinate(getScenePositionRotationHandle());
|
||
}
|
||
DEBUG_LOG(Rubberband::_internal->_logger) << LOGFUNCTION << " END";
|
||
}
|
||
|
||
QPointF RubberbandMultiEllipseFeature::getScenePositionRotationHandle() const
|
||
{
|
||
if (Rubberband::_internal->_handleList.size()<2)
|
||
return {};
|
||
|
||
RubberbandPointHandle *handlePointCenter = dynamic_cast<RubberbandPointHandle *>(Rubberband::_internal->_handleList.first().get());
|
||
if (!handlePointCenter)
|
||
return {};
|
||
const RubberbandHandle::RubberbandCoordinate &mapCenter = handlePointCenter->getCoordinate();
|
||
|
||
const QPointF &biggestRadius = getBiggestRadius();
|
||
|
||
Esri::ArcGISRuntime::Point handlePosPoint(mapCenter._mapCoordinate.x() + 0,
|
||
mapCenter._mapCoordinate.y() + biggestRadius.y(),
|
||
mapCenter._mapCoordinate.spatialReference());
|
||
|
||
RubberbandHandle::RubberbandCoordinate handlePos(Rubberband::_internal->_mapView, handlePosPoint);
|
||
|
||
QPointF scenePoint (handlePos._sceneCoordinate);
|
||
scenePoint.ry() -= _internal->_rotationHandleSize; // keep center of sceneCoordSystem in mind
|
||
|
||
qreal sinRect = 0;
|
||
qreal cosRect = 1;
|
||
getSceneRotation(sinRect, cosRect);
|
||
|
||
scenePoint = MathUtils::rotate(scenePoint, mapCenter._sceneCoordinate, -sinRect, cosRect); // be carefull the scene coordinate system is contra clockwise -- sinA must be negated
|
||
|
||
return scenePoint;
|
||
}
|
||
|
||
QPointF RubberbandMultiEllipseFeature::getSceneOffsetRotationHandle(qreal margin)
|
||
{
|
||
qreal sinPhi = _internal->_oVec.y(); // * _mapOVec.x() + _oVec.x() * _mapOVec.y(); // Addition-Theorem
|
||
qreal cosPhi = _internal->_oVec.x(); // * _mapOVec.x() - _oVec.y() * _mapOVec.y();
|
||
return rotateVertex( QPointF(0,0), 0.0,-(margin+_internal->_rotationHandleSize), sinPhi, cosPhi );
|
||
}
|
||
|
||
|
||
}
|
||
} // namespace SituationMap::RB
|