804 lines
29 KiB
C++
Executable File
804 lines
29 KiB
C++
Executable File
/**
|
|
* Handler for AES data received from SFM
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Philipp Dassow, NLST, 2018-04-11
|
|
*/
|
|
|
|
#include <QCoreApplication>
|
|
#include <QPointF>
|
|
|
|
#include <LtsUtilsCore/qbytearray_byteaccess.h>
|
|
|
|
#include "handler_aes_data.h"
|
|
#include "settings.h"
|
|
|
|
namespace TrainingAreaBaseOC
|
|
{
|
|
// mathematical positive north -> mathematical negativ, east = 0°, 0,01 degree in 1/100° -> factor 100
|
|
static inline int compassToMathAngleForSfm(double compassDegree)
|
|
{
|
|
int ret = qRound((90.0 - compassDegree / 100.0));
|
|
while (ret < 0)
|
|
ret += 360;
|
|
while (ret > 360)
|
|
ret -= 360;
|
|
return ret;
|
|
}
|
|
|
|
HandlerAesData::HandlerAesData(const std::shared_ptr<DdsHandler> &dds,
|
|
const std::shared_ptr<AreaEffectSimulation::Interface::Dtc> &aesDtc,
|
|
const std::shared_ptr<AreaEffectSimulation::Interface::Ftc> &aesFtc,
|
|
const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &pdmDtc)
|
|
: m_dds(dds)
|
|
, m_aesDtc(aesDtc)
|
|
, m_aesFtc(aesFtc)
|
|
, m_pdmDtc(pdmDtc)
|
|
, m_utmCoord(LtsCoordTrans::UtmCoordinate::fromMgrs(Settings::baseCoord()))
|
|
, m_logger(getLogger("HandlerAesData"))
|
|
{
|
|
}
|
|
|
|
bool HandlerAesData::init()
|
|
{
|
|
// Enable AES DTC
|
|
if (!m_aesDtc->enableBCContamination() || !m_aesDtc->enableExplosionArea() || !m_aesDtc->enableExplosionSingle() || !m_aesDtc->enableFunctionalArea()
|
|
|| !m_aesDtc->enableNContamination() || !m_aesDtc->enableMineArea() || !m_aesDtc->enableExplosionCluster())
|
|
{
|
|
ERROR_LOG(m_logger) << "Error enabling AES Data-Topics.";
|
|
return false;
|
|
}
|
|
|
|
// Enable AES FTC
|
|
if (!m_aesFtc->enableBCContaminationModify() || !m_aesFtc->enableExplosionAreaModify() || !m_aesFtc->enableExplosionSingleModify()
|
|
|| !m_aesFtc->enableFunctionalAreaModify() || !m_aesFtc->enableNContaminationModify() || !m_aesFtc->enableExplosionClusterOcModify()
|
|
|| !m_aesFtc->enableMineAreaModifyFromCtaData() || !m_aesFtc->enableBCContaminationRemove() || !m_aesFtc->enableExplosionAreaRemove()
|
|
|| !m_aesFtc->enableExplosionSingleRemove() || !m_aesFtc->enableFunctionalAreaRemove() || !m_aesFtc->enableNContaminationRemove()
|
|
|| !m_aesFtc->enableMineAreaRemove() || !m_aesFtc->enableExplosionClusterRemove() || !m_aesFtc->enableExplosionAreaPauseResume()
|
|
|| !m_aesFtc->enableMineAreaReferenceModify())
|
|
{
|
|
ERROR_LOG(m_logger) << "Error enabling AES Function-Topics.";
|
|
return false;
|
|
}
|
|
|
|
// Enable PDM DTC
|
|
|
|
if (!m_pdmDtc->enableChargeType() || !m_pdmDtc->enableGearTypeChargeType() || !m_pdmDtc->enableGearType())
|
|
{
|
|
ERROR_LOG(m_logger) << "Error enabling PDM Data-Topic.";
|
|
return false;
|
|
}
|
|
|
|
if (!m_aesDtc->waitForHistoricalDataBCContamination(10000) || !m_aesDtc->waitForHistoricalDataExplosionArea(10000)
|
|
|| !m_aesDtc->waitForHistoricalDataExplosionSingle(10000) || !m_aesDtc->waitForHistoricalDataFunctionalArea(10000)
|
|
|| !m_aesDtc->waitForHistoricalDataNContamination(10000) || !m_aesDtc->waitForHistoricalDataMineArea(10000)
|
|
|| !m_aesDtc->waitForHistoricalDataExplosionCluster(10000))
|
|
{
|
|
ERROR_LOG(m_logger) << "Error waiting for historical data AES.";
|
|
return false;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "Initialisation successful";
|
|
return true;
|
|
}
|
|
|
|
void HandlerAesData::process(const QByteArray &data, int multiplexer)
|
|
{
|
|
if (data.isEmpty())
|
|
return;
|
|
switch (multiplexer)
|
|
{
|
|
case MineArea:
|
|
{
|
|
mineAreas(data);
|
|
break;
|
|
}
|
|
case ExplosionArea:
|
|
{
|
|
explosionAreas(data);
|
|
break;
|
|
}
|
|
case ExplosionSingle:
|
|
{
|
|
explosionSingles(data);
|
|
break;
|
|
}
|
|
case NContamination:
|
|
{
|
|
nContaminations(data);
|
|
break;
|
|
}
|
|
case BcContamination:
|
|
{
|
|
bcContaminations(data);
|
|
break;
|
|
}
|
|
case FunctionalArea:
|
|
{
|
|
functionalAreas(data);
|
|
break;
|
|
}
|
|
case ExplosionAreaStop:
|
|
{
|
|
explosionAreasPause(data);
|
|
break;
|
|
}
|
|
case ExplosionAreaContinue:
|
|
{
|
|
explosionAreasResume(data);
|
|
break;
|
|
}
|
|
default:
|
|
WARNING_LOG(m_logger) << "Got unknown multiplexer.";
|
|
}
|
|
}
|
|
|
|
void HandlerAesData::specificsExercise(const OcTelegrams::SpecificsExercise &data)
|
|
{
|
|
m_utmCoord = LtsCoordTrans::UtmCoordinate::fromMgrs(QString::number(data.zone) + QLatin1Char(data.band) + QString::fromLatin1(data.square)
|
|
+ QString::number(data.northing).rightJustified(7, QLatin1Char('0'))
|
|
+ QString::number(data.easting).rightJustified(7, QLatin1Char('0')));
|
|
}
|
|
|
|
void HandlerAesData::onMineAreaModifyFromCtaDataReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "Mine area modify failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "Mine area modify successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onNContaminationModifyReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "N contamination modify failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "N contamination modify successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onFunctionalAreaModifyReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "Functional area modify failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "Functional area modify successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onExplosionSingleModifyReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "Explosion single modify failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "Explosion single modify successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onExplosionAreaModifyReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "Explosion area modify failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "Explosion area modify successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onBCContaminationModifyReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "BC contamination modify failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "BC contamination modify successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onExplosionClusterOcModifyReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "ExplosionCluster modify failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "ExplosionCluster successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onMineAreaRemoveReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "Mine area remove failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "Mine area remove successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onNContaminationRemoveReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "N contamination remove failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "N contamination remove successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onFunctionalAreaRemoveReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "Functional area remove failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "Functional area remove successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onExplosionSingleRemoveReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "Explosion single remove failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "Explosion single remove successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onExplosionAreaRemoveReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "Explosion area remove failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "Explosion area remove successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onBCContaminationRemoveReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "BC contamination remove failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "BC contamination remove successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onExplosionClusterRemoveReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "ExplosionCluster remove failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "ExplosionCluster remove successfull. Id: " << reply.id();
|
|
}
|
|
|
|
void HandlerAesData::onExplosionAreaPauseResumeReply(const Core::FunctionReplyObject &reply)
|
|
{
|
|
if (reply.error())
|
|
ERROR_LOG(m_logger) << "Explosion area pause/resume failed: " << reply.translated();
|
|
else
|
|
DEBUG_LOG(m_logger) << "Explosion area pause/resume successfull. Id: " << reply.id();
|
|
}
|
|
|
|
template <typename T> static inline void getBasicData(const QByteArray &data, size_t &pos, T &req, bool withoutEffectStart = false)
|
|
{
|
|
uint64_t tmp;
|
|
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
req.id(tmp);
|
|
req.name(data.mid(pos, 8).toStdString());
|
|
QString name = QString::fromStdString(req.name());
|
|
|
|
// Linux doesn't like it when there are non plausable charaters
|
|
name = name.replace(QRegExp(QStringLiteral("[^ -~]")), QLatin1String(""));
|
|
name = name.trimmed();
|
|
if (!name.isEmpty())
|
|
req.name(name.toStdString());
|
|
|
|
pos += 8;
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
if (tmp != 0)
|
|
req.partyId(dds::core::optional<int32_t>(tmp));
|
|
else
|
|
req.partyId(dds::core::optional<int32_t>());
|
|
if (!withoutEffectStart)
|
|
{
|
|
LtsUtils::get4Byte(data, pos, tmp);
|
|
if (tmp != 0)
|
|
req.effectStart(dds::core::optional<rti::core::int64>(tmp * 1000));
|
|
else
|
|
req.effectStart(dds::core::optional<rti::core::int64>());
|
|
}
|
|
}
|
|
// mathematical negativ east = 0° -> mathematical positiv, north = 0°, 1/100° as int -> factor 100
|
|
static inline double mathToCompassAngle(int mathDegree)
|
|
{
|
|
int ret = 9000 - mathDegree;
|
|
while (ret < 0)
|
|
ret += 36000;
|
|
while (ret > 36000)
|
|
ret -= 36000;
|
|
|
|
return ret / 100.0;
|
|
}
|
|
|
|
void HandlerAesData::bcContaminations(const QByteArray &data)
|
|
{
|
|
INFO_LOG(m_logger) << "Got new BC contamination data";
|
|
DEBUG_LOG(m_logger) << "Binary data: " << data.toHex(' ');
|
|
|
|
QList<int> aesToBeDeleted = m_aesDtc->bCContaminations().keys();
|
|
|
|
size_t pos = 0;
|
|
int cnt;
|
|
LtsUtils::get1Byte(data, pos, cnt);
|
|
|
|
AreaEffectSimulation::BCContaminationModifyRequest req;
|
|
req.weatherSource(AreaEffectSimulation::AesWeatherSource::AwsNoUpdate);
|
|
uint64_t tmp;
|
|
int x = 0, y = 0;
|
|
|
|
for (int i = 0; i < cnt; ++i)
|
|
{
|
|
getBasicData(data, pos, req);
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.effectDuration(tmp * 60 * 1000);
|
|
LtsUtils::get3Byte(data, pos, y); // north
|
|
LtsUtils::get3Byte(data, pos, x); // east
|
|
req.impactPosition(relativeToGeoPosition(x, y));
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
req.impactRadius(tmp);
|
|
LtsUtils::get1Byte(data, pos, tmp); // expanding factor -> is deduced from ChargeType
|
|
LtsUtils::get2Byte(data, pos, tmp); // wind direction
|
|
req.propagationDirection(dds::core::optional<double>(compassToMathAngleForSfm(tmp))); // what an angle
|
|
LtsUtils::get1Byte(data, pos, tmp); // wind speed
|
|
req.windSpeed(dds::core::optional<double>(tmp));
|
|
LtsUtils::get4Byte(data, pos, tmp); // timestamp since when weather is valid
|
|
req.weatherTimestamp(dds::core::optional<rti::core::int64>(tmp * 1000)); // secs to msecs
|
|
LtsUtils::get3Byte(data, pos, y); // north when weather changed
|
|
LtsUtils::get3Byte(data, pos, x); // east when weather changed
|
|
req.weatherPosition(dds::core::optional<Core::GeoPosition2D>(relativeToGeoPosition(x, y)));
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.chargeTypeId(chargeTypeIdFromChargeTasCode(ProjectDataManagement::GearClass_def::Chemical, tmp));
|
|
if (req.chargeTypeId() == 0)
|
|
req.chargeTypeId(chargeTypeIdFromChargeTasCode(ProjectDataManagement::GearClass_def::Biological, tmp));
|
|
LtsUtils::get1Byte(data, pos, tmp); // votality type -> is deduced from ChargeType
|
|
|
|
DEBUG_LOG(m_logger) << (aesToBeDeleted.contains(req.id()) ? "Modifying " : "Creating ") << "BC contamination: " << req;
|
|
|
|
aesToBeDeleted.removeAll(req.id()); // item was created/modified -> does not need to be deleted
|
|
req.id(req.id() * -1); // inverted id to mark as for oc
|
|
|
|
m_aesFtc->bCContaminationModifyRequest(req, this);
|
|
}
|
|
|
|
for (int id : qAsConst(aesToBeDeleted))
|
|
{
|
|
if (m_aesDtc->bCContamination(id).isCentral())
|
|
continue;
|
|
if (m_aesDtc->bCContamination(id).effectStateId().underlying() > AreaEffectSimulation::AesEffectState::EsRemoved)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Removing BC contamination id: " << id;
|
|
m_aesFtc->bCContaminationRemoveRequest(Core::RemoveElementRequest(id), this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerAesData::explosionAreas(const QByteArray &data)
|
|
{
|
|
INFO_LOG(m_logger) << "Got new explosion cluster data";
|
|
DEBUG_LOG(m_logger) << "Binary data: " << data.toHex(' ');
|
|
|
|
QList<int> aesToBeDeleted = m_aesDtc->explosionClusters().keys();
|
|
|
|
size_t pos = 0;
|
|
int cnt;
|
|
LtsUtils::get1Byte(data, pos, cnt);
|
|
|
|
AreaEffectSimulation::ExplosionClusterOcModifyRequest req;
|
|
uint64_t tmp;
|
|
int x = 0, y = 0;
|
|
|
|
for (int i = 0; i < cnt; ++i)
|
|
{
|
|
// basic data
|
|
LtsUtils::get2Byte(data, pos, tmp); // id
|
|
req.id(tmp);
|
|
|
|
req.name(data.mid(pos, 8).toStdString()); // name
|
|
QString name = QString::fromStdString(req.name());
|
|
// Linux doesn't like it when there are non plausable charaters
|
|
name = name.replace(QRegExp(QStringLiteral("[^ -~]")), QLatin1String(""));
|
|
name = name.trimmed();
|
|
if (!name.isEmpty())
|
|
req.name(name.toStdString());
|
|
|
|
pos += 8;
|
|
LtsUtils::get1Byte(data, pos, tmp); // party id
|
|
req.partyId(tmp);
|
|
|
|
LtsUtils::get4Byte(data, pos, tmp); // effect start
|
|
req.effectStart(tmp * 1000);
|
|
|
|
LtsUtils::get2Byte(data, pos, tmp); // effect duration
|
|
req.effectDuration(tmp * 1000);
|
|
|
|
// area
|
|
AreaEffectSimulation::Area area;
|
|
LtsUtils::get3Byte(data, pos, y); // north
|
|
LtsUtils::get3Byte(data, pos, x); // east
|
|
area.cornerBottomLeft(relativeToGeoPosition(x, y));
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
area.width(tmp * 5);
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
area.height(tmp * 5);
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
area.rotation(mathToCompassAngle(tmp + 9000)); // +9000, as other edge is used as reference to rotate in the sfm
|
|
req.area(area);
|
|
|
|
LtsUtils::get2Byte(data, pos, tmp); // mhp width (1 byte) and length (1 byte) --> just read and skip, since it is not needed here
|
|
|
|
LtsUtils::get2Byte(data, pos, tmp); // mhp rotation
|
|
req.mhpRotation(mathToCompassAngle(tmp + 9000)); // +9000, as other edge is used as reference to rotate in the sfm
|
|
|
|
LtsUtils::get2Byte(data, pos, tmp); // impact count
|
|
req.impactCount(tmp);
|
|
|
|
LtsUtils::get2Byte(data, pos, tmp); // impact edge length --> just read and skip, since it is not needed here
|
|
|
|
LtsUtils::get1Byte(data, pos, tmp); // charge type id
|
|
req.chargeStruct().chargeTypeId(chargeTypeIdFromChargeTasCode(ProjectDataManagement::GearClass_def::Artillery, tmp));
|
|
if (req.chargeStruct().chargeTypeId() == 0)
|
|
req.chargeStruct().chargeTypeId(chargeTypeIdFromChargeTasCode(ProjectDataManagement::GearClass_def::Mortar, tmp));
|
|
if (req.chargeStruct().chargeTypeId() == 0)
|
|
req.chargeStruct().chargeTypeId(chargeTypeIdFromChargeTasCode(ProjectDataManagement::GearClass_def::AirSupport, tmp));
|
|
|
|
LtsUtils::get2Byte(data, pos, tmp); // hazard distance (1 byte) and hazard type (1 byte) --> just read and skip, since it is not needed here
|
|
|
|
LtsUtils::get1Byte(data, pos, tmp); // mhp count
|
|
req.mhpCount(tmp);
|
|
|
|
// mhps --> just read and skip, since it is not needed here
|
|
for (int32_t mhpCounter = 0; mhpCounter < req.mhpCount(); ++mhpCounter)
|
|
{
|
|
LtsUtils::get3Byte(data, pos, tmp);
|
|
LtsUtils::get3Byte(data, pos, tmp);
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "New ExplosionClusterOcModifyRequest: "
|
|
<< "\nid:" << req.id() << "\nname:" << req.name() << "\neffectStart:" << req.effectStart() << "\neffectDuration:" << req.effectDuration()
|
|
<< "\narea:" << req.area() << "\nmhpCount:" << req.mhpCount() << "\nmhpRotation:" << req.mhpRotation() << "\nimpactCount:" << req.impactCount()
|
|
<< "\nchargeTypeId:" << req.chargeStruct().chargeTypeId() << "\npartyId:" << req.partyId();
|
|
|
|
DEBUG_LOG(m_logger) << (aesToBeDeleted.contains(req.id()) ? "Modifying " : "Creating ") << "explosion cluster: " << req;
|
|
aesToBeDeleted.removeOne(req.id()); // item was created/modified -> does not need to be deleted
|
|
req.id(req.id() * -1); // inverted id to mark as for oc
|
|
|
|
m_aesFtc->explosionClusterOcModifyRequest(req, this);
|
|
}
|
|
|
|
for (int id : qAsConst(aesToBeDeleted))
|
|
{
|
|
const AreaEffectSimulation::ExplosionCluster &exp = m_aesDtc->explosionCluster(id);
|
|
|
|
if (exp.isCentral())
|
|
continue;
|
|
|
|
if ((exp.effectStateId().underlying() >= AreaEffectSimulation::AesEffectState::EsPrepared)
|
|
|| ((exp.effectStateId().underlying() >= AreaEffectSimulation::AesEffectState::EsActivated)
|
|
&& (((exp.effectStart().is_set() && ((exp.effectStart().get() + exp.effectDuration())) < (m_dds->currentPartitionTime() - 5000)))
|
|
|| // is not recently expired
|
|
(exp.effectStateId().underlying() == AreaEffectSimulation::AesEffectState::EsPaused)))) // or is paused
|
|
{
|
|
DEBUG_LOG(m_logger) << "Removing explosion cluster with id: " << id;
|
|
m_aesFtc->explosionClusterRemoveRequest(Core::RemoveElementRequest(id), this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerAesData::explosionSingles(const QByteArray &data)
|
|
{
|
|
INFO_LOG(m_logger) << "Got new explosion single data";
|
|
DEBUG_LOG(m_logger) << "Binary data: " << data.toHex(' ');
|
|
|
|
QList<int> aesToBeDeleted = m_aesDtc->explosionSingles().keys();
|
|
|
|
size_t pos = 0;
|
|
int cnt;
|
|
LtsUtils::get1Byte(data, pos, cnt);
|
|
|
|
AreaEffectSimulation::ExplosionSingleModifyRequest req;
|
|
uint64_t tmp;
|
|
int x = 0, y = 0;
|
|
|
|
for (int i = 0; i < cnt; ++i)
|
|
{
|
|
getBasicData(data, pos, req);
|
|
|
|
LtsUtils::get3Byte(data, pos, y); // north
|
|
LtsUtils::get3Byte(data, pos, x); // east
|
|
req.impactPosition(relativeToGeoPosition(x, y));
|
|
if (m_use2BytesForSingleFireDiameter)
|
|
LtsUtils::get2Byte(data, pos, tmp); // impact radius -> is deduced from ChargeType
|
|
else
|
|
LtsUtils::get1Byte(data, pos, tmp); // impact radius -> is deduced from ChargeType
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.chargeTypeId(chargeTypeIdFromChargeTasCode(ProjectDataManagement::GearClass_def::Artillery, tmp));
|
|
if (req.chargeTypeId() == 0)
|
|
req.chargeTypeId(chargeTypeIdFromChargeTasCode(ProjectDataManagement::GearClass_def::Mortar, tmp));
|
|
DEBUG_LOG(m_logger) << (aesToBeDeleted.contains(req.id()) ? "Modifying " : "Creating ") << "explosion single: " << req;
|
|
|
|
aesToBeDeleted.removeAll(req.id()); // item was created/modified -> does not need to be deleted
|
|
req.id(req.id() * -1); // inverted id to mark as for oc
|
|
m_aesFtc->explosionSingleModifyRequest(req, this);
|
|
}
|
|
|
|
for (int id : qAsConst(aesToBeDeleted))
|
|
{
|
|
const AreaEffectSimulation::ExplosionSingle &exp = m_aesDtc->explosionSingle(id);
|
|
if (exp.isCentral())
|
|
continue;
|
|
if ((exp.effectStateId().underlying() > AreaEffectSimulation::AesEffectState::EsRemoved)
|
|
&& (exp.effectStart().is_set() && (exp.effectStart().get() > (m_dds->currentPartitionTime() + 5000)))) // is not about to expire
|
|
{
|
|
DEBUG_LOG(m_logger) << "Removing explosion single id: " << id;
|
|
m_aesFtc->explosionSingleRemoveRequest(Core::RemoveElementRequest(id), this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerAesData::functionalAreas(const QByteArray &data)
|
|
{
|
|
INFO_LOG(m_logger) << "Got functional area data";
|
|
DEBUG_LOG(m_logger) << "Binary data: " << data.toHex(' ');
|
|
|
|
QList<int> aesToBeDeleted = m_aesDtc->functionalAreas().keys();
|
|
|
|
size_t pos = 0;
|
|
int cnt;
|
|
LtsUtils::get1Byte(data, pos, cnt);
|
|
|
|
AreaEffectSimulation::FunctionalAreaModifyRequest req;
|
|
uint64_t tmp;
|
|
int x = 0, y = 0;
|
|
|
|
for (int i = 0; i < cnt; ++i)
|
|
{
|
|
getBasicData(data, pos, req, true);
|
|
if (!aesToBeDeleted.contains(req.id())) // is a create?
|
|
req.effectStart(dds::core::optional<rti::core::int64>(m_dds->currentPartitionTime() + 100)); // functional areas always start on create
|
|
|
|
// area
|
|
AreaEffectSimulation::Area area;
|
|
LtsUtils::get3Byte(data, pos, y); // north
|
|
LtsUtils::get3Byte(data, pos, x); // east
|
|
area.cornerBottomLeft(relativeToGeoPosition(x, y));
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
area.width(tmp * 5);
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
area.height(tmp * 5);
|
|
area.rotation(0);
|
|
req.area(area);
|
|
|
|
// modes and times
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.deconMode(static_cast<AreaEffectSimulation::AesOperatingMode::inner_enum>(tmp));
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.deconTime(tmp * 10 * 60 * 1000); // to ms
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.maintMode(static_cast<AreaEffectSimulation::AesOperatingMode::inner_enum>(tmp));
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.maintTime(tmp * 10 * 60 * 1000); // to ms
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.medicMode(static_cast<AreaEffectSimulation::AesOperatingMode::inner_enum>(tmp));
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.medicTime(tmp * 10 * 60 * 1000); // to ms
|
|
req.chargeTypeId(411); // Dummy
|
|
|
|
DEBUG_LOG(m_logger) << (aesToBeDeleted.contains(req.id()) ? "Modifying " : "Creating ") << "functional area: " << req;
|
|
|
|
aesToBeDeleted.removeAll(req.id()); // item was created/modified -> does not need to be deleted
|
|
req.id(req.id() * -1); // inverted id to mark as for oc
|
|
|
|
m_aesFtc->functionalAreaModifyRequest(req, this);
|
|
}
|
|
|
|
for (int id : qAsConst(aesToBeDeleted))
|
|
{
|
|
if (m_aesDtc->functionalArea(id).isCentral())
|
|
continue;
|
|
if (m_aesDtc->functionalArea(id).effectStateId().underlying() > AreaEffectSimulation::AesEffectState::EsRemoved)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Removing functional area id: " << id;
|
|
m_aesFtc->functionalAreaRemoveRequest(Core::RemoveElementRequest(id), this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerAesData::nContaminations(const QByteArray &data)
|
|
{
|
|
INFO_LOG(m_logger) << "Got new N contamination data";
|
|
DEBUG_LOG(m_logger) << "Binary data: " << data.toHex(' ');
|
|
|
|
QList<int> aesToBeDeleted = m_aesDtc->nContaminations().keys();
|
|
|
|
size_t pos = 0;
|
|
int cnt;
|
|
LtsUtils::get1Byte(data, pos, cnt);
|
|
|
|
AreaEffectSimulation::NContaminationModifyRequest req;
|
|
uint64_t tmp;
|
|
int x = 0, y = 0;
|
|
|
|
for (int i = 0; i < cnt; ++i)
|
|
{
|
|
getBasicData(data, pos, req);
|
|
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
req.effectDuration(tmp * 6 * 60 * 1000);
|
|
LtsUtils::get3Byte(data, pos, y); // north
|
|
LtsUtils::get3Byte(data, pos, x); // east
|
|
req.impactPosition(relativeToGeoPosition(x, y));
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
req.impactRadius(tmp);
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
req.borderLengthInner(tmp);
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
req.borderLengthOuter(tmp);
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
req.spanAngle(tmp / 100.0);
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
req.rotationAngle(mathToCompassAngle(tmp));
|
|
|
|
req.chargeTypeId(chargeTypeIdFromChargeTasCode(ProjectDataManagement::GearClass_def::Nuclear, 1));
|
|
|
|
DEBUG_LOG(m_logger) << (aesToBeDeleted.contains(req.id()) ? "Modifying " : "Creating ") << "N contamination: " << req;
|
|
|
|
aesToBeDeleted.removeAll(req.id()); // item was created/modified -> does not need to be deleted
|
|
req.id(req.id() * -1); // inverted id to mark as for oc
|
|
|
|
m_aesFtc->nContaminationModifyRequest(req, this);
|
|
}
|
|
|
|
for (int id : qAsConst(aesToBeDeleted))
|
|
{
|
|
if (m_aesDtc->nContamination(id).isCentral())
|
|
continue;
|
|
if (m_aesDtc->nContamination(id).effectStateId().underlying() > AreaEffectSimulation::AesEffectState::EsRemoved)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Removing N contamination id: " << id;
|
|
m_aesFtc->nContaminationRemoveRequest(Core::RemoveElementRequest(id), this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerAesData::mineAreas(const QByteArray &data)
|
|
{
|
|
INFO_LOG(m_logger) << "Got new mine area data";
|
|
DEBUG_LOG(m_logger) << "Binary data: " << data.toHex(' ');
|
|
|
|
QList<int> aesToBeDeleted = m_aesDtc->mineAreas().keys();
|
|
|
|
size_t pos = 0;
|
|
int cnt;
|
|
LtsUtils::get1Byte(data, pos, cnt);
|
|
|
|
AreaEffectSimulation::MineArea req;
|
|
uint64_t tmp;
|
|
int x = 0, y = 0;
|
|
|
|
for (int i = 0; i < cnt; ++i)
|
|
{
|
|
getBasicData(data, pos, req);
|
|
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.effectDuration(tmp * 60 * 60 * 1000); // convert to msecs
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.width(tmp);
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
req.density(tmp / 100.0);
|
|
|
|
LtsUtils::get1Byte(data, pos, tmp);
|
|
if (217 > tmp && 210 < tmp) // Legacy Ids
|
|
req.chargeStruct().chargeTypeId(chargeTypeIdFromChargeTasCode(ProjectDataManagement::GearClass_def::MineArea, tmp));
|
|
else // OSAG = ChargeTypeIs
|
|
req.chargeStruct().chargeTypeId(tmp);
|
|
|
|
LtsUtils::get2Byte(data, pos, tmp); // total mine count
|
|
|
|
// segments
|
|
int segmentCnt = 0;
|
|
LtsUtils::get1Byte(data, pos, segmentCnt);
|
|
req.segments().resize(segmentCnt);
|
|
|
|
for (int j = 0; j < segmentCnt; ++j)
|
|
{
|
|
AreaEffectSimulation::MineSegment &segment = req.segments().at(j);
|
|
LtsUtils::get3Byte(data, pos, y);
|
|
LtsUtils::get3Byte(data, pos, x);
|
|
segment.positionStart(relativeToGeoPosition(x, y));
|
|
LtsUtils::get3Byte(data, pos, y);
|
|
LtsUtils::get3Byte(data, pos, x);
|
|
segment.positionEnd(relativeToGeoPosition(x, y));
|
|
}
|
|
|
|
req.isCenterLine(true);
|
|
|
|
DEBUG_LOG(m_logger) << (aesToBeDeleted.contains(req.id()) ? "Modifying " : "Creating ") << "mine area: " << req;
|
|
|
|
aesToBeDeleted.removeAll(req.id()); // item was created/modified -> does not need to be deleted
|
|
req.id(req.id() * -1); // inverted id to mark as for oc
|
|
|
|
req.setMineSorted(false);
|
|
m_aesFtc->mineAreaModifyFromCtaDataRequest(req, this);
|
|
}
|
|
|
|
for (int id : qAsConst(aesToBeDeleted))
|
|
{
|
|
if (m_aesDtc->mineArea(id).isCentral())
|
|
continue;
|
|
if (m_aesDtc->mineArea(id).effectStateId().underlying() > AreaEffectSimulation::AesEffectState::EsRemoved)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Removing mine area id: " << id;
|
|
m_aesFtc->mineAreaRemoveRequest(Core::RemoveElementRequest(id), this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerAesData::explosionAreasPause(const QByteArray &data)
|
|
{
|
|
INFO_LOG(m_logger) << "Got new explosion area pause data";
|
|
DEBUG_LOG(m_logger) << "Binary data: " << data.toHex(' ');
|
|
|
|
size_t pos = 0;
|
|
int cnt;
|
|
LtsUtils::get1Byte(data, pos, cnt);
|
|
|
|
uint64_t id;
|
|
for (int i = 0; i < cnt; ++i)
|
|
{
|
|
LtsUtils::get2Byte(data, pos, id);
|
|
DEBUG_LOG(m_logger) << "Pausing ID: " << id;
|
|
m_aesFtc->explosionAreaPauseResumeRequest(AreaEffectSimulation::ExplosionAreaPauseResumeRequest(id,
|
|
false,
|
|
dds::core::optional<rti::core::int64>(),
|
|
dds::core::optional<int32_t>(),
|
|
dds::core::optional<int32_t>()),
|
|
this);
|
|
}
|
|
}
|
|
|
|
void HandlerAesData::explosionAreasResume(const QByteArray &data)
|
|
{
|
|
INFO_LOG(m_logger) << "Got new explosion area resume data";
|
|
DEBUG_LOG(m_logger) << "Binary data: " << data.toHex(' ');
|
|
|
|
size_t pos = 0;
|
|
int cnt;
|
|
LtsUtils::get1Byte(data, pos, cnt);
|
|
uint64_t tmp;
|
|
AreaEffectSimulation::ExplosionAreaPauseResumeRequest req;
|
|
req.resumeExecution(true);
|
|
for (int i = 0; i < cnt; ++i)
|
|
{
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
req.id(tmp);
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
req.resumeSeed(dds::core::optional<int32_t>(tmp));
|
|
LtsUtils::get2Byte(data, pos, tmp); // number of impact -> not used, calculated internally
|
|
LtsUtils::get4Byte(data, pos, tmp);
|
|
req.timeToResume(dds::core::optional<rti::core::int64>(tmp * 1000));
|
|
LtsUtils::get2Byte(data, pos, tmp);
|
|
req.remainingDuration(dds::core::optional<int32_t>(tmp));
|
|
DEBUG_LOG(m_logger) << "Resuming: " << req;
|
|
m_aesFtc->explosionAreaPauseResumeRequest(req, this);
|
|
}
|
|
}
|
|
|
|
int HandlerAesData::chargeTypeIdFromChargeTasCode(ProjectDataManagement::GearClass gearClass, int chargeTasCodeIndirect)
|
|
{
|
|
static bool initialized = false;
|
|
|
|
if (!initialized)
|
|
{
|
|
if (!m_pdmDtc->waitForHistoricalDataChargeType(20000)) // 20s
|
|
{
|
|
ERROR_LOG(m_logger) << "Can not read charge types from PDM";
|
|
QCoreApplication::exit(-1);
|
|
return -1;
|
|
}
|
|
initialized = true;
|
|
}
|
|
|
|
return m_pdmDtc->chargeTypeIdFromLegacyId(gearClass, chargeTasCodeIndirect);
|
|
}
|
|
|
|
Core::GeoPosition2D HandlerAesData::relativeToGeoPosition(int x, int y) const
|
|
{
|
|
const QPointF point(m_utmCoord.geographic(x, y));
|
|
return Core::GeoPosition2D(point.x(), point.y());
|
|
}
|
|
|
|
} // namespace TrainingAreaBaseOC
|