/** ** ** @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 #include #include #include 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 & vertexList, qreal sinA, qreal cosA ) { DEBUG_LOG(_logger) << LOGFUNCTION << "( const QVector & 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::infinity(); qreal maxX = -std::numeric_limits::infinity(); qreal minY = std::numeric_limits::infinity(); qreal maxY = -std::numeric_limits::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 */