/** * @RDE_HEADER@ * ObjectMap for EffectCluster * $Id$ * $HeadURL$ * $Author$ */ #pragma once #include "aes_db.h" #include "object_base.h" #include #include #include #include #include #include #include #include #include #include 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 , 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; 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 &effectorDatas); Core::FunctionReplyObject updateObject(const Database::AesEffectCluster &data, const QVector &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 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 &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 &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 &effectorData); std::vector generateGunToTargetForm(const std::vector &trajectoryRelativeToOriginator, int participantId); std::vector generateGunToTargetForm(QString *reasonOut = nullptr); static std::vector reduceSMArtTrajectoryToSingle(const std::vector &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 generateMHPs(const QVector &effectorData, const AreaEffectSimulation::AesExplosionGeometry &geometry); // QVector generateTrajectoryInternal(const QVector &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 m_publisedTrajectoriesForDebug; struct temporaryData { std::string annotationString; std::vector 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 gunToTargetLine; // single std::vector 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 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 m_readytoFire; QHash m_effectorNameToIdMap; QHash m_trajectoryCont; // key: explosionIndex (which is ExplosionNumber-1) QHash m_effectorData; // key: explosionIndex (which is ExplosionNumber-1) QMap m_aivGunToTargetTrajectoryMap; // AtEffectClusterGunToTargetLine QMap m_firedPerEfector; QSet m_firstFireSend; }; }