/** ** @RDE_HEADER@ ** Implementation of rubberband class to define multi point feature geoemtry with arrow ** $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 .........: ** ** 21.08.2015, JT : First edition for use with Qt5 ** ** ----------------------------------------------------------------------------------------------- */ #include "rubberband_arrow.h" #include "rubberband_frame_handle.h" #include "rubberband_line_handle.h" #include "rubberband_point_handle.h" #include "rubberband_drawable.h" #include "drawable_painter_path.h" #include "rubberband_internal.h" #include "rubberband_base_internal.h" namespace SituationMap { namespace RB { struct RubberbandArrow::InternalData { SituationMap::RefPointer _arrowHandle; SituationMap::RefPointer _arrowItem; }; /* struct RubberbandArrow::InternalData */ RubberbandArrow::RubberbandArrow( SituationMap::Map * map, QObject * parent ) : RubberbandMultiPointFeature(map,parent) , _internal(new InternalData) , _arrowSceneHalfWidth(0) , _arrowSceneLength(0) { _isClosed = false; } /* RubberbandArrow::RubberbandArrow */ RubberbandArrow::~RubberbandArrow() { delete _internal; _internal = nullptr; } /* RubberbandArrow::~RubberbandArrow */ unsigned int RubberbandArrow::arrowHalfWidth() const { return _arrowSceneHalfWidth; } unsigned int RubberbandArrow::arrowLength() const { return _arrowSceneLength; } void RubberbandArrow::setCoordinateVector(const QVector & coordinateVec, CoordinateSystem cs ) { setCoordinateVectorArrow( coordinateVec, 0.0, 0.0, cs ); } /* RubberbandArrow::coordinateVector */ void RubberbandArrow::setCoordinateVectorArrow(const QVector & coordinateVec, unsigned int arrowHalfWidth, unsigned int arrowLength, CoordinateSystem cs ) { if (coordinateVec.size() < 2) return; RubberbandMultiPointFeature::setCoordinateVector( coordinateVec, cs ); const QPointF & aux = pixel2ScenePosition(arrowHalfWidth,arrowLength); _arrowSceneHalfWidth = (unsigned int) aux.x(); _arrowSceneLength = (unsigned int) aux.y(); enableModificationState(); constructArrowHandle(); _baseInternal->_applyIsPossible = true; activateButtons(); } /* RubberbandArrow::setCoordinateVectorArrow */ QPointF RubberbandArrow::getArrowHandleScenePosition() { if (!_arrowSceneLength) _arrowSceneLength = 40; if (!_arrowSceneHalfWidth) _arrowSceneHalfWidth = 20; QPointF p0 = static_cast(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._sceneCoordinate; QPointF p1 = static_cast(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate; QPointF rv( p0.x()-p1.x(), p0.y()-p1.y() ); rv /= sqrt(rv.x()*rv.x()+rv.y()*rv.y()); return QPointF( p1.x() + rv.x()*_arrowSceneLength - rv.y()*_arrowSceneHalfWidth , p1.y() + rv.y()*_arrowSceneLength + rv.x()*_arrowSceneHalfWidth ); } /* RubberbandArrow::getArrowHandleScenePosition */ QPointF RubberbandArrow::getArrowHandlePosition() { const QPointF & handlePos = getArrowHandleScenePosition(); RubberbandDrawable::RubberbandCoordinate mapHandlePos(Rubberband::_internal->_mapView, handlePos); return QPointF( mapHandlePos._mapCoordinate.x(), mapHandlePos._mapCoordinate.y() ); } /* RubberbandArrow::getArrowhHandlePosition */ void RubberbandArrow::constructArrowHandle() { if (Rubberband::_internal->_handleList.size() < 2) return; const QPointF & p = getArrowHandlePosition(); _internal->_arrowHandle = new RubberbandPointHandle( Rubberband::_internal->_mapView, Rubberband::_internal->_mapScene, p ); // ensure thate the arrow the arrow size in pixel remain the same size connect( _internal->_arrowHandle.get(), &RubberbandHandle::adjusted, this, [this]() { this->_internal->_arrowHandle->updateCoordinate( this->getArrowHandleScenePosition() ); this->updateArrowPath(); } ); update(); } /* RubberbandArrow::constructArrowhHandle */ void RubberbandArrow::constructArrow( const QPointF & p ) { qreal p0X = static_cast(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._sceneCoordinate.x(); qreal p0Y = static_cast(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._sceneCoordinate.y(); qreal p1X = static_cast(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate.x(); qreal p1Y = static_cast(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate.y(); QPointF rv10( p0X-p1X , p0Y-p1Y ); QPointF rv1p( p.x()-p1X, p.y()-p1Y ); rv10 /= sqrt(rv10.x()*rv10.x()+rv10.y()*rv10.y()); qreal scalarProduct = QPointF::dotProduct(rv1p, rv10); if (scalarProduct > 0.0) { _internal->_arrowHandle->getCoordinate().updateSceneCoordinate( Rubberband::_internal->_mapView, p ); _arrowSceneLength = (unsigned int) scalarProduct; _arrowSceneHalfWidth = (unsigned int) sqrt( rv1p.x()*rv1p.x()+rv1p.y()*rv1p.y() - scalarProduct*scalarProduct ); } } /* RubberbandArrow::constructArrow */ void RubberbandArrow::updateHandleScenePosition() { if (!_internal->_arrowHandle) return; QPointF pos = getArrowHandleScenePosition(); _internal->_arrowHandle->updateCoordinate( pos ); } /* RubberbandArrow::updateHandleScenePosition */ void RubberbandArrow::updateArrowPath() { if (!_internal->_arrowHandle) return; if (Rubberband::_internal->_handleList.size() < 2) return; const QPointF & p0 = static_cast(Rubberband::_internal->_handleList.end()[-2].get())->getCoordinate()._sceneCoordinate; const QPointF & p1 = static_cast(Rubberband::_internal->_handleList.end()[-1].get())->getCoordinate()._sceneCoordinate; const QPointF & p = _internal->_arrowHandle->getCoordinate()._sceneCoordinate; QPointF rv( p0.x()-p1.x(), p0.y()-p1.y() ); rv /= sqrt(rv.x()*rv.x()+rv.y()*rv.y()); if (!_internal->_arrowItem) { _internal->_arrowItem = new DrawablePainterPath( Rubberband::_internal->_mapView ); _internal->_arrowItem -> enableClosedLine( true ); _internal->_arrowItem -> fillSolid( true ); _internal->_arrowItem -> zBufferPlane( RubberbandDrawable::ZBufferPlane::ArrowSymbol ); } QVector arrowPath; arrowPath.append( p1 ); arrowPath.append( p ); arrowPath.append( QPointF( p1.x() + rv.x()*_arrowSceneLength + rv.y()*_arrowSceneHalfWidth , p1.y() + rv.y()*_arrowSceneLength - rv.x()*_arrowSceneHalfWidth ) ); _internal->_arrowItem -> setPath( arrowPath ); RubberbandFrameHandle * frameHandle = getFrameHandle(); if (frameHandle) { QVector vertexSet; for (auto handle : qAsConst(Rubberband::_internal->_handleList)) { RubberbandPointHandle * pointHandlePtr = dynamic_cast(handle.get()); vertexSet.append(pointHandlePtr->getCoordinate() ); } vertexSet.append( _internal->_arrowHandle->getCoordinate() ); vertexSet.append( RubberbandDrawable::RubberbandCoordinate(Rubberband::_internal->_mapView,p) ); frameHandle->updateFrameShape( vertexSet ); } } /* RubberbandArrow::updateArrowPath */ bool RubberbandArrow::selectAction( AbstractEventDispatcher * causer, int x, int y ) { Q_UNUSED(causer); if (!rubberbandIsAlive()) return false; bool eventHandled = false; QPointF scenePos(pixel2ScenePosition(x,y)); if (_baseInternal->buttonProxyActive(scenePos)) return false; _baseInternal->_lastClickPosition = scenePos; if (isEnabledConstructionState()) return RubberbandMultiPointFeature::selectAction(causer,x,y); if (_internal->_arrowHandle->isPositionInside(scenePos)) { _internal->_arrowHandle->setSelection(); eventHandled = true; } else eventHandled = selectHandles( x, y, scenePos ); if (eventHandled) { update(); deactivateButtons(); } return eventHandled; } /* RubberbandArrow::selectAction */ bool RubberbandArrow::setCoordinateAction(AbstractEventDispatcher * causer, int x, int y) { Q_UNUSED(causer); if (!rubberbandIsAlive()) return false; bool eventHandled = false; QPointF scenePos(pixel2ScenePosition(x,y)); Rubberband::_internal->_lastClickPosition = scenePos; if (isEnabledConstructionState()) return RubberbandMultiPointFeature::setCoordinateAction(causer, x, y); if (_internal->_arrowHandle->isSelected()) { _internal->_arrowHandle->setSelection(false); constructArrow(scenePos); eventHandled = true; } else return RubberbandMultiPointFeature::setCoordinateAction(causer, x, y); if (eventHandled) update(); updateButtonPosition(); activateButtons(); return eventHandled; } /* RubberbandArrow::setCoordinateAction */ bool RubberbandArrow::movePickedAction(AbstractEventDispatcher * causer, int x, int y ) { if (!rubberbandIsAlive()) return false; if ((_internal->_arrowHandle) && (_internal->_arrowHandle->isSelected())) { QPointF scenePos(pixel2ScenePosition(x,y)); constructArrow( scenePos ); update(); return false; } return RubberbandMultiPointFeature::movePickedAction(causer,x,y); } /* RubberbandArrow::movePickedAction */ bool RubberbandArrow::moveAction(AbstractEventDispatcher * causer, int x, int y) { QPointF scenePos(pixel2ScenePosition(x,y)); if (_internal->_arrowHandle) { if (_internal->_arrowHandle->isPositionInside(scenePos)) { _internal->_arrowHandle->setSelection(true); return false; } _internal->_arrowHandle->setSelection(false); } return RubberbandMultiPointFeature::moveAction(causer,x,y); } /* RubberbandArrow::moveAction */ bool RubberbandArrow::completeStateAction(AbstractEventDispatcher * causer, int x, int y) { if ((rubberbandIsAlive()) && (Rubberband::_internal->_mapView) && (Rubberband::_internal->_mapScene)) { if (isEnabledConstructionState()) { if ((unsigned int)Rubberband::_internal->_handleList.size() >= _minimumPointCount) { constructArrowHandle(); } update(); } } return RubberbandMultiPointFeature::completeStateAction(causer,x,y);; } /* RubberbandArrow::completeStateAction */ void RubberbandArrow::update() { _isClosed = false; RubberbandMultiPointFeature::update(); if (_internal->_arrowHandle) { _internal->_arrowHandle -> setDrawColor(_handleDrawColor ); _internal->_arrowHandle -> setFillColor(_handleFillColor ); _internal->_arrowHandle -> setSelectionColor(_handleSelectionColor ); _internal->_arrowHandle -> setPickingRatio( _pickingRatio ); updateHandleScenePosition(); updateArrowPath(); } } /* RubberbandArrow::update */ } } /* namespace SituationMap::RB */