/** ** ** @RDE_HEADER@ ** Do all the work for complex selection operations. ** $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 .........: ** ** 05.07.2016, JT : First edition for use with Qt5 ** ** ----------------------------------------------------------------------------------------------- */ #include "selection_worker.h" #include "plan_editor.h" #include #include #include namespace PlanEditor { SelectionWorker::SelectionWorker(PlanEditor *planEditor , SituationMap::GeometryModel *geometryModel , SituationMap::Map *map , SelectionMode mode , const QPointF &viewPortPosition) : QObject(planEditor) , m_planEditor(planEditor) , m_geometryModel(geometryModel) , m_map(map) , m_rubberband(nullptr) , m_logger(getLogger("PlanEditor-SelectionWorker")) { switch (mode) { case SelectionMode::Line : { SituationMap::RB::RubberbandMultiPointFeature *rubberband = m_map->rubberbandFactory().create(planEditor); if (rubberband != nullptr) { rubberband->setAutoDelete(true); rubberband->enableClosed(false); rubberband->maximumPointCount(2); rubberband->enableFinishAfterConstruction(true); // setting first input coordinate which has been already clicked rubberband->autoSelectAction(int(viewPortPosition.x()), int(viewPortPosition.y())); connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &SelectionWorker::onLineSelect); connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &SelectionWorker::onAbortSelect); } else ERROR_LOG(m_logger) << LOGFUNCTION << "Creating rubberband for line selection failed."; } break; case SelectionMode::Lasso : { SituationMap::RB::RubberbandFreeHand *rubberband = m_map->rubberbandFactory().create(planEditor); if (rubberband != nullptr) { rubberband->setAutoDelete(true); rubberband->enableClosed(true); rubberband->enableFinishAfterConstruction(true); // setting first input coordinate which has been already clicked rubberband->autoSelectAction(int(viewPortPosition.x()), int(viewPortPosition.y())); connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &SelectionWorker::onLassoSelect); connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &SelectionWorker::onAbortSelect); } else ERROR_LOG(m_logger) << LOGFUNCTION << "Creating rubberband for lasso selection failed."; } break; case SelectionMode::Rectangle : { SituationMap::RB::RubberbandRectangle *rubberband = m_map->rubberbandFactory().create(planEditor); if (rubberband != nullptr) { rubberband->setAutoDelete(true); rubberband->enableFinishAfterConstruction(true); // setting first input coordinate which has been already clicked rubberband->autoSelectAction(int(viewPortPosition.x()), int(viewPortPosition.y())); connect(rubberband, &SituationMap::RB::Rubberband::apply, this, &SelectionWorker::onRectSelect); connect(rubberband, &SituationMap::RB::Rubberband::abort, this, &SelectionWorker::onAbortSelect); } else ERROR_LOG(m_logger) << LOGFUNCTION << "Creating rubberband for rectangle selection failed."; } break; case SelectionMode::Picking : case SelectionMode::PickingAndEdit : default : delete this; } } // SelectionWorker::SelectionWorker( PlanEditor * planEditor, SelectionMode mode ) SelectionWorker::~SelectionWorker() { // delete m_rubberband; // is not necessary because rubberband is a child QObject of this m_planEditor = nullptr; m_map = nullptr; m_rubberband = nullptr; } // SelectionWorker::~SelectionWorker void SelectionWorker::onAbortSelect(SituationMap::RB::RubberbandBase *) { m_planEditor->onClearSelection(); delete this; } // void SelectionWorker::onAbortSelect( SituationMap::RB::Rubberband * rubberband ) class IntersectLineVisitor : public SituationMap::GeometryNodeVisitor { PlanEditor *m_planEditor; SituationMap::Map *m_map; SituationMap::MathUtils::GeometryEngine::Geometry *m_intersector; unsigned int m_hits; public: IntersectLineVisitor(PlanEditor *planEditor , SituationMap::Map *map , SituationMap::GeometryModel *geoModel , const QVector &linePoints) : GeometryNodeVisitor(geoModel), m_planEditor(planEditor), m_map(map), m_hits(0) { m_intersector = SituationMap::MathUtils::GeometryEngine::createLine(map, linePoints[0], linePoints[1]); } virtual ~IntersectLineVisitor() { SituationMap::MathUtils::GeometryEngine::deleteGeometry(m_intersector); m_intersector = nullptr; } unsigned int hits() const { return m_hits; } bool apply(SituationMap::GeometryModel *geoModel , const SituationMap::GeometryModel::Node &node , SituationMap::GeometryModel::PrimitiveType primitiveType) override { if (SituationMap::GeometryModel::PrimitiveType::RootNode == primitiveType) return true; if (SituationMap::GeometryModel::PrimitiveType::Node == primitiveType) return true; if (SituationMap::GeometryModel::PrimitiveType::Unknown == primitiveType) return false; SituationMap::UniqueMapId uid = m_planEditor->getIdFromNode(node); if (SituationMap::isUniqueMapIdValid(uid)) { SituationMap::ObjectFactory &objFac = m_map->objectFactory(); SituationMap::AbstractMapObject *mapObj = objFac.idToMapObject(uid); if (SituationMap::MathUtils::GeometryEngine::intersect(mapObj, *m_intersector)) { m_planEditor->setSelected(node, true); m_hits++; } else { // Could it be that object is a symbol or text node if ((SituationMap::GeometryModel::PrimitiveType::DictionarySymbol == geoModel->getType(node)) || (SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol == geoModel->getType(node)) || (SituationMap::GeometryModel::PrimitiveType::Text == geoModel->getType(node))) { const QList &points = geoModel->getPrimitivePoints(node); const SituationMap::MathUtils::GeometryEngine::Geometry *geom = SituationMap::MathUtils::GeometryEngine::createPolygon(m_map, points); if (SituationMap::MathUtils::GeometryEngine::intersect(*geom, *m_intersector)) { m_planEditor->setSelected(node, true); m_hits++; } } } } return true; } // bool apply(SituationMap::GeometryModel * geoModel, const SituationMap::GeometryModel::Node & node, SituationMap::GeometryModel::PrimitiveType primitiveType ) }; // IntersectLineVisitor void SelectionWorker::onLineSelect(SituationMap::RB::RubberbandBase *rubberband) { if (rubberband) { const QVector &linePoints = rubberband->coordinateVector(); if (linePoints.size() != 2) return; IntersectLineVisitor selectionVisitor(m_planEditor, m_map, m_geometryModel, linePoints); selectionVisitor.traverse(); if (selectionVisitor.hits() < 1) m_planEditor->onClearSelection(); } m_planEditor->onTransformRubberband(); delete this; } // void SelectionWorker::onLineSelect(SituationMap::RB::Rubberband * rubberband) class IsInPolygonVisitor : public SituationMap::GeometryNodeVisitor { PlanEditor *m_planEditor; SituationMap::Map *m_map; SituationMap::MathUtils::GeometryEngine::Geometry *m_isInHull; unsigned int m_hits; public: IsInPolygonVisitor(PlanEditor *planEditor , SituationMap::Map *map , SituationMap::GeometryModel* geoModel , const QVector &hullPoints) : GeometryNodeVisitor(geoModel), m_planEditor(planEditor), m_map(map), m_hits(0) { m_isInHull = SituationMap::MathUtils::GeometryEngine::createPolygon(map, hullPoints); } virtual ~IsInPolygonVisitor() { SituationMap::MathUtils::GeometryEngine::deleteGeometry(m_isInHull); m_isInHull = nullptr; } unsigned int hits() const { return m_hits; } bool apply(SituationMap::GeometryModel *geoModel , const SituationMap::GeometryModel::Node &node , SituationMap::GeometryModel::PrimitiveType primitiveType) override { if (SituationMap::GeometryModel::PrimitiveType::RootNode == primitiveType) return true; if (SituationMap::GeometryModel::PrimitiveType::Node == primitiveType) return true; if (SituationMap::GeometryModel::PrimitiveType::Unknown == primitiveType) return false; SituationMap::UniqueMapId uid = m_planEditor->getIdFromNode(node); if (SituationMap::isUniqueMapIdValid(uid)) { SituationMap::ObjectFactory &objFac = m_map->objectFactory(); SituationMap::AbstractMapObject *mapObj = objFac.idToMapObject(uid); if (SituationMap::MathUtils::GeometryEngine::contains(mapObj, *m_isInHull)) { m_planEditor->setSelected(node, true); m_hits++; } else { // Could it be that object is a symbol or text node if ((SituationMap::GeometryModel::PrimitiveType::DictionarySymbol == geoModel -> getType(node)) || (SituationMap::GeometryModel::PrimitiveType::ParticipantSymbol == geoModel -> getType(node)) || (SituationMap::GeometryModel::PrimitiveType::Text == geoModel -> getType(node))) { const QList &points = geoModel->getPrimitivePoints(node); const SituationMap::MathUtils::GeometryEngine::Geometry *geom = SituationMap::MathUtils::GeometryEngine::createPolygon(m_map, points); if (SituationMap::MathUtils::GeometryEngine::contains(*geom, *m_isInHull)) { m_planEditor->setSelected(node, true); m_hits++; } } } } return true; } // bool apply(SituationMap::GeometryModel * geoModel, const SituationMap::GeometryModel::Node & node, SituationMap::GeometryModel::PrimitiveType primitiveType ) }; // IsInPolygonVisitor void SelectionWorker::onLassoSelect(SituationMap::RB::RubberbandBase *rubberband) { if (rubberband) { const QVector &linePoints = rubberband->coordinateVector(); if (linePoints.size() < 3) return; IsInPolygonVisitor selectionVisitor(m_planEditor, m_map, m_geometryModel, linePoints); selectionVisitor.traverse(); if (selectionVisitor.hits() < 1) m_planEditor->onClearSelection(); } m_planEditor->onTransformRubberband(); delete this; } // void SelectionWorker::onLassoSelect( SituationMap::RB::Rubberband * rubberband ) void SelectionWorker::onRectSelect(SituationMap::RB::RubberbandBase *rubberband) { if (rubberband) { const QVector &linePoints = rubberband->coordinateVector(); if (linePoints.size() == 2) return; IsInPolygonVisitor selectionVisitor(m_planEditor, m_map, m_geometryModel, linePoints); selectionVisitor.traverse(); if (selectionVisitor.hits() < 1) m_planEditor->onClearSelection(); } m_planEditor->onTransformRubberband(); delete this; } // void SelectionWorker::onRectSelect( SituationMap::RB::Rubberband * rubberband ); } // namespace PlanEditor