- Merged 292 changed files from dlbo snapshot - Fixed IDL enum collisions (PortType, PdmEventType) - Fixed Grantlee template for C++11 scoped enums - Fixed CMake VERSION_GREATER syntax - Added missing directories (THP, LtsRestClient, etc.) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1193 lines
57 KiB
C++
Executable File
1193 lines
57 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* AesHandler for AdlerJson Plugin
|
|
* $Id: aes_handler.cpp 62899 2024-05-29 11:08:50Z ewert_j $
|
|
* $HeadURL: svn://slssvn/TDS/branches/product/features/ufom/Lts/Proxies/TrainingAreaBase/Plugins/AdlerJson/aes_handler.cpp $
|
|
* $Author: ewert_j $
|
|
* Created by Julius Ewert, ESIM, 2024-03-20
|
|
*/
|
|
|
|
#include "aes_handler.h"
|
|
#include "DDS/Core/function_reply_object.h"
|
|
#include "aes.hpp"
|
|
#include "json_dispatcher.h"
|
|
#include <QJsonArray>
|
|
#include <QJsonDocument>
|
|
#include <QPointF>
|
|
#include <QRectF>
|
|
#include <QString>
|
|
#include <QTransform>
|
|
#include <QVector>
|
|
|
|
#include <time.h>
|
|
#include <vector>
|
|
|
|
#include <AreaEffectSimulation/Trajectory/trajectory_generator.h>
|
|
#include <AreaEffectSimulation/Utils/polygons.h>
|
|
#include <AreaEffectSimulation/aes_operator_rights.h>
|
|
|
|
#include <LtsCoordTrans/lts_coord_trans.h>
|
|
#include <OperatorManagement/opm_dtc.h>
|
|
#include <ProjectDataManagement/pdm_enums.hpp>
|
|
#include <ProjectDataManagement/pdm_translation.h>
|
|
|
|
namespace AdlerJson
|
|
{
|
|
AesHandler::AesHandler(std::shared_ptr<TrainingAreaBase::Interface::Fts> ftsTab, QObject *parent)
|
|
: QObject(parent)
|
|
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
|
, m_logger(getLogger("AesHandler"))
|
|
{
|
|
Q_UNUSED(ftsTab)
|
|
}
|
|
|
|
bool AesHandler::init(MainDispatcher *mainDispatcher)
|
|
{
|
|
m_mainDispatcher = mainDispatcher;
|
|
m_ftcAes = AreaEffectSimulation::Interface::Ftc::create(mainDispatcher->ddsHandler()->ddsConnector());
|
|
m_dtcAes = AreaEffectSimulation::Interface::Dtc::create(mainDispatcher->ddsHandler()->ddsConnector());
|
|
m_dtcPpm = ParticipantManagement::Interface::Dtc::create(mainDispatcher->ddsHandler()->ddsConnector());
|
|
m_ddsHandler = mainDispatcher->ddsHandler();
|
|
if (!m_ftcAes)
|
|
return false;
|
|
|
|
if (!m_ftcAes->enableAirSupportImpactModify() || !m_dtcAes->enableExplosionSingle())
|
|
{
|
|
ERROR_LOG(m_logger) << "Can not enableAirSupportImpactModify or enableExplosionSingle";
|
|
// return false;
|
|
}
|
|
|
|
if (!m_dtcAes->enableExplosionCluster() || !m_ftcAes->enableExplosionClusterModify() || !m_ftcAes->enableExplosionClusterReleaseReceived()
|
|
|| !m_ftcAes->enableExplosionClusterPauseResume() || !m_ftcAes->enableTrajectoryAdlerModify() || !m_ftcAes->enableEffectClusterFireHalt())
|
|
{
|
|
ERROR_LOG(m_logger) << "Can not enableExplosionCluster or enableExplosionClusterModify";
|
|
//
|
|
}
|
|
if (!m_dtcAes->enableEffectCluster() || !m_ftcAes->enableEffectClusterModify() || !m_ftcAes->enableEffectClusterReleaseReceived()
|
|
|| !m_ftcAes->enableEffectClusterPauseResume() || !m_ftcAes->enableEffectClusterRemove())
|
|
{
|
|
ERROR_LOG(m_logger) << "Can not enableEffectnCluster or enableEffectClusterModify";
|
|
//
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "------ Connect Explosion Single Changed ------- ";
|
|
connect(m_dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::explosionSingleChanged, this, &AesHandler::onExplosionSingleChanged);
|
|
connect(m_dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::effectClusterChanged, this, &AesHandler::onEffectClusterChanged);
|
|
|
|
return true;
|
|
}
|
|
|
|
void AesHandler::onOffRouteMineModifyReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onOffRouteMineModifyReply"
|
|
<< ", replyObject.id :" << replyObject.id() << ", str :" << replyObject.str() << ", tanslated :" << replyObject.translated();
|
|
};
|
|
|
|
void AesHandler::onEffectClusterModifyReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onEffectClusterModifyReply"
|
|
<< ", replyObject.id :" << replyObject.id() << ", str :" << replyObject.str() << ", tanslated :" << replyObject.translated()
|
|
<< ", additinal Info :" << replyObject.additionalInfo();
|
|
m_requestHelper->requestReply(replyObject);
|
|
|
|
DEBUG_LOG(m_logger) << "Got Reply";
|
|
|
|
if (replyObject.error())
|
|
{
|
|
// If the error isn't a json object (we use this to reply the reference and party id, as the object is not on dds yet)
|
|
// send an ExTq something went wront, either Data inconistencies or effector is alreaedy assigned.
|
|
DEBUG_LOG(m_logger) << "Got onEffectClusterModifyReply ERROR: " << replyObject.translated();
|
|
ExTqTechnischeQuittung extq;
|
|
extq.technischeDaten.beschreibung = replyObject.translated();
|
|
extq.technischeDaten.status = Status_L32::DAT;
|
|
// I dont Like it.. as we might get two request at the same time.. overriding but should work most of the
|
|
m_mainDispatcher->jsonDispatcher()->sendExTqTechnischeQuittung(extq, m_mainDispatcher->ppmHandler()->getDtc()->participant(m_participantId).partyId());
|
|
return;
|
|
}
|
|
QJsonObject propertiesObject = QJsonDocument::fromJson(QByteArray::fromStdString(replyObject.additionalInfo())).object();
|
|
|
|
ERROR_LOG(m_logger) << "Try send notification0";
|
|
m_aesId = replyObject.id();
|
|
ProjectDataManagement::EffectSource effectSource
|
|
= static_cast<ProjectDataManagement::EffectSource::type>(propertiesObject.value(QStringLiteral("effectSource")).toInt());
|
|
ERROR_LOG(m_logger) << "Try send notification1 " << effectSource;
|
|
|
|
if (effectSource != ProjectDataManagement::EffectSource::ES_ADLER)
|
|
return;
|
|
|
|
QString feuerkampfReferenz = propertiesObject.value(QStringLiteral("feuerkampfReferenz")).toString();
|
|
int partyId = propertiesObject.value(QStringLiteral("partyId")).toInt();
|
|
|
|
m_aesIdToFeuerkampfReferenz.insert(replyObject.id(), feuerkampfReferenz);
|
|
NotificationManagement::CreateNotificationRequest req;
|
|
// The message of the Notification.
|
|
QString content = QString::fromUtf8(tr_lts("Notification", "New Effect Cluster from SAA Verein= %1 <BR />[Open](//ExplosionGui/Adler/%2)"));
|
|
QStringList argsList;
|
|
argsList.append(m_wirkfeldPlanungsData.feuerkommando.verein);
|
|
argsList.append(QString::number(replyObject.id()));
|
|
|
|
std::vector<std::string> args;
|
|
args.reserve(argsList.size());
|
|
for (const auto &str : qAsConst(argsList))
|
|
args.emplace_back(str.toStdString());
|
|
|
|
req.notification().content(content.toStdString());
|
|
req.notification().contentArgs(args);
|
|
// Which Exercise should parse the notification
|
|
req.notification().exerciseId(m_mainDispatcher->exerciseId());
|
|
|
|
req.notification().timeStamp(m_mainDispatcher->ddsHandler()->partitionTime());
|
|
// Priority: Highest: Klick Links immediatly
|
|
// Priority: High: Show message Box
|
|
req.notification().priority(NotificationManagement::Priority::High);
|
|
|
|
// set priority after proccesed for all
|
|
req.notification().processedPriority(NotificationManagement::Priority::Low);
|
|
//req.notification().title(tr_lts("Notification", "Wirkfeldplanung"));
|
|
req.notification().title(tr_lts("Notification", "AES-Planning"));
|
|
// Who is the sender, most of the time a Service
|
|
NotificationManagement::Address addressSender;
|
|
addressSender.addressType(NotificationManagement::AddressType::Service);
|
|
auto saa = m_mainDispatcher->jsonDispatcher()->getSAAByParty(partyId);
|
|
if (saa)
|
|
{
|
|
addressSender.name(saa->getSAAName().toStdString());
|
|
}else
|
|
{
|
|
// use Backup
|
|
addressSender.name(QStringLiteral("TAB").toStdString());
|
|
}
|
|
req.notification().sender(addressSender);
|
|
req.notification().notificationType(NotificationManagement::NotificationType::CombatOrder);
|
|
req.notification().messageType(NotificationManagement::MessageType(NotificationManagement::MessageType::Success));
|
|
|
|
// Notify all Adler User for Party
|
|
std::vector<NotificationManagement::Address> recipentVec;
|
|
// Honestly... I don't know if this is the correct Right? but will do for now
|
|
const QVector<int> recipientIds = m_mainDispatcher->ddsHandler()->dtcOpm()->getNotificationRecipents(m_mainDispatcher->exerciseId(),
|
|
partyId,
|
|
OperatorRights::AdlerExplosionClusterEdit,
|
|
req.notification().notificationType().underlying());
|
|
std::vector<NotificationManagement::Address> recipientIdsDds;
|
|
recipientIdsDds.reserve(recipientIds.size());
|
|
|
|
for (const auto &recipientId : qAsConst(recipientIds))
|
|
{
|
|
NotificationManagement::Address addr;
|
|
addr.addressId(recipientId);
|
|
addr.isRead(false);
|
|
const OperatorManagement::User user = m_mainDispatcher->ddsHandler()->dtcOpm()->user(recipientId);
|
|
addr.name(user.name());
|
|
addr.addressType(NotificationManagement::AddressType_def::Operator);
|
|
recipentVec.emplace_back(addr);
|
|
}
|
|
req.notification().recipientIds(recipentVec);
|
|
if (req.notification().recipientIds().size() > 0)
|
|
{
|
|
m_mainDispatcher->ddsHandler()->ftcNom()->createNotificationRequest(req, this);
|
|
}
|
|
else
|
|
WARNING_LOG(m_logger) << "No recipent found for exercise";
|
|
// sendTrajectoryAdlerModifyRequest(m_wirkfeldPlanungsData, m_participantId, m_wirkmittelIndex, m_aesId);
|
|
}
|
|
|
|
void AesHandler::onCreateNotificationReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
if (replyObject.error())
|
|
ERROR_LOG(m_logger) << "Got onCreateNotificationReply ERROR: " << replyObject.translated();
|
|
}
|
|
|
|
bool AesHandler::sendAesModifyRequest(const QJsonObject &data)
|
|
{
|
|
int equipmentNumber = data[QStringLiteral("header")].toObject()[QStringLiteral("equipmentNumber")].toInt();
|
|
|
|
AreaEffectSimulation::AirSupportImpactModifyRequest request;
|
|
request.chargeTypeId(data[QStringLiteral("chargeTypeId")].toInt());
|
|
request.externalId(data[QStringLiteral("eventId")].toInt());
|
|
request.name(data[QStringLiteral("name")].toString().toStdString());
|
|
request.impactPosition(Core::GeoPosition2D(data[QStringLiteral("impactPosition")].toObject()[QStringLiteral("lon")].toDouble(),
|
|
data[QStringLiteral("impactPosition")].toObject()[QStringLiteral("lat")].toDouble()));
|
|
request.flightTime(0);
|
|
qint64 requestedTime = static_cast<qint64>(data[QStringLiteral("header")].toObject()[QStringLiteral("timeStamp")].toDouble());
|
|
if (requestedTime < m_mainDispatcher->ddsHandler()->partitionTime())
|
|
requestedTime = m_mainDispatcher->ddsHandler()->partitionTime() + 500;
|
|
request.effectStart(requestedTime);
|
|
|
|
QJsonDocument doc(data);
|
|
if (equipmentNumber)
|
|
request.participantId(m_dtcPpm->participantIdByEquipmentNumber(equipmentNumber));
|
|
m_requestHelper->startSingleRequest([this, request]() { return m_ftcAes->airSupportImpactModifyRequest(request, this); });
|
|
return true;
|
|
}
|
|
|
|
bool AesHandler::sendExplosionArea(const QJsonObject &data)
|
|
{
|
|
Q_UNUSED(data)
|
|
|
|
AreaEffectSimulation::OffRouteMine orm;
|
|
orm.id(0);
|
|
orm.name(QString(QStringLiteral("test_offRouteMine_02")).toStdString());
|
|
orm.chargeStruct().chargeTypeId(254);
|
|
orm.effectDuration(6000);
|
|
orm.partyId(2);
|
|
orm.impactRadius(10);
|
|
|
|
orm.area().cornerBottomLeft(Core::GeoPosition2D(0, 0));
|
|
orm.area().height(50);
|
|
orm.area().width(1);
|
|
orm.area().rotation(85);
|
|
|
|
orm.effectStart((time(nullptr) + 10) * 1000);
|
|
|
|
AreaEffectSimulation::OffRouteMineModifyRequest
|
|
req(orm.id(), orm.name(), orm.effectDuration(), orm.chargeStruct().chargeTypeId(), orm.area(), orm.impactRadius(), orm.effectStart(), orm.partyId());
|
|
|
|
m_ftcAes->offRouteMineModifyRequest(req, this);
|
|
|
|
return true;
|
|
}
|
|
|
|
void AesHandler::onAirSupportImpactModifyReply(const Core::FunctionReplyObject &reply) { m_requestHelper->requestReply(reply); }
|
|
|
|
void AesHandler::handleCreateSingleExplosion(const TrainingAreaBase::TetraIcd::CreateSingleExplosion &data)
|
|
{
|
|
auto strFromObj = QJsonDocument(data.toJson()).toJson(QJsonDocument::Compact);
|
|
m_singleExplosions.insert(data.aesDdsId, AreaEffectSimulation::AesEffectState_def::EsCreated);
|
|
DEBUG_LOG(m_logger) << "TEST SINGLE EXPLOSION CREATED " << strFromObj;
|
|
}
|
|
|
|
void AesHandler::handleEXFire(const Feuerkampfdaten &data, int wsId)
|
|
{
|
|
|
|
if (!m_mainDispatcher->jsonDispatcher()->getSAAByWs(wsId))
|
|
return;
|
|
|
|
auto saa = m_mainDispatcher->jsonDispatcher()->getSAAByWs(wsId);
|
|
int particpantId = m_dtcPpm->getParticipantByInternalName(saa->getPartyId(), data.verein, waffensystemkennerMap.key(data.kenner)).id();
|
|
TrainingAreaBase::EX_Fire outData;
|
|
outData.equipmentNumber() = particpantId;
|
|
outData.reference() = data.feuerkampfReferenz.toStdString();
|
|
outData.identifier() = data.verein.toStdString();
|
|
outData.effectorId() = data.kenner.underlying(); // static_cast<L27_EffectorId_def>((int)data.kenner);
|
|
m_ddsHandler->dtsTab()->publish(outData);
|
|
QTimer::singleShot(3000, [this, particpantId]() { m_ddsHandler->dtsTab()->removeEX_FireByKey(particpantId); });
|
|
|
|
const QString refTrimmed = data.feuerkampfReferenz.trimmed();
|
|
handleAmmoCount(data, saa->getPartyId(), m_feuerkampfReferenzUsedFeuerHalt[refTrimmed]);
|
|
// This is for pause Resume
|
|
/*
|
|
m_ftcAes->explosionClusterPauseResumeRequest(AreaEffectSimulation::ExplosionClusterPauseResumeRequest(aes.id(),
|
|
false, // resumeExecution
|
|
dds::core::optional<rti::core::int64>(),
|
|
dds::core::optional<int32_t>(),
|
|
dds::core::optional<int32_t>())
|
|
, this);
|
|
|
|
*/
|
|
}
|
|
|
|
void AesHandler::handleEXDontFire(const Feuerkampfdaten &data, int wsId)
|
|
{
|
|
if (!m_mainDispatcher->jsonDispatcher()->getSAAByWs(wsId))
|
|
return;
|
|
|
|
const auto saa = m_mainDispatcher->jsonDispatcher()->getSAAByWs(wsId);
|
|
|
|
DEBUG_LOG(m_logger) << "[EX-FQ(nFN)] data from SSA " << wsId << " : "
|
|
<< "verein: " << data.verein << " "
|
|
<< "kenner: " << data.kenner.underlying() << " "
|
|
<< "feuerkampfReferenz: " << data.feuerkampfReferenz;
|
|
|
|
handleAmmoCount(data, saa->getPartyId(), true);
|
|
// The EX-FQ(nFN) message is used to count shots during a General CEASE FIRE or a Referenced CEASE FIRE.
|
|
// After the CEASE FIRE is lifted, the remaining shots are transmitted again using an EX-FQ(FN) message.
|
|
|
|
const QString refTrimmed = data.feuerkampfReferenz.trimmed();
|
|
m_feuerkampfReferenzUsedFeuerHalt[refTrimmed] = true;
|
|
}
|
|
|
|
void AesHandler::onTrajectoryAdlerModifyReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onTrajectoryAdlerModifyReply"
|
|
<< ", aesId :" << reply.id() << ", str :" << reply.str() << ", m_wirkmittelIndex :" << m_wirkmittelIndex
|
|
<< ", m_data.feuerkommando.wirkmittel.size() :" << m_wirkfeldPlanungsData.feuerkommando.wirkmittel.size();
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << reply.translated();
|
|
if (m_wirkmittelIndex == m_wirkfeldPlanungsData.feuerkommando.wirkmittel.size() - 1)
|
|
{
|
|
// TODO TAB->SAA EX-MQ
|
|
DEBUG_LOG(m_logger) << "TAB->SAA EX-MQ"
|
|
<< ", feuerkampfReferenz :" << m_wirkfeldPlanungsData.feuerkampfReferenz;
|
|
|
|
DEBUG_LOG(m_logger) << "onTrajectoryAdlerModifyReply " << reply.id();
|
|
ExFeuerbereit exFB;
|
|
// exFB.feuerkampfdaten.feuerkampfReferenz = QString::fromStdString(data.element());
|
|
exFB.feuerkampfdaten.feuerkampfReferenz = m_wirkfeldPlanungsData.feuerkampfReferenz;
|
|
// exFB.feuerkampfdaten.verein = QString::fromStdString(m_dtcPpm->participant(data.participantId().get()).name());
|
|
exFB.feuerkampfdaten.verein = m_wirkfeldPlanungsData.feuerkommando.verein;
|
|
// exFB.feuerkampfdaten.kenner =
|
|
// m_mainDispatcher->jsonDispatcher()->sendExFeuerbereit(exFB, data.partyId().get());
|
|
}
|
|
if (m_wirkmittelIndex < m_wirkfeldPlanungsData.feuerkommando.wirkmittel.size() - 1)
|
|
{
|
|
m_wirkmittelIndex++;
|
|
DEBUG_LOG(m_logger) << "sendTrajectoryAdlerModifyRequest"
|
|
<< ", m_participantId :" << m_participantId << ", m_wirkmittelIndex :" << m_wirkmittelIndex << ", m_aesId :" << m_aesId;
|
|
sendTrajectoryAdlerModifyRequest(m_wirkfeldPlanungsData, m_participantId, m_wirkmittelIndex, m_aesId);
|
|
}
|
|
}
|
|
|
|
void AesHandler::sendTrajectoryAdlerModifyRequest(const WirkfeldplanungData &data, int participantId, int wirkmittelIndex, int aesId)
|
|
{
|
|
|
|
DEBUG_LOG(m_logger) << "sendTrajectoryAdlerModifyRequest"
|
|
<< ", participantId :" << participantId << ", wirkmittelIndex :" << wirkmittelIndex << ", aesId:" << aesId;
|
|
std::vector<Core::RelativePositionRelativeTime> geometryRef;
|
|
geometryRef.clear();
|
|
geometryRef.reserve(data.feuerkommando.wirkmittel.at(wirkmittelIndex).flugbahnpunkt.size());
|
|
|
|
QVector<int> subordinates = m_dtcPpm->getSubordinatesByParticipant(participantId);
|
|
QVector<ParticipantManagement::ParticipantPosition> subordinatePositions;
|
|
|
|
for (int subordinate : qAsConst(subordinates))
|
|
{
|
|
DEBUG_LOG(m_logger) << "subordinates(" << participantId << ") :" << subordinate;
|
|
subordinatePositions.append(m_dtcPpm->participantPosition(subordinate));
|
|
}
|
|
|
|
AreaEffectSimulation::TrajectoryAdlerModifyRequest *newRequest = new AreaEffectSimulation::TrajectoryAdlerModifyRequest();
|
|
newRequest->aesItemId(aesId);
|
|
newRequest->explosionIndex(wirkmittelIndex);
|
|
|
|
int zone = -1;
|
|
Core::GeoPosition positionLaunch = subordinatePositions.at(wirkmittelIndex).pos();
|
|
auto utmLaunch = LtsCoordTrans::UtmCoordinate::fromGeographic(positionLaunch.lon(), positionLaunch.lat(), zone);
|
|
|
|
double grad = (data.zieldaten.zielachse / 6400.) * 360.0;
|
|
|
|
for (Flugbahnpunkt pos : qAsConst(data.feuerkommando.wirkmittel.at(wirkmittelIndex).flugbahnpunkt))
|
|
{
|
|
/*
|
|
DEBUG_LOG(m_logger) << "Flugbahnpunkt:"
|
|
<< ", xRelativ :" << pos.xRelativ
|
|
<< ", yRelativ :" << pos.yRelativ
|
|
<< ", zRelativ :" << pos.zRelativ
|
|
<< ", zeit :" << pos.zeit
|
|
<< ", positionLaunch :" << positionLaunch.lon()
|
|
<< " / " << positionLaunch.lat()
|
|
<< " / " << positionLaunch.z()
|
|
<< "<< utmLaunch :" << utmLaunch.x
|
|
<< " / " << utmLaunch.y
|
|
<< " / " << utmLaunch.zone;
|
|
*/
|
|
QPointF utm = QPointF(pos.xRelativ, pos.zRelativ);
|
|
QPointF utmLaunchPt(utmLaunch.x, utmLaunch.y);
|
|
|
|
utm += utmLaunchPt;
|
|
double z = positionLaunch.z() + pos.yRelativ;
|
|
|
|
// see also: coordtrans_test::testRelativeMetricalOffet()
|
|
LtsCoordTrans::UtmCoordinate utmCoord;
|
|
utmCoord.x = utm.x();
|
|
utmCoord.y = utm.y();
|
|
utmCoord.zone = utmLaunch.zone;
|
|
QPointF pntGeo = utmCoord.geographic();
|
|
|
|
// Rotiert im Uhrzeigersinn um den Nullpunkt (0,0)
|
|
// double grad = (data.zieldaten.zielachse / 6400.) * 360;
|
|
// DEBUG_LOG(m_logger) << " milli rad to degree" <<(data.zieldaten.zielachse / 6400.) * 360;
|
|
|
|
// Rotiert im Uhrzeigersinn um den Nullpunkt (0,0)
|
|
// DEBUG_LOG(m_logger) << " mmilirad: " <<data.zieldaten.zielachse;
|
|
|
|
// double shussrichtung = effectorAdler.schussrichtung;
|
|
// DEBUG_LOG(m_logger) << " millii rad to degree" <<grad;
|
|
// use defatult degree from start to end! not target axis
|
|
|
|
// double shussrichtung = effectorAdler.schussrichtung;
|
|
QTransform matrix;
|
|
matrix.rotate(-grad);
|
|
|
|
QPointF point(pntGeo.x(), pntGeo.y());
|
|
DEBUG_LOG(m_logger) << " POS bevore rot: " << point;
|
|
|
|
auto rotatePoint = matrix.map(point);
|
|
DEBUG_LOG(m_logger) << " POS after rot: " << rotatePoint;
|
|
|
|
pntGeo.setX(rotatePoint.x());
|
|
pntGeo.setY(rotatePoint.y());
|
|
|
|
// DEBUG_LOG(m_logger) << "utmCoord :" << utmCoord.x << " / " << utmCoord.y << ", utmCoord.zone :" << utmCoord.zone
|
|
// << ", utmCoord.isValid() :" << utmCoord.isValid()
|
|
// << ", pntGeo :" << pntGeo.x() << " / " << pntGeo.y() << " / " << z;
|
|
|
|
|
|
// LS-669: Soweit ich das sehen kann, müssen hier relative Koordinaten übertragen werden.
|
|
const Core::RelativePositionRelativeTime relPos(pntGeo.x(), pntGeo.y(), z,
|
|
std::round(pos.zeit * 1000.0));
|
|
geometryRef.emplace_back(relPos);
|
|
}
|
|
|
|
Core::GeoPosition impactPosition;
|
|
impactPosition.lat(data.zieldaten.koordinate.koordinate.latitude * M_PI / 180.0);
|
|
impactPosition.lon(data.zieldaten.koordinate.koordinate.longitude * M_PI / 180.0);
|
|
impactPosition.z(data.zieldaten.koordinate.hoehe);
|
|
newRequest->impactPosition(impactPosition);
|
|
newRequest->geometry(geometryRef);
|
|
DEBUG_LOG(m_logger) << "geometryRef.size=" << geometryRef.size() << ", newRequest->geometry().size() :" << newRequest->geometry().size();
|
|
|
|
if (newRequest->aesItemId() <= 0)
|
|
{
|
|
ERROR_LOG(m_logger) << "newRequest->aesItemId() <=0"
|
|
<< ", aesItemId :" << newRequest->aesItemId();
|
|
return;
|
|
}
|
|
newRequest->peakAltitude(data.feuerkommando.wirkmittel.at(wirkmittelIndex).gipfelhoehe);
|
|
newRequest->mhpScatterLenght(data.feuerkommando.wirkmittel.at(wirkmittelIndex).streuung.laengsstreuung);
|
|
newRequest->mhpScatterWidth(data.feuerkommando.wirkmittel.at(wirkmittelIndex).streuung.seitenstreuung);
|
|
newRequest->mhpScatterLengthDetonationHeight(data.feuerkommando.wirkmittel.at(wirkmittelIndex).streuung.laengsstreuungH);
|
|
newRequest->mhpScatterWidthDetonationHeight(data.feuerkommando.wirkmittel.at(wirkmittelIndex).streuung.seitenstreuungH);
|
|
m_ftcAes->trajectoryAdlerModifyRequest(*newRequest, this);
|
|
}
|
|
|
|
void AesHandler::handleEffectCluster(const WirkfeldplanungData &data, int wsId)
|
|
{
|
|
DEBUG_LOG(m_logger) << "AesHandler::handleEffectCluster (Empfang WirkfeldplanungData)"
|
|
<< ", feuerkampfReferenz :" << data.feuerkampfReferenz << ", wirkmittel.size() :" << data.feuerkommando.wirkmittel.size();
|
|
// here we convert the FQBB to create EffectCluster
|
|
if (!m_mainDispatcher->jsonDispatcher()->getSAAByWs(wsId))
|
|
{
|
|
ERROR_LOG(m_logger) << "!m_mainDispatcher->jsonDispatcher()->getSAAByWs(" << wsId << ") return";
|
|
return;
|
|
}
|
|
const QString &verein = data.feuerkommando.verein;
|
|
// #ifdef LTS_DEBUG
|
|
// const ParticipantManagement::Participant &part = m_dtcPpm->participant(89);
|
|
// DEBUG_LOG(m_logger) << "participantId :" << part.id()
|
|
// << ", partyId :" << part.partyId();
|
|
// #else
|
|
const int partyId = m_mainDispatcher->jsonDispatcher()->getSAAByWs(wsId)->getPartyId();
|
|
const bool isVerbund = m_mainDispatcher->jsonDispatcher()->getSAAByWs(wsId)->getIsVerbund();
|
|
const ParticipantManagement::Participant &part = m_mainDispatcher->ppmHandler()->findParticipantByInternalName(verein, partyId, isVerbund);
|
|
// #endif
|
|
if (part.id() <= 0)
|
|
{
|
|
ERROR_LOG(m_logger) << "Got EffectClusterData for " << verein << " but unit not found";
|
|
return;
|
|
}
|
|
|
|
// get overall impacts
|
|
m_wirkfeldPlanungsData = data;
|
|
m_participantId = part.id();
|
|
m_wirkmittelIndex = 0;
|
|
|
|
// for (const auto &wm : data.feuerkommando.wirkmittel)
|
|
// {
|
|
// impactCount += wm.geschoss.anzahl;
|
|
// mhpCount ++; //TODO we could get the correct point
|
|
// //chargeTypeId = // TODO MAP wm.geschoss.geschosssorte
|
|
// sendTrajectoryAdlerModifyRequest(data, part.id(), mhpCount);
|
|
// }
|
|
|
|
// The worst part about the SAA we don't even get all the data needed to create a usefull effect cluster.
|
|
// Sometimes we will get a geometry (e.g. for mortar) but most of the time the "Target area" is lost
|
|
// in that case we need to create our own area from the target points.. and probably "guess" the target geometry
|
|
|
|
AreaEffectSimulation::AesExplosionGeometry geometry = AreaEffectSimulation::AesExplosionGeometry::EgArea;
|
|
AreaEffectSimulation::Area area;
|
|
const bool createArea = data.zieldaten.breiteRadius == 0 && data.zieldaten.tiefe == 0;
|
|
ERROR_LOG(m_logger) << "create AREA??? " << createArea << " breite " << data.zieldaten.breiteRadius << " tiefe " << data.zieldaten.tiefe;
|
|
|
|
if (!createArea && data.zieldaten.geometrie == ProjectDataManagement::L4_TargetGeometry::Point)
|
|
{
|
|
geometry = AreaEffectSimulation::AesExplosionGeometry::EgPoint;
|
|
// we need to set the area from pdm so we use the first actors charge type
|
|
const auto &chargeData = data.feuerkommando.wirkmittel.at(0).geschoss;
|
|
|
|
const int chargeTypeId = m_mainDispatcher->pdmHandler()->getDtc()->getChargeTypeIdFromAdlerCharges(chargeData.geschosssorte);
|
|
const int igniterTypeId = m_mainDispatcher->pdmHandler()->getDtc()->getIgniterTypeIdFromAdlerIgniter(chargeData.zuender);
|
|
const int igniterFunctionId = m_mainDispatcher->pdmHandler()->getDtc()->getIgniterFunctionIdFromAdlerIgniterFunction(chargeData.zuenderFunktion);
|
|
const int impactRadius = m_mainDispatcher->pdmHandler()->getDtc()->impactRadius(chargeTypeId, igniterTypeId, igniterFunctionId);
|
|
|
|
DEBUG_LOG(m_logger) << "Impact Radius for " << chargeTypeId << " " << igniterTypeId << " " << igniterTypeId << " is " << impactRadius;
|
|
area.height(impactRadius * 2);
|
|
area.width(impactRadius * 2);
|
|
}
|
|
if (!createArea && data.zieldaten.geometrie == ProjectDataManagement::L4_TargetGeometry::Radial)
|
|
{
|
|
geometry = AreaEffectSimulation::AesExplosionGeometry::EgRadial;
|
|
// In Radial we need to double the radius and also set it as height/width
|
|
area.height(data.zieldaten.breiteRadius * 2);
|
|
area.width(data.zieldaten.breiteRadius * 2);
|
|
}
|
|
else if (!createArea) // we need the rect or the line
|
|
{
|
|
// maye wrong?
|
|
// not only maybe.. we need to swap .. yes..
|
|
area.height(data.zieldaten.breiteRadius);
|
|
if (data.zieldaten.tiefe > 0)
|
|
area.width(data.zieldaten.tiefe);
|
|
else
|
|
if (data.zieldaten.geometrie == ProjectDataManagement::L4_TargetGeometry::Linear)
|
|
area.width(5); // E01562-472 [Verbund] ImpactWidth invalid. Ein Wirkfeld mit der Zielgeometrie "Linear" kann nicht verarbeitet werden.
|
|
}
|
|
|
|
if (!createArea)
|
|
{
|
|
area.rotation((data.zieldaten.zielachse / 6400.) * 360); // UTM STRICH?
|
|
|
|
// point is center
|
|
const QPointF centerPoint(data.zieldaten.koordinate.koordinate.longitude * (M_PI / 180.0), data.zieldaten.koordinate.koordinate.latitude * (M_PI / 180.0));
|
|
QRectF rect(QPointF(), QSizeF(area.height(), area.width()));
|
|
rect.moveCenter(QPointF());
|
|
// Compass, not mathematical! "90-" left out as Polygon already is rotated by 90 degree
|
|
const QPointF bl = QTransform().rotate(-area.rotation()).map(rect.topLeft());
|
|
const LtsCoordTrans::UtmCoordinate centerUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(centerPoint);
|
|
DEBUG_LOG(m_logger) << "centerUtm="
|
|
<< ", x :" << centerUtm.x << ", y :" << centerUtm.y << ", zone :" << centerUtm.zone;
|
|
const QPointF &bottomLeft = centerUtm.geographic(bl);
|
|
DEBUG_LOG(m_logger) << "bl="
|
|
<< ", x :" << bl.x() << ", y :" << bl.y();
|
|
DEBUG_LOG(m_logger) << "bottomLeft="
|
|
<< ", x :" << bottomLeft.x() << ", y :" << bottomLeft.y();
|
|
area.cornerBottomLeft(Core::GeoPosition2D(bottomLeft.x(), bottomLeft.y()));
|
|
DEBUG_LOG(m_logger) << "area.cornerBottomLeft="
|
|
<< ", lon :" << area.cornerBottomLeft().lon() << ", lat :" << area.cornerBottomLeft().lat();
|
|
|
|
const LtsCoordTrans::UtmCoordinate cornerBottomLeftUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(area.cornerBottomLeft().lon(), area.cornerBottomLeft().lat());
|
|
DEBUG_LOG(m_logger) << "cornerBottomLeftUtm="
|
|
<< ", x :" << cornerBottomLeftUtm.x << ", y :" << cornerBottomLeftUtm.y << ", zone :" << cornerBottomLeftUtm.zone;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << " Need to generate area";
|
|
if (data.feuerkommando.wirkmittel.size() == 1)
|
|
{
|
|
|
|
DEBUG_LOG(m_logger) << " Need to generate area SINGLE";
|
|
geometry = AreaEffectSimulation::AesExplosionGeometry::EgPoint;
|
|
|
|
// we need to set the area from pdm so we use the first actors charge type
|
|
|
|
const auto &wirkmittel = data.feuerkommando.wirkmittel.at(0);
|
|
const auto &chargeData = wirkmittel.geschoss;
|
|
|
|
const int chargeTypeId = m_mainDispatcher->pdmHandler()->getDtc()->getChargeTypeIdFromAdlerCharges(chargeData.geschosssorte);
|
|
const int igniterTypeId = m_mainDispatcher->pdmHandler()->getDtc()->getIgniterTypeIdFromAdlerIgniter(chargeData.zuender);
|
|
const int igniterFunctionId = m_mainDispatcher->pdmHandler()->getDtc()->getIgniterFunctionIdFromAdlerIgniterFunction(chargeData.zuenderFunktion);
|
|
const int impactRadius = m_mainDispatcher->pdmHandler()->getDtc()->impactRadius(chargeTypeId, igniterTypeId, igniterFunctionId);
|
|
|
|
DEBUG_LOG(m_logger) << "Impact Radius for " << chargeTypeId << " " << igniterTypeId << " " << igniterTypeId << " is " << impactRadius;
|
|
area.height(impactRadius * 2);
|
|
area.width(impactRadius * 2);
|
|
|
|
// point is center
|
|
|
|
const QPointF centerPoint(wirkmittel.auftreffpunkt.koordinate.longitude * (M_PI / 180.0), wirkmittel.auftreffpunkt.koordinate.latitude * (M_PI / 180.0));
|
|
QRectF rect(QPointF(), QSizeF(area.height(), area.width()));
|
|
rect.moveCenter(QPointF());
|
|
// Compass, not mathematical! "90-" left out as Polygon already is rotated by 90 degree
|
|
const QPointF bl = QTransform().rotate(-area.rotation()).map(rect.topLeft());
|
|
const LtsCoordTrans::UtmCoordinate centerUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(centerPoint);
|
|
DEBUG_LOG(m_logger) << "centerUtm="
|
|
<< ", x :" << centerUtm.x << ", y :" << centerUtm.y << ", zone :" << centerUtm.zone;
|
|
const QPointF bottomLeft = centerUtm.geographic(bl);
|
|
DEBUG_LOG(m_logger) << "bl="
|
|
<< ", x :" << bl.x() << ", y :" << bl.y();
|
|
DEBUG_LOG(m_logger) << "bottomLeft="
|
|
<< ", x :" << bottomLeft.x() << ", y :" << bottomLeft.y();
|
|
area.cornerBottomLeft(Core::GeoPosition2D(bottomLeft.x(), bottomLeft.y()));
|
|
DEBUG_LOG(m_logger) << "area.cornerBottomLeft="
|
|
<< ", lon :" << area.cornerBottomLeft().lon() << ", lat :" << area.cornerBottomLeft().lat();
|
|
|
|
const LtsCoordTrans::UtmCoordinate cornerBottomLeftUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(area.cornerBottomLeft().lon(), area.cornerBottomLeft().lat());
|
|
ERROR_LOG(m_logger) << "cornerBottomLeftUtm="
|
|
<< ", x :" << cornerBottomLeftUtm.x << ", y :" << cornerBottomLeftUtm.y << ", zone :" << cornerBottomLeftUtm.zone;
|
|
}
|
|
else if (data.feuerkommando.wirkmittel.size() > 1)
|
|
{
|
|
|
|
DEBUG_LOG(m_logger) << " Need to generate area AREA";
|
|
// Area even though thez might all target the same point
|
|
geometry = AreaEffectSimulation::AesExplosionGeometry::EgArea;
|
|
// Now we take the charge data from the first effector
|
|
// we need the impactradius to create an area
|
|
const auto &chargeData = data.feuerkommando.wirkmittel.at(0).geschoss;
|
|
const int chargeTypeId = m_mainDispatcher->pdmHandler()->getDtc()->getChargeTypeIdFromAdlerCharges(chargeData.geschosssorte);
|
|
const int igniterTypeId = m_mainDispatcher->pdmHandler()->getDtc()->getIgniterTypeIdFromAdlerIgniter(chargeData.zuender);
|
|
const int igniterFunctionId = m_mainDispatcher->pdmHandler()->getDtc()->getIgniterFunctionIdFromAdlerIgniterFunction(chargeData.zuenderFunktion);
|
|
const int impactRadius = m_mainDispatcher->pdmHandler()->getDtc()->impactRadius(chargeTypeId, igniterTypeId, igniterFunctionId);
|
|
|
|
DEBUG_LOG(m_logger) << "Impact Radius for " << chargeTypeId << " " << igniterTypeId << " " << igniterTypeId << " is " << impactRadius;
|
|
|
|
// Now that we know the impact radius we create a boundingbox around all impact areas
|
|
QList<AreaEffectSimulation::Area> areas;
|
|
QList<QRectF> rects;
|
|
int zone = 0;
|
|
QVector<QPointF> vecPoints;
|
|
for (const WirkmittelFeuerkommando &effector : qAsConst(data.feuerkommando.wirkmittel))
|
|
{
|
|
// get the target point for the effector
|
|
const QPointF centerPoint(effector.auftreffpunkt.koordinate.longitude * (M_PI / 180.0), effector.auftreffpunkt.koordinate.latitude * (M_PI / 180.0));
|
|
|
|
AreaEffectSimulation::Area areaEffector;
|
|
areaEffector.height() = impactRadius * 2;
|
|
areaEffector.width() = impactRadius * 2;
|
|
QRectF rect(QPointF(), QSizeF(areaEffector.height(), areaEffector.width()));
|
|
rect.moveCenter(QPointF());
|
|
|
|
// Compass, not mathematical! "90-" left out as Polygon already is rotated by 90 degree
|
|
const QPointF bl = QTransform().rotate(90).map(rect.topLeft());
|
|
|
|
const LtsCoordTrans::UtmCoordinate centerUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(centerPoint);
|
|
zone = centerUtm.zone;
|
|
const QPointF bottomLeft = centerUtm.geographic(bl);
|
|
areaEffector.cornerBottomLeft(Core::GeoPosition2D(bottomLeft.x(), bottomLeft.y()));
|
|
|
|
rect.moveCenter(QPointF(centerUtm.x, centerUtm.y));
|
|
// now add Area to list
|
|
areas.append(areaEffector);
|
|
rects.append(rect);
|
|
vecPoints.append(rect.topLeft());
|
|
vecPoints.append(rect.topRight());
|
|
vecPoints.append(rect.bottomLeft());
|
|
vecPoints.append(rect.bottomRight());
|
|
}
|
|
|
|
// Finally use the rerturning rect as Area
|
|
area = createMinimumRect(zone, vecPoints);
|
|
DEBUG_LOG(m_logger) << "FINAL AREA " << area.cornerBottomLeft() << " " << area.height() << " " << area.width();
|
|
}
|
|
else if (data.feuerkommando.wirkmittelRakete.size() > 0)
|
|
{
|
|
DEBUG_LOG(m_logger) << " Need to generate area AREA";
|
|
// Area even though thez might all target the same point
|
|
geometry = AreaEffectSimulation::AesExplosionGeometry::EgArea;
|
|
// Now we take the charge data from the first effector
|
|
// we need the impactradius to create an area
|
|
const auto &chargeData = data.feuerkommando.wirkmittelRakete.at(0).geschoss;
|
|
const int chargeTypeId = m_mainDispatcher->pdmHandler()->getDtc()->getChargeTypeIdFromAdlerCharges(chargeData.geschosssorte);
|
|
const int igniterTypeId = m_mainDispatcher->pdmHandler()->getDtc()->getIgniterTypeIdFromAdlerIgniter(chargeData.zuender);
|
|
const int igniterFunctionId = m_mainDispatcher->pdmHandler()->getDtc()->getIgniterFunctionIdFromAdlerIgniterFunction(chargeData.zuenderFunktion);
|
|
const int impactRadius = m_mainDispatcher->pdmHandler()->getDtc()->impactRadius(chargeTypeId, igniterTypeId, igniterFunctionId);
|
|
|
|
// Now that we know the impact radius we create a boundingbox around all impact areas
|
|
int zone = 0;
|
|
QVector<QPointF> vecPoints;
|
|
for (const WirkmittelFeuerkommandoRakete &effector : qAsConst(data.feuerkommando.wirkmittelRakete))
|
|
{
|
|
for (const Treffpunkt &treffpunkt : qAsConst(effector.treffpunkte))
|
|
{
|
|
const QPointF centerPoint(treffpunkt.koordinate.koordinate.longitude * (M_PI / 180.0), treffpunkt.koordinate.koordinate.latitude * (M_PI / 180.0));
|
|
|
|
AreaEffectSimulation::Area areaEffector;
|
|
areaEffector.height() = impactRadius * 2;
|
|
areaEffector.width() = impactRadius * 2;
|
|
QRectF rect(QPointF(), QSizeF(areaEffector.height(), areaEffector.width()));
|
|
rect.moveCenter(QPointF());
|
|
|
|
// Compass, not mathematical! "90-" left out as Polygon already is rotated by 90 degree
|
|
const QPointF bl = QTransform().rotate(90).map(rect.topLeft());
|
|
|
|
const LtsCoordTrans::UtmCoordinate centerUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(centerPoint);
|
|
zone = centerUtm.zone;
|
|
const QPointF bottomLeft = centerUtm.geographic(bl);
|
|
areaEffector.cornerBottomLeft(Core::GeoPosition2D(bottomLeft.x(), bottomLeft.y()));
|
|
|
|
rect.moveCenter(QPointF(centerUtm.x, centerUtm.y));
|
|
// now add Area to list
|
|
vecPoints.append(rect.topLeft());
|
|
vecPoints.append(rect.topRight());
|
|
vecPoints.append(rect.bottomLeft());
|
|
vecPoints.append(rect.bottomRight());
|
|
}
|
|
}
|
|
|
|
// Finally use the returning rect as Area
|
|
area = createMinimumRect(zone, vecPoints);
|
|
DEBUG_LOG(m_logger) << "FINAL AREA " << area.cornerBottomLeft() << " " << area.height() << " " << area.width();
|
|
}
|
|
}
|
|
|
|
AreaEffectSimulation::EffectClusterModifyRequest req;
|
|
for (const AreaEffectSimulation::EffectCluster &clus : m_dtcAes->effectClusters())
|
|
{
|
|
// ERROR_LOG(m_logger) << "Look for if: " << clus.element() << " is data: " << data.feuerkampfReferenz;
|
|
if (clus.partyId() != part.partyId())
|
|
continue;
|
|
if (clus.isDeleted())
|
|
continue;
|
|
if (clus.effectStateId() != AreaEffectSimulation::AesEffectState::EsPrepared && clus.effectStateId() != AreaEffectSimulation::AesEffectState::EsCreated
|
|
&& clus.effectStateId() != AreaEffectSimulation::AesEffectState::EsReceived)
|
|
continue;
|
|
|
|
if (clus.element() != data.feuerkampfReferenz.trimmed().toStdString())
|
|
continue;
|
|
req.id(clus.id());
|
|
}
|
|
|
|
QJsonObject obj;
|
|
obj[AdlerJson::JsonKeys::FEUERKAMPFREFERENZ()] = data.feuerkampfReferenz;
|
|
|
|
obj[QStringLiteral("useReceived")] = true;
|
|
obj[QStringLiteral("effectSource")] = ProjectDataManagement::EffectSource::ES_ADLER;
|
|
obj[AdlerJson::JsonKeys::ABFEUERUNGSART()] = static_cast<int>(data.abfeuerungsArt);
|
|
// TargetData is often only optional
|
|
obj[AdlerJson::JsonKeys::TYP()] = m_mainDispatcher->pdmHandler()->getDtc()->getTargetTypeIdFromAdlerTargetType(data.zieldaten.typ);
|
|
obj[AdlerJson::JsonKeys::SUB_TYP()] = m_mainDispatcher->pdmHandler()->getDtc()->getTargetSubTypeIdFromAdlerTargetSubType(data.zieldaten.subTyp);
|
|
obj[AdlerJson::JsonKeys::ELEMENTE()] = data.zieldaten.elemente;
|
|
obj[AdlerJson::JsonKeys::NUMMER()] = data.zieldaten.nummer;
|
|
|
|
obj[QStringLiteral("partyId")] = part.partyId();
|
|
// fill EffectorData
|
|
std::vector<AreaEffectSimulation::EffectorData> effectorVec;
|
|
|
|
if (data.feuerkommando.wirkmittel.size() > 0)
|
|
{
|
|
for (const auto &effectorAdler : qAsConst(data.feuerkommando.wirkmittel))
|
|
{
|
|
AreaEffectSimulation::EffectorData effectorData;
|
|
effectorData.angleOfFall() = 0;
|
|
effectorData.chargeAmount() = effectorAdler.geschoss.anzahl;
|
|
effectorData.chargeStruct().chargeTypeId() = m_mainDispatcher->pdmHandler()->getDtc()->getChargeTypeIdFromAdlerCharges(effectorAdler.geschoss.geschosssorte);
|
|
effectorData.chargeStruct().igniterTypeId() = m_mainDispatcher->pdmHandler()->getDtc()->getIgniterTypeIdFromAdlerIgniter(effectorAdler.geschoss.zuender);
|
|
effectorData.chargeStruct().igniterFunctionId()
|
|
= m_mainDispatcher->pdmHandler()->getDtc()->getIgniterFunctionIdFromAdlerIgniterFunction(effectorAdler.geschoss.zuenderFunktion);
|
|
DEBUG_LOG(m_logger) << "FOUND chargeTypeId " << effectorData.chargeStruct().chargeTypeId() << " for " << effectorAdler.geschoss.geschosssorte;
|
|
DEBUG_LOG(m_logger) << "igniterTypeId: " << effectorData.chargeStruct().igniterTypeId();
|
|
DEBUG_LOG(m_logger) << "igniterFunctionId: " << effectorData.chargeStruct().igniterFunctionId();
|
|
effectorData.participantId()
|
|
= m_dtcPpm->getParticipantByInternalName(part.partyId(), QString::fromStdString(part.name()), waffensystemkennerMap.key(effectorAdler.kenner)).id();
|
|
std::vector<Core::RelativePositionRelativeTime> flightCurve;
|
|
flightCurve.reserve(effectorAdler.flugbahnpunkt.size());
|
|
|
|
const auto &startPos = m_dtcPpm->participantPosition(effectorData.participantId());
|
|
const auto coordStart = LtsCoordTrans::UtmCoordinate::fromGeographic(startPos.pos().lon(), startPos.pos().lat());
|
|
DEBUG_LOG(m_logger) << "Start point: " << coordStart;
|
|
|
|
const auto coordEnd = LtsCoordTrans::UtmCoordinate::fromGeographic(effectorAdler.auftreffpunkt.koordinate.longitude * (M_PI / 180.0),
|
|
effectorAdler.auftreffpunkt.koordinate.latitude * (M_PI / 180.0));
|
|
DEBUG_LOG(m_logger) << "End point: " << coordEnd;
|
|
LtsCoordTrans::UtmCoordinate coordDiff = coordEnd;
|
|
|
|
coordDiff.x = coordDiff.x - coordStart.x;
|
|
coordDiff.y = coordDiff.y - coordStart.y;
|
|
DEBUG_LOG(m_logger) << "Last point: " << coordDiff.x << " " << coordDiff.y;
|
|
DEBUG_LOG(m_logger) << "Last point ATAN: " << std::atan2(coordDiff.y, coordDiff.x);
|
|
|
|
const double useNewGrad = -90 + std::atan2(coordDiff.y, coordDiff.x) * (180.0 / M_PI);
|
|
DEBUG_LOG(m_logger) << "Atan2 Deg to: last point " << std::atan2(coordDiff.y, coordDiff.x) * (180.0 / M_PI);
|
|
|
|
for (const auto &flightPointAdler : qAsConst(effectorAdler.flugbahnpunkt))
|
|
{
|
|
Core::RelativePositionRelativeTime flightPoint;
|
|
flightPoint.offsetX() = 0; // flightPointAdler.zRelativ;
|
|
flightPoint.offsetY() = flightPointAdler.xRelativ;
|
|
flightPoint.offsetZ() = flightPointAdler.yRelativ;
|
|
flightPoint.relativeTime() = flightPointAdler.zeit * 1000;
|
|
|
|
QTransform matrix;
|
|
matrix.rotate(useNewGrad);
|
|
const QPointF point(flightPoint.offsetX(), flightPoint.offsetY());
|
|
TRACE_LOG(m_logger) << " POS bevore rot: " << point;
|
|
|
|
const auto rotatePoint = matrix.map(point);
|
|
TRACE_LOG(m_logger) << " POS after rot: " << rotatePoint;
|
|
|
|
flightPoint.offsetX() = rotatePoint.x();
|
|
flightPoint.offsetY() = rotatePoint.y();
|
|
|
|
flightCurve.push_back(flightPoint);
|
|
}
|
|
effectorData.trajectoryRelative() = flightCurve;
|
|
effectorData.flightTime() = effectorAdler.flugzeit * 1000;
|
|
effectorData.chargeStruct().igniterTypeId() = 1; // effectorAdler.geschoss.zuender; //XKCD
|
|
effectorData.interval() = effectorAdler.geschoss.intervall;
|
|
Core::GeoPosition mhpPos;
|
|
mhpPos.lat() = effectorAdler.auftreffpunkt.koordinate.latitude * (M_PI / 180.0);
|
|
mhpPos.lon() = effectorAdler.auftreffpunkt.koordinate.longitude * (M_PI / 180.0);
|
|
mhpPos.z() = effectorAdler.auftreffpunkt.hoehe;
|
|
effectorData.mhpPosition() = mhpPos;
|
|
effectorData.mhpRotation() = 90.0 - (effectorAdler.schussrichtung / 6400.) * 360;
|
|
effectorData.mhpScatterLenght() = effectorAdler.streuung.laengsstreuung;
|
|
effectorData.mhpScatterLengthDetonationHeight() = effectorAdler.streuung.laengsstreuungH;
|
|
effectorData.mhpScatterWidth() = effectorAdler.streuung.seitenstreuung;
|
|
effectorData.mhpScatterWidthDetonationHeight() = effectorAdler.streuung.seitenstreuungH;
|
|
DEBUG_LOG(m_logger) << effectorAdler.kenner;
|
|
DEBUG_LOG(m_logger) << "Looking for participantID with stats = party: " << part.partyId() << " unitname: " << part.name()
|
|
<< " effectorname: " << waffensystemkennerMap.key(effectorAdler.kenner);
|
|
effectorData.peakHeight() = effectorAdler.gipfelhoehe;
|
|
effectorVec.push_back(effectorData);
|
|
|
|
// We will override with the last one but okay should be suffice
|
|
obj[AdlerJson::JsonKeys::LADUNG()] = m_mainDispatcher->pdmHandler()->getDtc()->getLoadTypeIdFromAdlerLoad(effectorAdler.geschoss.ladung);
|
|
obj[AdlerJson::JsonKeys::LADUNGSNUMMER()] = effectorAdler.geschoss.ladungsNummer;
|
|
}
|
|
}
|
|
else if (data.feuerkommando.wirkmittelRakete.size() > 0)
|
|
{
|
|
for (const auto &effectorAdler : qAsConst(data.feuerkommando.wirkmittelRakete))
|
|
{
|
|
AreaEffectSimulation::EffectorData effectorData;
|
|
|
|
effectorData.chargeAmount() = effectorAdler.geschoss.anzahl;
|
|
effectorData.angleOfFall() = effectorAdler.fallwinkel;
|
|
effectorData.chargeStruct().chargeTypeId() = m_mainDispatcher->pdmHandler()->getDtc()->getChargeTypeIdFromAdlerCharges(effectorAdler.geschoss.geschosssorte);
|
|
effectorData.chargeStruct().igniterTypeId() = m_mainDispatcher->pdmHandler()->getDtc()->getIgniterTypeIdFromAdlerIgniter(effectorAdler.geschoss.zuender);
|
|
effectorData.chargeStruct().igniterFunctionId()
|
|
= m_mainDispatcher->pdmHandler()->getDtc()->getIgniterFunctionIdFromAdlerIgniterFunction(effectorAdler.geschoss.zuenderFunktion);
|
|
|
|
DEBUG_LOG(m_logger) << "FOUND chargeTypeId " << effectorData.chargeStruct().chargeTypeId() << " for " << effectorAdler.geschoss.geschosssorte;
|
|
DEBUG_LOG(m_logger) << "igniterTypeId: " << effectorData.chargeStruct().igniterTypeId();
|
|
DEBUG_LOG(m_logger) << "igniterFunctionId: " << effectorData.chargeStruct().igniterFunctionId();
|
|
|
|
effectorData.participantId()
|
|
= m_dtcPpm->getParticipantByInternalName(part.partyId(), QString::fromStdString(part.name()), waffensystemkennerMap.key(effectorAdler.kenner)).id();
|
|
if (effectorData.participantId() == 0)
|
|
WARNING_LOG(m_logger) << "Could not find participant for partiyId " << part.partyId() << ", name " << part.name() << ", kenner " << effectorAdler.kenner;
|
|
effectorData.chargeStruct().igniterTypeId() = m_mainDispatcher->pdmHandler()->getDtc()->getIgniterTypeIdFromAdlerIgniter(effectorAdler.geschoss.zuender);
|
|
effectorData.interval() = effectorAdler.geschoss.intervall;
|
|
|
|
// create centroid
|
|
Core::GeoPosition mhpPos;
|
|
QPointF centroid;
|
|
for (const auto &treffpunkt : qAsConst(effectorAdler.treffpunkte))
|
|
centroid += {treffpunkt.koordinate.koordinate.latitude, treffpunkt.koordinate.koordinate.longitude};
|
|
|
|
centroid /= effectorAdler.treffpunkte.size();
|
|
|
|
mhpPos.lat() = centroid.x() * (M_PI / 180.0);
|
|
mhpPos.lon() = centroid.y() * (M_PI / 180.0);
|
|
mhpPos.z() = effectorAdler.treffpunkte.at(0).koordinate.hoehe;
|
|
effectorData.mhpPosition() = mhpPos;
|
|
effectorData.mhpRotation() = 90.0 - (effectorAdler.schussrichtung / 6400.) * 360;
|
|
effectorData.mhpScatterLenght() = 0.0;
|
|
effectorData.mhpScatterLengthDetonationHeight() = 0.0;
|
|
effectorData.mhpScatterWidth() = 0.0;
|
|
effectorData.mhpScatterWidthDetonationHeight() = 0.0;
|
|
effectorData.peakHeight() = effectorAdler.gipfelhoehe;
|
|
|
|
QJsonObject properties;
|
|
AdlerJson::wirkmittelFeuerkommandoRaketeToJson(properties, effectorAdler);
|
|
effectorData.properties() = QJsonDocument(properties).toJson(QJsonDocument::Compact).toStdString();
|
|
|
|
// trajectory without time start ------------------------------------------
|
|
const ParticipantManagement::ParticipantPosition &participantPosition = m_dtcPpm->participantPosition(effectorData.participantId());
|
|
const LtsUtils::QPoint3D trajectoryStart(participantPosition.pos().lon(), participantPosition.pos().lat(), participantPosition.pos().z());
|
|
|
|
const LtsUtils::QPoint3D trajectoryEnd(effectorData.mhpPosition().lon(), effectorData.mhpPosition().lat(), effectorData.mhpPosition().z());
|
|
|
|
AreaEffectSimulation::TrajectoryGeoPosition trajectoryWithoutTime;
|
|
|
|
if (!AreaEffectSimulation::TrajectoryGenerator::getInstance()->generateTrajectoryBiedziak(trajectoryStart, trajectoryEnd, 45.0, trajectoryWithoutTime))
|
|
ERROR_LOG(m_logger) << "Could not create trajectory for Feuerkommando " << data.feuerkommando.verein;
|
|
// trajectory without time end -------------------------------------------
|
|
|
|
// trajectory with time start -------------------------------------------
|
|
effectorData.flightTime() = effectorAdler.flugzeit * 1000;
|
|
const double flightTimeStep = effectorData.flightTime() / static_cast<double>(trajectoryWithoutTime.size());
|
|
double currentFlightTime = 0.0;
|
|
|
|
const LtsCoordTrans::UtmCoordinate utmStartPos = LtsCoordTrans::UtmCoordinate::fromGeographic(participantPosition.pos().lon(), participantPosition.pos().lat());
|
|
for (const Core::GeoPosition &pos : qAsConst(trajectoryWithoutTime))
|
|
{
|
|
const LtsCoordTrans::UtmCoordinate utmCurrentPos = LtsCoordTrans::UtmCoordinate::fromGeographic(pos.lon(), pos.lat());
|
|
|
|
effectorData.trajectoryRelative().emplace_back(utmCurrentPos.x - utmStartPos.x, utmCurrentPos.y - utmStartPos.y, pos.z(),
|
|
currentFlightTime);
|
|
|
|
currentFlightTime += flightTimeStep;
|
|
}
|
|
// trajectory with time end --------------------------------------------
|
|
|
|
obj[AdlerJson::JsonKeys::LADUNG()] = m_mainDispatcher->pdmHandler()->getDtc()->getLoadTypeIdFromAdlerLoad(effectorAdler.geschoss.ladung);
|
|
obj[AdlerJson::JsonKeys::LADUNGSNUMMER()] = effectorAdler.geschoss.ladungsNummer;
|
|
|
|
effectorVec.push_back(effectorData);
|
|
}
|
|
}
|
|
req.effectors() = effectorVec;
|
|
|
|
QString propertiesStr = QString::fromStdString(QJsonDocument(obj).toJson(QJsonDocument::Compact).toStdString());
|
|
std::string properties = propertiesStr.toStdString();
|
|
req.properties(properties);
|
|
req.area(area);
|
|
req.effectMarkingInTa(true);
|
|
req.partyId(part.partyId());
|
|
req.explosionGeometry(geometry);
|
|
req.firePurposeId(static_cast<int>(data.forderung.underlying())); // TODO Mapping
|
|
req.effectSourceId(ProjectDataManagement::EffectSource::ES_ADLER);
|
|
req.name(data.feuerkampfReferenz.toStdString());
|
|
req.element(data.feuerkampfReferenz.toStdString());
|
|
req.effectDuration(data.dauer * 1000);
|
|
req.participantId(part.id());
|
|
req.externalId(7);
|
|
req.tla(data.zieldaten.zog); // defaults to 0 if not set
|
|
|
|
if (data.feuerkommando.wirkmittel.empty())
|
|
DEBUG_LOG(m_logger) << "flugzeit :"
|
|
<< " -";
|
|
else
|
|
DEBUG_LOG(m_logger) << "flugzeit :" << data.feuerkommando.wirkmittel.at(0).flugzeit;
|
|
|
|
DEBUG_LOG(m_logger) << "SEND " << data.feuerkampfReferenz << " ";
|
|
int ammoCounter = 0;
|
|
std::vector<ProjectDataManagement::L27_EffectorId> refWirkmittel;
|
|
refWirkmittel.reserve(data.feuerkommando.wirkmittel.size());
|
|
|
|
for (const auto &wm : qAsConst(data.feuerkommando.wirkmittel))
|
|
{
|
|
ammoCounter += wm.geschoss.anzahl; // Counts every Ammo that will be shooted
|
|
DEBUG_LOG(m_logger) << "INSERT KENNER INTO MAP: " << data.feuerkampfReferenz << "---------" << wm.kenner;
|
|
refWirkmittel.push_back(wm.kenner);
|
|
}
|
|
|
|
m_feuerkampReferenzAmmoCounter.insert(data.feuerkampfReferenz, ammoCounter);
|
|
m_feuerkampfReferenzWirkmittel.insert(data.feuerkampfReferenz, refWirkmittel);
|
|
m_feuerkampfReferenzUsedFeuerHalt.insert(data.feuerkampfReferenz, false);
|
|
|
|
m_ftcAes->effectClusterModifyRequest(req, this);
|
|
}
|
|
|
|
QList<qint32> AesHandler::findAllPendingEffectCluster(int partyId)
|
|
{
|
|
// QList<AreaEffectSimulation::EffectCluster> ret;
|
|
QList<qint32> ret;
|
|
const auto &effectClusters = m_dtcAes->effectClusters();
|
|
for (const auto &effectCluster : qAsConst(effectClusters))
|
|
{
|
|
if (effectCluster.partyId() != partyId)
|
|
continue;
|
|
if (effectCluster.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsReceived
|
|
&& effectCluster.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsCreated)
|
|
continue;
|
|
if (effectCluster.effectSourceId() != ProjectDataManagement::EffectSource_def::ES_ADLER /*&&
|
|
effectCluster.effectSourceId() != ProjectDataManagement::EffectSource_def::ES_ADLER_STANDALONE*/)
|
|
continue;
|
|
|
|
ret.append(effectCluster.id());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* * handleAmmoCount handhabt die Munitionszählung (AmmoCount).
|
|
* TODO: Behebung des Persistenz-Problems:
|
|
* Aktuell gehen die Map-Daten bei einem Service-Restart verloren.
|
|
* ! 'm_feuerkampReferenzAmmoCounter' ist nach Restart leer.
|
|
* Dies kann zu Inkonsistenzen führen, falls die SAA eine VM (Vollzugsmeldung) erwartet,
|
|
* der Zählerstand aber zurückgesetzt wurde.
|
|
* ? Refactoring-Option:
|
|
* Sobald der 'EffectCluster' die reale Munition der Adler-Bekämpfungspläne führt,
|
|
* sollte diese Map durch den 'EffectCluster'-Counter ersetzt werden, um eine
|
|
* "Single Source of Truth" zu gewährleisten.
|
|
*
|
|
* STAND (16.04.2026)
|
|
*/
|
|
void AesHandler::handleAmmoCount(const Feuerkampfdaten &data, int saaPartyId, bool sendExVollzug)
|
|
{
|
|
const QString refTrimmed = data.feuerkampfReferenz.trimmed();
|
|
|
|
if (!m_feuerkampReferenzAmmoCounter.contains(refTrimmed))
|
|
return;
|
|
|
|
const auto &aesEffetClusters = m_dtcAes->effectClusters();
|
|
|
|
for (const auto &aes : qAsConst(aesEffetClusters))
|
|
{
|
|
if (aes.isDeleted() || aes.partyId() != saaPartyId || aes.element() != refTrimmed.toStdString())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int refAmmoCounter = 0;
|
|
refAmmoCounter = m_feuerkampReferenzAmmoCounter.value(refTrimmed, -1);
|
|
|
|
bool outOfAmmo = false;
|
|
const int newAmmoAmount = std::max(0, refAmmoCounter - 1);
|
|
|
|
DEBUG_LOG(m_logger) << "Handle ammo count - ID: " << aes.id() << " | Ref: " << refTrimmed << " | PartyID: " << saaPartyId << " | oldAmmoCount: " << refAmmoCounter
|
|
<< " | newAmmoCount: " << newAmmoAmount;
|
|
|
|
if (newAmmoAmount <= 0)
|
|
{
|
|
m_feuerkampReferenzAmmoCounter.remove(refTrimmed);
|
|
}
|
|
else
|
|
{
|
|
m_feuerkampReferenzAmmoCounter[refTrimmed] = newAmmoAmount;
|
|
}
|
|
|
|
outOfAmmo = (newAmmoAmount == 0);
|
|
|
|
if (outOfAmmo && sendExVollzug)
|
|
{
|
|
auto refKenners = m_feuerkampfReferenzWirkmittel.value(refTrimmed);
|
|
|
|
for (const auto &kenner : qAsConst(refKenners))
|
|
{
|
|
ExVollzugsmeldung exvm;
|
|
exvm.feuerkampfdaten.feuerkampfReferenz = data.feuerkampfReferenz;
|
|
exvm.feuerkampfdaten.kenner = kenner;
|
|
exvm.feuerkampfdaten.verein = data.verein;
|
|
|
|
DEBUG_LOG(m_logger) << "------------ SENDE ExVollzugsmeldung für ------------ " << kenner;
|
|
|
|
m_mainDispatcher->jsonDispatcher()->sendExVollzugsmeldung(exvm, saaPartyId);
|
|
}
|
|
|
|
Core::RemoveElementRequest req;
|
|
req.id(aes.id());
|
|
|
|
m_ftcAes->effectClusterRemoveRequest(req);
|
|
// After remove effectCluster remove FeuerkampfReferenz from Maps
|
|
m_feuerkampfReferenzUsedFeuerHalt.remove(refTrimmed);
|
|
m_feuerkampfReferenzWirkmittel.remove(refTrimmed);
|
|
m_feuerkampReferenzAmmoCounter.remove(refTrimmed);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AesHandler::removeAllPendingEffectCluster(int partyId)
|
|
{
|
|
const QList<qint32> &effectClusterIds = findAllPendingEffectCluster(partyId);
|
|
if (effectClusterIds.isEmpty())
|
|
return;
|
|
|
|
INFO_LOG(m_logger) << "Pending effect cluster size: " << effectClusterIds.size();
|
|
Core::RemoveElementRequest req;
|
|
for (const qint32 id : qAsConst(effectClusterIds))
|
|
{
|
|
req.id(id);
|
|
INFO_LOG(m_logger) << "Remove effect cluster id: " << id;
|
|
|
|
qint32 ret = m_ftcAes->effectClusterRemoveRequest(req);
|
|
INFO_LOG(m_logger) << "m_ftsAes->effectClusterRemoveRequest(req) --> " << ret;
|
|
}
|
|
}
|
|
|
|
AreaEffectSimulation::Area AesHandler::createMinimumRect(int zone, const QVector<QPointF> &points)
|
|
{
|
|
double angle = 0.0;
|
|
AreaEffectSimulation::Area ret;
|
|
|
|
auto rec = AreaEffectSimulation::Polygons::getMinAreaRect(points, angle);
|
|
|
|
LtsCoordTrans::UtmCoordinate coord(zone, rec.bottomLeft().x(), rec.bottomLeft().y());
|
|
ret.cornerBottomLeft() = Core::GeoPosition2D(coord.geographic().x(), coord.geographic().y());
|
|
ret.rotation() = angle;
|
|
ret.height() = abs(rec.height());
|
|
ret.width() = abs(rec.width());
|
|
|
|
return ret;
|
|
}
|
|
void AesHandler::onExplosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType)
|
|
{
|
|
|
|
if (modType == DataModification::eRemoved)
|
|
{
|
|
DEBUG_LOG(m_logger) << "----------------- remove area ------------- ";
|
|
m_singleExplosions.remove(data.id());
|
|
return;
|
|
}
|
|
if (modType == DataModification::eAdded)
|
|
{
|
|
DEBUG_LOG(m_logger) << "----------------- add area ------------- " << data.effectStateId();
|
|
m_singleExplosions.insert(data.id(), data.effectStateId());
|
|
return;
|
|
}
|
|
if (data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated
|
|
&& m_singleExplosions.value(data.id(), AreaEffectSimulation::AesEffectState::EsActivated) != AreaEffectSimulation::AesEffectState_def::EsActivated)
|
|
{
|
|
const auto state = data.effectStateId();
|
|
DEBUG_LOG(m_logger) << "----------------- switch state ------------- " << state;
|
|
m_singleExplosions.insert(data.id(), state);
|
|
QJsonObject telegram;
|
|
telegram[QStringLiteral("typeId")] = 80082;
|
|
telegram[QStringLiteral("type")] = QStringLiteral("UFomHlaExplosionSingleChanged");
|
|
|
|
QJsonObject headerJson;
|
|
headerJson[QStringLiteral("aesId")] = data.id();
|
|
headerJson[QStringLiteral("timeStamp")] = m_mainDispatcher->ddsHandler()->partitionTime();
|
|
|
|
QJsonObject impactPosition;
|
|
impactPosition[QStringLiteral("lon")] = data.impactPosition().lon();
|
|
impactPosition[QStringLiteral("lat")] = data.impactPosition().lat();
|
|
|
|
QJsonObject jsonData;
|
|
jsonData[QStringLiteral("header")] = headerJson;
|
|
jsonData[QStringLiteral("impactPosition")] = impactPosition; // detonationLocation
|
|
if (data.participantId().is_set())
|
|
{
|
|
jsonData[QStringLiteral("participantId")] = data.participantId().get(); // firingObjectIdentifier
|
|
}
|
|
|
|
telegram[QStringLiteral("data")] = jsonData;
|
|
emit explosionSingleChanged(telegram);
|
|
}
|
|
}
|
|
|
|
void AesHandler::onEffectClusterChanged(const AreaEffectSimulation::EffectCluster &data, DataModification modType)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Try auto handle effectCluster: " << data.name();
|
|
|
|
if (modType == DataModification::eRemoved)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "Try auto handle effectCluster: probs: " << data.properties();
|
|
|
|
if (data.properties().empty())
|
|
return;
|
|
|
|
if (!data.partyId().is_set())
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "has PARTY " << data.properties();
|
|
|
|
if (!data.participantId().is_set())
|
|
return;
|
|
|
|
if (data.effectSourceId() != ProjectDataManagement::EffectSource::ES_ADLER)
|
|
return;
|
|
DEBUG_LOG(m_logger) << "has PARTICIPANTID " << data.properties();
|
|
|
|
QJsonObject propertiesObject = QJsonDocument::fromJson(QByteArray::fromStdString(data.properties())).object();
|
|
if (!propertiesObject.value(QStringLiteral("useReceived")).toBool())
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "has USE RECEIVED " << data.effectStateId().underlying();
|
|
|
|
switch (data.effectStateId().underlying())
|
|
{
|
|
case AreaEffectSimulation::AesEffectState::EsCreated:
|
|
{
|
|
// Auftragsannahme (manuelle Quittung)
|
|
// Could be send via notification managment??
|
|
if (m_aesIdToFeuerkampfReferenz.contains(data.id()))
|
|
{
|
|
const QJsonObject probObject = QJsonDocument::fromJson(QByteArray::fromStdString(data.properties())).object();
|
|
const QString reference = probObject[AdlerJson::JsonKeys::FEUERKAMPFREFERENZ()].toString();
|
|
|
|
ExMqManuelleQuittung exmq;
|
|
// exmq.mqManuelleQuittungDaten.feuerkampfreferenz = QString::fromStdString(data.element());
|
|
|
|
exmq.mqManuelleQuittungDaten.feuerkampfreferenz = reference;
|
|
m_mainDispatcher->jsonDispatcher()->sendExMqManuelleQuittung(exmq, data.partyId().get());
|
|
|
|
// After that we'll remove it form the list to not send an MQ again!
|
|
m_aesIdToFeuerkampfReferenz.remove(data.id());
|
|
DEBUG_LOG(m_logger) << "SEND MQ for " << data.name() << " " << reference;
|
|
break;
|
|
}
|
|
}
|
|
case AreaEffectSimulation::AesEffectState::EsReceived:
|
|
case AreaEffectSimulation::AesEffectState::EsPrepared:
|
|
case AreaEffectSimulation::AesEffectState::EsFired: // EsFired! will be handled by fired topic
|
|
case AreaEffectSimulation::AesEffectState::EsExpired: // EX Expired is not for ADLER it just need the ConfirmationReport
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
} // namespace AdlerJson
|