/** * Handler for all oc situation data at the server per client * $Id: handler_oc_situation_data.cpp 57938 2022-08-26 09:56:44Z diers $ * $HeadURL: svn://192.168.133.21/TDS/branches/product/features/3dws_devel/Lts/Services/OcSituationServer/handler_oc_situation_data.cpp $ * $Author: diers $ * Created by Philipp Dassow, NLST, 27-02-2018 */ #include "handler_oc_central_aes_data.h" #include #include #include #include #include #include "settings.h" #include #include "central_aes_data_queue.h" #include namespace OcSituationServer { //// //// ThreadOcSituationData //// ThreadOcCentralAesData::ThreadOcCentralAesData(MainHandler *mainHandler, int equipmentId, int centerEquipmentId, int radius) : m_baseCoordinate(mainHandler->positionConverter()->baseCoordinate()) , m_equipmentId(equipmentId) , m_centerEquipmentId(centerEquipmentId) , m_radius(radius) , m_mainHandler(mainHandler) , m_logger(getLogger(QStringLiteral("ThreadOcCentralAesData.") + QString::number(equipmentId))) {} void ThreadOcCentralAesData::requestOcCentralAesData(OcSituation::SituationCenterType centerType, int centerEquipmentId, const Core::GeoPosition2D &position, int radius, bool initial) { INFO_LOG(m_logger) << "OC-Situation Request for centerEquipmentId: " << centerEquipmentId << " from O/C-laptop-Id: " << m_equipmentId << " with radius of " << radius << "m, initial: " << initial; QMutexLocker l(&m_accessMutex); m_centerType = centerType; m_centerEquipmentId = centerEquipmentId; m_radius = radius; m_position = position; if (m_handler) m_handler->setRequestCentralAesData(centerType, centerEquipmentId, position, radius, initial); else DEBUG_LOG(m_logger) << "Thread doesn't exist up to now! Do nothing."; } void ThreadOcCentralAesData::run() { static QMutex s_ddsAccesMutex; { QMutexLocker l(&m_accessMutex); QMutexLocker m(&s_ddsAccesMutex); DEBUG_LOG(m_logger) << "Instance new OC-Thread for O/C-Laptop-Id: " << m_equipmentId; m_handler = new HandlerOcCentralAesData(m_mainHandler->dds(), m_baseCoordinate, m_equipmentId); connect(m_handler, &HandlerOcCentralAesData::sendOcData, this, &ThreadOcCentralAesData::sendOcData, Qt::QueuedConnection); m_handler->setRequestCentralAesData(m_centerType, m_centerEquipmentId, m_position, m_radius, true); } INFO_LOG(m_logger) << "OC-Thread started for O/C-Laptop-Id: " << m_equipmentId; exec(); { QMutexLocker l(&m_accessMutex); QMutexLocker m(&s_ddsAccesMutex); delete m_handler; m_handler = nullptr; } } // // HandlerOcSituationData // HandlerOcCentralAesData::HandlerOcCentralAesData(const std::shared_ptr &dds, const LtsCoordTrans::UtmCoordinate &baseCoordinate, int equipmentId) : m_baseCoordinate(baseCoordinate) , m_aesDtc(AreaEffectSimulation::Interface::Dtc::create(dds->dds())) , m_ppmDtc(ParticipantManagement::Interface::Dtc::create(dds->dds())) , m_equipmentId(equipmentId) , m_partitionTime(QDateTime::currentMSecsSinceEpoch()) , m_aliveTimer(new QTimer(this)) , m_txTimer(new QTimer(this)) , m_dataQueue(new CentralAesDataQueue(this)) , m_logger(getLogger(QStringLiteral("HandlerOcCentralAesData.") + QString::number(equipmentId))) { INFO_LOG(m_logger) << "Create O/C-CentralAesHandler for O/C-Laptop-Id: " << equipmentId << " aliveTimeout: " << Settings::aliveTimeout() << " sec" << " txCyleTime: " << Settings::txCycleTime() << " sec" << " maxTransferBytes: " << Settings::maxNumOfBytePerTxCycle(); connect(dds.get(), &DdsHandler::partitionTimeChanged, this, &HandlerOcCentralAesData::onPartitionTimeChanged); connect(m_aliveTimer, &QTimer::timeout, this, &HandlerOcCentralAesData::aliveTimeout); m_aliveTimer->setSingleShot(true); m_aliveTimer->start(Settings::aliveTimeout()); connect(m_txTimer, &QTimer::timeout, this, &HandlerOcCentralAesData::handleSituation); m_txTimer->start(Settings::txCycleTime()); connect(this, &HandlerOcCentralAesData::resetInternalData, this, &HandlerOcCentralAesData::onResetInternalData, Qt::QueuedConnection); connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantPositionChanged, this, &HandlerOcCentralAesData::onParticipantPositionChanged); connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::effectClusterChanged, this, &HandlerOcCentralAesData::onEffectClusterChanged); connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::nContaminationChanged, this, &HandlerOcCentralAesData::onNContaminationChanged); connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::bCContaminationChanged, this, &HandlerOcCentralAesData::onBCContaminationChanged); connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionAreaChanged, this, &HandlerOcCentralAesData::onExplosionAreaChanged); connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionSingleChanged, this, &HandlerOcCentralAesData::onExplosionSingleChanged); connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::mineAreaChanged, this, &HandlerOcCentralAesData::onMineAreaChanged); connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::functionalAreaChanged, this, &HandlerOcCentralAesData::onFunctionalAreaChanged); connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::boobyTrapChanged, this, &HandlerOcCentralAesData::onBoobyTrapChanged); connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::offRouteMineChanged, this, &HandlerOcCentralAesData::onOffRouteMineChanged); connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionClusterChanged, this, &HandlerOcCentralAesData::onExplosionClusterChanged); connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged, this, &HandlerOcCentralAesData::onAesItemViewChanged); // fetch aes items m_aesDtc->effectClusters([this](const AreaEffectSimulation::EffectCluster & data) { if (data.isCentral()) m_allCentralEffectClusters.insert(data.id(), data); }); TRACE_LOG(m_logger) << "Got " << m_allCentralEffectClusters.size() << " central EffectClusters on startup."; m_aesDtc->nContaminations([this](const AreaEffectSimulation::NContamination & data) { if (data.isCentral()) m_allCentralNContaminations.insert(data.id(), data); }); TRACE_LOG(m_logger) << "Got " << m_allCentralNContaminations.size() << " central NContaminations on startup."; m_aesDtc->bCContaminations([this](const AreaEffectSimulation::BCContamination & data) { if (data.isCentral()) m_allCentralBCContaminations.insert(data.id(), data); }); TRACE_LOG(m_logger) << "Got " << m_allCentralBCContaminations.size() << " central BCContaminations on startup."; m_aesDtc->explosionAreas([this](const AreaEffectSimulation::ExplosionArea & data) { if (data.isCentral()) m_allCentralExplosionsArea.insert(data.id(), data); }); TRACE_LOG(m_logger) << "Got " << m_allCentralExplosionsArea.size() << " central ExplosionsAreas on startup."; m_aesDtc->explosionSingles([this](const AreaEffectSimulation::ExplosionSingle & data) { if (data.isCentral()) m_allCentralExplosionsSingle.insert(data.id(), data); }); TRACE_LOG(m_logger) << "Got " << m_allCentralExplosionsSingle.size() << " central ExplosionsSingles on startup."; m_aesDtc->mineAreas([this](const AreaEffectSimulation::MineArea & data) { if (data.isCentral()) m_allCentralMineAreas.insert(data.id(), data); }); TRACE_LOG(m_logger) << "Got " << m_allCentralMineAreas.size() << " central MineAreas on startup."; m_aesDtc->functionalAreas([this](const AreaEffectSimulation::FunctionalArea & data) { if (data.isCentral()) m_allCentralFunctionalAreas.insert(data.id(), data); }); TRACE_LOG(m_logger) << "Got " << m_allCentralFunctionalAreas.size() << " central FunctionalAreas on startup."; m_aesDtc->boobyTraps([this](const AreaEffectSimulation::BoobyTrap & data) { if (data.isCentral()) m_allCentralBoobyTraps.insert(data.id(), data); }); TRACE_LOG(m_logger) << "Got " << m_allCentralBoobyTraps.size() << " central BoobyTraps on startup."; m_aesDtc->offRouteMines([this](const AreaEffectSimulation::OffRouteMine & data) { if (data.isCentral()) m_allCentralOffRouteMines.insert(data.id(), data); }); TRACE_LOG(m_logger) << "Got " << m_allCentralOffRouteMines.size() << " central OffRouteMines on startup."; m_aesDtc->explosionClusters([this](const AreaEffectSimulation::ExplosionCluster &data) { if (data.isCentral()) m_allCentralExplosionClusters.insert(data.id(), data); }); TRACE_LOG(m_logger) << "Got " << m_allCentralExplosionClusters.size() << " central ExplosionClusters on startup."; //fetch aes itemviews QList aesItemIds = allInternalAesItemIds(); m_aesDtc->aesItemViews([this, aesItemIds](const AreaEffectSimulation::AesItemView & data) { if (aesItemIds.contains(data.aesItemId())) m_allCentralAesItemViews.insert(data.aesItemId(), data); }); TRACE_LOG(m_logger) << "Got " << allInternalAesItemIds().size() << " central AesItems in total on startup. And " << m_allCentralAesItemViews.size() << " AesItemViews."; m_aesDtc->enableEffectCluster(); m_aesDtc->enableNContamination(); m_aesDtc->enableBCContamination(); m_aesDtc->enableExplosionArea(); m_aesDtc->enableExplosionSingle(); m_aesDtc->enableMineArea(); m_aesDtc->enableFunctionalArea(); m_aesDtc->enableBoobyTrap(); m_aesDtc->enableOffRouteMine(); m_aesDtc->enableExplosionCluster(); m_aesDtc->enableAesItemView(); m_ppmDtc->enableParticipant(); } void HandlerOcCentralAesData::setRequestCentralAesData(OcSituation::SituationCenterType centerType, int centerEquipmentId, const Core::GeoPosition2D ¢erPosition, int radius, bool initial) { TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION; QMutexLocker l(&m_accessMutex); DEBUG_LOG(m_logger) << "Requested CenterEquipmentId: " << centerEquipmentId << " radius: " << radius; bool endThread = false; if (initial) onResetInternalData(); m_centerType = centerType; m_centerEquipmentId = centerEquipmentId; m_centerPosition = centerPosition; m_centerParticipantId = 0; m_radius = radius; if (centerType == OcSituation::SituationCenterType::Equipment) { if (m_centerEquipmentId > 0) { ParticipantManagement::Participant centerParticipant = m_ppmDtc->participant(m_ppmDtc->participantIdByEquipmentNumber(m_centerEquipmentId)); if (centerParticipant.id() <= 0) { ERROR_LOG(m_logger) << "Participant with EqId " << m_centerEquipmentId << " as center of the oc situation request does not exist!"; endThread = true; } else { const ParticipantManagement::ParticipantPosition &partPosition = m_ppmDtc->participantPosition(m_ppmDtc->participantIdByEquipmentNumber(m_centerEquipmentId)); if (partPosition.participantId() == 0) { ERROR_LOG(m_logger) << "Participant with EqId " << m_centerEquipmentId << " as center of the oc situation request has no position!"; endThread = true; } else { m_centerPosition = partPosition.pos(); m_centerParticipantId = centerParticipant.id(); } } if (endThread && ++m_retryCount < 5) { INFO_LOG(m_logger) << "Retry setting data - maybe participant is not yet available... " << m_retryCount; QTimer::singleShot(1000 * m_retryCount, this, [this]() { // must be initial here setRequestCentralAesData(m_centerType, m_centerEquipmentId, m_centerPosition, m_radius, true); }); return; } } else { INFO_LOG(m_logger) << "Situation is not requested anymore -> end thread"; endThread = true; } } if (!endThread) { if (centerType == OcSituation::SituationCenterType::Equipment) { if (m_centerParticipantId == 0) { DEBUG_LOG(m_logger) << "m_centerParticipantId == 0"; endThread = true; } } else if ((centerPosition.lon() == std::nan("")) || (centerPosition.lat() == std::nan(""))) { DEBUG_LOG(m_logger) << "m_centerParticipantId == 0"; endThread = true; } } m_retryCount = 0; if (endThread) m_radius = 0; // ==> no data transfer on handleSituation() and quit buildSituationCircle(); QTimer::singleShot(0, this, &HandlerOcCentralAesData::resetAliveTimer); if (endThread && !initial) { DEBUG_LOG(m_logger) << "Ending Thread --> stopping txTimer and resetting internal data."; QTimer::singleShot(0, this, &HandlerOcCentralAesData::handleSituation); emit resetInternalData(); } } void HandlerOcCentralAesData::onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &data, DataModification modType) { if (modType != DataModification::eModified || m_centerType != OcSituation::SituationCenterType::Equipment || data.participantId() != m_centerParticipantId) return; m_centerPosition = data.pos(); buildSituationCircle(); } void HandlerOcCentralAesData::onEffectClusterChanged(const AreaEffectSimulation::EffectCluster &data, DataModification modType) { onAesItemChanged(m_allCentralEffectClusters, data, modType); } void HandlerOcCentralAesData::onNContaminationChanged(const AreaEffectSimulation::NContamination &data, DataModification modType) { onAesItemChanged(m_allCentralNContaminations, data, modType); } void HandlerOcCentralAesData::onBCContaminationChanged(const AreaEffectSimulation::BCContamination &data, DataModification modType) { onAesItemChanged(m_allCentralBCContaminations, data, modType); } void HandlerOcCentralAesData::onExplosionAreaChanged(const AreaEffectSimulation::ExplosionArea &data, DataModification modType) { onAesItemChanged(m_allCentralExplosionsArea, data, modType); } void HandlerOcCentralAesData::onExplosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType) { onAesItemChanged(m_allCentralExplosionsSingle, data, modType); } void HandlerOcCentralAesData::onMineAreaChanged(const AreaEffectSimulation::MineArea &data, DataModification modType) { onAesItemChanged(m_allCentralMineAreas, data, modType); } void HandlerOcCentralAesData::onFunctionalAreaChanged(const AreaEffectSimulation::FunctionalArea &data, DataModification modType) { onAesItemChanged(m_allCentralFunctionalAreas, data, modType); } void HandlerOcCentralAesData::onBoobyTrapChanged(const AreaEffectSimulation::BoobyTrap &data, DataModification modType) { onAesItemChanged(m_allCentralBoobyTraps, data, modType); } void HandlerOcCentralAesData::onOffRouteMineChanged(const AreaEffectSimulation::OffRouteMine &data, DataModification modType) { onAesItemChanged(m_allCentralOffRouteMines, data, modType); } void HandlerOcCentralAesData::onExplosionClusterChanged(const AreaEffectSimulation::ExplosionCluster &data, DataModification modType) { onAesItemChanged(m_allCentralExplosionClusters, data, modType); } void HandlerOcCentralAesData::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType) { const QVector validTypes = {AreaEffectSimulation::AesType::inner_enum::AtEffectCluster, AreaEffectSimulation::AesType::inner_enum::AtNContamination, AreaEffectSimulation::AesType::inner_enum::AtBCContamination , AreaEffectSimulation::AesType::inner_enum::AtExplosionArea, AreaEffectSimulation::AesType::inner_enum::AtExplosionSingle, AreaEffectSimulation::AesType::inner_enum::AtMineArea, AreaEffectSimulation::AesType::inner_enum::AtFunctionalArea, AreaEffectSimulation::AesType::inner_enum::AtBoobyTrap, AreaEffectSimulation::AesType::inner_enum::AtOffRouteMine, AreaEffectSimulation::AesType::inner_enum::AtExplosionCluster}; if (!validTypes.contains(data.aesTypeId())) return; switch (modType) { case DataModification::eAdded: if (!allInternalAesItemIds().contains(data.aesItemId())) return; m_allCentralAesItemViews.insert(data.aesItemId(), data); break; case DataModification::eModified: { if (!m_allCentralAesItemViews.contains(data.aesItemId())) return; m_allCentralAesItemViews[data.aesItemId()] = data; break; } case DataModification::eRemoved: // AesItemViews are removed from m_allCentralAesItemViews in HandlerOcCentralAesData::onAesItemChanged break; } } void HandlerOcCentralAesData::handleSituation() { TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION; QMutexLocker l(&m_accessMutex); if (m_radius == 0) { INFO_LOG(m_logger) << "Do not send Situation as radius is 0, centerEquipmentId " << m_centerEquipmentId << ", m_position " << m_centerPosition; QTimer::singleShot(0, this, &HandlerOcCentralAesData::aliveTimeout); // ending thread return; } QSet oldAesItemsInRange = m_aesItemsInRange; fetchAesItemsInRange(); // 50 is the max number of AesItems which are allowed to be handled on the ABT. // So we have to just take the 50 nearest items. bool hasOverload = m_aesItemsInRange.size() > 50; if (hasOverload) { DEBUG_LOG(m_logger) << "Got more than 50 AesItems in range. " << m_aesItemsInRange.size() << " in total --> Sorting out."; QMultiMap distances; for (qint32 currentAesItemId : qAsConst(m_aesItemsInRange)) { qreal distance = calculateDistanceToCircleCenter(currentAesItemId); if (distance >= 0.0) distances.insert(distance, currentAesItemId); } DEBUG_LOG(m_logger) << "We have " << distances.size() << " valid distances."; m_aesItemsInRange.clear(); qint32 counter = 0; for (auto it = distances.constBegin(); (it != distances.constEnd()) && (counter < 50); ++it, ++counter) m_aesItemsInRange.insert(it.value()); DEBUG_LOG(m_logger) << "We now have " << m_aesItemsInRange.size() << " AES Items to send."; } QSet validIds = m_aesItemsInRange - oldAesItemsInRange; DEBUG_LOG(m_logger) << "After sorting out old items, we have " << validIds.size() << " items left."; removeKickedOutAesItems(oldAesItemsInRange); addAesItemsToBuilder(m_allCentralEffectClusters, validIds); addAesItemsToBuilder(m_allCentralNContaminations, validIds); addAesItemsToBuilder(m_allCentralBCContaminations, validIds); addAesItemsToBuilder(m_allCentralExplosionsArea, validIds); addAesItemsToBuilder(m_allCentralExplosionsSingle, validIds); addAesItemsToBuilder(m_allCentralMineAreas, validIds); addAesItemsToBuilder(m_allCentralFunctionalAreas, validIds); addAesItemsToBuilder(m_allCentralBoobyTraps, validIds); addAesItemsToBuilder(m_allCentralOffRouteMines, validIds); addAesItemsToBuilder(m_allCentralExplosionClusters, validIds); if (m_dataQueue->hasMessages()) { QByteArray payload; LtsUtils::set1Byte(m_bInitialDataTransfer ? OcSituation::TelegramId::CentralAesDataInitial : OcSituation::TelegramId::CentralAesData, payload); LtsUtils::set1Byte(hasOverload, payload); // info, if there are more than 50 aes items in range m_bInitialDataTransfer = false; QByteArray sendingData = m_dataQueue->getSendingData(Settings::maxNumOfBytePerTxCycle()); payload += m_bWithCompression ? qCompress(sendingData) : sendingData; TrainingAreaBase::SendOcDataRequest req; req.equipmentNumber(m_equipmentId); req.payload(LtsUtils::convert>(payload)); DEBUG_LOG(m_logger) << "Sending " << req.payload().size() << " Bytes payload."; emit sendOcData(req); } else DEBUG_LOG(m_logger) << "Sending timeout, but nothing to send."; } void HandlerOcCentralAesData::resetAliveTimer() { m_aliveTimer->start(); } void HandlerOcCentralAesData::aliveTimeout() { INFO_LOG(m_logger) << "O/C-Thread keep alive timeout for O/C-Laptop-Id: " << m_equipmentId << " - Thread will be finished id: " << QThread::currentThreadId(); QThread::currentThread()->quit(); } void HandlerOcCentralAesData::onResetInternalData() { TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION; DEBUG_LOG(m_logger) << "Resetting internal data!"; m_aesItemsInRange.clear(); m_dataQueue->clear(); m_bInitialDataTransfer = true; } void HandlerOcCentralAesData::fetchAesItemsInRange() { TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION; if (m_radius == 0) return; const QPointF relCenterPos = PositionConverter::relativeFromGeographic(m_centerPosition, m_baseCoordinate); if (m_centerType == OcSituation::SituationCenterType::Equipment) INFO_LOG(m_logger) << "Fetching AesItems in radius around equipment " << m_centerEquipmentId << " with position " << relCenterPos.x() << "/" << relCenterPos.y() << " and radius: " << m_radius << ", " << m_baseCoordinate.mgrs() << ", " << m_centerPosition.lon() << ", " << m_centerPosition.lat(); else INFO_LOG(m_logger) << "Fetching AesItems in radius of position " << relCenterPos.x() << "/" << relCenterPos.y() << " radius: " << m_radius; m_aesItemsInRange.clear(); qint32 effectClustersInRange = fetchAesItemsInCircle(m_allCentralEffectClusters); qint32 nContaminationsInRange = fetchAesItemsInCircle(m_allCentralNContaminations); qint32 bCContaminationsInRange = fetchAesItemsInCircle(m_allCentralBCContaminations); qint32 explosionsAreaInRange = fetchAesItemsInCircle(m_allCentralExplosionsArea); qint32 explosionsSingleInRange = fetchAesItemsInCircle(m_allCentralExplosionsSingle); qint32 mineAreasInRange = fetchAesItemsInCircle(m_allCentralMineAreas); qint32 functionalAreasInRange = fetchAesItemsInCircle(m_allCentralFunctionalAreas); qint32 boobyTrapsInRange = fetchAesItemsInCircle(m_allCentralBoobyTraps); qint32 offRouteMinesInRange = fetchAesItemsInCircle(m_allCentralOffRouteMines); qint32 explosionClustersInRage = fetchAesItemsInCircle(m_allCentralExplosionClusters); TRACE_LOG(m_logger) << "Got " << effectClustersInRange << " EffectClusters in range."; TRACE_LOG(m_logger) << "Got " << nContaminationsInRange << " NContaminations in range."; TRACE_LOG(m_logger) << "Got " << bCContaminationsInRange << " BCContaminations in range."; TRACE_LOG(m_logger) << "Got " << explosionsAreaInRange << " ExplosionsArea in range."; TRACE_LOG(m_logger) << "Got " << explosionsSingleInRange << " ExplosionsSingle in range."; TRACE_LOG(m_logger) << "Got " << mineAreasInRange << " MineAreas in range."; TRACE_LOG(m_logger) << "Got " << functionalAreasInRange << " FunctionalAreas in range."; TRACE_LOG(m_logger) << "Got " << boobyTrapsInRange << " BoobyTraps in range."; TRACE_LOG(m_logger) << "Got " << offRouteMinesInRange << " OffRouteMines in range."; TRACE_LOG(m_logger) << "Got " << explosionClustersInRage << " ExplosionClusters in range."; } template qint32 HandlerOcCentralAesData::fetchAesItemsInCircle(const QHash &aesItems) { qint32 aesItemsInRangeCount = 0; for (auto it = aesItems.constBegin(); it != aesItems.constEnd(); ++it) { if (!m_allCentralAesItemViews.contains(it.key())) { WARNING_LOG(m_logger) << "Got AesItem::id " << it.key() << " but there is no corresponding AesItemView."; continue; } AreaEffectSimulation::AesItemView aesItemView = m_allCentralAesItemViews.value(it.key()); if (it.value().effectStateId() == AreaEffectSimulation::AesEffectState::inner_enum::EsExpired || it.value().effectStateId() == AreaEffectSimulation::AesEffectState::inner_enum::EsRemoved) { TRACE_LOG(m_logger) << "AesItem of type " << aesItemView.aesTypeId() << ", with id " << it.key() << " is removed or expired --> skipping."; continue; } #if QT_VERSION < QT_VERSION_CHECK(5,10,0) if (polygonFromForm(aesItemView.form()).intersected(m_situationCircle).size() > 0) #else if (polygonFromForm(aesItemView.form()).intersects(m_situationCircle)) #endif { m_aesItemsInRange.insert(it.key()); ++aesItemsInRangeCount; } } return aesItemsInRangeCount; } QPolygonF HandlerOcCentralAesData::polygonFromForm(const std::vector &form) const { QPolygonF result; result.reserve(form.size()); for (const Core::GeoPosition ¤tPosition : qAsConst(form)) result.append(PositionConverter::relativeFromGeographic({currentPosition.lon(), currentPosition.lat()}, m_baseCoordinate)); return result; } QList HandlerOcCentralAesData::allInternalAesItemIds() const { QList result; result.reserve(m_allCentralEffectClusters.size() + m_allCentralNContaminations.size() + m_allCentralBCContaminations.size() + m_allCentralExplosionsArea.size() + m_allCentralExplosionsSingle.size() + m_allCentralMineAreas.size() + m_allCentralFunctionalAreas.size() + m_allCentralBoobyTraps.size() + m_allCentralOffRouteMines.size() + m_allCentralExplosionClusters.size()); for (auto it = m_allCentralEffectClusters.constBegin(); it != m_allCentralEffectClusters.constEnd(); ++it) result.append(it.key()); for (auto it = m_allCentralNContaminations.constBegin(); it != m_allCentralNContaminations.constEnd(); ++it) result.append(it.key()); for (auto it = m_allCentralBCContaminations.constBegin(); it != m_allCentralBCContaminations.constEnd(); ++it) result.append(it.key()); for (auto it = m_allCentralExplosionsArea.constBegin(); it != m_allCentralExplosionsArea.constEnd(); ++it) result.append(it.key()); for (auto it = m_allCentralExplosionsSingle.constBegin(); it != m_allCentralExplosionsSingle.constEnd(); ++it) result.append(it.key()); for (auto it = m_allCentralMineAreas.constBegin(); it != m_allCentralMineAreas.constEnd(); ++it) result.append(it.key()); for (auto it = m_allCentralFunctionalAreas.constBegin(); it != m_allCentralFunctionalAreas.constEnd(); ++it) result.append(it.key()); for (auto it = m_allCentralBoobyTraps.constBegin(); it != m_allCentralBoobyTraps.constEnd(); ++it) result.append(it.key()); for (auto it = m_allCentralOffRouteMines.constBegin(); it != m_allCentralOffRouteMines.constEnd(); ++it) result.append(it.key()); for (auto it = m_allCentralExplosionClusters.constBegin(); it != m_allCentralExplosionClusters.constEnd(); ++it) result.append(it.key()); return result; } void HandlerOcCentralAesData::removeKickedOutAesItems(const QSet &aesItemsSentBefore) { QSet kickedOutAesItems = aesItemsSentBefore - m_aesItemsInRange; DEBUG_LOG(m_logger) << "Found " << kickedOutAesItems.size() << " AesItems to kick out."; AreaEffectSimulation::AesType aesType = AreaEffectSimulation::AesType::inner_enum::AtUnknown; for (qint32 currentAesItemId : qAsConst(kickedOutAesItems)) { if (m_allCentralAesItemViews.contains(currentAesItemId)) aesType = m_allCentralAesItemViews.value(currentAesItemId).aesTypeId(); else if (m_allCentralEffectClusters.contains(currentAesItemId)) aesType = AreaEffectSimulation::AesType::inner_enum::AtEffectCluster; else if (m_allCentralNContaminations.contains(currentAesItemId)) aesType = AreaEffectSimulation::AesType::inner_enum::AtNContamination; else if (m_allCentralBCContaminations.contains(currentAesItemId)) aesType = AreaEffectSimulation::AesType::inner_enum::AtBCContamination; else if (m_allCentralExplosionsArea.contains(currentAesItemId)) aesType = AreaEffectSimulation::AesType::inner_enum::AtExplosionArea; else if (m_allCentralExplosionsSingle.contains(currentAesItemId)) aesType = AreaEffectSimulation::AesType::inner_enum::AtExplosionSingle; else if (m_allCentralMineAreas.contains(currentAesItemId)) aesType = AreaEffectSimulation::AesType::inner_enum::AtMineArea; else if (m_allCentralFunctionalAreas.contains(currentAesItemId)) aesType = AreaEffectSimulation::AesType::inner_enum::AtFunctionalArea; else if (m_allCentralBoobyTraps.contains(currentAesItemId)) aesType = AreaEffectSimulation::AesType::inner_enum::AtBoobyTrap; else if (m_allCentralOffRouteMines.contains(currentAesItemId)) aesType = AreaEffectSimulation::AesType::inner_enum::AtOffRouteMine; else if (m_allCentralExplosionClusters.contains(currentAesItemId)) aesType = AreaEffectSimulation::AesType::inner_enum::AtExplosionCluster; else { WARNING_LOG(m_logger) << "Could not remove AesItem with id " << currentAesItemId << ". There is no way to find out its AesType"; continue; } m_dataQueue->addRemoveMessage(currentAesItemId, aesType); } } void HandlerOcCentralAesData::buildSituationCircle() { TRACE_LOG(m_logger) << "Thread " << QThread::currentThreadId() << " function: " << LOGFUNCTION; // building the situation "circle" --> we use a regular polygon with 8 edges m_situationCircle.clear(); QLineF tempLine; const qint32 edges = 8; const qreal angle = 360.0 / edges; tempLine.setP1(PositionConverter::relativeFromGeographic(m_centerPosition, m_baseCoordinate)); tempLine.setLength(m_radius); tempLine.setAngle(angle); m_situationCircle << tempLine.p2(); for (qint32 counter = 1; counter < edges; ++counter) { tempLine.setAngle(tempLine.angle() + angle); m_situationCircle << tempLine.p2(); } } qreal HandlerOcCentralAesData::calculateDistanceToCircleCenter(qint32 aesItemId) const { if (!m_allCentralAesItemViews.contains(aesItemId)) { WARNING_LOG(m_logger) << "Could not calculate distance to circle center, because there is no AesItemView for AesItem::id " << aesItemId; return -1.0; } QPolygonF aesItemForm = polygonFromForm(m_allCentralAesItemViews.value(aesItemId).form()); QLineF distanceLine(aesItemForm.boundingRect().center(), m_situationCircle.boundingRect().center()); return distanceLine.length(); } template void HandlerOcCentralAesData::onAesItemChanged(QHash &container, const T &data, DataModification modType) { switch (modType) { case DataModification::eAdded: if (!data.isCentral()) return; container.insert(data.id(), data); return; case DataModification::eModified: container[data.id()] = data; if (m_aesItemsInRange.contains(data.id())) { if (data.effectStateId() == AreaEffectSimulation::AesEffectState::inner_enum::EsExpired || data.effectStateId() == AreaEffectSimulation::AesEffectState::inner_enum::EsRemoved) { m_aesItemsInRange.remove(data.id()); m_dataQueue->addRemoveMessage(data); } else m_dataQueue->addAesItem(data); } return; case DataModification::eRemoved: container.remove(data.id()); if (m_allCentralAesItemViews.contains(data.id())) { AreaEffectSimulation::AesItemView aesItemView = m_allCentralAesItemViews.take(data.id()); if (m_aesItemsInRange.contains(data.id())) { m_aesItemsInRange.remove(data.id()); m_dataQueue->addRemoveMessage(data.id(), aesItemView.aesTypeId()); } } return; } } template void HandlerOcCentralAesData::addAesItemsToBuilder(const QHash &aesItems, const QSet &validIds) { for (auto it = aesItems.constBegin(); it != aesItems.constEnd(); ++it) { if (validIds.contains(it.key())) m_dataQueue->addAesItem(it.value()); } } } // namespace OcSituationServer