/** The PlanCreator class creates a tactical plan with the information given by a collateral damage simulation * @RDE_HEADER@ * $Id: ppm_msdl_edit.h 52239 2020-10-05 11:33:12Z thoden $ * $HeadURL: svn://192.168.133.21/TDS/branches/product/features/3dws_devel/Lts/Plugins/ParticipantManagement/Gui/MSDL/ppm_msdl_edit.h $ * $Author: thoden $ * Created by Hannes Fritsche, ESZS, 2024-08-20 */ #include "cds_plan_creator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "cds_calculations.h" namespace CollateralDamageSimulation { CollateralDamageSimulation::PlanCreator::PlanCreator(QWidget *parent) : QObject(parent) {} PlanCreator::~PlanCreator() { if (m_geometryModel != nullptr) { delete m_geometryModel; m_geometryModel = nullptr; } } void PlanCreator::init(const std::shared_ptr &ismDtc, const std::shared_ptr &ppmDtc, const std::shared_ptr &flmFtc) { if (m_geometryModel != nullptr) { delete m_geometryModel; m_geometryModel = nullptr; } m_geometryModel = SituationMap::GeometryModelFactory::singleton()->create(); clear(); m_ismDtc = ismDtc; m_ppmDtc = ppmDtc; m_flmFtc = flmFtc; if (!m_ppmDtc->isPartyEnabled()) { m_ppmDtc->enableParty(); m_ppmDtc->waitForHistoricalDataParty(3000); } if (!m_ppmDtc->isParticipantPositionEnabled()) { m_ppmDtc->enableParticipantPosition(); m_ppmDtc->waitForHistoricalDataParticipantPosition(3000); } if (!m_ppmDtc->isParticipantEnabled()) { m_ppmDtc->enableParticipant(); m_ppmDtc->waitForHistoricalDataParticipant(3000); } } void PlanCreator::addBuildings(const QHash &buildingFootprints, const QVector &directlyHitBuildings) { m_directlyHitBuildings.reserve(directlyHitBuildings.size()); for (auto it = buildingFootprints.constBegin(); it != buildingFootprints.constEnd(); ++it) addBuilding(it.value(), directlyHitBuildings.contains(it.key())); } void PlanCreator::addProtectionAreas(const QVector &protectionAreas) { m_protectionAreas.reserve(protectionAreas.size()); for (const QPolygonF &protectionArea : protectionAreas) addProtectionArea(protectionArea); } void PlanCreator::addParticipantsWithProtection(const QVector &participantIds) { addParticipants(participantIds, ProtectionState::WithProtection); } void PlanCreator::addParticipantsWithoutProtection(const QVector &participantIds) { addParticipants(participantIds, ProtectionState::WithoutProtection); } void PlanCreator::addParticipantsInUnderground(const QVector &participantIds) { addParticipants(participantIds, ProtectionState::Underground); } void PlanCreator::save(const QString &name, int folderId, int exerciseId) { if (!m_protectionAreas.isEmpty()) m_geometryModel->reorderPrimitives(m_protectionAreas, SituationMap::GeometryModel::PrimitivOrder::Raise); if (!m_directlyHitBuildings.isEmpty()) m_geometryModel->reorderPrimitives(m_directlyHitBuildings, SituationMap::GeometryModel::PrimitivOrder::Raise); FileManagement::FileContentModifyRequest data; data.name(name.toStdString()); data.isTemplate(false); data.isHidden(false); data.folderId(folderId); data.fileStatus(FileManagement::FileStatus::Valid); data.fileCategory(FileManagement::FileCategory::Exercise); data.fileType(FileManagement::FileType::TacticalPlan); data.operatorId(LtsSessionData::LtsSessionData::getInstance()->getOperatorId()); data.lastModified(QDateTime::currentMSecsSinceEpoch()); data.content(LtsUtils::convert>(m_geometryModel->toByteArray())); data.exerciseId(exerciseId); bool isModifyRequestOk = m_flmFtc->fileContentModifyRequest(data, [this](const Core::FunctionReplyObject &reply) { if (reply.error()) warnSafeDidNotWork(tr("Could not save plan: %1").arg(QString::fromStdString(reply.str()))); }); if (!isModifyRequestOk) warnSafeDidNotWork(tr("Could not save plan.")); } void PlanCreator::clear() { if (m_geometryModel == nullptr) return; m_protectionAreas.clear(); m_directlyHitBuildings.clear(); m_geometryModel->clearModel(); m_partyCache.clear(); } void PlanCreator::warnSafeDidNotWork(const QString &message) { new LtsWidgets::LtsMessageDialogNew(static_cast(parent()), message, tr("Save failed")); } void PlanCreator::addDetonationArea(const QPointF &impactPosition, double lethalRadius, double nonLethalRadius) { if (!m_geometryModel) return; using namespace SituationMap; QList> symbolAttributes; // impact position symbolAttributes.reserve(4); symbolAttributes.append(QPair(GeometryModel::Attribute::Fill, QVariant(true))); symbolAttributes.append(QPair(GeometryModel::Attribute::Close, QVariant(true))); symbolAttributes.append(QPair(GeometryModel::Attribute::FillColor, QVariant(QColor(Qt::black)))); symbolAttributes.append(QPair(GeometryModel::Attribute::FillPattern, QVariant(static_cast(GeometryModel::FillPattern::Solid)))); m_geometryModel->addPrimitive(GeometryModel::PrimitiveType::Polyline, AreaEffectSimulation::Polygons::circle(impactPosition, 1.0).toList(), symbolAttributes); // lethal radius symbolAttributes.clear(); symbolAttributes.reserve(2); symbolAttributes.append(QPair(GeometryModel::Attribute::Close, QVariant(true))); symbolAttributes.append(QPair(GeometryModel::Attribute::LineWidth, QVariant(3))); m_geometryModel->addPrimitive(GeometryModel::PrimitiveType::Polyline, AreaEffectSimulation::Polygons::circle(impactPosition, lethalRadius).toList(), symbolAttributes); // nonlethal radius if (nonLethalRadius == 0.0) return; symbolAttributes.clear(); symbolAttributes.reserve(3); symbolAttributes.append(QPair(GeometryModel::Attribute::Close, QVariant(true))); symbolAttributes.append(QPair(GeometryModel::Attribute::LineWidth, QVariant(3))); symbolAttributes.append(QPair(GeometryModel::Attribute::LineStyle, QVariant(static_cast(GeometryModel::LineStyle::Dashed)))); m_geometryModel->addPrimitive(GeometryModel::PrimitiveType::Polyline, AreaEffectSimulation::Polygons::circle(impactPosition, nonLethalRadius).toList(), symbolAttributes); } void PlanCreator::addBuilding(const QPolygonF &footprint, bool isDirectlyHit) { if (!m_geometryModel) return; using namespace SituationMap; QList> symbolAttributes; symbolAttributes.reserve(4); symbolAttributes.append(QPair(GeometryModel::Attribute::Fill, QVariant(true))); symbolAttributes.append(QPair(GeometryModel::Attribute::Close, QVariant(true))); symbolAttributes.append(QPair(GeometryModel::Attribute::FillColor, QVariant(QColor(isDirectlyHit ? Qt::red : Qt::lightGray)))); symbolAttributes.append(QPair(GeometryModel::Attribute::FillPattern, QVariant(static_cast(GeometryModel::FillPattern::Solid)))); GeometryModel::Node node = m_geometryModel->addPrimitive(GeometryModel::PrimitiveType::Polyline, footprint.toList(), symbolAttributes); if (isDirectlyHit) m_directlyHitBuildings.append(node); } void PlanCreator::addParticipants(const QVector &participantIds, ProtectionState protectionState) { for (int participantId: participantIds) addParticipant(participantId, protectionState); } void PlanCreator::addParticipant(int participantId, ProtectionState protectionState) { if (!m_geometryModel) return; using namespace SituationMap; const ParticipantManagement::Participant &participant = m_ppmDtc->participant(participantId); const ParticipantManagement::ParticipantPosition &position = m_ppmDtc->participantPosition(participantId); if (!m_partyCache.contains(participant.partyId())) m_partyCache.insert(participant.partyId(), m_ppmDtc->party(participant.partyId())); QList> symbolAttributes; QPointF positionPoint(position.pos().lon(), position.pos().lat()); const QList positionList = {positionPoint}; // participant symbolAttributes.reserve(2); QString sidc = QString::fromStdString(participant.symbol()); if (sidc.size() > 16) sidc.replace(16, 1, QString::number(static_cast(protectionState))); symbolAttributes.append(QPair(GeometryModel::Attribute::SIDC, QVariant(sidc))); symbolAttributes.append(QPair(GeometryModel::Attribute::ForceId, QVariant(participant.partyId()))); m_geometryModel->addPrimitive(GeometryModel::PrimitiveType::ParticipantSymbol, positionList, symbolAttributes); } void PlanCreator::addProtectionArea(const QPolygonF &areaPolygon) { if (!m_geometryModel) return; using namespace SituationMap; QList> symbolAttributes; symbolAttributes.reserve(4); symbolAttributes.append(QPair(GeometryModel::Attribute::Fill, QVariant(true))); symbolAttributes.append(QPair(GeometryModel::Attribute::Close, QVariant(true))); symbolAttributes.append(QPair(GeometryModel::Attribute::FillColor, QVariant(QGuiApplication::palette().color(QPalette::Link)))); symbolAttributes.append(QPair(GeometryModel::Attribute::FillPattern, QVariant(static_cast(GeometryModel::FillPattern::Diag2)))); m_protectionAreas.append(m_geometryModel->addPrimitive(GeometryModel::PrimitiveType::Polyline, areaPolygon.toList(), symbolAttributes)); } SymbologyXML::SymbolTypes::t_affil PlanCreator::partyRoleToSymbolAffiliation(const ParticipantManagement::Role &partyRole) const { switch (partyRole.underlying()) { case ParticipantManagement::Role_def::Unknown: return SymbologyXML::SymbolTypes::UNKNOWN; case ParticipantManagement::Role_def::Friend: return SymbologyXML::SymbolTypes::FRIEND; case ParticipantManagement::Role_def::Neutral: return SymbologyXML::SymbolTypes::NEUTRAL; case ParticipantManagement::Role_def::Enemy: return SymbologyXML::SymbolTypes::ENEMY; case ParticipantManagement::Role_def::Pending: return SymbologyXML::SymbolTypes::PENDING; case ParticipantManagement::Role_def::AssumedFriend: return SymbologyXML::SymbolTypes::ASSUMED_FRIEND; case ParticipantManagement::Role_def::Suspect: return SymbologyXML::SymbolTypes::SUSPECT; default: return SymbologyXML::SymbolTypes::AFFIL_UNDEFINED; } } } //namespace CollateralDamageSimulation