- 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>
222 lines
8.6 KiB
C++
Executable File
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
|