314 lines
14 KiB
C++
Executable File
314 lines
14 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* ObjectMap for EffectCluster
|
|
* $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/polygons.h>
|
|
#include <Utils/aes_helper.h>
|
|
|
|
#include <AreaEffectSimulation/Utils/fire_automaton.h>
|
|
|
|
#include <QDateTime>
|
|
|
|
using DetonationLocationRequest = CentralEffectSimulation::DetonationLocationRequest;
|
|
using DetonationLocationReply = CentralEffectSimulation::DetonationLocationReply;
|
|
|
|
const static int DEFAULT_EFFECT_DURATION = 777777;
|
|
|
|
namespace AreaEffectSimulation
|
|
{
|
|
|
|
//inline bool chargeTypeIdIsVulcano(int chargeTypeId) { return (chargeTypeId == 376) || (chargeTypeId == 393) ; }
|
|
|
|
class ObjectEffectCluster final
|
|
: public ObjectBaseTmpl<Database::AesEffectCluster>
|
|
, protected CentralEffectSimulation::Interface::Ftc::DetonationLocationReplyHandler
|
|
, protected TrainingAreaBase::Interface::Ftc::AdlerCalculateTrajectoryReplyHandler
|
|
, protected TrainingAreaBase::Interface::Ftc::SendExFireReadinessReplyHandler
|
|
, protected TrainingAreaBase::Interface::Ftc::SendExFiredReportReplyHandler
|
|
, protected TrainingAreaBase::Interface::Ftc::SendExConfirmationReportReplyHandler
|
|
{
|
|
Q_OBJECT
|
|
|
|
using BaseClass = ObjectBaseTmpl<Database::AesEffectCluster>;
|
|
|
|
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 ObjectEffectCluster(MainHandler *mainHandler,
|
|
QObject *parent = nullptr);
|
|
~ObjectEffectCluster();
|
|
|
|
bool isActivationTimeReached() const override
|
|
{
|
|
|
|
if (noTracjectoryRequired())
|
|
return BaseClass::isActivationTimeReached();
|
|
|
|
return BaseClass::isActivationTimeReached();
|
|
}
|
|
bool isFiringTimeReached() const override
|
|
{
|
|
return m_firingTimeReached;
|
|
}
|
|
|
|
|
|
qint32 flightDurationMsec() const override { return m_data.flightDuration; }
|
|
QString name() const { return m_data.name; }
|
|
bool isOnlyObjectNameModifiable() const override;
|
|
bool isObjectModifiable() const override; // is at least one parameter in the object modifyable
|
|
|
|
Core::FunctionReplyObject createObject(const Database::AesEffectCluster &data, const QVector<Database::AesEffectorData> &effectorDatas);
|
|
Core::FunctionReplyObject updateObject(const Database::AesEffectCluster &data, const QVector<Database::AesEffectorData> &effectorDatas) ;
|
|
Core::FunctionReplyObject removeObject() override;
|
|
|
|
Core::FunctionReplyObject checkObjectData(const Database::AesEffectCluster &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 EffectClusterPauseResumeRequest &req);
|
|
Core::FunctionReplyObject targetPositionsModify(const TargetPositionsModifyRequest &req);
|
|
Core::FunctionReplyObject trajectoryAdlerModify(const TrajectoryAdlerModifyRequest &req);
|
|
Core::FunctionReplyObject effectClusterModifyActor(const EffectClusterModifyActorRequest &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 isEffectClusterMarkedValid() const { return m_temporaryData.annotationString.empty(); }
|
|
|
|
bool intersectWithCircle(double lonRad, double latRad, int radius);
|
|
void markAsExpired(bool fireLoadedRound);
|
|
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 EffectClusterDialog, a value of zero is an error!
|
|
// to skip trajectory, provied -1.
|
|
bool isOriginatorParticipantIdProvided() const { return m_data.participantId >= 0; } // !! >= !! For EffectClusterDialog, a value of zero is an error!
|
|
|
|
void setAirSupportSource(bool isAirSupportSource) { m_isAirSupportSource = isAirSupportSource; }
|
|
|
|
bool setEffectors(const QVector<Database::AesEffectorData> &effectors);
|
|
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);
|
|
//EffectorControl
|
|
bool sendFireCommand(const QString &identifier);
|
|
bool sendFireCommand(int participantId);
|
|
bool overrideEffectorStates(const AesEffectorState &newState);
|
|
|
|
void onSendReadinessToTab();
|
|
|
|
protected:
|
|
void setEffectState(AesEffectState newState) override;
|
|
void publishAiv();
|
|
|
|
protected Q_SLOTS:
|
|
void onPublishData() override;
|
|
void onDetonationLocationReply(const DetonationLocationReply &reply) override;
|
|
void onAdlerCalculateTrajectoryReply(const Core::FunctionReplyObject &reply) override;
|
|
void onSendExFireReadinessReply(const Core::FunctionReplyObject &reply) override;
|
|
void onSendExFiredReportReply(const Core::FunctionReplyObject &reply) override;
|
|
void onSendExConfirmationReportReply(const Core::FunctionReplyObject &reply) override;
|
|
|
|
void checkNextFire();
|
|
void checkAutomaton();
|
|
void onAutomatonFinished();
|
|
// void checkNextSingleExplosion();
|
|
|
|
//slots triggered by effectors
|
|
void onEffectorNotReadyToFire(int participantId, int aesItemId);
|
|
void onEffectorReadyToFire(int participantId, int aesItemId);
|
|
void onEffectorReceivedOrder(int participantId, int aesItemId);
|
|
void onEffectorReportedFired(int participantId, int aesItemId);
|
|
void onEffectorFired(int participantId, int aesItemId, const QVector<int> &chargeEffectIds);
|
|
|
|
|
|
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;
|
|
|
|
void sendCalculateTrajectoryAdlerRequest(const QVector<Database::AesEffectorData> &effectorData);
|
|
std::vector<Core::GeoPosition> generateGunToTargetForm(const std::vector<Core::RelativePositionRelativeTime> &trajectoryRelativeToOriginator,
|
|
int participantId);
|
|
std::vector<Core::GeoPosition> generateGunToTargetForm(QString *reasonOut = nullptr);
|
|
static std::vector<Core::RelativePositionRelativeTime> reduceSMArtTrajectoryToSingle(const std::vector<Core::RelativePositionRelativeTime> &trajectory); // E01562-294: Falsche Darstellung Flugkurve SMArt
|
|
void publishTrajectory(int explosionIndex);
|
|
ParticipantManagement::Participant getParticipantFromInternalName(const QString &name);
|
|
bool assignEffector(int participantId);
|
|
bool updateEffector(int participantId, const Database::AesEffectorData &data);
|
|
|
|
void freeEffectors();
|
|
|
|
//
|
|
QVector<Database::AesEffectorData> generateMHPs(const QVector<Database::AesEffectorData> &effectorData, const AreaEffectSimulation::AesExplosionGeometry &geometry);
|
|
// QVector<Database::AesEffectorData> generateTrajectoryInternal(const QVector<Database::AesEffectorData> &effectorData);
|
|
|
|
// to TAB Stuff
|
|
void onSendConfirmationReportToTab(int participantId);
|
|
//Internal stuff
|
|
void onChargeEffectChanged(int chargeEffectId);
|
|
// void publishDetonationAiv();
|
|
|
|
private:
|
|
AreaEffectSimulation::EffectorData fromDatabase(const Database::AesEffectorData &data);
|
|
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};
|
|
QTimer *m_fireHoldWaitforLateFire{nullptr};
|
|
QTimer *m_automatonTimer{nullptr};
|
|
int m_lastSentTriggeredExplosionNumber;
|
|
int m_chargeCountUntilLastStart;
|
|
|
|
EffectCluster m_EffectCluster;
|
|
AesItemView m_aiv; // AtEffectCluster
|
|
AesItemView m_aiv2; // AtEffectClusterSingleExplosions - SingleExplosions
|
|
bool m_aiv2HasChanged{true};
|
|
|
|
// Effects
|
|
Effects m_effects; // replacement for m_aiv2 & TriggeredImpacts
|
|
|
|
bool m_aivGunToTargetTrajectoryDirty{false};
|
|
|
|
bool m_isAirSupportSource{false};
|
|
|
|
FireAutomaton *m_fireAutomaton {nullptr};
|
|
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};
|
|
int m_lookoutChargeEffectStart {0};
|
|
int m_lookoutChargeEffectEnd {0};
|
|
int m_lookoutChargeEffectPaused {0};
|
|
|
|
rti::core::SampleIdentity m_cookie;
|
|
bool m_firingTimeReached {false};
|
|
bool m_firstTimeReady {true};
|
|
QSet<int> m_readytoFire;
|
|
QHash<QString, int> m_effectorNameToIdMap;
|
|
QHash<int, TracjectoryData> m_trajectoryCont; // key: explosionIndex (which is ExplosionNumber-1)
|
|
QHash<int, Database::AesEffectorData> m_effectorData; // key: explosionIndex (which is ExplosionNumber-1)
|
|
QMap<int,AesItemView> m_aivGunToTargetTrajectoryMap; // AtEffectClusterGunToTargetLine
|
|
QMap<int,int> m_firedPerEfector;
|
|
QSet<int> m_firstFireSend;
|
|
|
|
};
|
|
}
|