Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
@@ -0,0 +1,318 @@
|
||||
/**
|
||||
**
|
||||
** @RDE_HEADER@
|
||||
** Definition of rubberband class to define multi point feature geometry with an additional width coordinate
|
||||
** $Id$
|
||||
** $HeadURL$
|
||||
** $Author$
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Hardware-Environment: Intel-PC
|
||||
** Software-Environment: Linux, Windows 7, Qt 5.7. ArcGISRuntimeQt 100
|
||||
**
|
||||
** Language ........: C++ 11
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
**
|
||||
** Notes .........:
|
||||
**
|
||||
** 7.12.2016, JT : First edition for use with Qt5
|
||||
**
|
||||
** -----------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "rubberband_polyline_width.h"
|
||||
#include "rubberband_point_handle.h"
|
||||
|
||||
#include "rubberband_internal.h"
|
||||
#include "rubberband_base_internal.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <arcgis/Map.h>
|
||||
|
||||
|
||||
|
||||
namespace SituationMap { namespace RB
|
||||
{
|
||||
|
||||
struct RubberbandPolylineWidth::InternalData
|
||||
{
|
||||
SituationMap::RefPointer<RubberbandPointHandle> _widthItem;
|
||||
}; /* RubberbandPolylineWidth::InternalData*/
|
||||
|
||||
|
||||
RubberbandPolylineWidth::RubberbandPolylineWidth( SituationMap::Map * map, QObject * parent )
|
||||
: RubberbandMultiPointFeature(map,true,parent), _internal( new InternalData() )
|
||||
{
|
||||
} /* RubberbandPolylineWidth::RubberbandPolylineWidth */
|
||||
|
||||
|
||||
RubberbandPolylineWidth::~RubberbandPolylineWidth()
|
||||
{
|
||||
delete _internal;
|
||||
} /* RubberbandPolylineWidth::~RubberbandPolylineWidth */
|
||||
|
||||
|
||||
void RubberbandPolylineWidth::buildWidthItem(const QPointF & mapPos1, const QPointF & mapPos2) const
|
||||
{
|
||||
double dx = mapPos2.x() - mapPos1.x();
|
||||
double dy = mapPos2.y() - mapPos1.y();
|
||||
QPointF handleMapPos = mapPos1 + QPointF(dx,dy)*0.35 + QPointF(dy,dx)*0.35;
|
||||
|
||||
setUpWidthItem(handleMapPos);
|
||||
} /* RubberbandPolylineWidth::buildWidthItem */
|
||||
|
||||
|
||||
void RubberbandPolylineWidth::setUpWidthItem(const QPointF & mapPos) const
|
||||
{
|
||||
RubberbandHandle::RubberbandCoordinate coordinate( Rubberband::_internal->_mapView, convert(mapPos,Rubberband::_internal->_mapView->map()->spatialReference()) );
|
||||
|
||||
_internal->_widthItem = new RubberbandPointHandle(Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, coordinate._sceneCoordinate);
|
||||
} /* RubberbandPolylineWidth::setUpWidthItem */
|
||||
|
||||
|
||||
QVector<QPointF> RubberbandPolylineWidth::coordinateVector( CoordinateSystem cs ) const
|
||||
{
|
||||
QVector<QPointF> polylineCoords = RubberbandMultiPointFeature::coordinateVector(cs);
|
||||
if (polylineCoords.size() > 1)
|
||||
{
|
||||
if (_internal->_widthItem == nullptr)
|
||||
{
|
||||
RubberbandPointHandle * pointHandle1Ptr = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[0].get());
|
||||
RubberbandPointHandle * pointHandle2Ptr = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[1].get());
|
||||
Esri::ArcGISRuntime::Point p1 = pointHandle1Ptr->getCoordinate()._mapCoordinate;
|
||||
Esri::ArcGISRuntime::Point p2 = pointHandle2Ptr->getCoordinate()._mapCoordinate;
|
||||
|
||||
buildWidthItem( QPointF(p1.x(),p1.y()), QPointF(p2.x(),p2.y()) );
|
||||
|
||||
}
|
||||
polylineCoords += projectCoordinateFromMap(cs, _internal->_widthItem->getCoordinate()._mapCoordinate);
|
||||
}
|
||||
return polylineCoords;
|
||||
} /* RubberbandPolylineWidth::coordinateVector */
|
||||
|
||||
|
||||
QPointF RubberbandPolylineWidth::singleCoordinate( unsigned int idx, CoordinateSystem cs ) const
|
||||
{
|
||||
if (static_cast<unsigned int>(Rubberband::_internal->_handleList.size()) == idx)
|
||||
{
|
||||
return projectCoordinateFromMap(cs, _internal->_widthItem->getCoordinate()._mapCoordinate);
|
||||
}
|
||||
return RubberbandMultiPointFeature::singleCoordinate(idx, cs);
|
||||
} /* RubberbandPolylineWidth::singleCoordinate */
|
||||
|
||||
|
||||
void RubberbandPolylineWidth::setCoordinateVector( const QVector<QPointF> & coordinateVector, CoordinateSystem cs )
|
||||
{
|
||||
if (coordinateVector.size() > 2)
|
||||
{
|
||||
QVector<QPointF> lineCoords = coordinateVector;
|
||||
setUpWidthItem( projectCoordinateToMap(cs, lineCoords.last()) );
|
||||
lineCoords.removeLast();
|
||||
RubberbandMultiPointFeature::setCoordinateVector(lineCoords, cs);
|
||||
|
||||
return;
|
||||
}
|
||||
if (coordinateVector.size() == 2)
|
||||
{
|
||||
const QPointF & mapP1 = projectCoordinateToMap(cs, coordinateVector[0]);
|
||||
const QPointF & mapP2 = projectCoordinateToMap(cs, coordinateVector[1]);
|
||||
|
||||
buildWidthItem(mapP1, mapP2);
|
||||
}
|
||||
RubberbandMultiPointFeature::setCoordinateVector(coordinateVector,cs);
|
||||
} /* RubberbandPolylineWidth::setCoordinateVector */
|
||||
|
||||
|
||||
bool RubberbandPolylineWidth::selectAction( AbstractEventDispatcher * causer, int x, int y )
|
||||
{
|
||||
if (rubberbandIsAlive() && (nullptr != _internal->_widthItem.get()))
|
||||
{
|
||||
_internal->_widthItem->setSelection(false);
|
||||
QPointF scenePos(pixel2ScenePosition(x, y));
|
||||
if (_baseInternal->buttonProxyActive(scenePos)) return false;
|
||||
if (_internal->_widthItem->isPositionInside(scenePos))
|
||||
{
|
||||
_internal->_widthItem->setSelection();
|
||||
_baseInternal->_lastClickPosition = scenePos;
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return RubberbandMultiPointFeature::selectAction(causer,x,y);
|
||||
} /* RubberbandPolylineWidth::selectAction */
|
||||
|
||||
|
||||
bool RubberbandPolylineWidth::setCoordinateAction( AbstractEventDispatcher * causer, int x, int y )
|
||||
{
|
||||
if (rubberbandIsAlive() && (nullptr != _internal->_widthItem.get()))
|
||||
{
|
||||
if (_internal->_widthItem->isSelected())
|
||||
{
|
||||
QPointF scenePos(pixel2ScenePosition(x, y));
|
||||
QPointF deltaMove = scenePos - _baseInternal->_lastClickPosition;
|
||||
|
||||
_internal->_widthItem->setSelection(false);
|
||||
_internal->_widthItem->moveCoordinate(deltaMove);
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return RubberbandMultiPointFeature::setCoordinateAction(causer, x, y);
|
||||
} /* RubberbandPolylineWidth::setCoordinateAction */
|
||||
|
||||
|
||||
bool RubberbandPolylineWidth::movePickedAction( AbstractEventDispatcher * causer, int x, int y )
|
||||
{
|
||||
if (rubberbandIsAlive() && (nullptr != _internal->_widthItem.get()))
|
||||
{
|
||||
if (_internal->_widthItem->isSelected())
|
||||
{
|
||||
adjustConnectedPreviewPixmap(x, y);
|
||||
|
||||
QPointF scenePos(pixel2ScenePosition(x, y));
|
||||
QPointF deltaMove = scenePos - _baseInternal->_lastClickPosition;
|
||||
_baseInternal->_lastClickPosition = scenePos;
|
||||
|
||||
_internal->_widthItem->moveCoordinate(deltaMove);
|
||||
update();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
RubberbandPointHandle * handlePoint1Ptr = dynamic_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[0].get());
|
||||
RubberbandPointHandle * handlePoint2Ptr = dynamic_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[1].get());
|
||||
|
||||
if (handlePoint1Ptr && handlePoint2Ptr)
|
||||
{
|
||||
const RubberbandDrawable::RubberbandCoordinate & loc1Start = handlePoint1Ptr->getCoordinate();
|
||||
const RubberbandDrawable::RubberbandCoordinate & loc2Start = handlePoint2Ptr->getCoordinate();
|
||||
|
||||
bool ret = RubberbandMultiPointFeature::movePickedAction(causer, x, y);
|
||||
|
||||
const RubberbandDrawable::RubberbandCoordinate & loc1End = handlePoint1Ptr->getCoordinate();
|
||||
const RubberbandDrawable::RubberbandCoordinate & loc2End = handlePoint2Ptr->getCoordinate();
|
||||
|
||||
QPointF deltaMove1 = loc1End._sceneCoordinate - loc1Start._sceneCoordinate;
|
||||
QPointF deltaMove2 = loc2End._sceneCoordinate - loc2Start._sceneCoordinate;
|
||||
|
||||
|
||||
if ((fabs(deltaMove1.x()) >= 1) || (fabs(deltaMove1.y()) >= 1) || (fabs(deltaMove2.x()) >= 1) || (fabs(deltaMove2.y()) >= 1))
|
||||
{
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* First or second point have been moved. Now recalculate the coordinate of the width handle point as follows:
|
||||
* The width handle "C" and the first two coordinates ("A","B") are providing a triangle:
|
||||
* B
|
||||
* / \
|
||||
* / \
|
||||
* /sinB \
|
||||
* / cosB \
|
||||
* / \
|
||||
* / \
|
||||
* c / \ a
|
||||
* / \
|
||||
* / \
|
||||
* / \
|
||||
* / \
|
||||
* / sinA sinC \
|
||||
* / cosA cosC \
|
||||
* A ------------------------- C
|
||||
* b
|
||||
* If the coordinates of "A" or "B" are changed, try to keep the ratio of angles and sides of the triangle constant. For this
|
||||
* use some trigonometric identities.
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
auto rotate = []( const QPointF & p, qreal sinPhi, qreal cosPhi ) -> QPointF
|
||||
{
|
||||
return QPointF( p.x()*cosPhi - p.y()*sinPhi, p.y()*cosPhi + p.x()*sinPhi );
|
||||
};
|
||||
|
||||
QPointF A = loc2Start._sceneCoordinate;
|
||||
QPointF B = loc1Start._sceneCoordinate;
|
||||
QPointF C = _internal->_widthItem->getCoordinate()._sceneCoordinate;
|
||||
|
||||
qreal a = QLineF(B,C).length(); // side length of triangle
|
||||
qreal b = QLineF(A,C).length();
|
||||
qreal c = QLineF(A,B).length();
|
||||
qreal cosA = (b*b+c*c-a*a)/(b*c*2); // cosin rule
|
||||
qreal cosB = (a*a+c*c-b*b)/(a*c*2);
|
||||
qreal cosC = (a*a+b*b-c*c)/(a*b*2);
|
||||
qreal sinA = sqrt(1-cosA*cosA); // pythagorean trigonometric identity
|
||||
qreal sinB = sqrt(1-cosB*cosB);
|
||||
qreal sinC = sqrt(1-cosC*cosC);
|
||||
|
||||
// now we have all angle of the triangle, set A and B to the new coordinates ...
|
||||
|
||||
A = loc2End._sceneCoordinate;
|
||||
B = loc1End._sceneCoordinate;
|
||||
|
||||
// ... and calculate the coordinate of C with the same ratio of angles as before ...
|
||||
|
||||
QPointF AB = B-A;
|
||||
|
||||
// c = QLineF(QPointF(0,0),AB).length();
|
||||
|
||||
if (sinC != 0.0)
|
||||
{
|
||||
// ... rotate AB and scale it to the right length
|
||||
C = A + rotate(AB,sinA,cosA) * sinB / sinC;
|
||||
|
||||
// the RubberbandPointHandle dosn't has a set to set scene coordinate. Using the moveCoordinate methode instead.
|
||||
|
||||
_internal->_widthItem->moveCoordinate( C - _internal->_widthItem->getCoordinate()._sceneCoordinate );
|
||||
}
|
||||
// else could only happen when the triangle is degenrated to a line
|
||||
update();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return RubberbandMultiPointFeature::movePickedAction(causer, x, y);
|
||||
} /* RubberbandPolylineWidth::movePickedAction */
|
||||
|
||||
|
||||
bool RubberbandPolylineWidth::moveAction( AbstractEventDispatcher * causer, int x, int y )
|
||||
{
|
||||
if (rubberbandIsAlive() && (nullptr != _internal->_widthItem.get()))
|
||||
{
|
||||
QPointF scenePos(pixel2ScenePosition(x, y));
|
||||
_internal->_widthItem->setSelection( _internal->_widthItem->isPositionInside(scenePos) );
|
||||
}
|
||||
return RubberbandMultiPointFeature::moveAction( causer, x, y);
|
||||
|
||||
} /* RubberbandPolylineWidth::moveAction */
|
||||
|
||||
|
||||
void RubberbandPolylineWidth::update()
|
||||
{
|
||||
if ((_internal->_widthItem.get() == nullptr) && (Rubberband::_internal->_handleList.size() > 1))
|
||||
{
|
||||
RubberbandPointHandle * pointHandle1Ptr = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[0].get());
|
||||
RubberbandPointHandle * pointHandle2Ptr = static_cast<RubberbandPointHandle*>(Rubberband::_internal->_handleList[1].get());
|
||||
Esri::ArcGISRuntime::Point p1 = pointHandle1Ptr->getCoordinate()._mapCoordinate;
|
||||
Esri::ArcGISRuntime::Point p2 = pointHandle2Ptr->getCoordinate()._mapCoordinate;
|
||||
|
||||
buildWidthItem(QPointF(p1.x(), p1.y()), QPointF(p2.x(), p2.y()));
|
||||
}
|
||||
|
||||
if (_internal->_widthItem)
|
||||
{
|
||||
Rubberband::_internal->_handleList += static_cast<SituationMap::RefPointer<RubberbandHandle>>(_internal->_widthItem);
|
||||
RubberbandMultiPointFeature::update();
|
||||
Rubberband::_internal->_handleList.removeLast();
|
||||
}
|
||||
else RubberbandMultiPointFeature::update();
|
||||
|
||||
} /* RubberbandPolylineWidth::update */
|
||||
|
||||
|
||||
|
||||
} } /* namespace SituationMap::RB */
|
||||
Reference in new issue
Block a user