Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Services/GuezMinelayerProcessing/handler_minelayer_data.cpp
T
berrux-dev c3eda18234 Migrates remaining services and plugins to generated rtiddsgen API
Converts accessor calls to plain member access across the residual service set.
2026-09-21 02:47:48 +02:00

354 lines
14 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Handler for incoming data from minelayer trialer/thrower and thier lane data
* $Id$
* $HeadURL$
* $Author$
* created by Philipp Dassow, SLEA, 2017-04-06
*/
#include "handler_minelayer_data.h"
#include <AreaEffectSimulation/aes_ftc.h>
#include <AssetManagement/asm_dtc.h>
#include <ExerciseManagement/exm_dtc.h>
#include "dds_handler.h"
#include "zssi_wi_Minenfeld_Interpreter.h"
#include <QtCore/QLineF>
namespace GuezMinelayerProcessing
{
HandlerMinelayerData::HandlerMinelayerData(const std::shared_ptr<DdsHandler> &ddsHandler,
QObject *parent)
: QObject(parent)
, m_ddsHandler(ddsHandler)
, m_tabDtc(nullptr)
, m_ppmDtc(nullptr)
, m_aesFtc(nullptr)
, m_minefieldInterpreter(new ZSSI_WI_Minenfeld_Interpreter(this))
, m_minefieldInterpreterTimer(new QTimer(this))
, m_logger(getLogger("HandlerMinelayerData"))
{}
HandlerMinelayerData::~HandlerMinelayerData()
{}
bool HandlerMinelayerData::init()
{
// AES-Ftc
m_aesFtc = AreaEffectSimulation::Interface::Ftc::create(m_ddsHandler->ddsConnector());
bool ret = m_aesFtc->enableMineAreaModifyFromCtaData();
if (!ret)
{
ERROR_LOG(m_logger) << "AesFtc Can not enable MineAreaCreateFromCtaData()";
return false;
}
// Data from training area base
m_tabDtc = TrainingAreaBase::Interface::Dtc::create(m_ddsHandler->ddsConnector());
ret &= m_tabDtc->enableSpecialSensorData();
ret &= m_tabDtc->enableMinelayerTrailerData();
ret &= m_tabDtc->enableMinelayerThrowerData();
if (!ret)
{
ERROR_LOG(m_logger) << "TabDtc Can not ebale Data";
return false;
}
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::specialSensorDataChanged, this, &HandlerMinelayerData::onSpecialSensorDataChanged);
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::minelayerTrailerDataChanged, this, &HandlerMinelayerData::onMinelayerTrailerData);
connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::minelayerThrowerDataChanged, this, &HandlerMinelayerData::onMinelayerThrowerData);
// PPM for partyId Mapping
m_ppmDtc = ParticipantManagement::Interface::Dtc::create(m_ddsHandler->ddsConnector());
ret &= m_ppmDtc->enableParticipant();
if (!ret)
{
ERROR_LOG(m_logger) << "PpmDtc Can not enable Participant Data";
return false;
}
// connect to minefield generator
connect(m_minefieldInterpreter, &ZSSI_WI_Minenfeld_Interpreter::sendeWirkfeld, this, &HandlerMinelayerData::onSendMinefield);
// start Interpreter
connect(m_minefieldInterpreterTimer, &QTimer::timeout, this, &HandlerMinelayerData::onStartMinefieldInterpreter);
m_minefieldInterpreterTimer->start(m_minefieldInterpreter->triggerIntervall * 1000);
return ret;
}
void HandlerMinelayerData::onSpecialSensorDataChanged(const TrainingAreaBase::SpecialSensorData &data, DataModification modType)
{
if (modType != DataModification::eAdded &&
modType != DataModification::eModified)
return;
if (data.operationalState != MV_VERLEGEN &&
data.operationalState != WMV_VERLEGEN)
return;
if (!data.position.is_set())
return;
{
// convert TrainingAreaBase::LaneData back to sondersensorik_fahrspur_rt
FAHRSPUR_INTERN daten_intern;
//Interpretationsstatus auf 0 setzen
daten_intern.intstat = 0;
daten_intern.daten.header.identitaet = data.equipmentNumber;
daten_intern.daten.gps_zeit.gps_zeit = data.sampleTime / 1000;
daten_intern.daten.gps_position = relativeFromGeographic(data.position.get().lon, data.position.get().lat);
daten_intern.daten.ss_betriebszustand = data.operationalState;
// old code copied from zssi_wi_Empfaenger.cpp
/*
if ( checkeTelegrammZeit(telegramm_rt.gps_zeit.gps_zeit) ) {
ERROR_LOG(m_logger) << QStringLiteral("Keine plausible gps_zeit !! gps_zeit=%1").arg(telegramm_rt.gps_zeit.gps_zeit);
return;
}
if ( checkeKoordinaten(telegramm_rt.gps_pos)!=0 ) {
ERROR_LOG(m_logger) << QStringLiteral("Keine plausible gps_pos !! pos_x=%1 Keine plausible gps_pos !! pos_y=%2").arg(telegramm_rt.gps_pos.utm_ostwert).arg(telegramm_rt.gps_pos.utm_nordwert);
return;
}
*/
VERLEGEDATEN_KEY key_intern;
key_intern.fz_id = daten_intern.daten.header.identitaet;
key_intern.zeitpunkt.gps_zeit = daten_intern.daten.gps_zeit.gps_zeit;
interne_datenbasis_Fahrspur.eintrag_container(key_intern, daten_intern);
INFO_LOG(m_logger) << "Inserted new lane data into old interne_datenbasis_Fahrspur succesfully! Lane data:" << data;
// end old code
}
}
template<typename T>
void HandlerMinelayerData::convertMinelayerDataToXdrData(const TrainingAreaBase::MinelayerTrailerData &inData, T &outData)
{
outData.header.identitaet = inData.equipmentNumber;
outData.gps_zeit.gps_zeit = inData.sampleTime / 1000; // derived from Tetra telegram
outData.gps_position = relativeFromGeographic(inData.position.lon, inData.position.lat);
outData.verlegedaten.sperren_id = inData.barrierId;
outData.verlegedaten.verlegedichte = inData.layingDensity;
outData.verlegedaten.wirkbeginn.gps_zeit = inData.effectStart / 1000; // derived from Tetra telegram
outData.verlegedaten.wirkzeit = inData.effectDuration;
outData.verlegedaten.minentyp = inData.chargeTypeId;
outData.verlegedaten.anzahl_verlegter_minen = inData.mineCount;
}
void HandlerMinelayerData::onMinelayerTrailerData(const TrainingAreaBase::MinelayerTrailerData &data, DataModification modType)
{
if ((modType == DataModification::eAdded) ||
(modType == DataModification::eModified))
{
VERLEGEDATEN_INTERN daten_intern;
convertMinelayerDataToXdrData(data, daten_intern.daten);
// old code copied from zssi_wi_Empfaenger.cpp
/*
INFO_LOG(m_logger) << log_tr("Telegramm 'SONDERSENSORIK_MIVANH_VERLEGEDATEN' empfangen");
if ( checkeTelegrammZeit(telegramm_rt.gps_zeit.gps_zeit) ) {
ERROR_LOG(m_logger) << log_tr("Keine plausible gps_zeit !! gps_zeit=%1").arg(telegramm_rt.gps_zeit.gps_zeit);
return;
}
if ( checkeKoordinaten(telegramm_rt.gps_pos)!=0 ) {
ERROR_LOG(m_logger) << log_tr("Keine plausible gps_pos !! pos_x=%1 Keine plausible gps_pos !! pos_y=%2").arg(telegramm_rt.gps_pos.utm_ostwert).arg(telegramm_rt.gps_pos.utm_nordwert);
return;
}
*/
daten_intern.daten.verlegedaten.ausstossart = ausstossart_et(0);
//Diese Null gilt als Unterscheidung zwischen Scorpion und
//Minenverlegeangaenger, da der Scorpion nur ausstossart 1..3 hat
if (daten_intern.daten.verlegedaten.anzahl_verlegter_minen > 1200)
{
WARNING_LOG(m_logger) << QStringLiteral("Anzahl_verlegter_minen = %1, wird auf 1200 zurueckgesetzt").arg(daten_intern.daten.verlegedaten.anzahl_verlegter_minen);
daten_intern.daten.verlegedaten.anzahl_verlegter_minen = 1200;
}
VERLEGEDATEN_KEY key_intern;
key_intern.fz_id = daten_intern.daten.header.identitaet;
key_intern.zeitpunkt.gps_zeit = daten_intern.daten.gps_zeit.gps_zeit;
interne_datenbasis_Verlegedaten.eintrag_container(
key_intern, daten_intern);
INFO_LOG(m_logger) << "Inserted new minelayertrailer data into old interne_datenbasis_Verlegedaten succesfully! Minelayerthrower data:" << data;
}
}
void HandlerMinelayerData::onMinelayerThrowerData(const TrainingAreaBase::MinelayerThrowerData &data, DataModification modType)
{
if ((modType == DataModification::eAdded) ||
(modType == DataModification::eModified))
{
VERLEGEDATEN_INTERN daten_intern;
convertMinelayerDataToXdrData(data, daten_intern.daten);
daten_intern.daten.verlegedaten.ausstossart = static_cast<ausstossart_et>(data.throwingType);
/*
if ( checkeTelegrammZeit(telegramm_rt.gps_zeit.gps_zeit) ) {
ERROR_LOG(m_logger) << log_tr("Keine plausible gps_zeit !! gps_zeit=%1").arg(telegramm_rt.gps_zeit.gps_zeit);
return;
}
if ( checkeKoordinaten(telegramm_rt.gps_pos) !=0 ) {
ERROR_LOG(m_logger) << log_tr("Keine plausible gps_pos !! pos_x=%1 Keine plausible gps_pos !! pos_y=%2").arg(telegramm_rt.gps_pos.utm_ostwert).arg(telegramm_rt.gps_pos.utm_nordwert);
return;
}
*/
if (daten_intern.daten.verlegedaten.anzahl_verlegter_minen > 1200)
{
WARNING_LOG(m_logger) << QStringLiteral("Anzahl_verlegter_minen = %1, wird auf 1200 zurueckgesetzt").arg(daten_intern.daten.verlegedaten.anzahl_verlegter_minen);
daten_intern.daten.verlegedaten.anzahl_verlegter_minen = 1200;
}
VERLEGEDATEN_KEY key_intern;
key_intern.fz_id = daten_intern.daten.header.identitaet;
key_intern.zeitpunkt.gps_zeit = daten_intern.daten.gps_zeit.gps_zeit;
if (daten_intern.daten.verlegedaten.ausstossart >= 5 && daten_intern.daten.verlegedaten.ausstossart <= 7)
{
daten_intern.daten.verlegedaten.anzahl_verlegter_minen = 5;
m_minefieldInterpreter->ZSSI_WI_modifiziere_Verlegedaten(key_intern, daten_intern);
}
else
{
interne_datenbasis_Verlegedaten.eintrag_container(
key_intern, daten_intern);
}
INFO_LOG(m_logger) << "Inserted new minelayerthrower data into old interne_datenbasis_Verlegedaten succesfully! Minelayerthrower data:" << data;
}
}
Core::GeoPosition2D HandlerMinelayerData::geographicFromRelative(const gps_position_rt &position) const
{
// this function is called after m_baseCoord is set within relativeFromGeographic()
// since we do a mgrs->geographic conversion only when a mine area is created
const QPointF point(m_baseCoord.geographic(position.utm_ostwert - m_baseCoord.x, position.utm_nordwert - m_baseCoord.y));
Core::GeoPosition2D ret;
ret.lon = point.x();
ret.lat = point.y();
return ret;
}
gps_position_rt HandlerMinelayerData::relativeFromGeographic(double lon, double lat)
{
const LtsCoordTrans::UtmCoordinate coord(LtsCoordTrans::UtmCoordinate::fromGeographic(lon, lat, m_baseCoord.zone));
if (m_baseCoord.zone == -1)
{
const QString mgrs = coord.mgrs(0) + QStringLiteral("00000000000000");
// our mgrs base point (taken from the first coordinate we get from Tetra)
m_baseCoord = LtsCoordTrans::UtmCoordinate::fromMgrs(mgrs);
}
gps_position_rt ret;
ret.utm_ostwert = qRound(coord.x);
ret.utm_nordwert = qRound(coord.y);
return ret;
}
int HandlerMinelayerData::partyIdFromEquipmentNumber(int eqNumber) const
{
int partyId = 0;
std::function<bool(const ParticipantManagement::Participant &data)> cb =
[eqNumber, &partyId](const ParticipantManagement::Participant & participant) -> bool
{
if (participant.equipmentNumber == eqNumber)
{
partyId = participant.partyId;
return true;
}
return false;
};
m_ppmDtc->participants(cb);
return partyId;
}
// mathmatisch positiv nordbezogen <- mathematisch negativ, ost = 0°, 0,01degree in 1/100° -> Faktor 100
static inline double compassFromMathAngleForSfm(int mathAngle)
{
double ret = (9000.0 - mathAngle) / 100;
while (ret < 0.0)
ret += 360.0;
while (ret > 360.0)
ret -= 360.0;
return ret;
}
void HandlerMinelayerData::onSendMinefield(const wirkfeld_minensperre_rt &minefield, int fzArt)
{
AreaEffectSimulation::MineArea outData;
outData.participantId = minefield.header.identitaet;
outData.partyId = partyIdFromEquipmentNumber(minefield.header.identitaet); // Get from PPM;
outData.name = QString::fromUtf8(tr_lts("dds", "_%1")).arg(minefield.beschreibung.kennung).toStdString();
outData.effectStart = minefield.beschreibung.wirkbeginn.gps_zeit * 1000LL; // derived from Tetra telegram
outData.effectDuration = minefield.beschreibung.wirkdauer * (1000 * 60 * 60); // orig resolution is 1h based
outData.density = minefield.beschreibung.verlegedichte / 100.0; // derived from Tetra telegram
outData.chargeStruct.chargeTypeId = minefield.beschreibung.minentyp; // is already in TAB converted to chargeTypeId
outData.layingProcedureType = static_cast<AreaEffectSimulation::AesMaLayingProcedureType>(fzArt);
outData.width = minefield.beschreibung.verlegetiefe;
outData.isLaidHidden = false;
outData.layingProcedureType = AreaEffectSimulation::AesMaLayingProcedureType::LptPioneer;
outData.isCenterLine = true;
// segments
std::vector<AreaEffectSimulation::MineSegment> segVec;
segVec.reserve(minefield.beschreibung.segmente.size());
for (const auto &seg : minefield.beschreibung.segmente)
{
AreaEffectSimulation::MineSegment segment;
segment.positionStart = geographicFromRelative(seg.startpunkt);
const LtsCoordTrans::UtmCoordinate startPositionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic({segment.positionStart.lon, segment.positionStart.lat});
QLineF line;
line.setP1({startPositionUtm.x, startPositionUtm.y});
line.setAngle(seg.drehwinkel);
line.setLength(double(seg.anzahl / outData.density));
LtsCoordTrans::UtmCoordinate endPositionUtm = startPositionUtm;
endPositionUtm.x = line.p2().x();
endPositionUtm.y = line.p2().y();
QPointF endPos = endPositionUtm.geographic();
segment.positionEnd = {endPos.x(), endPos.y()};
segVec.emplace_back(segment);
}
outData.segments = segVec;
INFO_LOG(m_logger) << "Sending new minefield from generator to AES: " << outData;
// request create mine area from aes
m_aesFtc->mineAreaModifyFromCtaDataRequest(outData, this);
}
void HandlerMinelayerData::onStartMinefieldInterpreter()
{
INFO_LOG(m_logger) << "Starting minefield interpreter ...";
m_minefieldInterpreter->processData();
}
void HandlerMinelayerData::onMineAreaModifyFromCtaDataReply(const Core::FunctionReplyObject &replyObject)
{
if (replyObject.error())
ERROR_LOG(m_logger) << "Error inserting minefield via AES->FTC";
else
INFO_LOG(m_logger) << "Got onMineAreaCreateFromCtaDataReply reply with id " << replyObject.id();
}
}