Files
qt5-legatus-legacy/Lts/Services/AreaEffectSimulation/EffectorFiringStrategy/abstract_firing_strategy.cpp
T
torstenandCopilot 3028302f7b Qt6 Migration: Merge latest Qt5 devel content and apply migration fixes
- 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>
2026-09-15 18:20:51 +00:00

222 lines
8.6 KiB
C++
Executable File

/**
* Base Class for Effector Firing Strategy
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Fritsche, ESZS, 2025-05-11
*/
#include "abstract_firing_strategy.h"
#include "object_effector.h"
#include "main_handler.h"
#include "handler_charge_effect.h"
#include <ParticipantManagement/ppm.hpp>
#include "Trajectory/trajectory_transform.h"
#include <LtsCoordTrans/lts_coord_trans.h>
#include <LtsUtilsCore/qpoint3d.h>
#include <QJsonDocument>
#include <QRandomGenerator>
namespace AreaEffectSimulation
{
AbstractFiringStrategy::AbstractFiringStrategy(ObjectEffector *parent)
: QObject(parent)
, m_effector(parent)
, m_logger(getLogger("FiringStrategy"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
AbstractFiringStrategy::~AbstractFiringStrategy()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool AbstractFiringStrategy::calculateDispersionTrajectory()
{
DEBUG_LOG(m_logger) << "calculateDispersionTrajectory";
// 1. Neuen Zielpunkt berechnen
const auto intendendTrajectory = m_effector->intendendTrajectory();
// sanity check:
if (intendendTrajectory.size() < 2)
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " size of intendendTrajectory not sufficiant, size=" << intendendTrajectory.size();
return false;
}
LtsUtils::QPoint3D newTarget = intendendTrajectory.last().position;
const int scatterLength = qRound(m_effector->effectorData().mhpScatterLenght());
const int randomValueX = QRandomGenerator::global()->bounded(-scatterLength, scatterLength + 1);
const int scatterWidth = qRound(m_effector->effectorData().mhpScatterWidth());
const int randomValueY = QRandomGenerator::global()->bounded(-scatterWidth, scatterWidth + 1);
newTarget.setX(newTarget.x() + randomValueX);
newTarget.setY(newTarget.y() + randomValueY);
// 2. Neue Trajektorie berechnen
m_transformedTrajectory = TrajectoryTransform::transformToNewTarget(intendendTrajectory, newTarget);
// sanity check:
if (m_transformedTrajectory.size() < 2)
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " size of m_transformedTrajectory not sufficiant, size=" << m_transformedTrajectory.size();
return false;
}
return true;
}
std::vector<Core::GeoPositionRelativeTime> AbstractFiringStrategy::buildTrajectoryGeometry(const QVector<TrajectoryPoint> &relativeTrajectory)
{
// sanity check:
if (relativeTrajectory.size() < 2)
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " size of relativeTrajectory not sufficiant, size=" << relativeTrajectory.size();
return {};
}
// setup some vars of effector, which is used as launch position:
Core::GeoPosition effectorPositionGeo = participantPosition(m_effector->participantId());
const LtsCoordTrans::UtmCoordinate &launchUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(effectorPositionGeo.lon(), effectorPositionGeo.lat());
std::vector<Core::GeoPositionRelativeTime> geometry;
geometry.reserve(relativeTrajectory.size());
// Aehnlich wie Lts/Proxies/TrainingAreaBase/Plugins/AdlerJson/aes_handler.cpp Zeile 365
for (const TrajectoryPoint &trajPntRelPos : qAsConst(relativeTrajectory))
{
DEBUG_LOG(m_logger) << "Flugbahnpunkt: trajPntRelPos :" << trajPntRelPos; // benefit from operator<<:
// // geographic offers nice feature to add an offset:
// const QPointF &trajectoryAbsGeo = launchUtm.geographic(trajPntRelPos);
// but lets stay with trajectoryAbsUtm to enable DEBUG_LOG
const QPointF &trajPntRelPosUtm = trajPntRelPos.position.toPointF(); // still relativ to launch
const LtsCoordTrans::UtmCoordinate trajPntAbsUtm(launchUtm.zone,
launchUtm.x + trajPntRelPosUtm.x(),
launchUtm.y + trajPntRelPosUtm.y());
const QPointF &trajPntAbsGeo = trajPntAbsUtm.geographic();
// Position des Participants mit der m_participantId
const double zValue = effectorPositionGeo.z() + trajPntRelPos.position.z(); // trajPntRelPos.position.z() ist die Hoehe
DEBUG_LOG(m_logger) << "trajPntAbsUtm :" << trajPntAbsUtm << ", trajPntAbsGeo :" << trajPntAbsGeo;
geometry.emplace_back(Core::GeoPositionRelativeTime(trajPntAbsGeo.x(), trajPntAbsGeo.y(), zValue, trajPntRelPos.time));
}
return geometry;
}
TrajectoryTimeAware AbstractFiringStrategy::buildTrajectoryTimeAware(const std::vector<Core::GeoPositionRelativeTime> &trajectoryGeometry, qint64 trajectoryStartTime, int index)
{
// sanity check:
if (trajectoryGeometry.size() < 2)
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " size of trajectoryGeometry not sufficiant, size=" << trajectoryGeometry.size();
return {};
}
TrajectoryTimeAware trajectory;
trajectory.trajectoryStartTime(trajectoryStartTime);
trajectory.index(index); // see SituationMap : charge_effect_to_map ::updateSingleTrajectory()
// [E01562-259] use originatorId, originatorTypeId (instead of aesItemId, aesTypeId)
trajectory.originatorId(m_effector->aesItemId());
trajectory.originatorTypeId(ProjectDataManagement::StateChangeOriginator::ChargeEffect);
trajectory.geometry(trajectoryGeometry);
return trajectory;
}
int AbstractFiringStrategy::sendChargeEffect(const TrajectoryTimeAware &trajectoryTimeAware, const QJsonObject &properties)
{
DEBUG_LOG(m_logger) << "sendChargeEffect";
const auto trajGeometry = trajectoryTimeAware.geometry();
// sanity check:
if (trajGeometry.size() < 2)
{
ERROR_LOG(m_logger) << LOGFUNCTION
<< " size of trajectoryTimeAware.geometry not sufficiant, size=" << trajGeometry.size();
return -1;
}
const qint64 trajectoryStartTime = trajectoryTimeAware.trajectoryStartTime();
ChargeEffectModifyRequest chargeEffect;
chargeEffect.id(0);
chargeEffect.effectDuration(3000);
chargeEffect.name("Schuss");
chargeEffect.chargeTypeId(m_effector->effectorData().chargeStruct().chargeTypeId());
chargeEffect.effectStart(trajectoryStartTime + trajectoryTimeAware.geometry().back().relativeTime()); // Einschlag Zeit
chargeEffect.igniterTypeId(m_effector->effectorData().chargeStruct().igniterTypeId());
chargeEffect.gearTypeId(gearTypeId(m_effector->effectorData().chargeStruct().chargeTypeId(), m_effector->participantId()));
chargeEffect.originatorId(m_effector->aesItemId());
chargeEffect.originatorTypeId(ProjectDataManagement::StateChangeOriginator::AreaEffectSimulation);
chargeEffect.properties(QJsonDocument(properties).toJson().toStdString());
const Core::GeoPosition &impactPosition = trajGeometry.back();
chargeEffect.position(impactPosition); // Impact Position
chargeEffect.trajectoryTimeAware(trajectoryTimeAware);
const auto &reply = m_effector->mainHandler()->chargeEffectHandler()->createChargeEffect(chargeEffect);
DEBUG_LOG(m_logger) << LOGFUNCTION << " reply.id=" << reply.id() << ", str:" << reply.str() << ", uniqueId:" << reply.uniqueId();
return reply.id();
}
Core::GeoPosition AbstractFiringStrategy::participantPosition(int participantId)
{
m_effector->mainHandler()->dds()->ppmDtc()->enableParticipantPosition(true);
const ParticipantManagement::ParticipantPosition &pos = m_effector->mainHandler()->dds()->ppmDtc()->participantPosition(participantId);
return pos.pos();
}
int32_t AbstractFiringStrategy::gearTypeId(int chargeTypeId, int participantId)
{
DEBUG_LOG(m_logger) << "getGearTypeId"
<< ", chargeTypeId:" << chargeTypeId << ", participantId:" << participantId;
m_effector->mainHandler()->dds()->ppmDtc()->enableDynamicParticipantData(true);
m_effector->mainHandler()->dds()->ppmDtc()->waitForHistoricalDataDynamicParticipantData(1000);
const ParticipantManagement::DynamicParticipantData &dynamicParticipantData = m_effector->mainHandler()->dds()->ppmDtc()->dynamicParticipantData(participantId);
DEBUG_LOG(m_logger) << "gearSize " << dynamicParticipantData.gear().size();
const auto& participantData_gear = dynamicParticipantData.gear();
for (const auto &gear : qAsConst(participantData_gear))
{
DEBUG_LOG(m_logger) << "gear.chargeTypeId(): " << gear.chargeTypeId() << ", chargeTypeId:" << chargeTypeId;
if (gear.chargeTypeId() == chargeTypeId)
{
DEBUG_LOG(m_logger) << "getGearTypeId return: " << gear.gearTypeId();
if (gear.gearTypeId() != 0)
return gear.gearTypeId();
else
return 701; // MALTE XKCD
}
}
return 701; // MALTE XKCD
}
qint64 AbstractFiringStrategy::getStartTime() const
{
const auto trajectoryAndEffectStartTime = m_effector->mainHandler()->dds()->currentPartitionTimeMSec() + 1000;
return trajectoryAndEffectStartTime;
}
} // namespace AreaEffectSimulation