831 lines
34 KiB
C++
Executable File
831 lines
34 KiB
C++
Executable File
/**
|
|
* 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 <LtsCoordTrans/lts_coord_trans.h>
|
|
#include <LtsUtilsCore/qbytearray_byteaccess.h>
|
|
#include <LtsUtilsCore/dds_vector.h>
|
|
#include <LtsUtilsCore/outdated_position.h>
|
|
#include <ParticipantManagement/ppm_common.h>
|
|
#include "settings.h"
|
|
#include <QLineF>
|
|
#include "central_aes_data_queue.h"
|
|
#include <QMultiMap>
|
|
|
|
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<DdsHandler> &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<qint32> 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<AreaEffectSimulation::AesType> 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<qint32> 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<qreal, qint32> 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<qint32> 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<std::vector<uint8_t>>(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<typename T>
|
|
qint32 HandlerOcCentralAesData::fetchAesItemsInCircle(const QHash<qint32, T> &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<Core::GeoPosition> &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<qint32> HandlerOcCentralAesData::allInternalAesItemIds() const
|
|
{
|
|
QList<qint32> 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<qint32> &aesItemsSentBefore)
|
|
{
|
|
QSet<qint32> 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<typename T>
|
|
void HandlerOcCentralAesData::onAesItemChanged(QHash<qint32, T> &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<typename T>
|
|
void HandlerOcCentralAesData::addAesItemsToBuilder(const QHash<qint32, T> &aesItems, const QSet<qint32> &validIds)
|
|
{
|
|
for (auto it = aesItems.constBegin(); it != aesItems.constEnd(); ++it)
|
|
{
|
|
if (validIds.contains(it.key()))
|
|
m_dataQueue->addAesItem(it.value());
|
|
}
|
|
}
|
|
|
|
} // namespace OcSituationServer
|