315 lines
11 KiB
C++
Executable File
315 lines
11 KiB
C++
Executable File
|
|
/**
|
|
**
|
|
** @RDE_HEADER@
|
|
** Implementation of base class for rubberband frame handles
|
|
** $Id$
|
|
** $HeadURL$
|
|
** $Author$
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
**
|
|
** Hardware-Environment: Intel-PC
|
|
** Software-Environment: Windows 7, Qt 5.4. ArcGIS 10.2.5
|
|
**
|
|
** Language ........: C++ 11
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
**
|
|
** Author ...........: Jörg Turla, SPD G, Tel. 3132
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
**
|
|
** Notes .........:
|
|
**
|
|
** 27.03.2015, JT : First edition for use with Qt5
|
|
**
|
|
** -----------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "rubberband_frame_handle.h"
|
|
|
|
#include <MathUtils/math_const.h>
|
|
|
|
#include <arcgis/Map.h>
|
|
#include <arcgis/MapGraphicsView.h>
|
|
|
|
#include <QtWidgets/QGraphicsScene>
|
|
|
|
|
|
namespace SituationMap { namespace RB
|
|
{
|
|
|
|
|
|
|
|
|
|
static QGraphicsPolygonItem * createFrameGraphic( QGraphicsScene * mapScene, qreal zBufferValue )
|
|
{
|
|
if (mapScene != nullptr)
|
|
{
|
|
QGraphicsPolygonItem * frameSymbol = new QGraphicsPolygonItem();
|
|
|
|
frameSymbol -> setZValue( zBufferValue );
|
|
frameSymbol -> setFlags( QGraphicsItem::ItemIgnoresTransformations );
|
|
|
|
mapScene -> addItem( frameSymbol );
|
|
|
|
return frameSymbol;
|
|
}
|
|
return nullptr;
|
|
} /* createFrameGraphic */
|
|
|
|
|
|
class FramePoint : public QPointF
|
|
{
|
|
public:
|
|
Q_DECL_CONSTEXPR FramePoint(const QPointF &p) : QPointF(p) {}
|
|
Q_DECL_CONSTEXPR FramePoint(qreal x, qreal y) : QPointF(x, y) {}
|
|
|
|
FramePoint rotate(const QPointF ¢er, qreal sinA, qreal cosA) const
|
|
{
|
|
qreal cx = x() - center.x();
|
|
qreal cy = y() - center.y();
|
|
qreal px = cx*cosA - cy*sinA + center.x();
|
|
qreal py = cy*cosA + cx*sinA + center.y();
|
|
return FramePoint(px, py);
|
|
} // rotate( const QPointF & center, qreal sin qreal cosA )
|
|
|
|
FramePoint rotate(const RubberbandHandle::RubberbandCoordinate & center, qreal sinA, qreal cosA) const
|
|
{
|
|
return rotate(QPointF(center._mapCoordinate.x(), center._mapCoordinate.y()), sinA, cosA);
|
|
} /* rotate */
|
|
|
|
FramePoint rotate(qreal sinA, qreal cosA) const
|
|
{
|
|
return rotate(QPointF(), sinA, cosA);
|
|
} // rotate( const QPointF & center, qreal sin qreal cosA )
|
|
|
|
|
|
}; /* FramePoint */
|
|
|
|
|
|
RubberbandFrameHandle::RubberbandFrameHandle( Esri::ArcGISRuntime::MapGraphicsView * mapView
|
|
, QGraphicsScene * scene
|
|
, qreal sceneMargin )
|
|
: RubberbandHandle(mapView,scene)
|
|
, _frameSymbol(nullptr)
|
|
, _frameSceneMargin(sceneMargin)
|
|
, _frameRotationSin(0)
|
|
, _frameRotationCos(1)
|
|
, _frameWidth(0)
|
|
, _frameHeight(0)
|
|
, _frameCenterCoordinate()
|
|
, _mapRotateSin(0)
|
|
, _mapRotateCos(1)
|
|
, _drawDisabled(false)
|
|
, _frameLineHandleList()
|
|
{
|
|
qreal mapRotatePhi = _mapView->mapRotation() * MathConst::pi / 180.0;
|
|
|
|
_mapRotateSin = sin(mapRotatePhi);
|
|
_mapRotateCos = cos(mapRotatePhi);
|
|
|
|
zBufferPlane( ZBufferPlane::FrameHandle );
|
|
|
|
_frameSymbol = createFrameGraphic( _scene, _zBufferValue );
|
|
if (_drawDisabled) _frameSymbol->hide();
|
|
updateGraphic();
|
|
} /* RubberbandFrameHandle::RubberbandFrameHandle */
|
|
|
|
|
|
|
|
RubberbandFrameHandle::~RubberbandFrameHandle()
|
|
{
|
|
if (_scene)
|
|
{
|
|
if (_frameSymbol)
|
|
{
|
|
_scene->removeItem(_frameSymbol);
|
|
delete _frameSymbol;
|
|
}
|
|
}
|
|
_frameSymbol = nullptr;
|
|
} /* RubberbandFrameHandle::~RubberbandFrameHandle */
|
|
|
|
|
|
void RubberbandFrameHandle::buildFrameVertexCoordinates()
|
|
{
|
|
auto length = [](qreal x, qreal y) -> qreal { return sqrt(x*x+y*y); };
|
|
|
|
QPointF center( _frameCenterCoordinate._mapCoordinate.x(), _frameCenterCoordinate._mapCoordinate.y());
|
|
RubberbandCoordinate marginP( _mapView, _frameCenterCoordinate._sceneCoordinate+QPointF(_frameSceneMargin,0) );
|
|
qreal margin = length( marginP._mapCoordinate.x()-center.x(), marginP._mapCoordinate.y()-center.y() );
|
|
|
|
QPointF vertex[4];
|
|
|
|
qreal frameWidth2 = _frameWidth * 0.5;
|
|
qreal frameHeight2 = _frameHeight * 0.5;
|
|
|
|
vertex[0] = QPointF( center.x() - frameWidth2 - margin, center.y() - frameHeight2 - margin );
|
|
vertex[1] = QPointF( center.x() + frameWidth2 + margin, center.y() - frameHeight2 - margin );
|
|
vertex[2] = QPointF( center.x() + frameWidth2 + margin, center.y() + frameHeight2 + margin );
|
|
vertex[3] = QPointF( center.x() - frameWidth2 - margin, center.y() + frameHeight2 + margin );
|
|
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
const FramePoint & v = FramePoint(vertex[i]).rotate(_frameCenterCoordinate, -_frameRotationSin, _frameRotationCos );
|
|
_frameVertexCoordinate[i] = RubberbandCoordinate(_mapView, convert(v, _mapView->map()->spatialReference()));
|
|
}
|
|
// Now we have the vertex coordinates in map coordinate system
|
|
|
|
} /* RubberbandFrameHandle::buildFrameVertexCoordinates */
|
|
|
|
|
|
void RubberbandFrameHandle::adjustCoordinates()
|
|
{
|
|
qreal mapRotatePhi = _mapView->mapRotation() * MathConst::pi / 180.0;
|
|
|
|
_mapRotateSin = sin(mapRotatePhi);
|
|
_mapRotateCos = cos(mapRotatePhi);
|
|
|
|
_frameCenterCoordinate.mapToScene(_mapView);
|
|
|
|
buildFrameVertexCoordinates();
|
|
updateFramePolygonItem();
|
|
|
|
emit adjusted();
|
|
|
|
} /* RubberbandFrameHandle::adjustCoordinates */
|
|
|
|
|
|
void RubberbandFrameHandle::adjustWindow( const QRectF& )
|
|
{
|
|
onDo_adjustCoordinates();
|
|
} /* RubberbandFrameHandle::adjustWindow */
|
|
|
|
|
|
void RubberbandFrameHandle::updateFrameShape( const QVector<RubberbandCoordinate> & vertexList, qreal sinA, qreal cosA )
|
|
{
|
|
DEBUG_LOG(_logger) << LOGFUNCTION << "( const QVector<RubberbandCoordinate> & vertexList, qreal sinA, qreal cosA )";
|
|
|
|
qreal sinPhi = sinA * _mapRotateCos - cosA * _mapRotateSin; // Addition-Theorem get rotation of the frame without map rotation
|
|
qreal cosPhi = cosA * _mapRotateCos + sinA * _mapRotateSin;
|
|
|
|
qreal minX = std::numeric_limits<qreal>::infinity();
|
|
qreal maxX = -std::numeric_limits<qreal>::infinity();
|
|
qreal minY = std::numeric_limits<qreal>::infinity();
|
|
qreal maxY = -std::numeric_limits<qreal>::infinity();
|
|
|
|
for (const RubberbandCoordinate & vertex : vertexList)
|
|
{
|
|
// eliminate rotation from vertex scene coordinate
|
|
FramePoint xy = FramePoint(vertex._sceneCoordinate.x(),vertex._sceneCoordinate.y()).rotate( -sinPhi, cosPhi );
|
|
qreal x = xy.x();
|
|
qreal y = xy.y();
|
|
|
|
if (minX > x) minX = x;
|
|
if (minY > y) minY = y;
|
|
if (maxX < x) maxX = x;
|
|
if (maxY < y) maxY = y;
|
|
}
|
|
|
|
_frameRotationSin = sinA;
|
|
_frameRotationCos = cosA;
|
|
|
|
// calculate rotated coordinates (map rotation) of (minX,minY), (maxX,maxY) and frame scene center
|
|
FramePoint frameSceneV0 = FramePoint( minX , minY ).rotate( sinPhi, cosPhi );
|
|
FramePoint frameSceneVW = FramePoint( maxX , minY ).rotate( sinPhi, cosPhi );
|
|
FramePoint frameSceneVH = FramePoint( minX , maxY ).rotate( sinPhi, cosPhi );
|
|
FramePoint frameSceneCenter = FramePoint( (minX+maxX)*0.5, (minY+maxY)*0.5 ).rotate( sinPhi, cosPhi );
|
|
|
|
_frameCenterCoordinate.updateSceneCoordinate( _mapView, frameSceneCenter );
|
|
|
|
// Calculate map coordinates of bounding rectangle
|
|
RubberbandCoordinate frameV0( _mapView, QPointF(frameSceneV0.x(),frameSceneV0.y()) );
|
|
RubberbandCoordinate frameVW( _mapView, QPointF(frameSceneVW.x(),frameSceneVW.y()) );
|
|
RubberbandCoordinate frameVH( _mapView, QPointF(frameSceneVH.x(),frameSceneVH.y()) );
|
|
|
|
|
|
auto length = []( qreal x1, qreal y1, qreal x2, qreal y2 ) -> qreal
|
|
{
|
|
qreal dx = x2-x1;
|
|
qreal dy = y2-y1;
|
|
return sqrt(dx*dx+dy*dy);
|
|
};
|
|
|
|
// get frame width and height in map coordinates
|
|
|
|
_frameWidth = length( frameV0._mapCoordinate.x(), frameV0._mapCoordinate.y(), frameVW._mapCoordinate.x(), frameVW._mapCoordinate.y() );
|
|
_frameHeight = length( frameV0._mapCoordinate.x(), frameV0._mapCoordinate.y(), frameVH._mapCoordinate.x(), frameVH._mapCoordinate.y() );
|
|
|
|
buildFrameVertexCoordinates();
|
|
updateFramePolygonItem();
|
|
|
|
} /* RubberbandFrameHandle::updateFrameShape */
|
|
|
|
|
|
void RubberbandFrameHandle::updateFrameShape()
|
|
{
|
|
DEBUG_LOG(_logger) << LOGFUNCTION;
|
|
|
|
buildFrameVertexCoordinates();
|
|
updateFramePolygonItem();
|
|
|
|
} /* RubberbandFrameHandle::updateFrameShape */
|
|
|
|
|
|
void RubberbandFrameHandle::updateFramePolygonItem()
|
|
{
|
|
QPolygonF framePolygon;
|
|
|
|
framePolygon.reserve( 4 );
|
|
for (auto vertex : _frameVertexCoordinate)
|
|
{
|
|
framePolygon.append(vertex.mapToScene(_mapView));
|
|
}
|
|
framePolygon.append(_frameVertexCoordinate[0]._sceneCoordinate);
|
|
|
|
_frameSymbol->setPolygon(framePolygon);
|
|
|
|
} /* RubberbandFrameHandle::updateFramePolygonItem */
|
|
|
|
|
|
void RubberbandFrameHandle::updateGraphic()
|
|
{
|
|
if (_frameSymbol)
|
|
{
|
|
_frameSymbol -> setPen( QPen(QColor("black"),1,Qt::PenStyle::DashDotLine) );
|
|
_frameSymbol -> setVisible( _isVisible );
|
|
|
|
if (isSelected())
|
|
_frameSymbol -> setBrush( QBrush(_selectionColor) );
|
|
else
|
|
_frameSymbol -> setBrush( QBrush(_fillColor) );
|
|
}
|
|
} /* RubberbandFrameHandle::updateGraphic */
|
|
|
|
|
|
void RubberbandFrameHandle::updateCoordinate(const QPointF & scenePosition)
|
|
{
|
|
_frameCenterCoordinate.updateSceneCoordinate( _mapView, scenePosition );
|
|
updateFrameShape();
|
|
} /* RubberbandFrameHandle::updateCoordinate */
|
|
|
|
|
|
void RubberbandFrameHandle::moveCoordinate(const QPointF & sceneDelta)
|
|
{
|
|
_frameCenterCoordinate.updateSceneCoordinate( _mapView, _frameCenterCoordinate._sceneCoordinate+sceneDelta );
|
|
updateFrameShape();
|
|
} /* RubberbandFrameHandle::moveCoordinate */
|
|
|
|
|
|
RubberbandHandle::RubberbandCoordinate RubberbandFrameHandle::getCoordinate() const { return _frameCenterCoordinate; }
|
|
|
|
|
|
bool RubberbandFrameHandle::isPositionInside( const QPointF & scenePosition ) const
|
|
{
|
|
if (_frameSymbol)
|
|
{
|
|
return _frameSymbol->contains( scenePosition );
|
|
}
|
|
return false;
|
|
} /* RubberbandFrameHandle::isPositionInside */
|
|
|
|
} } /* namespace SituationMap::RB */
|