Files
qt5-legatus-legacy/Lts/Plugins/CollateralDamageSimulation/Gui/CreateSimulation/cds_plan_creator.cpp
T
2026-08-13 18:33:10 +02:00

306 lines
11 KiB
C++
Executable File

/**
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 <GeometryModel/geometry_model.h>
#include <GeometryModel/geometry_model_factory.h>
#include <LtsUtilsCore/dds_vector.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <FileManagement/flm_ftc.h>
#include <QPolygonF>
#include <QDateTime>
#include <QGuiApplication>
#include <LtsSession/lts_session_data.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <AreaEffectSimulation/Utils/polygons.h>
#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<InfrastructureManagement::Interface::Dtc> &ismDtc, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc, const std::shared_ptr<FileManagement::Interface::Ftc> &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<int, QPolygonF> &buildingFootprints, const QVector<int> &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<QPolygonF> &protectionAreas)
{
m_protectionAreas.reserve(protectionAreas.size());
for (const QPolygonF &protectionArea : protectionAreas)
addProtectionArea(protectionArea);
}
void PlanCreator::addParticipantsWithProtection(const QVector<int> &participantIds)
{
addParticipants(participantIds, ProtectionState::WithProtection);
}
void PlanCreator::addParticipantsWithoutProtection(const QVector<int> &participantIds)
{
addParticipants(participantIds, ProtectionState::WithoutProtection);
}
void PlanCreator::addParticipantsInUnderground(const QVector<int> &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<std::vector<uint8_t>>(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<QWidget*>(parent()), message, tr("Save failed"));
}
void PlanCreator::addDetonationArea(const QPointF &impactPosition, double lethalRadius, double nonLethalRadius)
{
if (!m_geometryModel)
return;
using namespace SituationMap;
QList<QPair<GeometryModel::Attribute, QVariant>> symbolAttributes;
// impact position
symbolAttributes.reserve(4);
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::Fill, QVariant(true)));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::Close, QVariant(true)));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::FillColor, QVariant(QColor(Qt::black))));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::FillPattern, QVariant(static_cast<int>(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, QVariant>(GeometryModel::Attribute::Close, QVariant(true)));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(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, QVariant>(GeometryModel::Attribute::Close, QVariant(true)));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::LineWidth, QVariant(3)));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::LineStyle, QVariant(static_cast<int>(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<QPair<GeometryModel::Attribute, QVariant>> symbolAttributes;
symbolAttributes.reserve(4);
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::Fill, QVariant(true)));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::Close, QVariant(true)));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::FillColor, QVariant(QColor(isDirectlyHit ? Qt::red : Qt::lightGray))));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::FillPattern, QVariant(static_cast<int>(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<int> &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<QPair<GeometryModel::Attribute, QVariant>> symbolAttributes;
QPointF positionPoint(position.pos().lon(), position.pos().lat());
const QList<QPointF> positionList = {positionPoint};
// participant
symbolAttributes.reserve(2);
QString sidc = QString::fromStdString(participant.symbol());
if (sidc.size() > 16)
sidc.replace(16, 1, QString::number(static_cast<int>(protectionState)));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::SIDC, QVariant(sidc)));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(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<QPair<GeometryModel::Attribute, QVariant>> symbolAttributes;
symbolAttributes.reserve(4);
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::Fill, QVariant(true)));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::Close, QVariant(true)));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::FillColor, QVariant(QGuiApplication::palette().color(QPalette::Link))));
symbolAttributes.append(QPair<GeometryModel::Attribute, QVariant>(GeometryModel::Attribute::FillPattern, QVariant(static_cast<int>(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