/** ** ** @RDE_HEADER@ ** Implementation of base class for rubberbands ** $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 ** 30.09.2015, JT : New create method for creating rubberbands fitting to a special sidc code ** ** ----------------------------------------------------------------------------------------------- */ #include "rubberband_factory.h" #include "rubberband_corridor.h" #include #include #include namespace SituationMap { namespace RB { class RubberbandFactory::Defaults { public: QColor _rubberbandDrawColor = QColor(); QColor _rubberbandFillColor = QColor(); QColor _rubberbandHandleDrawColor = QColor(); QColor _rubberbandHandleFillColor = QColor(); QColor _rubberbandSelectionColor = QColor(); QColor _rubberbandFrameColor = QColor(); QColor _rubberbandFrameFillColor = QColor(); int _rubberbandFrameHandleMargin = 0; QPoint _rubberbandPreviewOffset = QPoint(); unsigned int _rubberbandPreviewSize = 0; unsigned int _rubberbandPickingRatio = 0; unsigned int _rubberbandLineHandleWidth = 0; }; // RubberbandFactory::Defaults RubberbandFactory::RubberbandFactory( SituationMap::Map * map ) : QObject() , _map(map) , _defaults(new Defaults()) , _allowMultipleRubberbands(false) , _logger(getLogger("RubberbandFactory")) {} RubberbandFactory::~RubberbandFactory() { delete _defaults; } class SymbolConstruction { public: enum class Mode { Unknown = 0, Point, ArcCurve, Triangle, MultiPoint, PolyLine, PolyLineWidth, Polygon, Rectangle, Circular, Corridor }; // Mode Mode _mode; unsigned int _minPoints; unsigned int _maxPoints; explicit SymbolConstruction( const AdvancedSymbology::GeometryType & geomType, const QString & gctString ) : _mode(Mode::Unknown), _minPoints(-1), _maxPoints(-1) { if (QLatin1String("gct_arrow") == gctString) { _mode = Mode::PolyLine; _minPoints = 2; _maxPoints = 0; } if (QLatin1String("gct_arrow_with_offset") == gctString) { _mode = Mode::PolyLineWidth; _minPoints = 2; _maxPoints = 0; } if (QLatin1String("gct_arrow_with_tail") == gctString) { _mode = Mode::Triangle; _minPoints = 3; _maxPoints = 3; } if (QLatin1String("gct_circle") == gctString) { _mode = Mode::MultiPoint; _minPoints = 2; _maxPoints = 2; } if (QLatin1String("gct_circular") == gctString) { _mode = Mode::Circular; _minPoints = 1; _maxPoints = 1; } if (QLatin1String("gct_freehand_arrow") == gctString) { _mode = Mode::ArcCurve; _minPoints = 3; _maxPoints = 3; } if (QLatin1String("gct_freehand_line") == gctString) { _mode = Mode::ArcCurve; _minPoints = 3; _maxPoints = 3; } if (QLatin1String("gct_freehand_reverse_arrow") == gctString) { _mode = Mode::ArcCurve; _minPoints = 3; _maxPoints = 3; } if (QLatin1String("gct_freehand_u") == gctString) { _mode = Mode::ArcCurve; _minPoints = 4; _maxPoints = 4; } if (QLatin1String("gct_hook") == gctString) { _mode = Mode::MultiPoint; _minPoints = 3; _maxPoints = 3; } if (QLatin1String("gct_horns") == gctString) { _mode = Mode::MultiPoint; _minPoints = 4; _maxPoints = 4; } if (QLatin1String("gct_open_triangle") == gctString) { _mode = Mode::Triangle; _minPoints = 3; _maxPoints = 3; } if (QLatin1String("gct_parallel_lines") == gctString) { _mode = Mode::PolyLineWidth; _minPoints = 2; _maxPoints = 2; } if (QLatin1String("gct_parallel_lines_mid_line") == gctString) { _mode = Mode::PolyLineWidth; _minPoints = 2; _maxPoints = 2; } if (QLatin1String("gct_parallel_lines_with_ticks") == gctString) { _mode = Mode::MultiPoint; // ESRI implmentation seems to differ from symbology standard and takes always 4 input // coordinates here to construct the symbol! // // if (AdvancedSymbology::GeometryType::Polygon == geomType) _minPoints = _maxPoints = 4; // else _minPoints = _maxPoints = 3; _minPoints = _maxPoints = 4; } if (QLatin1String("gct_rectangular") == gctString) { _mode = Mode::Corridor; _minPoints = 2; _maxPoints = 2; } if (QLatin1String("gct_rectangular_1_pt") == gctString) { _mode = Mode::Rectangle; _minPoints = 1; _maxPoints = 1; } if (QLatin1String("gct_t") == gctString) { _mode = Mode::MultiPoint; _minPoints = 3; _maxPoints = 3; } if (QLatin1String("gct_triple_arrow") == gctString) { _mode = Mode::MultiPoint; _minPoints = 3; _maxPoints = 3; } if (QLatin1String("gct_two_line") == gctString) { _mode = Mode::Triangle; _minPoints = 3; _maxPoints = 3; } if (QLatin1String("gct_two_line_3_or_4_pt") == gctString) { _mode = Mode::MultiPoint; _minPoints = 3; _maxPoints = 4; } if (QLatin1String("gct_u_or_t_shape") == gctString) { _mode = Mode::MultiPoint; _minPoints = 3; _maxPoints = 3; } if (Mode::Unknown == _mode) { // gct string is empty or not supported yet switch (geomType) { case AdvancedSymbology::GeometryType::Point : { _mode = Mode::Point; _minPoints = 1; _maxPoints = 1; } break; case AdvancedSymbology::GeometryType::Polyline : { _mode = Mode::PolyLine; _minPoints = 2; _maxPoints = 0; } break; case AdvancedSymbology::GeometryType::Polygon : { _mode = Mode::Polygon; _minPoints = 3; _maxPoints = 0; } break; case AdvancedSymbology::GeometryType::Undefined : break; default : break; } // switch } } // SymbolConstruction( const QString & gctString ) ~SymbolConstruction() = default; Mode mode() const { return _mode; } unsigned int minPoints() const { return _minPoints; } unsigned int maxPoints() const { return _maxPoints; } bool unlimitedMaxPoints() const { return (_maxPoints == 0); } }; // SymbolConstruction struct ActivateRubberbandInfo { Rubberband * _rubberband; SymbolConstruction _symbolConstruction; explicit ActivateRubberbandInfo( Rubberband * r, const SymbolConstruction & sc ) : _rubberband(r), _symbolConstruction(sc) {;} ~ActivateRubberbandInfo() = default; ActivateRubberbandInfo() = delete; }; // ActivateRubberbandInfo QString toString( SymbolConstruction::Mode mode ) { switch (mode) { case SymbolConstruction::Mode::Unknown : return QStringLiteral("Unknown Rubberband"); break; case SymbolConstruction::Mode::Point : return QStringLiteral("Point Rubberband"); break; case SymbolConstruction::Mode::PolyLine : return QStringLiteral("Polyline Rubberband"); break; case SymbolConstruction::Mode::PolyLineWidth : return QStringLiteral("PolylineWidth Rubberband"); break; case SymbolConstruction::Mode::Polygon : return QStringLiteral("Polygon Rubberband"); break; case SymbolConstruction::Mode::Triangle : return QStringLiteral("Triangle Rubberband"); break; case SymbolConstruction::Mode::ArcCurve : return QStringLiteral("ArcCurve Rubberband"); break; case SymbolConstruction::Mode::Rectangle : return QStringLiteral("Rectangle Rubberband"); break; case SymbolConstruction::Mode::Circular : return QStringLiteral("Circular Rubberband"); break; case SymbolConstruction::Mode::Corridor : return QStringLiteral("Corridor Rubberband"); break; case SymbolConstruction::Mode::MultiPoint : return QStringLiteral("MultiPoint Rubberband"); break; } return QString(); } // QString toString( SymbolConstruction::Mode mode ) static bool defaultSymbolRubberbandCoordinates( Map * map, Rubberband * rbnd, const QPointF & pixelPos, const SymbolConstruction & symbolConstruction ); Rubberband * RubberbandFactory::createSymbol(const QString & sidc, QObject * parent) const { return createSymbol(sidc,QPoint(-1,-1),parent); } Rubberband * RubberbandFactory::createSymbol( const QString & sidc, const QPoint & winPos, QObject * parent ) const { if (Mode::Mode_2D != _map->mode()) return nullptr; const QString & baseSymbolCode = AdvancedSymbology::SidcBuilderBase::concreteSidcToBaseSymbolCode( sidc ); const AdvancedSymbology::SymbolProperties & symbolProperties = _map->symbolDictionary().symbolProperties( baseSymbolCode ); const AdvancedSymbology::GeometryType & geomType = symbolProperties.geometryType(); SymbolConstruction symbolConstruction( geomType, symbolProperties.gctString() ); Rubberband::currentFactoryMap(_map); Rubberband::allowMultipleRubberbands(_allowMultipleRubberbands); Rubberband *rubberband = nullptr; DEBUG_LOG(_logger) << LOGFUNCTION << QStringLiteral(" - %1").arg(toString(geomType), 30); DEBUG_LOG(_logger) << LOGFUNCTION << QStringLiteral(" - %1").arg(symbolProperties.gctString(), 30); DEBUG_LOG(_logger) << LOGFUNCTION << QStringLiteral(" - %1").arg(toString(symbolConstruction.mode()),30); bool rubberbandConstructionMode = ((winPos.x() < 0) || (winPos.y() < 0)); try { switch (geomType) { case AdvancedSymbology::GeometryType::Point : { rubberband = new RubberbandPointFeature(_map, parent); } break; case AdvancedSymbology::GeometryType::Polyline : { switch (symbolConstruction.mode()) { case SymbolConstruction::Mode::PolyLine : { RubberbandMultiPointFeature * r = new RubberbandMultiPointFeature(_map,false,parent); if (r) { r->minimumPointCount( symbolConstruction.minPoints() ); r->maximumPointCount( symbolConstruction.maxPoints() ); r->enableFinishAfterConstruction(true); rubberband = r; } } break; case SymbolConstruction::Mode::PolyLineWidth : { RubberbandMultiPointFeature * r = new RubberbandPolylineWidth(_map,parent); if (r) { r->minimumPointCount( symbolConstruction.minPoints() ); r->maximumPointCount( symbolConstruction.maxPoints() ); r->enableFinishAfterConstruction(true); rubberband = r; } } break; case SymbolConstruction::Mode::ArcCurve : case SymbolConstruction::Mode::MultiPoint : case SymbolConstruction::Mode::Triangle : { RubberbandPointCluster * r = new RubberbandPointCluster(_map,parent,false); if (r) { r->minimumPointCount(symbolConstruction.minPoints()); r->maximumPointCount(symbolConstruction.maxPoints()); r->enableFinishAfterConstruction(true); rubberband = r; if ((!symbolConstruction.unlimitedMaxPoints()) && rubberbandConstructionMode) { // Rubberband is not active here because we need one position to initialize // the coordinates Rubberband::currentFactoryMap(_map); RubberbandPointFeature * askPosition = new RubberbandPointFeature(_map, parent); setDefaults(askPosition); askPosition -> enableFinishAfterConstruction(true); askPosition -> setUserData( new ActivateRubberbandInfo(rubberband, symbolConstruction) ); askPosition -> setPreviewSidc(sidc); askPosition -> setAutoDelete(true); connect(askPosition, &SituationMap::RB::Rubberband::apply, this, &RubberbandFactory::onActivateRubberband ); connect(askPosition, &SituationMap::RB::Rubberband::abort, this, &RubberbandFactory::onAbortRubberband ); } else rubberband->activate(); } } break; default: { rubberband = new RubberbandPointCluster(_map,parent); if (rubberband) rubberband->activate(); } break; } // switch } break; case AdvancedSymbology::GeometryType::Polygon : { switch (symbolConstruction.mode()) { case SymbolConstruction::Mode::Circular : { RubberbandEllipse * r = new RubberbandEllipse(_map, parent); if (r) { r->enableSector(false); r->constrainOrthogonal(true); r->constrainQuadratic(true); r->enableFinishAfterConstruction(true); } rubberband = r; } break; case SymbolConstruction::Mode::Rectangle : { RubberbandRectangle * r = new RubberbandRectangle(_map, parent); if (r) { r->constrainOrthogonal(false); r->enableFinishAfterConstruction(true); } rubberband = r; } break; case SymbolConstruction::Mode::Corridor : { RubberbandCorridor * r = new RubberbandCorridor(_map, RubberbandCorridor::InputMode::InputCenterLine, 0, parent); if (r) { r->setCorridorBorderColor( QColor("Black") ); r->setCorridorFillColor( QColor(255,255,0,100) ); r->minimumPointCount( symbolConstruction.minPoints() ); r->maximumPointCount( symbolConstruction.maxPoints() ); r->enableFinishAfterConstruction(true); rubberband = r; } } break; case SymbolConstruction::Mode::MultiPoint : { RubberbandPointCluster * r = new RubberbandPointCluster(_map,parent,false); if (r) { r->minimumPointCount(symbolConstruction.minPoints()); r->maximumPointCount(symbolConstruction.maxPoints()); r->enableFinishAfterConstruction(true); rubberband = r; if ((!symbolConstruction.unlimitedMaxPoints()) && rubberbandConstructionMode) { // Rubberband is not active here because we need one position to initialize // the coordinates Rubberband::currentFactoryMap(_map); RubberbandPointFeature * askPosition = new RubberbandPointFeature(_map, parent); setDefaults(askPosition); askPosition -> enableFinishAfterConstruction(true); askPosition -> setUserData( new ActivateRubberbandInfo(rubberband, symbolConstruction) ); askPosition -> setPreviewSidc(sidc); askPosition -> setAutoDelete(true); connect(askPosition, &SituationMap::RB::Rubberband::apply, this, &RubberbandFactory::onActivateRubberband ); connect(askPosition, &SituationMap::RB::Rubberband::abort, this, &RubberbandFactory::onAbortRubberband ); } else rubberband->activate(); } } break; case SymbolConstruction::Mode::Polygon : default: { RubberbandMultiPointFeature * rubberArea = new RubberbandMultiPointFeature( _map, parent ); if (rubberArea) { rubberArea -> enableClosed(true); } rubberband = rubberArea; } break; } // switch } break; default : break; } //switch } catch (const SituationMap::Exception &) {;} if (rubberband) { setDefaults( rubberband ); rubberband -> setAutoDelete(true); rubberband -> setPreviewSidc( sidc ); if (!rubberbandConstructionMode) { QPointF pixelPos( winPos.x(), winPos.y() ); if (!defaultSymbolRubberbandCoordinates(_map, rubberband, pixelPos, symbolConstruction)) { ERROR_LOG(_logger) << LOGFUNCTION << "Can't init symbol rubberband coordinate list, undefined proposal."; rubberband->deleteMySelf(); rubberband = nullptr; } } } return rubberband; } /* RubberbandFactory::create */ static bool defaultSymbolRubberbandCoordinates( Map * map, Rubberband * rbnd, const QPointF & pixelPos, const SymbolConstruction & symbolConstruction ) { QVector pointList; pointList.reserve( symbolConstruction.maxPoints() ); switch (symbolConstruction.mode()) { case SymbolConstruction::Mode::ArcCurve: { if (4 == symbolConstruction.maxPoints()) { pointList.append(pixelPos + QPointF(-150,-100)); pointList.append(pixelPos + QPointF(-100,-100)); pointList.append(pixelPos + QPointF(-100, 100)); pointList.append(pixelPos + QPointF(-150, 100)); } if (3 == symbolConstruction.maxPoints()) { pointList.append(pixelPos + QPointF(-150, 100)); pointList.append(pixelPos + QPointF(+150, -20)); pointList.append(pixelPos); } } break; case SymbolConstruction::Mode::MultiPoint: { if (4 == symbolConstruction.maxPoints()) { pointList.append(pixelPos + QPointF(-100, 100)); pointList.append(pixelPos + QPointF( 100, 100)); pointList.append(pixelPos + QPointF(-150,-100)); pointList.append(pixelPos + QPointF( 150,-100)); } if (3 == symbolConstruction.maxPoints()) { pointList.append(pixelPos + QPointF(-150, 0)); pointList.append(pixelPos + QPointF( 150, 0)); pointList.append(pixelPos + QPointF(-150,-100)); } if (2 == symbolConstruction.maxPoints()) { pointList.append(pixelPos); pointList.append(pixelPos + QPointF(150, 150)); } } break; case SymbolConstruction::Mode::Polygon: case SymbolConstruction::Mode::Triangle: { pointList.append(pixelPos); pointList.append(pixelPos + QPointF(-150, +150)); pointList.append(pixelPos + QPointF(+150, +150)); } break; case SymbolConstruction::Mode::Point: { pointList.append(pixelPos); } break; case SymbolConstruction::Mode::Circular: case SymbolConstruction::Mode::Rectangle: { pointList.append(pixelPos + QPointF(-150, 150)); pointList.append(pixelPos + QPointF( 150, 150)); pointList.append(pixelPos + QPointF( 150,-150)); pointList.append(pixelPos + QPointF(-150,-150)); } break; case SymbolConstruction::Mode::PolyLineWidth: { pointList.append(pixelPos + QPointF( 50, 0)); pointList.append(pixelPos + QPointF(-150, 0)); pointList.append(pixelPos + QPointF( 0, +50)); } break; case SymbolConstruction::Mode::Corridor: case SymbolConstruction::Mode::PolyLine: { pointList.append(pixelPos); pointList.append(pixelPos + QPointF(150, 150)); } break; case SymbolConstruction::Mode::Unknown: default: { // empty } break; } // switch if (!pointList.isEmpty()) { for (int i = 0; i < pointList.size(); ++i) { pointList[i] = map->viewPortWindowPointToGeoCoordinate(pointList[i]); } if (SymbolConstruction::Mode::Corridor == symbolConstruction.mode()) { SituationMap::CoordTranslationFunctor * cf = map->coordTranslationFunctor(); QPointF p1 = pointList[0]; QPointF p2 = pointList[1]; if (cf) { p1 = cf->geographicToMap(p1); p2 = cf->geographicToMap(p2); } p1 -= p2; qreal wCorr = sqrt(p1.x()*p1.x()+p1.y()*p1.y()) * 0.15; RubberbandCorridor * rbndCorr = static_cast(rbnd); rbndCorr->setCoordinateVectorWidth(pointList,wCorr); } else rbnd->setCoordinateVector(pointList); return true; } return false; } /* RubberbandFactory::defaultSymbolRubberbandCoordinates */ void RubberbandFactory::onActivateRubberband( RubberbandBase * rubberband ) { if (nullptr == rubberband) return; ActivateRubberbandInfo * arbInfo = static_cast( rubberband->userData() ); if (nullptr == arbInfo) return; const QPointF & position = rubberband->singleCoordinate(); const QPointF & pixelPos = _map->geoCoordinateToViewPortWindowPoint(position); if (defaultSymbolRubberbandCoordinates( _map, arbInfo->_rubberband, pixelPos, arbInfo->_symbolConstruction)) { arbInfo->_rubberband->activate(); } else { arbInfo->_rubberband->deleteMySelf(); ERROR_LOG(_logger) << LOGFUNCTION << "Can't init symbol rubberband coordinate list, undefined proposal."; } delete arbInfo; rubberband->setUserData(nullptr); } /* RubberbandFactory::onActivateRubberband */ void RubberbandFactory::onAbortRubberband( RubberbandBase * rubberband ) { if (nullptr == rubberband) return; ActivateRubberbandInfo * arbInfo = static_cast(rubberband->userData()); if (arbInfo) { arbInfo->_rubberband->deleteMySelf(); delete arbInfo; } rubberband->setUserData(nullptr); } /* RubberbandFactory::onAbortRubberband */ void RubberbandFactory::setRubberbandDrawColor ( const QColor & c ) { _defaults->_rubberbandDrawColor = c; } void RubberbandFactory::setRubberbandFillColor ( const QColor & c ) { _defaults->_rubberbandFillColor = c; } void RubberbandFactory::setRubberbandHandleDrawColor ( const QColor & c ) { _defaults->_rubberbandHandleDrawColor = c; } void RubberbandFactory::setRubberbandHandleFillColor ( const QColor & c ) { _defaults->_rubberbandHandleFillColor = c; } void RubberbandFactory::setRubberbandSelectionColor ( const QColor & c ) { _defaults->_rubberbandSelectionColor = c; } void RubberbandFactory::setRubberbandFrameColor ( const QColor & c ) { _defaults->_rubberbandFrameColor = c; } void RubberbandFactory::setRubberbandFrameFillColor ( const QColor & c ) { _defaults->_rubberbandFrameFillColor = c; } void RubberbandFactory::setRubberbandFrameHandleMargin ( int m ) { _defaults->_rubberbandFrameHandleMargin = m; } void RubberbandFactory::setRubberbandPreviewOffset ( const QPoint & o ) { _defaults->_rubberbandPreviewOffset = o; } void RubberbandFactory::setRubberbandPreviewSize ( unsigned int s ) { _defaults->_rubberbandPreviewSize = s; } void RubberbandFactory::setRubberbandPickingRatio ( unsigned int s ) { _defaults->_rubberbandPickingRatio = s; } void RubberbandFactory::setRubberbandLineHandleWidth ( unsigned int s ) { _defaults->_rubberbandLineHandleWidth = s; } void RubberbandFactory::setDefaults(RubberbandBase * rband) const { if (nullptr == rband) return; if ( _defaults->_rubberbandDrawColor.isValid() ) rband->setDrawColor ( _defaults->_rubberbandDrawColor ); if ( _defaults->_rubberbandFillColor.isValid() ) rband->setFillColor ( _defaults->_rubberbandFillColor ); if ( _defaults->_rubberbandHandleDrawColor.isValid()) rband->setHandleDrawColor ( _defaults->_rubberbandHandleDrawColor ); if ( _defaults->_rubberbandHandleFillColor.isValid()) rband->setHandleFillColor ( _defaults->_rubberbandHandleFillColor ); if ( _defaults->_rubberbandSelectionColor.isValid() ) rband->setHandleSelectionColor( _defaults->_rubberbandSelectionColor ); if ( _defaults->_rubberbandFrameColor.isValid() ) rband->setFrameColor ( _defaults->_rubberbandFrameColor ); if ( _defaults->_rubberbandFrameFillColor.isValid() ) rband->setFrameFillColor ( _defaults->_rubberbandFrameFillColor ); rband->setFrameHandleMargin( _defaults->_rubberbandFrameHandleMargin ); } /* RubberbandFactory::setDefaults */ void RubberbandFactory::setDefaults(Rubberband * rband) const { if (nullptr == rband) return; setDefaults( static_cast(rband) ); if (_defaults->_rubberbandPreviewSize > 0) rband->setPreviewSize ( _defaults->_rubberbandPreviewSize ); if (_defaults->_rubberbandPickingRatio > 0) rband->setPickingRatio ( _defaults->_rubberbandPickingRatio ); if (!_defaults->_rubberbandPreviewOffset.isNull()) rband->setPreviewOffset( _defaults->_rubberbandPreviewOffset ); if (_defaults->_rubberbandLineHandleWidth > 0) rband->setLineHandleWidth ( _defaults->_rubberbandLineHandleWidth ); RubberbandCorridor *rbCorridor = qobject_cast(rband); if (rbCorridor) { rbCorridor->setCorridorBorderColor(rband->getDrawColor()); rbCorridor->setCorridorFillColor(rband->getFillColor()); } } /* RubberbandFactory::setDefaults */ } } /* namespace SituationMap::RB */