Files
berrux-dev 598fc2560e Complete Qt6 migration: full clean build green across groups G1-G12 incl. runtime plugin set
new_docker_build.sh gains Group 12 (212 GUI/Data plugins); fixes LtsUtilsGuiDds visibility (LTO-stripped exports), LtsProjectionWorkstation unity name shadow, 6 unity-off dirs (dup file-scope statics, ddsftc INTERFACE sources) and reconfigures BUILD_FILTERMANAGEMENT/BUILD_PLUGINS_SERVICEMONITOR=ON
2026-10-20 09:36:57 +02:00

996 lines
37 KiB
C++
Executable File

/**
* @RDE_HEADER@
* GeoPairing
* $Id$
* $HeadURL$
* $Author$
*/
#include "GeoPairing.hpp"
#include <GeoPairingImpl/GeoPairingImplFactory.hpp>
#include <GeoPairingImpl/GeoPairingImplDted.hpp>
#include <GeoPairingImpl/GeoPairingImplBalistic.hpp>
#include <GeoPairingImpl/GeoPairingDataFireReport.hpp>
#include <Schusstafel.h>
#include <QtCore/QScopedPointer>
#include <FW_Ballistic/AmmunitionTypes.hpp>
#include <GBL_ConfigSystem/ammuconfig.h>
#include "../settings.h"
static const double ANGULAR_MIL = 6400.0 / 360.0;
using namespace N_GeoPairingImpl;
using namespace N_ConfigSystem;
using namespace CentralEffectSimulation;
using namespace NGL;
GeoPairing::GeoPairing(const std::shared_ptr<N_Ballistic::BallisticService> &ballisticService)
: //m_airTargets(new ZSSIWI::AirTargetsInt)
//, m_automaticCannon(new ZSSIWI::AutomaticCannonInt)
//, m_geoPairingData(new ZSSIWI::GeoPairingDataInt)
//, m_mortarHowitzer(new ZSSIWI::MortarHowitzerInt)
//, m_surfaceToAir(new ZSSIWI::SurfaceToAirInt)
m_ballisticService(ballisticService)
, m_logger(CesGeoPairing::getLogger("Plugin.GeoPairing.GeoPairing"))
{
INFO_LOG(m_logger) << "konfigPath = " << ballisticService->getConfigPath() ;
const QString s_configPath = ballisticService->getConfigPath();
INFO_LOG(m_logger) << "GeoPairing Config location : " << s_configPath ;
GeoPairingImpl *l_impl = new GeoPairingImplDted;
INFO_LOG(m_logger) << "--> Installing GeoPairingImplDted..." ;
GeoPairingImplFactory::setImpl(l_impl);
readAmmunitionIni();
// initialize the GeoPairing implementation
if (!GeoPairingImplFactory::initialize(s_configPath))
{
ERROR_LOG(m_logger) << "Couldn't initialize GeoPairingImplFactory with GeoPairingImplDted!" ;
l_impl = new GeoPairingImplBalistic();
INFO_LOG(m_logger) << "--> Installing GeoPairingImplBalistic...";
GeoPairingImplFactory::setImpl(l_impl);
if (!GeoPairingImplFactory::initialize(s_configPath))
{
ERROR_LOG(m_logger) << "Couldn't initialize GeoPairingImplFactory with GeoPairingImplBalistic!" ;
abort();
}
else
INFO_LOG(m_logger) << "GeoPairingImplBalistic correctly initialized" ;
}
else
INFO_LOG(m_logger) << "GeoPairingImplDted correctly initialized" ;
#ifdef _PSEUDO_TARGETS_
// initial lat long position
// N_Math::GeoCoord l_UtmPos;
// l_UtmPos.setLlPositionDegree(22.5, 40.5, 59);
//
// const SInt32 l_NbrOfObjects = 4;
//
// std::cout << "Creating Pseudotargets : " << l_NbrOfObjects << std::endl;
//
// N_Types::Coord3 l_Direction(0, 1000, 0);
//
// for (int i=0;i<l_NbrOfObjects/2; i++)
// {
// N_Types::Coord3 l_PosInitial;
// l_PosInitial.m_X = l_UtmPos.m_UtmEast;
// l_PosInitial.m_Y = l_UtmPos.m_UtmNorth;
// l_PosInitial.m_Z = l_UtmPos.m_UtmHeight;
//
// l_PosInitial += l_Direction;
//
// N_Math::GeoCoord l_Utm1;
// l_Utm1.setTotalUtmPosition(l_PosInitial.m_X, l_PosInitial.m_Y, l_PosInitial.m_Z, l_UtmPos.m_UtmZone, l_UtmPos.m_UtmZoneChar);
//
// ZSSIWI::AirTargetsInt::AirTarget l_Target;
// l_Target.playerId = i+1;
// l_Target.positionLat = l_Utm1.m_LlLat;
// l_Target.positionLon = l_Utm1.m_LlLong;
// l_Target.positionAlt = l_Utm1.m_LlHeight;
// l_Target.positionTime = 1;
// l_Target.state = 0;
//
// m_airTargets->getAirTargetsList().append(l_Target);
//
// l_Direction = l_Direction.rotateZ(-M_PI / (l_NbrOfObjects/2));
// }
ZSSIWI::AirTargetsInt::AirTarget l_Target;
l_Target.playerId = 7701;
l_Target.positionLat = 53.0412;
l_Target.positionLon = 8.87471;
l_Target.positionAlt = 120;
l_Target.positionTime = 1;
l_Target.state = 0;
m_airTargets->getAirTargetsList().append(l_Target);
#endif
INFO_LOG(m_logger) << "Initialization finished";
}
void GeoPairing::calculateAirFire(const QByteArray &transparentData,
const QHash<int, CentralEffectSimulation::HandlerParticipant::CesParticipantData> &aircrafts)
{
INFO_LOG(m_logger) << "calculateAirFire (IGLA)..." ;
GeoPairingDataFireReport l_Report;
if (!l_Report.parse(transparentData))
{
WARNING_LOG(m_logger) << "Error: Couldn't parse Fire Report" ;
return;
}
if (aircrafts.size() == 0)
{
INFO_LOG(m_logger) << "No Aircraft available";
return;
}
QScopedPointer<GeoPairingImplAirTargetUpdater> l_Updater(GeoPairingImplFactory::createAirTargetUpdater());
QHashIterator<int, HandlerParticipant::CesParticipantData> i(aircrafts);
while (i.hasNext())
{
i.next();
SInt32 vulnerabilityState = i.value().vulnerabilityState;
Float64 lat = i.value().pos().lat() * 180 / M_PI;
Float64 lon = i.value().pos().lon() * 180 / M_PI;
DEBUG_LOG(m_logger) << "GeoPairing::calculateAirFire"
<< "\nl_Updater->update : " << i.key()
<< "\n: participantId=" << i.value().participantId()
<< "\n participantTypeId= " << i.value().participantTypeId()
<< "\n pos lat=" << lat
<< "\n lon=" << lon
<< "\n alt=" << i.value().pos().z()
<< "\n posTime=" << i.value().sampleTime()
<< "\n state=" << i.value().vulnerabilityState
<< "\n state (SInt32)=" << vulnerabilityState;
l_Updater->update(i.value().participantId(),
lat,
lon,
i.value().pos().z(),
i.value().sampleTime() / 1000, //s
vulnerabilityState);
}
// Prepare SensorData to take into account terrain altitude and geomagnetic differences
GeoPairingImplSensorData l_SensorData;
l_SensorData.WeaponPositionLat = m_PositionLat;
l_SensorData.WeaponPositionLong = m_PositionLon;
l_SensorData.FireTime = m_Time;
l_SensorData.WeaponElevation = 0;
INFO_LOG(m_logger) << "--> IGLA : Report Target Fire (createSensorData)"
<< "\nl_SensorData.WeaponPositionLat = " << l_SensorData.WeaponPositionLat
<< "\nl_SensorData.WeaponPositionLong = " << l_SensorData.WeaponPositionLong
<< "\nl_SensorData.WeaponAzimuth=" << l_SensorData.WeaponAzimuth
<< "\nl_SensorData.WeaponElevation=" << l_SensorData.WeaponElevation
<< "\nl_SensorData.FireTime = " << l_SensorData.FireTime
;
SInt32 l_DeviceID = GeoPairingImplFactory::createSensorData(&l_SensorData, transparentData);
INFO_LOG(m_logger) << "createSensorData -> SensorData.WeaponAzimuth=" << l_SensorData.WeaponAzimuth
<< "\nl_SensorData.WeaponElevation=" << l_SensorData.WeaponElevation;
if (l_DeviceID == -1)
{
ERROR_LOG(m_logger) << "Couldn't create SensorData" ;
return;
}
m_PositionHeight = l_SensorData.WeaponPositionHeight;
Float64 l_Azimuth = -l_SensorData.WeaponAzimuth * 180 / M_PI; // negate to convert ccw back to cw
Float64 l_Elevation = l_SensorData.WeaponElevation * 180 / M_PI;
if (l_Report.m_DeviceID == PAN_GP_REQUEST_IGLA)
{
INFO_LOG(m_logger) << " -> IGLA : Request Target Detection " ;
QScopedPointer<GeoPairingImplAirTargetCache> l_Cache(GeoPairingImplFactory::createAirTargetCache(m_equipmentNumber));
int l_TargetPlayerId = 0;
uint64_t l_ImpactTime = 0;
INFO_LOG(m_logger) << "-> IGLA : Request Target Detection -> searchAirTarget (vor dem aufruf)"
<< "\nl_Elevation = " << l_Elevation
<< "\nl_Azimuth = " << l_Azimuth
;
bool l_TargetFound = searchAirTarget(l_Elevation, l_Azimuth, l_TargetPlayerId, l_ImpactTime);
INFO_LOG(m_logger) << "-> IGLA : Request Target Detection -> searchAirTarget (nach dem aufruf)"
<< "\nl_TargetFound = " << l_TargetFound
<< "\nl_TargetPlayerId = " << l_TargetPlayerId
<< "\nl_ImpactTime = " << l_ImpactTime
;
bool l_CachedTrackingState = l_Cache->getLatestTrackState(l_TargetPlayerId);
UInt32 l_CachedTrackingTime = l_Cache->getLatestTrackTime(l_TargetPlayerId);
INFO_LOG(m_logger) << "-> IGLA : Retrieved Target Detection Results from Cache"
<< "\nl_CachedTrackingState = " << l_CachedTrackingState
<< "\nl_CachedTrackingTime = " << l_CachedTrackingTime
;
SInt32 l_DeltaTime = m_Time - l_CachedTrackingTime;
bool l_TimeoutPassed = l_DeltaTime > static_cast<SInt32>(l_Cache->getCacheTimeout());
if (l_TargetFound != l_CachedTrackingState || l_TimeoutPassed)
{
// prepare response for player
m_reportTarget.playerId = i.value().participantId();
m_reportTarget.sendData.clear();
m_reportTarget.sendData.append(0xEB); // Report Target Detection
UInt8 l_DetectionResult = ((UInt8) l_TargetFound) & 0x03;
l_DetectionResult += (l_Report.m_IGLARequestNbr << 2);
m_reportTarget.sendData.append(l_DetectionResult);
// add 3 reserved bytes
m_reportTarget.sendData.append((char)0x00);
m_reportTarget.sendData.append((char)0x00);
m_reportTarget.sendData.append((char)0x00);
m_reportTarget.send = true;
// Richtung Gefechtsfeld
INFO_LOG(m_logger) << "<-- EC : Report Target Detection " ;
INFO_LOG(m_logger) << "Target Found : " << l_TargetFound ;
//m_geoPairingData->sendData(m_PlayerId, l_SendData.data(), l_SendData.size() );
l_Cache->storeLatestTrackState(l_TargetPlayerId, m_Time, l_TargetFound);
}
}
INFO_LOG(m_logger) << "\n\nPAN_GP_REPORT_IGLA m_DeviceID=" << l_Report.m_DeviceID
<< " PAN_GP_REPORT_IGLA=" << PAN_GP_REPORT_IGLA;
if (l_Report.m_DeviceID == PAN_GP_REPORT_IGLA)
{
INFO_LOG(m_logger) << "--> IGLA : Report Target Fire " ;
int l_TargetPlayerId = 0;
UInt64 l_ImpactTime = 0;
QScopedPointer<GeoPairingImplAirTargetTracker> l_Tracker(GeoPairingImplFactory::createAirTargetTracker());
INFO_LOG(m_logger) << "--> IGLA : Report Target Fire (l_Tracker->setPosition)"
<< "\nm_PositionLat = " << m_PositionLat
<< "\nm_PositionLon = " << m_PositionLon
<< "\nm_PositionHeight = " << m_PositionHeight
;
l_Tracker->setPosition(m_PositionLat, m_PositionLon, m_PositionHeight);
INFO_LOG(m_logger) << "--> IGLA : Report Target Fire (setTime)"
<< "\nm_Time = " << m_Time ;
l_Tracker->setTime(m_Time);
INFO_LOG(m_logger) << "--> IGLA : Report Target Fire (vor l_Tracker->track)"
<< "\nl_Azimuth = " << l_Azimuth
<< "\nl_Elevation = " << l_Elevation
<< "\nl_TargetPlayerId = " << l_TargetPlayerId
<< "\nl_ImpactTime = " << l_ImpactTime
;
bool l_TargetFound = l_Tracker->track(l_Azimuth, l_Elevation, l_TargetPlayerId, l_ImpactTime);
INFO_LOG(m_logger) << "--> IGLA : Report Target Fire (nach l_Tracker->track)"
<< "\nl_TargetFound = " << l_TargetFound ;
if (l_TargetFound)
{
int l_AmmunitionType = N_Ballistic::IGLA;
m_fireToAircraft.participantIdTarget = l_TargetPlayerId;
m_fireToAircraft.impactTime = l_ImpactTime;
m_fireToAircraft.ammunitionTypeId = l_AmmunitionType;
m_fireToAircraft.equipmentNumberGunner = m_equipmentNumber;
if (l_Tracker->hitCheck(l_TargetPlayerId, l_Report.m_IGLAModeAuto, l_Report.m_IGLAChangeOverPressed))
{
//m_surfaceToAir->fire(l_TargetPlayerId, l_ImpactTime, l_AmmunitionType, m_PlayerId, true);
m_fireToAircraft.hit = true;
INFO_LOG(m_logger) << "Air Target " << l_TargetPlayerId << " in reach and hit" ;
}
else
{
//m_surfaceToAir->fire(l_TargetPlayerId, l_ImpactTime, l_AmmunitionType, m_PlayerId, false);
m_fireToAircraft.hit = false;
INFO_LOG(m_logger) << "Air Target " << l_TargetPlayerId << " in reach, but not hit" ;
}
}
else
INFO_LOG(m_logger) << "No Air Target withing reach..." ;
}
}
void GeoPairing::calculateAreaFire(const QByteArray &transparentData,
const std::shared_ptr<N_Ballistic::BallisticService> &ballisticService)
{
INFO_LOG(m_logger) << "calculateAreaFire (MK19)..." ;
// Prepare SensorData for Implementation
GeoPairingImplSensorData l_SensorData;
l_SensorData.WeaponPositionLat = m_PositionLat;
l_SensorData.WeaponPositionLong = m_PositionLon;
l_SensorData.FireTime = m_Time;
GeoPairingDataFireReport l_Report;
if (!l_Report.parse(transparentData))
{
ERROR_LOG(m_logger) << "Error: Couldn't parse Fire Report" ;
return;
}
SInt32 l_DeviceID = GeoPairingImplFactory::createSensorData(&l_SensorData, transparentData);
if (l_DeviceID == -1)
{
ERROR_LOG(m_logger) << "Couldn't create SensorData" ;
return;
}
QScopedPointer<GeoPairingImplFiredBullet> l_FiredBullet(GeoPairingImplFactory::createFiredBullet(l_SensorData));
if (l_FiredBullet == nullptr)
{
ERROR_LOG(m_logger) << "Error: Couldn't create FiredBullet object" ;
return;
}
double l_FieldWidth = 0;
double l_FieldLength = 0;
double l_Duration = 0;
double l_Heading = 0;
UInt8 nbrRounds = 0;
nbrRounds = l_Report.m_MK19NbrRounds;
l_FiredBullet->calculateSalve(ballisticService, nbrRounds, l_FieldWidth, l_FieldLength, l_Duration, l_Heading);
GeoPairingImplImpactData *l_ImpactData = l_FiredBullet->getImpactData();
if (l_ImpactData == nullptr)
{
ERROR_LOG(m_logger) << "Error: Couldn't create ImpactData object" ;
return;
}
N_Ballistic::ammunitionTypeIndirectFire l_AmmunitionType;
N_Ballistic::ammunitionTypeOSAG l_AmmunitionTypeOSAG;
switch (l_SensorData.AmmunitionType)
{
case MK19Type_m385:
l_AmmunitionType = N_Ballistic::MK19_M385;
l_AmmunitionTypeOSAG = N_Ballistic::MK19_M385_OSAG;
INFO_LOG(m_logger) << "Wirkfeld Ammunition MK19_M385" ;
break;
case MK19Type_m430:
l_AmmunitionType = N_Ballistic::MK19_M430;
l_AmmunitionTypeOSAG = N_Ballistic::MK19_M430_OSAG;
INFO_LOG(m_logger) << "Wirkfeld Ammunition MK19_M430" ;
break;
default:
ERROR_LOG(m_logger) << "Default Ammunition. Must not be called : " << l_SensorData.AmmunitionType ;
return;
}
// Richtung Zentrale
// * Create an area fire to CTAS
// * @param playerId Id of the player
// * @param impactTime Time of impact
// * @param fireDuration Duration [sec] of the fire
// * @param impactAreaLat Latitude - Centercoordinate of impact-area
// * @param impactAreaLon Longitude - Centercoordinate of impact-area
// * @param impactAreaDimensionWidth Width [m] of impact-area
// * Width: At right angle to the direction gunner position to impact position
// * @param impactAreaDimensionDepth Depth [m] of impact-area.
// * Depth: Direction of gunner position to impact position
// * @param direction Direction from gunner position to impact position.
// * Angle of rotation [0.01 degree] counterclockwise against direction east.
// * @param numberOfImpacts Number of impacts
// * @param ammunitionType Type of the ammunition
/*
m_automaticCannon->areaFire(m_PlayerId,
l_ImpactData->ImpactTime,
l_Duration,
l_ImpactData->ImpactPositionLat,
l_ImpactData->ImpactPositionLong,
l_FieldWidth,
l_FieldLength,
l_Heading,
nbrRounds,
l_AmmunitionType,
l_AmmunitionTypeOSAG);*/
m_areaFireToCtas.playerId = m_equipmentNumber;
m_areaFireToCtas.impactTime = l_ImpactData->ImpactTime;
m_areaFireToCtas.duration = l_Duration;
m_areaFireToCtas.impactPositionLat = l_ImpactData->ImpactPositionLat;
m_areaFireToCtas.impactPositionLong = l_ImpactData->ImpactPositionLong;
m_areaFireToCtas.fieldWidth = l_FieldWidth;
m_areaFireToCtas.fieldLength = l_FieldLength;
m_areaFireToCtas.heading = l_Heading;
m_areaFireToCtas.nbrRounds = nbrRounds;
m_areaFireToCtas.ammunitionType = l_AmmunitionType;
m_areaFireToCtas.ammunitionTypeOSAG = l_AmmunitionTypeOSAG;
m_areaFireToCtas.hit = true;
INFO_LOG(m_logger) << "calculateAreaFire m_equipmentNumber=" << m_equipmentNumber
<< " ImpactTime=" << l_ImpactData->ImpactTime
<< " ImpactPositionLat=" << l_ImpactData->ImpactPositionLat
<< " ImpactPositionLong=" << l_ImpactData->ImpactPositionLong
<< " l_AmmunitionType=" << l_AmmunitionType
<< " l_AmmunitionTypeOSAG=" << l_AmmunitionTypeOSAG
<< " l_DeviceID=" << l_DeviceID;
m_DeviceID = l_DeviceID;
}
void GeoPairing::calculateSingleFire(const QByteArray &transparentData, const std::shared_ptr<N_Ballistic::BallisticService> &ballisticService)
{
INFO_LOG(m_logger) << "calculateSingleFire ..." ;
ElevationError error_elevation = ElevationError::NoError;
int error_charge = 0;
int error_mun = 0;
bool usage_ok = true;
// Prepare SensorData for Implementation
GeoPairingImplSensorData l_SensorData;
l_SensorData.WeaponPositionLat = m_PositionLat;
l_SensorData.WeaponPositionLong = m_PositionLon;
l_SensorData.FireTime = m_Time;
l_SensorData.IgnitionType = -1; // Unknown
SInt32 l_DeviceID = GeoPairingImplFactory::createSensorData(&l_SensorData, transparentData, error_mun);
INFO_LOG(m_logger) << "l_DeviceID=" << l_DeviceID;
if (l_DeviceID == -1)
{
ERROR_LOG(m_logger) << "Couldn't create SensorData" ;
return;
}
QScopedPointer<GeoPairingImplFiredBullet> l_FiredBullet(GeoPairingImplFactory::createFiredBullet(l_SensorData));
if ((l_DeviceID == PAN_GP_REPORT_G5_G6) || (l_DeviceID == PAN_GP_REPORT_M109) || (l_DeviceID == PAN_GP_REPORT_MORTAR))
{
// Fuer die Waffe G5/G6 wird die Entfernung aus einer Schusstafel-Datei ausgelesen
// und nicht ueber einen ballistischen Algorithmus berechnet
Schusstafel::TAFEL_NAMEN_ET tafelName = Schusstafel::ST_AUFSATZ;
//std::string pfad = "./";
QString pfadQstr = CesGeoPairing::Settings::cesGeopairingIniPath() + QStringLiteral("/");
std::string pfad = pfadQstr.toStdString();
std::string munart;
INFO_LOG(m_logger) << "Vor switch AmmunitionType=" << l_SensorData.AmmunitionType
<< " ChargeType=" << l_SensorData.ChargeType;
// Ammunition HE-M1
switch (l_SensorData.AmmunitionType)
{
case HE_M1A2:
{
INFO_LOG(m_logger) << "HE_M1A2";
switch (l_SensorData.ChargeType)
{
case 0:
munart = "HE-M1-M64Base-TableE";
break;
case 1:
munart = "HE-M1-M64Incr3-TableE";
break;
case 2:
munart = "HE-M1-M64Incr4-TableE";
break;
case 3:
munart = "HE-M1-M64Incr5-TableE";
break;
case 4:
munart = "HE-M1-M64Incr5BaseBleed-TableE";
break;
default:
break;
}
break;
}
case M60mm_m385:
case M60mm_m430:
{
INFO_LOG(m_logger) << "M60mm_m385 M60mm_m430";
switch (l_SensorData.IgnitionType) // ChargeType = Ladung...
{
// Todo: Umbenennen und ggf. Zuordnung korrigieren
case 0:
INFO_LOG(m_logger) << "Moerser-60mm-Lad1";
munart = "Moerser-60mm-Lad1";
break;
case 1:
INFO_LOG(m_logger) << "Moerser-60mm-Lad2";
munart = "Moerser-60mm-Lad2";
break;
case 2:
INFO_LOG(m_logger) << "Moerser-60mm-Lad3";
munart = "Moerser-60mm-Lad3";
break;
case 3:
INFO_LOG(m_logger) << "Moerser-60mm-Lad4";
munart = "Moerser-60mm-Lad4";
break;
case 4:
INFO_LOG(m_logger) << "Moerser-60mm-Lad5";
munart = "Moerser-60mm-Lad5";
break;
case 5:
INFO_LOG(m_logger) << "Moerser-60mm-La6";
munart = "Moerser-60mm-Lad6";
break;
default:
break;
}
break;
}
case VLAP_M9703:
{
INFO_LOG(m_logger) << "VLAP_M9703";
// Sonderfall Ammunition VLAP-M64. Da hier nur 5 x M64 Incr als Ladung vorhanden ist.
// Sollten wir eine andere Ladung aus dem Gefechtsfeld bekommen, dann Munition HE M1A2 benutzen
switch (l_SensorData.ChargeType)
{
case 0:
munart = "HE-M1-M64Base-TableE";
break;
case 1:
munart = "HE-M1-M64Incr3-TableE";
break;
case 2:
munart = "HE-M1-M64Incr4-TableE";
break;
case 3:
munart = "VLAP-M64Incr5-TableE";
break;
case 4:
munart = "VLAP-M64Incr5-TableE";
break;
default:
break;
}
break;
}
case SMK_BE_M2:
{
switch (l_SensorData.ChargeType)
{
case 0:
munart = "SMK-BE-RED-RED-PHOSPH-M1-M64Base-TableE";
break;
case 1:
munart = "SMK-BE-RED-RED-PHOSPH-M1-M64Incr3-TableE";
break;
case 2:
munart = "SMK-BE-RED-RED-PHOSPH-M1-M64Incr4-TableE";
break;
case 3:
munart = "SMK-BE-RED-RED-PHOSPH-M1-M64Incr5-TableE";
break;
case 4:
munart = "SMK-BE-RED-RED-PHOSPH-M1-M64Incr5BaseBleed-TableE";
break;
default:
break;
}
break;
}
case CLUSTER_HEHC_M9609:
{
switch (l_SensorData.ChargeType)
{
case 0:
munart = "Cluster-M64Base-TableE";
break;
case 1:
munart = "Cluster-M64BaseIncr3-TableE";
break;
case 2:
munart = "Cluster-M64BaseIncr4-TableE";
break;
case 3:
munart = "Cluster-M64BaseIncr5-TableE";
break;
case 4:
munart = "Cluster-M64BaseIncr5BaseBleed-TableE";
break;
default:
break;
}
break;
}
default:
break;
}
if (munart.empty())
{
WARNING_LOG(m_logger) << "No valid charge type " << l_SensorData.ChargeType <<
" for ammunition " << l_SensorData.AmmunitionType <<
" (internal ids!)" ;
munart = "HE-M1-M64Base-TableE";
error_mun = 1; //Keine richtige Muntion/Charge Kombination
}
std::string suffix = ".sus";
DEBUG_LOG(m_logger) << "schusstafel pfad=" << pfad
<< " munart=" << munart
<< " suffix=" << suffix;
Schusstafel schusstafel(pfad, munart, suffix);
float entfernung1 = 0.0;
float aufsatz1 = 0.0;
float flugzeit1 = 0.0;
float drift1 = 0.0;
float entfernung2 = 0.0;
float aufsatz2 = 0.0;
float flugzeit2 = 0.0;
float drift2 = 0.0;
float elevation = l_SensorData.WeaponElevation.getZeroTo360();
float arg_wert = elevation * ANGULAR_MIL * MILRAD; // Funktion will den Wert in milrad
float zielhoehenwinkel = 0.0;
double evalMil = elevation * ANGULAR_MIL; //angular mil
//Wir holen uns nur bei der Haubitze die Daten
const GeoPCharge mun = m_geoPMunMap.value(l_SensorData.AmmunitionType + 1).value(l_SensorData.ChargeType);
//Der type l_DeviceID gibt an, ob es sich um eine G5/G6 oder M109 handelt.
usage_ok = mun.checkArty(l_DeviceID, evalMil, error_elevation, error_charge);
double elevationGrad = l_SensorData.WeaponElevation.getDegree();
if (elevationGrad <= 0.0)
{
INFO_LOG(m_logger) << "Elevation ist <= 0 Grad. Entfernung wird auf 50% des ersten Wertes aus der Schusstafel festgesetzt" ;
// Dazu aus der minimal moeglichen Elevation die Entfernung bestimmen und halbieren
float minEval = mun.minEleval * MILRAD;
DEBUG_LOG(m_logger) << "schusstafel tafelName=" << tafelName
<< " minEval=" << minEval
<< "zielhoehenwinkel=" << zielhoehenwinkel;
schusstafel.ST_artillerie(tafelName, minEval, zielhoehenwinkel, &entfernung1, &aufsatz1, &flugzeit1, &drift1,
&entfernung2, &aufsatz2, &flugzeit2, &drift2);
entfernung1 = entfernung1 / 2;
flugzeit1 = flugzeit1 / 2;
}
else if (elevationGrad >= 90.0)
{
INFO_LOG(m_logger) << "Elevation ist >= 90 Grad. Entfernung wird auf den letzten Wert aus der Schusstafel festgesetzt" ;
// Dazu aus der maximal moeglichen Elevation die Entfernung bestimmen
double maxEval = mun.maxEleval * MILRAD;
DEBUG_LOG(m_logger) << "schusstafel tafelName=" << tafelName
<< " maxEval=" << maxEval
<< "zielhoehenwinkel=" << zielhoehenwinkel;
schusstafel.ST_artillerie(tafelName, maxEval, zielhoehenwinkel, &entfernung1, &aufsatz1, &flugzeit1, &drift1,
&entfernung2, &aufsatz2, &flugzeit2, &drift2);
}
else
{
DEBUG_LOG(m_logger) << "schusstafel tafelName=" << tafelName
<< " arg_wert=" << arg_wert
<< "zielhoehenwinkel=" << zielhoehenwinkel;
schusstafel.ST_artillerie(tafelName, arg_wert, zielhoehenwinkel, &entfernung1, &aufsatz1, &flugzeit1, &drift1,
&entfernung2, &aufsatz2, &flugzeit2, &drift2);
}
INFO_LOG(m_logger) << "Schusstafel " << munart << ".sus: "
<< "Entfernung [m]: " << entfernung1
<< " Elevation [mil]: " << evalMil
<< " Drift [grad]: " << drift1 * 180 / M_PI
<< " Drift [mil]: " << drift1 * 180 / M_PI *ANGULAR_MIL
<< " Flugzeit [s]: " << flugzeit1 ;
l_FiredBullet->calculateG5G6(entfernung1, drift1, flugzeit1);
}
else
{
// != G5G6 && != M109
INFO_LOG(m_logger) << "calculate(ballisticService)";
l_FiredBullet->calculate(ballisticService);
}
GeoPairingImplImpactData *l_ImpactData = l_FiredBullet->getImpactData();
if (!l_ImpactData)
{
ERROR_LOG(m_logger) << "No impact Data available";
return;
}
N_Ballistic::ammunitionTypeIndirectFire l_AmmunitionType = N_Ballistic::UNKNOWN;
N_Ballistic::ammunitionTypeOSAG l_AmmunitionTypeOSAG = N_Ballistic::UNKNOWN_OSAG;
if ((l_DeviceID != PAN_GP_REPORT_G5_G6) && (l_DeviceID != PAN_GP_REPORT_M109))
{
l_AmmunitionTypeOSAG = N_Ballistic::UNKNOWN_OSAG;
switch (l_SensorData.AmmunitionType)
{
case MortarType1:
default:
l_AmmunitionType = N_Ballistic::MOERSER;
l_AmmunitionTypeOSAG = N_Ballistic::MORTAR_PRC_OSAG;
break;
case MortarType2:
l_AmmunitionType = N_Ballistic::NEBEL;
l_AmmunitionTypeOSAG = N_Ballistic::MORTAR_PRX_OSAG;
break;
}
}
else
{
// Zuordnung Geopairing - Code -> sys_db.munitionsarten (OSAG-Code)
// 4 -> 30 oder 31
// 5 -> 33 oder 32
// 6 -> 34
// 7 -> 35
l_AmmunitionType = N_Ballistic::STEILFEUER_HE_AZ;
l_AmmunitionTypeOSAG = N_Ballistic::UNKNOWN_OSAG;
switch (l_SensorData.AmmunitionType)
{
case HE_M1A2:
switch (l_SensorData.IgnitionTypeG5G6)
{
case IgnitionTypePercussion:
default:
l_AmmunitionType = N_Ballistic::STEILFEUER_HE_AZ;
l_AmmunitionTypeOSAG = N_Ballistic::M1A2_PRC_OSAG;
break;
case IgnitionTypeProximity:
l_AmmunitionType = N_Ballistic::STEILFEUER_HE_DZ;
l_AmmunitionTypeOSAG = N_Ballistic::M1A2_PRX_OSAG;
break;
}
break;
case VLAP_M9703:
switch (l_SensorData.IgnitionTypeG5G6)
{
case IgnitionTypePercussion:
default:
l_AmmunitionType = N_Ballistic::STEILFEUER_HE_AZ;
l_AmmunitionTypeOSAG = N_Ballistic::VLAP_PRC_OSAG;
break;
case IgnitionTypeProximity:
l_AmmunitionType = N_Ballistic::STEILFEUER_HE_DZ;
l_AmmunitionTypeOSAG = N_Ballistic::VLAP_PRX_OSAG;
break;
}
break;
case SMK_BE_M2:
l_AmmunitionType = N_Ballistic::NEBEL;
l_AmmunitionTypeOSAG = N_Ballistic::SMK_OSAG;
break;
case CLUSTER_HEHC_M9609:
l_AmmunitionType = N_Ballistic::STEILFEUER_BOMBLET;
l_AmmunitionTypeOSAG = N_Ballistic::CLUSTER_OSAG;
break;
default:
break;
}
}
// TODO: wird alles nicht ausgewertet
// -> in TES-UAE wurde in diesem Fall ein zt_artillery_usage_error_rt telegramm erzeugt was später ausgewertet wurde
// wird also einen RP in AHTC geben wenn es auffällt
Q_UNUSED(error_elevation);
Q_UNUSED(error_charge);
Q_UNUSED(error_mun);
Q_UNUSED(usage_ok);
// Richtung Zentrale
// Der ammunitionType ist in zssiwi_service_base.hpp zu finden
// TODO m_mortarHowitzer
// Treffer Einzelfeuer zum DDS schicken:
//int wirkfeld_id = m_mortarHowitzer->impact(m_equipmentNumber,
// l_ImpactData->ImpactTime,
// l_ImpactData->ImpactPositionLat,
// l_ImpactData->ImpactPositionLong,
// l_AmmunitionType,
// l_AmmunitionTypeOSAG,
// l_DeviceID);
QString latStr = QString::number(l_ImpactData->ImpactPositionLat, 'f', 8);
QString lonStr = QString::number(l_ImpactData->ImpactPositionLong, 'f', 8);
INFO_LOG(m_logger) << "calculateSingleFire m_equipmentNumber=" << m_equipmentNumber
<< " ImpactTime=" << l_ImpactData->ImpactTime
<< " ImpactPositionLat=" << latStr
<< " ImpactPositionLong=" << lonStr
<< " l_AmmunitionType=" << l_AmmunitionType
<< " l_AmmunitionTypeOSAG=" << l_AmmunitionTypeOSAG
<< " l_DeviceID=" << l_DeviceID;
m_DeviceID = l_DeviceID;
m_singleFireToCtas.impactTime = l_ImpactData->ImpactTime;
m_singleFireToCtas.impactPositionLat = l_ImpactData->ImpactPositionLat;
m_singleFireToCtas.impactPositionLong = l_ImpactData->ImpactPositionLong;
m_singleFireToCtas.ammunitionType = l_AmmunitionType;
m_singleFireToCtas.hit = true;
}
bool GeoPairing::geoPairingData(const std::shared_ptr<N_Ballistic::BallisticService> &ballisticService,
int equipmentNumber,
qint64 time,
double positionLat,
double positionLon,
const QByteArray &transparentDataAr,
const QHash<int, CentralEffectSimulation::HandlerParticipant::CesParticipantData> &aircrafts)
{
// first of all, we save the basic info that is directly available
m_equipmentNumber = equipmentNumber;
m_Time = time;
m_PositionLat = positionLat;
m_PositionLon = positionLon;
m_ballisticService = ballisticService;
m_fireToAircraft.hit = false;
m_singleFireToCtas.hit = false;
m_areaFireToCtas.hit = false;
m_reportTarget.send = false;
INFO_LOG(m_logger) << "--------------- geoPairingData empfangen! -----------------" ;
INFO_LOG(m_logger) << "playerId = " << m_equipmentNumber ;
INFO_LOG(m_logger) << "time = " << (SInt64) m_Time ;
INFO_LOG(m_logger) << "positionLat = " << m_PositionLat ;
INFO_LOG(m_logger) << "positonLon = " << m_PositionLon ;
INFO_LOG(m_logger) << "tr.Data-Size = " << transparentDataAr.size() ;
INFO_LOG(m_logger) << "transparentData = " << transparentDataAr.toHex() ;
QHashIterator<int, CentralEffectSimulation::HandlerParticipant::CesParticipantData> i(aircrafts);
while (i.hasNext())
{
i.next();
DEBUG_LOG(m_logger) << i.key() << ": participantId=" << i.value().participantId()
<< " participantTypeId= " << i.value().participantTypeId()
<< " pos lat=" << i.value().pos().lat()
<< " pos lon=" << i.value().pos().lon()
<< " z=" << i.value().pos().z();
}
GeoPairingDataBase l_Header;
if (!l_Header.parse(transparentDataAr))
{
ERROR_LOG(m_logger) << "Error: Couldn't parse header of transparent Data!" ;
return false;
}
UInt8 l_MessageID = l_Header.m_MessageID;
PanGeoPairingDeviceId l_DeviceID = l_Header.m_DeviceID;
INFO_LOG(m_logger) << "l_MessageID = " << std::hex << (int)l_MessageID ;
INFO_LOG(m_logger) << "l_DeviceID = " << l_DeviceID ;
if (l_MessageID == 0xE3) // Firing_Report
{
INFO_LOG(m_logger) << "--> E3 : Firing Report " ;
switch (l_DeviceID)
{
case PAN_GP_REPORT_MORTAR:
case PAN_GP_REPORT_G5_G6:
case PAN_GP_REPORT_M109:
calculateSingleFire(transparentDataAr, ballisticService);
INFO_LOG(m_logger) << "PAN_GP_REPORT_MORTAR PAN_GP_REPORT_G5_G6 PAN_GP_REPORT_M109 calculateSingleFire";
break;
case PAN_GP_REPORT_MK19:
calculateAreaFire(transparentDataAr, ballisticService);
break;
case PAN_GP_REPORT_IGLA:
case PAN_GP_REQUEST_IGLA:
calculateAirFire(transparentDataAr, aircrafts);
INFO_LOG(m_logger) << "PAN_GP_REPORT_IGLA PAN_GP_REQUEST_IGLA ";
break;
default:
WARNING_LOG(m_logger) << "--> Unknown DeviceID " << l_DeviceID << " used !" ;
return false;
}
}
else
{
WARNING_LOG(m_logger) << "--> Unknown MessageID used ! " ;
return false;
}
return true;
}
void GeoPairing::setMeteo(double winddirection, double windspeed, double temperature, double pressure)
{
// create the global meteodata object
GeoPairingImplMeteoData l_meteoData;
l_meteoData.AirPressure = pressure;
l_meteoData.Temperature = temperature;
l_meteoData.WindDirection = winddirection;
l_meteoData.WindSpeed = windspeed;
GeoPairingImplFactory::setMeteoData(l_meteoData);
}
bool GeoPairing::searchAirTarget(double a_elevation, double azimuth, int &playerId, uint64_t &impactTime)
{
INFO_LOG(m_logger) << "searchAirTarget (IGLA)..." ;
QScopedPointer<GeoPairingImplAirTargetTracker> l_Tracker(GeoPairingImplFactory::createAirTargetTracker());
l_Tracker->setPosition(m_PositionLat, m_PositionLon, m_PositionHeight);
l_Tracker->setTime(m_Time);
return l_Tracker->track(azimuth,
a_elevation,
playerId,
impactTime);
}
void GeoPairing::readAmmunitionIni()
{
AmmuConfig *ammuConfig;
QString FileName = CesGeoPairing::Settings::cesGeopairingIniPath() + QStringLiteral("/") + CesGeoPairing::Settings::cesAmmunitionIniFile();
ammuConfig = AmmuConfig::getInstance();
ammuConfig->initFilename(FileName);
//Zu erst holen wir uns alle WaffenTypen
const QVector<int> typesList = ammuConfig->getIntegerVector(QStringLiteral("WeaponRestriction"), QStringLiteral("Types"));
DEBUG_LOG(m_logger) << "typesList.size=" << typesList.size();
//Wir holen uns alle Munitionen die in Frage kommen heraus // evtl mit Liste?
const QVector<int> ammoList = ammuConfig->getIntegerVector(QStringLiteral("WeaponRestriction"), QStringLiteral("AmmoList"));
DEBUG_LOG(m_logger) << "ammoList=" << ammoList.size();
for (int ammo : ammoList)
{
DEBUG_LOG(m_logger) << "ammoListValue=" << ammo;
QString eleGroup = QStringLiteral("Ammunition") + QStringLiteral("P") + QString::number(ammo) + QStringLiteral("/CWParams");
const QVector<double> minElevataion = ammuConfig->getFloatVector(eleGroup, QStringLiteral("ElevMin"));
DEBUG_LOG(m_logger) << "ammo = " << ammo << " minElevataion.size() =" << minElevataion.size()
<< " " << eleGroup << "/" << QStringLiteral("ElevMin");
const QVector<double> maxElevataion = ammuConfig->getFloatVector(eleGroup, QStringLiteral("ElevMax"));
DEBUG_LOG(m_logger) << "ammo = " << ammo << " maxElevataion.size() =" << maxElevataion.size() << eleGroup << "/" << QStringLiteral("ElevMax");
if (minElevataion.size() != maxElevataion.size())
{
DEBUG_LOG(m_logger) << "Invalid Ammunition Config for : Ammunition" << ammo ;
continue;
}
// Get Allowd fpr all Types
QMap<int, GeoPCharge> mun;
QMap<int, QMap<int, bool> > allowedCombi;
for (int weaponTypeId : typesList)
{
QString alloweKey = QStringLiteral("Allowed") + QString::number(weaponTypeId);
const QMap<int, bool> allowed = ammuConfig->getBoolMap(eleGroup, alloweKey);
DEBUG_LOG(m_logger) << "alloweKey allowed.size() =" << allowed.size() << " " << eleGroup << "/" << alloweKey;
allowedCombi.insert(weaponTypeId, allowed);
//DEBUG_LOG(m_logger) << "allowedCombi.insert(" << weaponTypeId <<", " << allowed << ")";
}
for (int j = 0; j < minElevataion.size(); j++)
{
int _chargeId = j;
double _minEleval = minElevataion.at(j);
double _maxEleval = maxElevataion.at(j);
QMap<int, bool> allowedCombiForCharge;
for (int weaponTypeId : typesList)
{
//hier holen wir nur den erlaubtstatus für die jeweilige ChargeElevation und packen sie in die
//Map des ChargeType
allowedCombiForCharge.insert(weaponTypeId, allowedCombi.value(weaponTypeId).value(j));
DEBUG_LOG(m_logger) << "allowedCombiForCharge.insert(" << weaponTypeId << ", " << allowedCombi.value(weaponTypeId).value(j) << ")";
}
GeoPCharge geoPCharge = GeoPCharge(_chargeId, _minEleval, _maxEleval, allowedCombiForCharge);
mun.insert(j, geoPCharge);
}
m_geoPMunMap.insert(ammo, mun);
}
DEBUG_LOG(m_logger) << "m_geoPMunMap.size=" << m_geoPMunMap.size();
}