/** * Send AES data to NGS * $Id$ * $HeadURL$ * $Author$ * Created by Hannes Baeuerle, SLSE, 2017-05-08 */ #include "aes_handler.h" #include "ngs_handler.h" #include #include #include #include #include #include #include #include using namespace AreaEffectSimulation; namespace HighLevelArchitecture { static MineCorridorModifyRequest *makeMinefieldBreachRequest(const MineCorridor& mc) { MineCorridorModifyRequest *req = new MineCorridorModifyRequest; req->effectDuration(mc.effectDuration()); req->effectStart(mc.effectStart()); req->externalId(mc.externalId()); req->id(mc.id()); req->name(mc.name()); req->participantId(mc.participantId()); req->partyId(mc.partyId()); req->segments(mc.segments()); req->width(mc.width()); return req; } static MineAreaModifyRequest *makeMinefieldRequest(const MineArea& ma) { if (ma.segments().size() <= 0) return nullptr; MineAreaModifyRequest *req = new MineAreaModifyRequest; req->chargeStruct().chargeTypeId(ma.chargeStruct().chargeTypeId()); req->density(ma.density()); req->distance(0.5); req->effectDuration(ma.effectDuration()); req->effectMarkingInTa(ma.effectMarkingInTa()); req->effectStart(ma.effectStart()); req->externalId(ma.externalId()); req->id(ma.id()); req->isCenterLine(ma.isCenterLine()); req->isLaidHidden(ma.isLaidHidden()); req->layingProcedureType(ma.layingProcedureType()); req->name(ma.name()); req->participantId(ma.participantId()); req->partyId(ma.partyId()); for (const MineSegment &ms : ma.segments()) req->segments().push_back(ms.positionStart()); const MineSegment &lastSegment = ma.segments().at(ma.segments().size()-1); req->segments().push_back(Core::GeoPosition2D(lastSegment.positionEnd().lon(), lastSegment.positionEnd().lat())); req->width(ma.width()); return req; } AesHandler::AesHandler(NgsHandler *ngsHandler) : m_ngsHandler(ngsHandler) , m_dtcAes(nullptr) , m_ftcAes(nullptr) , m_requestHelper(new LtsUtils::RequestHelper(this)) , m_logger(getLogger("AesHandler")) { } void AesHandler::onMineAreaModifyReply(const Core::FunctionReplyObject &replyObject) { if (replyObject.error()) WARNING_LOG(m_logger) << "ModifyReply: " << replyObject(); else DEBUG_LOG(m_logger) << "ModifyReply: " << replyObject(); m_requestHelper->requestReply(replyObject); } int64_t AesHandler::externalId(int aesItemId) const { AesItem aesItem; if (!m_dtcAes->aesItemFromId(aesItemId, aesItem)) return 0; return aesItem.externalId(); } bool AesHandler::init() { m_dtcAes = Interface::Dtc::create(m_ngsHandler->ddsHandler()->ddsConnector()); m_ftcAes = Interface::Ftc::create(m_ngsHandler->ddsHandler()->ddsConnector()); connect(m_dtcAes.get(), &Interface::Dtc::aesItemViewChanged, this, &AesHandler::onAesItemViewChanged); connect(m_dtcAes.get(), &Interface::Dtc::triggeredImpactsChanged, this, &AesHandler::onTriggeredImpactsChanged); #ifdef SUPPORT_AES_EFFECTS connect(m_dtcAes.get(), &Interface::Dtc::effectsChanged, this, &AesHandler::onEffectsChanged); #endif // SUPPORT_AES_EFFECTS connect(m_dtcAes.get(), &Interface::Dtc::explosionSingleChanged, this, &AesHandler::onAesExplosionSingleChanged); connect(m_dtcAes.get(), &Interface::Dtc::mineAreaChanged, this, &AesHandler::onAesMineAreaChanged); connect(m_dtcAes.get(), &Interface::Dtc::mineCorridorChanged, this, &AesHandler::onAesMineCorridorChanged); connect(m_dtcAes.get(), &Interface::Dtc::nContaminationChanged, this, &AesHandler::onAesNContaminationChanged); connect(m_dtcAes.get(), &Interface::Dtc::bCContaminationChanged, this, &AesHandler::onAesBCContaminationChanged); connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesNameChanged, this, &AesHandler::onAesNameChanged); connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesForceIdentifierChanged, this, &AesHandler::onAesForceIdentifierChanged); connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesActivationTimeChanged, this, &AesHandler::onAesActivationTimeChanged); connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesChargeChanged, this, &AesHandler::onAesChargeChanged); connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesDurationChanged, this, &AesHandler::onAesDurationChanged); connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesPointsDataChanged, this, &AesHandler::onAesPointsDataChanged); connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::aesRemoveItem, this, &AesHandler::onAesRemoveItem); connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::newMinefield, this, &AesHandler::onNewMinefield); connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::newMinefieldBreach, this, &AesHandler::onNewMinefieldBreach); connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::munitionDetonation, this, &AesHandler::onMunitionDetonation); #ifdef SUPPORT_EXPLOSION_CLUSTER_SINGLE_EFFECT connect(m_ngsHandler->ngsConnector().get(), &NgsConnector::munitionDetonationExplosionClusterSingleEffectOnly, this, &AesHandler::onMunitionDetonationExplosionClusterSingleEffect); #endif return m_dtcAes->enableAesItemView() && m_dtcAes->enableExplosionSingle() && m_dtcAes->enableMineArea() && m_dtcAes->enableTriggeredImpacts() && #ifdef SUPPORT_EXPLOSION_CLUSTER_SINGLE_EFFECT m_ftcAes->enableExplosionClusterSingleEffectOnlyModify() && #endif #ifdef SUPPORT_AES_EFFECTS // GUEZE-2570 / EXPLOSION_CLUSTER m_dtcAes->enableEffects() && #endif m_dtcAes->enableMineCorridor() && m_ftcAes->enableMineCorridorModify() && m_ftcAes->enableMineCorridorRemove() && m_dtcAes->enableNContamination() && m_dtcAes->enableBCContamination() && m_ftcAes->enableMineAreaRemove() && m_ftcAes->enableMineAreaModify() && m_ftcAes->enableExplosionSingleModify(); } void AesHandler::onAesItemViewChanged(const AesItemView &data, DataModification modType) { if (m_logger.isDebugEnabled()) { QStringList formString; formString.reserve(data.form().size()); for (const auto &pos : data.form()) formString << ParticipantPosition(pos).toString(); DEBUG_LOG(m_logger) << "\n##############################" << "\n##### AesItemViewChanged #####" << "\n##############################" << "\nid: " << data.id() << "\nsampleTime: " << data.sampleTime() << "\naesTypeId: " << toString(data.aesTypeId()) << "\naesItemId: " << data.aesItemId() << "\nform: " << formString.join(QStringLiteral(", ")) << "\nboundingBoxBottomLeft: " << ParticipantPosition(data.boundingBoxBottomLeft()).toString() << "\nboundingBoxTopRight: " << ParticipantPosition(data.boundingBoxTopRight()).toString() << "\neffectStateId: " << toString(data.effectStateId()) << "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set")) << "\nchargeTypeId: " << data.chargeStruct().chargeTypeId() << "\neffectStart: " << data.effectStart() << "\n"; } if (modType == DataModification::eRemoved || data.effectStateId() == AesEffectState::EsExpired || data.effectStateId() == AesEffectState::EsRemoved) { DEBUG_LOG(m_logger) << "Item view with id " << data.aesItemId() << " removed"; m_aesItemViews.remove(data.aesItemId()); m_takenIndicesForAesItem.remove(data.aesItemId()); m_ngsHandler->ngsConnector()->setItemForm(data.aesItemId()); } // Only care about Explosion Areas for triggered impacts and for storing: else if (data.effectStateId() == AesEffectState::EsPrepared && data.aesTypeId() == AesType_def::AtExplosionAreaSingleExplosions) { DEBUG_LOG(m_logger) << "Item view with id " << data.aesItemId() << " added"; m_aesItemViews.insert(data.aesItemId(), data); m_takenIndicesForAesItem.insert(data.aesItemId(), QVector()); } // On BCContaminations directly update in NgsConnector: else if (data.aesTypeId() == AesType_def::AtBCContamination) { m_ngsHandler->ngsConnector()->setItemForm(data.aesItemId(), data.aesTypeId().underlying(), data.form()); DEBUG_LOG(m_logger) << "Item view with id " << data.aesItemId() << " directly updated in ngsConnector"; } } void AesHandler::onTriggeredImpactsChanged(const TriggeredImpacts &data, DataModification modType) { if (m_logger.isDebugEnabled()) { QString bitfield = QStringLiteral("[ "); for (uint8_t bit : data.bitfield()) { bitfield.append(QString::number(bit)); bitfield.append(QStringLiteral(" ")); } bitfield.append(QStringLiteral("]")); DEBUG_LOG(m_logger) << "\n#####################################" << "\n##### triggered impacts changed #####" << "\n#####################################" << "\nid: " << data.id() << "\naesItemId: " << data.aesItemId() << "\naesTypeId: " << toString(data.aesTypeId()) << "\nbitfield: " << bitfield << "\nimpactCount: " << data.impactCount() << "\nsampleTime: " << data.sampleTime() << "\n"; } // Clean up if removed / Don't care if not in before. if (modType == DataModification::eRemoved) { m_aesItemViews.remove(data.aesItemId()); m_takenIndicesForAesItem.remove(data.aesItemId()); return; } if (data.aesTypeId() != AesType_def::AtExplosionAreaSingleExplosions) return; // If no aesItemView, no takenIndices also. They are in sync. if (!m_aesItemViews.contains(data.aesItemId())) return; const AesItemView &aesItemView = m_aesItemViews[data.aesItemId()]; // Triggered Impacts are either belonging to Explosion Areas or Mine Areas. int chargeTypeId = m_dtcAes->explosionArea(data.aesItemId()).chargeStruct().chargeTypeId(); if (chargeTypeId <= 0) return; rpr2::ForceIdentifierEnum8::ET forceId = aesItemView.partyId().is_set() ? m_ngsHandler->ppmHandler()->forceIdentifierFromPartyId(aesItemView.partyId().get()) : rpr2::ForceIdentifierEnum8::Other; for (int32_t bitFieldIdx = 0; bitFieldIdx < data.impactCount(); ++bitFieldIdx) { // no break, because every bit can be a hit if (LtsUtils::BitArray::testBit(data.bitfield(), bitFieldIdx) || m_takenIndicesForAesItem.value(data.aesItemId()).contains(bitFieldIdx)) continue; m_takenIndicesForAesItem[data.aesItemId()].append(bitFieldIdx); ParticipantPosition pos(aesItemView.form()[bitFieldIdx], data.sampleTime()); m_ngsHandler->ngsConnector()->sendMunitionDetonation(pos, chargeTypeId, forceId); } } #ifdef SUPPORT_AES_EFFECTS void AesHandler::onEffectsChanged(const Effects &data, DataModification modType) { // GUEZE-2570 3D Wirksim - Umstellung HLA auf ExplosionCluster // Part1: DDS -> HLA const int aesItemId = data.aesItemId(); // Clean up if removed / Don't care if not in before. if (modType == DataModification::eRemoved) { m_handledImpactsStorage.removeAesItem(aesItemId); return; } if (data.aesTypeId() != AesType_def::AtExplosionClusterSingleExplosions) return; const std::vector &singleEffectsRef = data.singleEffects(); if (singleEffectsRef.empty()) return; // if explosionCluster could not be found, the values is also 0; No extra check needed. const AreaEffectSimulation::ExplosionCluster &exCluster = m_dtcAes->explosionCluster(aesItemId); if (exCluster.id() != aesItemId) return; // If neither Party nor Participant is set or participant id is smaller than 0, this is an external one that should not be published! // Fix for [GUEZE-3601] External impacts are being published for a second time by us if (!exCluster.partyId().is_set() && (!exCluster.participantId().is_set() || exCluster.participantId().get() <= 0)) return; const int chargeTypeId = exCluster.chargeStruct().chargeTypeId(); if (chargeTypeId <= 0) return; // // real work: // // partyId to forceId: const rpr2::ForceIdentifierEnum8::ET forceId = exCluster.partyId().is_set() ? m_ngsHandler->ppmHandler()->forceIdentifierFromPartyId(exCluster.partyId().get()) : rpr2::ForceIdentifierEnum8::Other; int curSeIndex = -1; for (const AreaEffectSimulation::SingleEffect &se : qAsConst(singleEffectsRef)) { ++curSeIndex; // only SesTriggered are relevant: if (se.singleEffectState() != AreaEffectSimulation::AesSingleEffectState_def::SesTriggered) continue; // compare current triggered idx with triggered idx of the past if (m_handledImpactsStorage.isIndexProcessed(aesItemId, curSeIndex)) continue; // send to ngsHandler // ParticipantPosition pos(aesItemView.form()[bitFieldIdx], data.sampleTime()); ParticipantPosition pos(se.position(), se.singleEffectTime()); m_ngsHandler->ngsConnector()->sendMunitionDetonation(pos, chargeTypeId, forceId); // update storage m_handledImpactsStorage.setIndexProcessed(aesItemId, curSeIndex); } // for } #endif // SUPPORT_AES_EFFECTS void AesHandler::onAesExplosionSingleChanged(const ExplosionSingle &data, DataModification modType) { Q_UNUSED(modType); // Maybe this works also...? // if (data.externalId() > 0) // return; DEBUG_LOG(m_logger) << "\n####################################" << "\n##### single explosion changed #####" << "\n####################################" << "\nid: " << data.id() << "\nname: " << data.name() << "\nisDeleted: " << data.isDeleted() << "\nisUsed: " << data.isUsed() << "\nsampleTime: " << data.sampleTime() << "\nchargeTypeId: " << data.chargeStruct().chargeTypeId() << "\neffectDuration: " << data.effectDuration() << "\neffectStart: " << (data.effectStart().is_set() ? QString::number(data.effectStart().get()) : QStringLiteral("not set")) << "\neffectStateId: " << toString(data.effectStateId()) << "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set")) << "\nparticipantId: " << (data.participantId().is_set() ? QString::number(data.participantId().get()) : QStringLiteral("not set")) << "\nimpactPosition: " << ParticipantPosition(data.impactPosition()).toString() << "\nfireRequestTime: " << data.fireRequestTime() << "\naltitude: " << data.altitude() << "\npurpose: " << data.purpose() << "\n"; if (data.effectStateId() != AesEffectState::EsActivated) return; // If neither Party nor Participant is set or participant id is smaller than 0, this is an external one that should not be published! if (!data.partyId().is_set() && (!data.participantId().is_set() || data.participantId().get() <= 0)) return; // If it's active (it's only one second active and not likely to have several updates in the meantime... ParticipantPosition pos(data.impactPosition(), data.effectStart().is_set() ? data.effectStart().get() : data.sampleTime()); rpr2::ForceIdentifierEnum8::ET forceId = data.partyId().is_set() ? m_ngsHandler->ppmHandler()->forceIdentifierFromPartyId(data.partyId().get()) : rpr2::ForceIdentifierEnum8::Other; m_ngsHandler->ngsConnector()->sendMunitionDetonation(pos, data.chargeStruct().chargeTypeId(), forceId); } void AesHandler::onAesMineAreaChanged(const MineArea &data, DataModification modType) { Q_UNUSED(modType); DEBUG_LOG(m_logger) << "\n#############################" << "\n##### mine area changed #####" << "\n#############################" << "\nid: " << data.id() << "\nname: " << data.name() << "\nisDeleted: " << data.isDeleted() << "\nisUsed: " << data.isUsed() << "\nsampleTime: " << data.sampleTime() << "\nchargeTypeId: " << data.chargeStruct().chargeTypeId() << "\neffectDuration: " << data.effectDuration() << "\neffectStart: " << (data.effectStart().is_set() ? QString::number(data.effectStart().get()) : QStringLiteral("not set")) << "\neffectStateId: " << toString(data.effectStateId()) << "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set")) << "\nparticipantId: " << (data.participantId().is_set() ? QString::number(data.participantId().get()) : QStringLiteral("not set")) << "\n"; m_ngsHandler->ngsConnector()->guezMineField(data); } void AesHandler::onAesMineCorridorChanged(const MineCorridor &data, DataModification modType) { Q_UNUSED(modType); DEBUG_LOG(m_logger) << "\n#################################" << "\n##### mine corridor changed #####" << "\n#################################" << "\nid: " << data.id() << "\nname: " << data.name() << "\nisDeleted: " << data.isDeleted() << "\nisUsed: " << data.isUsed() << "\nsampleTime: " << data.sampleTime() << "\nchargeTypeId: " << data.chargeStruct().chargeTypeId() << "\neffectDuration: " << data.effectDuration() << "\neffectStart: " << (data.effectStart().is_set() ? QString::number(data.effectStart().get()) : QStringLiteral("not set")) << "\neffectStateId: " << toString(data.effectStateId()) << "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set")) << "\nparticipantId: " << (data.participantId().is_set() ? QString::number(data.participantId().get()) : QStringLiteral("not set")) << "\n"; m_ngsHandler->ngsConnector()->guezMineFieldBreach(data); } void AesHandler::onAesNContaminationChanged(const NContamination &data, DataModification modType) { Q_UNUSED(modType); m_ngsHandler->ngsConnector()->guezNuclearAgent(data); DEBUG_LOG(m_logger) << "\n####################################" << "\n##### n contamination changed #####" << "\n####################################" << "\nid: " << data.id() << "\nname: " << data.name() << "\nisDeleted: " << data.isDeleted() << "\nisUsed: " << data.isUsed() << "\nsampleTime: " << data.sampleTime() << "\nchargeTypeId: " << data.chargeStruct().chargeTypeId() << "\neffectDuration: " << data.effectDuration() << "\neffectStart: " << (data.effectStart().is_set() ? QString::number(data.effectStart().get()) : QStringLiteral("not set")) << "\neffectStateId: " << toString(data.effectStateId()) << "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set")) << "\nparticipantId: " << (data.participantId().is_set() ? QString::number(data.participantId().get()) : QStringLiteral("not set")) << "\n"; } void AesHandler::onAesBCContaminationChanged(const BCContamination &data, DataModification modType) { Q_UNUSED(modType); m_ngsHandler->ngsConnector()->guezChemicalAgent(data); DEBUG_LOG(m_logger) << "\n####################################" << "\n##### bc contamination changed #####" << "\n####################################" << "\nid: " << data.id() << "\nname: " << data.name() << "\nisDeleted: " << data.isDeleted() << "\nisUsed: " << data.isUsed() << "\nsampleTime: " << data.sampleTime() << "\nchargeTypeId: " << data.chargeStruct().chargeTypeId() << "\neffectDuration: " << data.effectDuration() << "\neffectStart: " << (data.effectStart().is_set() ? QString::number(data.effectStart().get()) : QStringLiteral("not set")) << "\neffectStateId: " << toString(data.effectStateId()) << "\npartyId: " << (data.partyId().is_set() ? QString::number(data.partyId().get()) : QStringLiteral("not set")) << "\nparticipantId: " << (data.participantId().is_set() ? QString::number(data.participantId().get()) : QStringLiteral("not set")) << "\n"; } bool AesHandler::isModifiable(const AreaEffectSimulation::AesItem &item) { return (item.effectStateId() == AesEffectState_def::EsCreated || item.effectStateId() == AesEffectState_def::EsPrepared || item.effectStateId() == AesEffectState_def::EsUnknown || item.effectStateId() == AesEffectState_def::EsReceived); } // HLA -> DDS void AesHandler::onAesNameChanged(qint64 identifierInt, const std::string &newName) { // No "isModifiable(item)" used here, as Name is more likely changeable. int aesItemId = 0; AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId); switch (type.underlying()) { case AreaEffectSimulation::AesType_def::AtBCContamination: break; case AreaEffectSimulation::AesType_def::AtMineCorridor: { MineCorridorModifyRequest *req = static_cast(m_pendingRequests.value(aesItemId)); if (!req) { AreaEffectSimulation::MineCorridor item = m_dtcAes->mineCorridor(aesItemId); if (item.name() == newName) return; req = makeMinefieldBreachRequest(item); addRequestToQueue(aesItemId, req); } req->name(newName); break; } case AreaEffectSimulation::AesType_def::AtMineArea: { MineAreaModifyRequest *req = static_cast(m_pendingRequests.value(aesItemId)); if (!req) { AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId); if (item.name() == newName) return; req = makeMinefieldRequest(item); addRequestToQueue(aesItemId, req); } req->name(newName); break; } case AreaEffectSimulation::AesType_def::AtNContamination: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionArea: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionSingle: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtAirSupportImpact: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtUnknown: case AreaEffectSimulation::AesType_def::AtDangerArea: case AreaEffectSimulation::AesType_def::AtFunctionalArea: case AreaEffectSimulation::AesType_def::AtBorderline: case AreaEffectSimulation::AesType_def::AtTechnicalArea: case AreaEffectSimulation::AesType_def::AtReconArea: case AreaEffectSimulation::AesType_def::AtDusSingleMine: case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions: case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines: case AreaEffectSimulation::AesType_def::AtGasPipe: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory: case AreaEffectSimulation::AesType_def::AtBoobyTrap: case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary: case AreaEffectSimulation::AesType_def::AtOffRouteMine: case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary: case AreaEffectSimulation::AesType_def::AtExplosionCluster: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory: case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine: break; } } void AesHandler::onAesRemoveItem(qint64 identifierInt) { int aesItemId = 0; AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId); Core::RemoveElementRequest req(aesItemId); DEBUG_LOG(m_logger) << "Remove Item for " << aesItemId << " requested. Type: " << type; switch (type.underlying()) { case AreaEffectSimulation::AesType_def::AtBCContamination: break; case AreaEffectSimulation::AesType_def::AtMineCorridor: { m_requestHelper->startSingleRequest([req, this]() { return m_ftcAes->mineCorridorRemoveRequest(req, this); }); break; } case AreaEffectSimulation::AesType_def::AtMineArea: { m_requestHelper->startSingleRequest([req, this]() { return m_ftcAes->mineAreaRemoveRequest(req, this); }); break; } case AreaEffectSimulation::AesType_def::AtNContamination: return; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionArea: return; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionSingle: return; // Maybe handled later case AreaEffectSimulation::AesType_def::AtAirSupportImpact: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtUnknown: case AreaEffectSimulation::AesType_def::AtDangerArea: case AreaEffectSimulation::AesType_def::AtFunctionalArea: case AreaEffectSimulation::AesType_def::AtBorderline: case AreaEffectSimulation::AesType_def::AtTechnicalArea: case AreaEffectSimulation::AesType_def::AtReconArea: case AreaEffectSimulation::AesType_def::AtDusSingleMine: case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions: case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines: case AreaEffectSimulation::AesType_def::AtGasPipe: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory: case AreaEffectSimulation::AesType_def::AtBoobyTrap: case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary: case AreaEffectSimulation::AesType_def::AtOffRouteMine: case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary: case AreaEffectSimulation::AesType_def::AtExplosionCluster: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory: case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine: return; } } void AesHandler::onAesActivationTimeChanged(qint64 identifierInt, qint64 msecsSinceEpoch) { int aesItemId = 0; AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId); qint64 earliest = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch() + 5000; if (msecsSinceEpoch < earliest && msecsSinceEpoch > 0) msecsSinceEpoch = earliest; switch (type.underlying()) { case AreaEffectSimulation::AesType_def::AtBCContamination: break; case AreaEffectSimulation::AesType_def::AtMineCorridor: { MineCorridorModifyRequest *req = static_cast(m_pendingRequests.value(aesItemId)); if (!req) { AreaEffectSimulation::MineCorridor item = m_dtcAes->mineCorridor(aesItemId); if ((item.effectStart().is_set() && item.effectStart().get() == msecsSinceEpoch) || !isModifiable(item)) return; req = makeMinefieldBreachRequest(item); addRequestToQueue(aesItemId, req); } req->effectStart(msecsSinceEpoch); break; } case AreaEffectSimulation::AesType_def::AtMineArea: { DEBUG_LOG(m_logger) << "onAesActivationTimeChanged / MineArea"; MineAreaModifyRequest *req = static_cast(m_pendingRequests.value(aesItemId)); if (!req) { DEBUG_LOG(m_logger) << "onAesActivationTimeChanged / MineArea - Request NOT found"; AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId); if ((item.effectStart().is_set() && item.effectStart().get() == msecsSinceEpoch) || !isModifiable(item)) return; req = makeMinefieldRequest(item); addRequestToQueue(aesItemId, req); } req->effectStart(msecsSinceEpoch); break; } case AreaEffectSimulation::AesType_def::AtNContamination: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionArea: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionSingle: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtAirSupportImpact: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtUnknown: case AreaEffectSimulation::AesType_def::AtDangerArea: case AreaEffectSimulation::AesType_def::AtFunctionalArea: case AreaEffectSimulation::AesType_def::AtBorderline: case AreaEffectSimulation::AesType_def::AtTechnicalArea: case AreaEffectSimulation::AesType_def::AtReconArea: case AreaEffectSimulation::AesType_def::AtDusSingleMine: case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions: case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines: case AreaEffectSimulation::AesType_def::AtGasPipe: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory: case AreaEffectSimulation::AesType_def::AtBoobyTrap: case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary: case AreaEffectSimulation::AesType_def::AtOffRouteMine: case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary: case AreaEffectSimulation::AesType_def::AtExplosionCluster: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory: case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine: break; } } // HLA -> DDS void AesHandler::onAesForceIdentifierChanged(qint64 identifierInt, int partyId) { int aesItemId = 0; AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId); switch (type.underlying()) { case AreaEffectSimulation::AesType_def::AtBCContamination: break; case AreaEffectSimulation::AesType_def::AtMineCorridor: { MineCorridorModifyRequest *req = static_cast(m_pendingRequests.value(aesItemId)); if (!req) { AreaEffectSimulation::MineCorridor item = m_dtcAes->mineCorridor(aesItemId); if (item.partyId() == partyId || !isModifiable(item)) return; req = makeMinefieldBreachRequest(item); addRequestToQueue(aesItemId, req); } req->partyId(partyId); break; } case AreaEffectSimulation::AesType_def::AtMineArea: { MineAreaModifyRequest *req = static_cast(m_pendingRequests.value(aesItemId)); if (!req) { AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId); if (item.partyId() == partyId || !isModifiable(item)) return; req = makeMinefieldRequest(item); addRequestToQueue(aesItemId, req); } req->partyId(partyId); break; } case AreaEffectSimulation::AesType_def::AtNContamination: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionArea: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionSingle: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtAirSupportImpact: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtUnknown: case AreaEffectSimulation::AesType_def::AtDangerArea: case AreaEffectSimulation::AesType_def::AtFunctionalArea: case AreaEffectSimulation::AesType_def::AtBorderline: case AreaEffectSimulation::AesType_def::AtTechnicalArea: case AreaEffectSimulation::AesType_def::AtReconArea: case AreaEffectSimulation::AesType_def::AtDusSingleMine: case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions: case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines: case AreaEffectSimulation::AesType_def::AtGasPipe: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory: case AreaEffectSimulation::AesType_def::AtBoobyTrap: case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary: case AreaEffectSimulation::AesType_def::AtOffRouteMine: case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary: case AreaEffectSimulation::AesType_def::AtExplosionCluster: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory: case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine: break; } } static inline int checkDuration(quint32 u_time, quint32 div, NGL::INGLLogger &logger) { const auto maxDuration = std::numeric_limits::max() / div; if (u_time > maxDuration) { WARNING_LOG(logger) << "Got an effect duration which is too long for us - limiting to " << maxDuration << "msec"; u_time = maxDuration; Q_ASSERT(false); } const int timeMSec = static_cast(u_time); return timeMSec; } void AesHandler::onAesDurationChanged(qint64 identifierInt, quint32 u_time) { int aesItemId = 0; AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId); switch (type.underlying()) { case AreaEffectSimulation::AesType_def::AtBCContamination: break; case AreaEffectSimulation::AesType_def::AtMineCorridor: { MineCorridorModifyRequest *req = static_cast(m_pendingRequests.value(aesItemId)); const int timeMSec = checkDuration(u_time, 60 * 60 * 1000, m_logger); // Hours if (!req) { AreaEffectSimulation::MineCorridor item = m_dtcAes->mineCorridor(aesItemId); if (item.effectDuration() == timeMSec || !isModifiable(item)) return; req = makeMinefieldBreachRequest(item); addRequestToQueue(aesItemId, req); } req->effectDuration(timeMSec); break; } case AreaEffectSimulation::AesType_def::AtMineArea: { MineAreaModifyRequest *req = static_cast(m_pendingRequests.value(aesItemId)); const int timeMSec = checkDuration(u_time, 60 * 60 * 1000, m_logger); // Hours if (!req) { AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId); if (item.effectDuration() == timeMSec || !isModifiable(item)) return; req = makeMinefieldRequest(item); addRequestToQueue(aesItemId, req); } req->effectDuration(timeMSec); break; } case AreaEffectSimulation::AesType_def::AtNContamination: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionArea: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionSingle: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtAirSupportImpact: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtUnknown: case AreaEffectSimulation::AesType_def::AtDangerArea: case AreaEffectSimulation::AesType_def::AtFunctionalArea: case AreaEffectSimulation::AesType_def::AtBorderline: case AreaEffectSimulation::AesType_def::AtTechnicalArea: case AreaEffectSimulation::AesType_def::AtReconArea: case AreaEffectSimulation::AesType_def::AtDusSingleMine: case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions: case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines: case AreaEffectSimulation::AesType_def::AtGasPipe: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory: case AreaEffectSimulation::AesType_def::AtBoobyTrap: case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary: case AreaEffectSimulation::AesType_def::AtOffRouteMine: case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary: case AreaEffectSimulation::AesType_def::AtExplosionCluster: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory: case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine: break; } } void AesHandler::onAesChargeChanged(qint64 identifierInt, int chargeTypeId) { int aesItemId = 0; AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId); switch (type.underlying()) { case AreaEffectSimulation::AesType_def::AtBCContamination: break; case AreaEffectSimulation::AesType_def::AtMineCorridor: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtMineArea: { MineAreaModifyRequest *req = static_cast(m_pendingRequests.value(aesItemId)); if (!req) { AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId); if (item.chargeStruct().chargeTypeId() == chargeTypeId && !isModifiable(item)) return; req = makeMinefieldRequest(item); addRequestToQueue(aesItemId, req); } req->chargeStruct().chargeTypeId(chargeTypeId); break; } case AreaEffectSimulation::AesType_def::AtNContamination: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionArea: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionSingle: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtAirSupportImpact: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtUnknown: case AreaEffectSimulation::AesType_def::AtDangerArea: case AreaEffectSimulation::AesType_def::AtFunctionalArea: case AreaEffectSimulation::AesType_def::AtBorderline: case AreaEffectSimulation::AesType_def::AtTechnicalArea: case AreaEffectSimulation::AesType_def::AtReconArea: case AreaEffectSimulation::AesType_def::AtDusSingleMine: case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions: case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines: case AreaEffectSimulation::AesType_def::AtGasPipe: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory: case AreaEffectSimulation::AesType_def::AtBoobyTrap: case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary: case AreaEffectSimulation::AesType_def::AtOffRouteMine: case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary: case AreaEffectSimulation::AesType_def::AtExplosionCluster: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory: case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine: break; } } bool getCorridorSegment(const std::vector &pointsDataIn, std::vector &segmentsOut, double &widthOut) { // P0 P3 // L *-------------------* L // i | | i // n * S0 S1 * n // e | | e // 1 *-------------------* 2 // P1 P2 // Calculate width = P0->P1 // Calculate S0, S1 if (pointsDataIn.size() != 4) return false; ParticipantPosition p0(pointsDataIn[0]); ParticipantPosition p1(pointsDataIn[1]); ParticipantPosition p2(pointsDataIn[2]); ParticipantPosition p3(pointsDataIn[3]); LtsCoordTrans::UtmCoordinate utmP0 = LtsCoordTrans::UtmCoordinate::fromGeographic(p0.toPoint()); LtsCoordTrans::UtmCoordinate utmP1 = LtsCoordTrans::UtmCoordinate::fromGeographic(p1.toPoint(), utmP0.zone); LtsCoordTrans::UtmCoordinate utmP2 = LtsCoordTrans::UtmCoordinate::fromGeographic(p2.toPoint(), utmP0.zone); LtsCoordTrans::UtmCoordinate utmP3 = LtsCoordTrans::UtmCoordinate::fromGeographic(p3.toPoint(), utmP0.zone); QLineF line1(utmP0.x, utmP0.y, utmP1.x, utmP1.y); widthOut = line1.length(); line1.setLength(0.5 * line1.length()); LtsCoordTrans::UtmCoordinate utmS0(utmP0.zone, line1.p2().x(), line1.p2().y(), utmP0.northp); QLineF line2(utmP2.x, utmP2.y, utmP3.x, utmP3.y); widthOut = line2.length(); line2.setLength(0.5 * line2.length()); LtsCoordTrans::UtmCoordinate utmS1(utmP0.zone, line2.p2().x(), line2.p2().y(), utmP0.northp); segmentsOut.resize(2); segmentsOut[0] = Core::GeoPosition2D(utmS0.geographic().x(), utmS0.geographic().y()); segmentsOut[1] = Core::GeoPosition2D(utmS1.geographic().x(), utmS1.geographic().y()); return true; } void AesHandler::onAesPointsDataChanged(qint64 identifierInt, const std::vector &pos) { int aesItemId = 0; AesType type = m_dtcAes->aesItemIdFromExternalId(identifierInt, aesItemId); DEBUG_LOG(m_logger) << "Points Data changed for Aes Item ID: " << aesItemId << ". Type: " << type; switch (type.underlying()) { case AreaEffectSimulation::AesType_def::AtBCContamination: break; case AreaEffectSimulation::AesType_def::AtMineCorridor: { MineCorridorModifyRequest *req = static_cast(m_pendingRequests.value(aesItemId)); if (!req) { AreaEffectSimulation::MineCorridor item = m_dtcAes->mineCorridor(aesItemId); if (!isModifiable(item)) return; req = makeMinefieldBreachRequest(item); addRequestToQueue(aesItemId, req); } double width; std::vector segments; if (!getCorridorSegment(pos, segments, width)) { ERROR_LOG(m_logger) << "Could not calculate Mine Area from given Points Data!"; return; } req->segments(segments); req->width(width); break; } case AreaEffectSimulation::AesType_def::AtMineArea: { MineAreaModifyRequest *req = static_cast(m_pendingRequests.value(aesItemId)); if (!req) { AreaEffectSimulation::MineArea item = m_dtcAes->mineArea(aesItemId); if (!isModifiable(item)) return; req = makeMinefieldRequest(item); addRequestToQueue(aesItemId, req); } double width; std::vector segments; if (!getCorridorSegment(pos, segments, width)) { ERROR_LOG(m_logger) << "Could not calculate Mine Area from given Points Data!"; return; } req->segments(segments); req->isCenterLine(true); req->width(width); break; } case AreaEffectSimulation::AesType_def::AtNContamination: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionArea: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtExplosionSingle: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtAirSupportImpact: break; // Maybe handled later case AreaEffectSimulation::AesType_def::AtUnknown: case AreaEffectSimulation::AesType_def::AtDangerArea: case AreaEffectSimulation::AesType_def::AtFunctionalArea: case AreaEffectSimulation::AesType_def::AtBorderline: case AreaEffectSimulation::AesType_def::AtTechnicalArea: case AreaEffectSimulation::AesType_def::AtReconArea: case AreaEffectSimulation::AesType_def::AtDusSingleMine: case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions: case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines: case AreaEffectSimulation::AesType_def::AtGasPipe: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral: case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory: case AreaEffectSimulation::AesType_def::AtBoobyTrap: case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary: case AreaEffectSimulation::AesType_def::AtOffRouteMine: case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary: case AreaEffectSimulation::AesType_def::AtExplosionCluster: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions: case AreaEffectSimulation::AesType_def::AtExplosionClusterSingleTrajectory: case AreaEffectSimulation::AesType_def::AtExplosionClusterGunToTargetLine: break; } } bool AesHandler::onNewMinefield(const MineAreaModifyRequest &ma) { if (!ma.externalId()) return false; return m_requestHelper->startSingleRequest([this, ma]() { return m_ftcAes->mineAreaModifyRequest(ma, this); }); } template <> void AesHandler::onSendRequest(const MineAreaModifyRequest &item) { onNewMinefield(item); } bool AesHandler::onNewMinefieldBreach(const MineCorridorModifyRequest &mc) { if (!mc.externalId().is_set()) return false; return m_requestHelper->startSingleRequest([this, mc]() { return m_ftcAes->mineCorridorModifyRequest(mc, this); }); } template <> void AesHandler::onSendRequest(const MineCorridorModifyRequest &item) { onNewMinefieldBreach(item); } void AesHandler::onMunitionDetonation(const ExplosionSingleModifyRequest &es) { if (!es.externalId().is_set()) return; m_requestHelper->startSingleRequest([this, es]() { return m_ftcAes->explosionSingleModifyRequest(es, this); }); } #ifdef SUPPORT_EXPLOSION_CLUSTER_SINGLE_EFFECT void AesHandler::onMunitionDetonationExplosionClusterSingleEffect(const ExplosionClusterSingleEffectOnlyRequest &es) { if (!es.externalId().is_set()) return; m_requestHelper->startSingleRequest([this, es]() { return m_ftcAes->explosionClusterSingleEffectOnlyModifyRequest(es, this); }); } #endif // SUPPORT_EXPLOSION_CLUSTER_SINGLE_EFFECT template <> void AesHandler::onSendRequest(const ExplosionSingleModifyRequest &item) { onMunitionDetonation(item); } template void AesHandler::addRequestToQueue(int aesItemId, T *request) { m_pendingRequests.insert(aesItemId, request); QTimer::singleShot(100, this, [this, request, aesItemId]() { onSendRequest(*request); m_pendingRequests.take(aesItemId); delete request; }); } } // namespace HighLevelArchitecture