Files
qt5-legatus-legacy/Lts/Services/AreaEffectSimulation/object_explosion_cluster.h
T
2026-08-13 18:33:10 +02:00

249 lines
9.9 KiB
C++
Executable File

/**
* @RDE_HEADER@
* ObjectMap for ExplosionCluster
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include "aes_db.h"
#include "object_base.h"
#include <CentralEffectSimulation/ces_ftc.h>
#include <TrainingAreaBase/tab_ftc.h>
#include <Trajectory/trajectory_generator.h>
#include <LtsUtilsCore/qpoint3d.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <Utils/firing_timer.h>
#include <Utils/aes_helper.h>
#include <QDateTime>
using DetonationLocationRequest = CentralEffectSimulation::DetonationLocationRequest;
using DetonationLocationReply = CentralEffectSimulation::DetonationLocationReply;
namespace AreaEffectSimulation
{
class ObjectExplosionCluster final
: public ObjectBaseTmpl<Database::AesExplosionCluster>
, protected CentralEffectSimulation::Interface::Ftc::DetonationLocationReplyHandler
{
Q_OBJECT
using BaseClass = ObjectBaseTmpl<Database::AesExplosionCluster>;
public:
constexpr static double s_defaultZ_Value = 100; // default Elevation for GUEZ / Altmark. Hopefully fine for other areas..
constexpr static double s_invalid_rotation_angle = -1000;
explicit ObjectExplosionCluster(MainHandler *mainHandler,
QObject *parent = nullptr);
~ObjectExplosionCluster();
bool isActivationTimeReached() const override
{
if (noTracjectoryRequired())
return BaseClass::isActivationTimeReached();
return false;
}
qint32 flightDurationMsec() const override { return m_data.flightDuration; }
bool isOnlyObjectNameModifiable() const override;
bool isObjectModifiable() const override; // is at least one parameter in the object modifyable
bool isFiringTimeReached() const override;
Core::FunctionReplyObject createObject(const Database::AesExplosionCluster &data);
Core::FunctionReplyObject updateObject(const Database::AesExplosionCluster &data) override;
Core::FunctionReplyObject removeObject() override;
Core::FunctionReplyObject checkObjectData(const Database::AesExplosionCluster &data) const;
/*!
* \brief removeObjectFromDb
* \details Removes the object from db, Used if the object is created but there are to much objects (amount border)
* \author Niklas Schmidt
* \return bool if the deletion was working
*/
bool removeObjectFromDb();
Core::FunctionReplyObject resumePause(const ExplosionClusterPauseResumeRequest &req);
Core::FunctionReplyObject targetPositionsModify(const TargetPositionsModifyRequest &req);
Core::FunctionReplyObject checkPreConditionsComplete();
Core::FunctionReplyObject checkPreConditions();
bool initialCalculations(QString *reasonOut = nullptr);
void abortPreStartTimer();
std::vector<Core::GeoPosition> form() const override { return m_aiv.form(); }
QPolygonF generateForm() override;
AesType aesType() const override { return AesType::AtExplosionArea; }
bool isCentral() const override { return m_data.isCentral; }
bool isExplosionClusterMarkedValid() const { return m_temporaryData.annotationString.empty(); }
void removeTopics();
void setCookie(const rti::core::SampleIdentity &cookie) {m_cookie = cookie;}
// Vulcano
bool isVulcano() const { return chargeTypeIdIsVulcano(m_data.chargeTypeId); }
// From HLA, no participantId -> -1;
// 0 is default. For ExplosionClusterDialog, a value of zero is an error!
// to skip trajectory, provied -1.
bool isOriginatorParticipantIdProvided() const { return m_data.participantId >= 0; } // !! >= !! For ExplosionClusterDialog, a value of zero is an error!
void setAirSupportSource(bool isAirSupportSource) { m_isAirSupportSource = isAirSupportSource; }
bool isMhpRotationProvided() const { return m_data.mhpRotationRequest > s_invalid_rotation_angle; }
bool noTracjectoryRequired() const { return (m_data.externalId > 0) || (m_data.participantId <= 0); }
void setAesProperty(QJsonObject property, bool pubish = true);
protected:
void setEffectState(AesEffectState newState) override;
void publishAiv();
protected Q_SLOTS:
void onPublishData() override;
void onDetonationLocationReply(const DetonationLocationReply &reply) override;
void checkNextFire();
// void checkNextSingleExplosion();
void onFiringTimerFiring(int currentFiringNumber, int totalAmmoCount);
void onFiringTimerImpact(int currentExplosionNumber, int totalAmmoCount);
void onFiringTimerStateChangeDelayedCommandAsInt(int cmdAsInt, int firedAmmoCount);
protected:
bool generateTrajectory(int explosionNumber, bool startDetonationLocationRequest = true, QString *reasonOut = nullptr);
bool generateTrajectoryVulcanoSpecific(int explosionNumber, const TrajectoryGeneratorVulcano::Options options, QString *reasonOut = nullptr);
double getElevationFor(const QPointF &originGeoRadiant, const QString &context) const;
void adjustTrajectoryToDetonationLocation(int explosionIndex, const Core::GeoPosition &intersectionLocation, const int buildingId);
// void setTrajectoryStartTime(int explosionIndex);
Core::FunctionReplyObject setupFiringOrigin();
bool getFiringUnitOrigin(const int firingParticipantId, LtsUtils::QPoint3D &firingOriginOut, QString *reasonOut = nullptr);
bool firingOriginIsValid(const LtsUtils::QPoint3D &firingOrigin, QString *reasonOut) const;
LtsUtils::QPoint3D getFiringCannonGeoPosition(int explosionIndex) const;
LtsUtils::QPoint3D getFiringCannonUtmPosition(int explosionIndex, int zoneToUse) const;
std::vector<Core::GeoPosition> generateGunToTargetForm(QString *reasonOut = nullptr);
void publishTrajectory(int explosionIndex);
void publishTrajectoryViaHandler(const TrajectoryTimeAware& trajectoryTimeAwareRef);
// void publishDetonationAiv();
private:
void dump(const char *file = nullptr, int lineNo = 0) const;
// void startSingleExplosionHandling();
// void stopSingleExplosionHandling(AesEffectState newState);
// qint64 impactDeltaMSec() const;
// int currentExplosionNumber() const;
DetonationLocationRequest detonationLocationRequest(int explosionIndex) const;
private:
QTimer *m_singleExplosionTriggerTimer{nullptr};
QTimer *m_preStartTimer{nullptr};
int m_lastSentTriggeredExplosionNumber;
int m_chargeCountUntilLastStart;
FiringTimer m_firingTimer;
ExplosionCluster m_explosionCluster;
AesItemView m_aiv; // AtExplosionCluster
AesItemView m_aiv2; // AtExplosionClusterSingleExplosions - SingleExplosions
bool m_aiv2HasChanged{true};
// Effects
Effects m_effects; // replacement for m_aiv2 & TriggeredImpacts
AesItemView m_aivGunToTargetTrajectory; // AtExplosionClusterGunToTargetLine
bool m_aivGunToTargetTrajectoryDirty{false};
bool m_isAirSupportSource{false};
QMap<int, QString> m_publisedTrajectoriesForDebug;
struct temporaryData
{
std::string annotationString;
std::vector<Core::GeoPosition2D> mhPoints;
double mhpWidth {0.0};
double mhpLength {0.0};
double mhpRotation {0.0};
long estimatedMaxFlightDurationMSec{0};
double calculatedFiringAngle {0}; // degree
double calculatedFiringSpeed {0}; // m/sec
double calculatedPeakHeightAbs {0};
long calculatedFlightDurationMsec {0};
double calculatedMhpRotationNorthDeg {0};
// center
LtsCoordTrans::UtmCoordinate m_firingUnitOriginUtm;
LtsUtils::QPoint3D m_firingUnitOriginUtmPoint3D;
std::vector<Core::GeoPosition> gunToTargetLine;
// single
std::vector<Core::GeoPosition> singleFiringPositions; // 1..4
bool isObjectModifiable{true}; // will be set to false via checkNextFire by m_preStartTimer
void reset()
{
annotationString.clear();
mhPoints.clear();
mhpWidth = 0.0;
mhpLength = 0.0;
mhpRotation = 0.0;
estimatedMaxFlightDurationMSec = 0;
calculatedFiringAngle = 0;
calculatedFiringSpeed = 0;
calculatedPeakHeightAbs = 0;
calculatedFlightDurationMsec = 0;
calculatedMhpRotationNorthDeg = 0;
gunToTargetLine.clear();
m_firingUnitOriginUtm = LtsCoordTrans::UtmCoordinate();
m_firingUnitOriginUtmPoint3D = LtsUtils::QPoint3D();
singleFiringPositions.clear();
isObjectModifiable = true;
}
Core::GeoPosition getFiringCannonGeoPosition(int explosionIndex) const
{
if (singleFiringPositions.empty())
return Core::GeoPosition(std::nan(""), std::nan(""), std::nan(""));
const int numberCannons = singleFiringPositions.size();
int curIdx = explosionIndex % numberCannons;
return singleFiringPositions[curIdx];
}
} m_temporaryData;
struct TracjectoryData
{
int index{-1};
int buildingId{-1}; // BuildingId, which has intersection with trajectory
std::vector<Core::GeoPosition> trajectoryGeometry;
TrajectoryTimeAware trajectoryTimeAware;
long flightDurationMSec{0}; // idealValue, intersection with building ist not considered
double peakHeightAbs{0};
};
int m_explosionIndex = 0;
rti::core::SampleIdentity m_cookie;
QHash<int, TracjectoryData> m_trajectoryCont; // key: explosionIndex (which is ExplosionNumber-1)
QHash<int, int> m_trajectoryHandlerExplosionIndexToTopicId; // key: explosionIndex ; value: id in context TrajectoryHandler
};
}