Files
qt5-legatus-legacy/Lts/Services/CentralEffectSimulation/Plugins/NBC/handler_nbc.cpp
T
2026-08-13 18:33:10 +02:00

1493 lines
63 KiB
C++
Executable File

/**
* Handler for player data
* $Id$
* $HeadURL$
* $Author$
* Created by gr, SLSE, 2017-02-20
*/
#include "handler_nbc.h"
#include <QTimer>
#include <QDateTime>
#include <LtsUtilsCore/dds_bitarray.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <ProjectDataManagement/pdm_enums.hpp>
#include <cmath>
namespace dds
{
namespace core
{
inline uint qHash(ProjectDataManagement::EventType et)
{
return ::qHash(et.underlying());
}
}
}
namespace CES_NBC
{
inline uint qHash(EffectType et)
{
return ::qHash(int(et));
}
QString toString(EffectType et)
{
switch (et)
{
case EffectType::Unknown: return QStringLiteral("Unknown");
case EffectType::EffectiveMineRangeEnter: return QStringLiteral("EffectiveMineRangeEnter");
case EffectType::EffectiveMineRangeLeave: return QStringLiteral("EffectiveMineRangeLeave");
case EffectType::NContaminationLeave: return QStringLiteral("NContaminationLeave");
case EffectType::NContaminationEnterArea1: return QStringLiteral("NContaminationEnterArea1");
case EffectType::NContaminationEnterArea2: return QStringLiteral("NContaminationEnterArea2");
case EffectType::NContaminationDetonation: return QStringLiteral("NContaminationDetonation");
case EffectType::FunctionalAreaLeave: return QStringLiteral("FunctionalAreaLeave");
case EffectType::FunctionalAreaEnter: return QStringLiteral("FunctionalAreaEnter");
case EffectType::ExplosionArea: return QStringLiteral("ExplosionArea");
case EffectType::ExplosionSingle: return QStringLiteral("ExplosionSingle");
case EffectType::BCContaminationLeave: return QStringLiteral("BCContaminationLeave");
case EffectType::BCContaminationEnterFloating: return QStringLiteral("BCContaminationEnterFloating");
case EffectType::BCContaminationEnterResident: return QStringLiteral("BCContaminationEnterResident");
case EffectType::BCContaminationEnterFloatingArea: return QStringLiteral("BCContaminationEnterFloatingArea");
case EffectType::BeStillWarning: return QStringLiteral("BeStillWarning");
}
return QStringLiteral("Unknown (%1)").arg(int(et));
}
HandlerNBC::HandlerNBC(const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler,
const std::shared_ptr<CentralEffectSimulation::HandlerParticipant> &participantHandler,
QObject *parent)
: QObject(parent)
, m_ddsHandler(ddsHandler)
, m_handlerParticipant(participantHandler)
, m_logger(CentralEffectSimulation::getLogger("Plugin.NBC.HandlerNBC"))
{
} // end of ctor()
//-----------------------------------------------------------------------------
HandlerNBC::~HandlerNBC()
{
} // end of dtor()
//-----------------------------------------------------------------------------
bool HandlerNBC::init()
{
auto dtcAes = m_ddsHandler->dtcAes();
dtcAes->waitForHistoricalDataBCContamination(2000);
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::bCContaminationChanged,
this, &HandlerNBC::onBCContaminationChanged);
dtcAes->waitForHistoricalDataNContamination(2000);
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::nContaminationChanged,
this, &HandlerNBC::onNContaminationChanged);
dtcAes->waitForHistoricalDataAesItemView(2000);
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
this, &HandlerNBC::onAesItemViewChanged);
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::newIndoorPosition,
this, &HandlerNBC::onNewIndoorParticipantPosition);
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::newOutdoorPosition,
this, &HandlerNBC::onNewOutdoorParticipantPosition);
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::participantDecontaminated,
this, &HandlerNBC::onParticipantDecontaminated);
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::restoreRadioReadinessChanged,
this, &HandlerNBC::onRestoreRadioReadinessChanged);
// Get 'static' data for all bcContaminations
{
auto cb = [this](const AreaEffectSimulation::BCContamination & bc)
{
onBCContaminationChanged(bc, DataModification::eAdded);
};
if (!dtcAes->bCContaminations(cb))
return false;
}
// Get 'static' data for all NContaminations
{
auto cb = [this](const AreaEffectSimulation::NContamination & nc)
{
onNContaminationChanged(nc, DataModification::eAdded);
};
if (!dtcAes->nContaminations(cb))
return false;
}
// Get 'static' data for all onAesItemView
{
auto cb = [this](const AreaEffectSimulation::AesItemView & aiv)
{
onAesItemViewChanged(aiv, DataModification::eAdded);
};
if (!dtcAes->aesItemViews(cb))
return false;
}
INFO_LOG(m_logger) << "HandlerParticipantArea::init() finished.";
return true;
} // end of init()
//-----------------------------------------------------------------------------
void HandlerNBC::onSendCesHitReply(const Core::FunctionReplyObject &replyObject)
{
DEBUG_LOG(m_logger) << "onSendCesHitReply for id " << replyObject.id() << " success= " << replyObject.error();
if (replyObject.error())
WARNING_LOG(m_logger) << "Can not send enter/leave Area to participant in training area: " << replyObject();
// Send next Request, if available
if (!m_sendCesHitRequestQueue.isEmpty())
{
DEBUG_LOG(m_logger) << "m_sendCesAreaActionRequestQueue.size()=" << m_sendCesHitRequestQueue.size();
m_sendCesHitRequestQueue.dequeue();
// Send next Message
if (!m_sendCesHitRequestQueue.isEmpty())
{
const auto &hr = m_sendCesHitRequestQueue.head();
DEBUG_LOG(m_logger) << "sendCesHitRequest: " << hr;
m_ddsHandler->ftcTab()->sendCesHitRequest(hr, this);
}
}
}
// ///////////////////////////////////
// A E S (AreaEffectSimulation)
// ///////////////////////////////////
void HandlerNBC::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
{
const bool isSupplyTruck = false;
const double hazardDistance = 0.0;
double upperOffset = 0;
double lowerOffset = 0;
bool offsetIsSet = false;
TRACE_LOG(m_logger) << "onAesItemViewChanged"
<< " aesItemId=" << data.aesItemId();
AreaEffectSimulation::BCContamination bCContamination = m_ddsHandler->dtcAes()->bCContamination(data.aesItemId());
const int aesItemId = data.aesItemId();
const AreaEffectSimulation::AesEffectState &effectState = data.effectStateId();
if ((data.aesTypeId().underlying() != AreaEffectSimulation::AesType_def::AtDangerArea)
&& (data.aesTypeId().underlying() != AreaEffectSimulation::AesType_def::AtBCContamination)
&& (data.aesTypeId().underlying() != AreaEffectSimulation::AesType_def::AtNContamination))
return;
if (data.aesTypeId().underlying() == AreaEffectSimulation::AesType_def::AtBCContamination)
{
const AreaEffectSimulation::BCContamination &bc = m_ddsHandler->dtcAes()->bCContamination(data.aesItemId());
if (!bc.isCentral())
{
DEBUG_LOG(m_logger) << "!Central BCContamination id: " << aesItemId;
return;
}
offsetIsSet = true;
upperOffset = bCContamination.upperOffset();
lowerOffset = bCContamination.lowerOffset();
}
else if (data.aesTypeId().underlying() == AreaEffectSimulation::AesType_def::AtDangerArea)
{
const AreaEffectSimulation::DangerArea &da = m_ddsHandler->dtcAes()->dangerArea(data.aesItemId());
if (!da.isCentral())
{
DEBUG_LOG(m_logger) << "!Central DangerArea id: " << aesItemId;
return;
}
}
else if (data.aesTypeId().underlying() == AreaEffectSimulation::AesType_def::AtNContamination)
{
const AreaEffectSimulation::NContamination &nc = m_ddsHandler->dtcAes()->nContamination(data.aesItemId());
if (!nc.isCentral())
{
DEBUG_LOG(m_logger) << "!Central NContamination id: " << aesItemId;
return;
}
}
TRACE_LOG(m_logger) << "Got AesItemView id: " << aesItemId
<< ", type: " << data.aesTypeId()
<< ", effectState: " << data.effectStateId()
<< ", modType: " << modType;
const double impactRadius = m_ddsHandler->chargeTypeRadius(data.chargeStruct());
DEBUG_LOG(m_logger) << "impactRadius=" << impactRadius;
switch (effectState.underlying())
{
case AreaEffectSimulation::AesEffectState_def::EsPrepared:
{
const auto &aesItemViewUtm = CentralEffectSimulation::AesItemViewUtm::create(data,
m_aesItemViews[data.aesItemId()],
impactRadius,
isSupplyTruck,
hazardDistance,
offsetIsSet,
upperOffset,
lowerOffset);
m_aesItemViews.insert(data.aesItemId(), aesItemViewUtm);
}
break;
case AreaEffectSimulation::AesEffectState_def::EsActivated:
{
CentralEffectSimulation::AesItemViewUtm aesItemViewUtm =
CentralEffectSimulation::AesItemViewUtm::create(data,
m_aesItemViews[data.aesItemId()],
impactRadius,
isSupplyTruck,
hazardDistance,
offsetIsSet,
upperOffset,
lowerOffset);
const Core::GeoPosition2D &pointGeo = bCContamination.impactPosition();
int zone = aesItemViewUtm.zone;
//aesItemViewUtm.center = CentralEffectSimulation::geographic2Utm(pointGeo, &zone);
auto utm = LtsCoordTrans::UtmCoordinate::fromGeographic(pointGeo.lon(), pointGeo.lat(), zone);
QPointF impactPositionUtm = QPointF(utm.x, utm.y);
aesItemViewUtm.center = impactPositionUtm;
switch (data.aesTypeId().underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
case AreaEffectSimulation::AesType_def::AtNContamination:
// for each participant:
// Bounding-Box Check,
// form-Check
// if new field for this participant send sendCesHitRequest
calculateBcContamination(aesItemViewUtm);
m_aesItemViews.insert(data.aesItemId(), aesItemViewUtm);
// DEBUG_LOG(m_logger) << "insert AtBCContamination oder AtNContamination AesItemView id: " << aesItemId
// << ", type: " << data.aesTypeId();
break;
case AreaEffectSimulation::AesType_def::AtDangerArea:
calculateDangerArea(aesItemViewUtm);
m_aesItemViews.insert(data.aesItemId(), aesItemViewUtm);
DEBUG_LOG(m_logger) << "insert AtDangerArea AesItemView id: " << aesItemId
<< ", type: " << data.aesTypeId();
break;
default:
break;
} // switch aesTypeId
break;
} // case EsActivated
case AreaEffectSimulation::AesEffectState_def::EsRemoved:
case AreaEffectSimulation::AesEffectState_def::EsExpired:
{
aesItemViewRemoved(aesItemId);
break;
}
default:
// do nothing
break;
} // switch effectStateId
} // onAesItemViewChanged
void HandlerNBC::onBCContaminationChanged(const AreaEffectSimulation::BCContamination &data, DataModification modType)
{
if (!data.isCentral())
{
aesItemViewRemoved(data.id());
return;
}
switch (modType)
{
case DataModification::eRemoved:
break;
case DataModification::eAdded:
case DataModification::eModified:
switch (data.effectStateId().underlying())
{
case AreaEffectSimulation::AesEffectState_def::EsActivated:
{
CentralEffectSimulation::AesItemViewUtm &ref = m_aesItemViews[data.id()];
if (m_ddsHandler->volatilityTypeId(data.chargeStruct()) == ProjectDataManagement::VolatilityType_def::Resident)
{
ref.radials = {data.impactRadius()};
ref.center = CentralEffectSimulation::geographic2Utm(data.impactPosition(), &ref.zone);
}
else
ref.radials.clear();
break;
}
default:
break;
}
}
}
void HandlerNBC::onNContaminationChanged(const AreaEffectSimulation::NContamination &data, DataModification modType)
{
DEBUG_LOG(m_logger) << "onNContaminationChanged"
<< " id=" << data.id();
switch (modType)
{
case DataModification::eRemoved:
break;
case DataModification::eAdded:
case DataModification::eModified:
switch (data.effectStateId().underlying())
{
case AreaEffectSimulation::AesEffectState_def::EsActivated:
{
CentralEffectSimulation::AesItemViewUtm &ref = m_aesItemViews[data.id()];
ref.radials = {data.impactRadius(),
data.borderLengthInner(),
data.borderLengthInner() + data.borderLengthOuter()
};
ref.center = CentralEffectSimulation::geographic2Utm(data.impactPosition(), &ref.zone);
const QHash<int, CentralEffectSimulation::HandlerParticipant::CesParticipantData> participantsMap = m_handlerParticipant->positions();
for (const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPos : participantsMap)
{
if (m_handlerParticipant->isOutdated(participantPos))
continue;
DEBUG_LOG(m_logger) << "onNContaminationChanged participantId=" << participantPos.participantId()
<< " insideBuilding=" << participantPos.insideBuilding()
<< " buildingId=" << participantPos.buildingId();
const QPointF posUtm = CentralEffectSimulation::geographic2Utm(participantPos.pos(), &ref.zone);
const bool isInCircle = inCircle(ref.center, data.impactRadius(), posUtm);
const EffectType effectType = CES_NBC::EffectType::NContaminationDetonation;
const int ctasEffectType = static_cast<int>(effectType) & 0xffff;
DEBUG_LOG(m_logger) << "onNContaminationChanged isInCircle=" << isInCircle
<< " aesItemId=" << data.id();
if ( isInCircle)
{
QHash<int, bool> aesIds = m_participantAes.value(participantPos.participantId());
aesIds.insert(data.id(), true);
m_participantAes.insert( participantPos.participantId(), aesIds);
QHash<int, QSet<EffectType>> effectTypeStatesFromAesItem = m_effectTypeStates.value(data.id());
QSet<EffectType> effectSet = effectTypeStatesFromAesItem.value(participantPos.participantId());
effectSet.insert(EffectType::NContaminationDetonation);
effectTypeStatesFromAesItem.insert(participantPos.participantId(), effectSet);
m_effectTypeStates.insert(data.id(), effectTypeStatesFromAesItem);
DEBUG_LOG(m_logger) << "m_participantAes.insert participantId=" << participantPos.participantId()
<< " aesId=" << data.id();
sendCesHitRequest(ref,
participantPos,
//effectTime >= 0 ? effectTime : participantPosition.sampleTime(),
QDateTime::currentMSecsSinceEpoch(),
ctasEffectType,
0);
}
}
break;
}
default:
break;
}
}
}
void HandlerNBC::calculateBcContamination(const CentralEffectSimulation::AesItemViewUtm &itemView)
{
TRACE_LOG(m_logger) << "HandlerParticipantArea::calculateBcContamination aesItemId =" << itemView.aesItemId;
const auto participantsMap = m_handlerParticipant->positions();
for (const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPos : participantsMap)
{
if (m_handlerParticipant->isOutdated(participantPos))
continue;
DEBUG_LOG(m_logger) << "participantId=" << participantPos.participantId()
<< " insideBuilding=" << participantPos.insideBuilding()
<< " buildingId=" << participantPos.buildingId()
<< " roomId=" << participantPos.roomId();
inFormCheck(itemView, participantPos);
}
// for
} // calculateBcContamination
void HandlerNBC::calculateDangerArea(const CentralEffectSimulation::AesItemViewUtm &itemView)
{
DEBUG_LOG(m_logger) << "HandlerParticipantArea::calculateDangerArea aesItemId =" << itemView.aesItemId;
const auto partPosMap = m_handlerParticipant->positions();
for (const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPos : partPosMap)
inFormCheck(itemView, participantPos);
} // calculateDangerArea
void HandlerNBC::deleteDangerArea(const int aesItemId)
{
CentralEffectSimulation::AesItemViewUtm itemView = m_aesItemViews.value(aesItemId);
DEBUG_LOG(m_logger) << "delete " << itemView.aesItemId << ", aesItemId: " << aesItemId;
const auto partPosMap = m_handlerParticipant->positions();
for (const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPos : partPosMap)
{
sendParticipantEvent(aesItemId, participantPos, ProjectDataManagement::EventType_def::LeaveDangerArea);
DEBUG_LOG(m_logger) << "Participant inside id=" << participantPos.participantId();
}// for all Participants
} // deleteDangerArea
void HandlerNBC::onNewOutdoorParticipantPosition(const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantData)
{
bool leave = false;
DEBUG_LOG(m_logger) << "++++++++ onNewOutdoorParticipantPosition participantId=" << participantData.participantId()
<< " buildingId=" << participantData.buildingId()
<< " roomId=" << participantData.roomId()
<< " reportingSource=" << participantData.reportingSource()
<< " m_aesItemViews.size=" << m_aesItemViews.size();
if (m_handlerParticipant->isOutdated(participantData))
return;
if (m_handlerParticipant->getEquipmentNumber(participantData.participantId()) == 0)
{
DEBUG_LOG(m_logger) << "Not handle position: participant has no equipment number";
return;
}
if (m_lastRoomId.value(participantData.participantId()) > 0)
{
DEBUG_LOG(m_logger) << "Leave Building m_isInContaminatedRoom.contains participantId=" << participantData.participantId()
<< " m_isInContaminatedRoom.\nremove!!!";
AreaEffectSimulation::AesItemView aesItemView;
bool aesIsAvailable = m_ddsHandler->dtcAes()->aesItemViewFromEntityId(m_isInContaminatedRoom.value(participantData.participantId()),AreaEffectSimulation::AesType::AtUnknown, aesItemView );
if (aesIsAvailable
&& (aesItemView.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated))
{
DEBUG_LOG(m_logger) << "Feld ist nicht mehr da. id=" << aesItemView.aesItemId();
m_isInContaminatedRoom.remove(participantData.participantId());
}
else
{
DEBUG_LOG(m_logger) << "Feld ist nicht mehr da. id=" << aesItemView.aesItemId();
sendLeaveEvent(aesItemView.aesItemId(),participantData );
}
leave = true;
}
else
{
DEBUG_LOG(m_logger) << "m_lastRoomId.contains(" << m_lastRoomId.contains(participantData.participantId())
<< " roomId=" << m_lastRoomId.value(participantData.participantId());
}
m_lastRoomId.insert(participantData.participantId(), 0);
DEBUG_LOG(m_logger) << "HandlerParticipantArea::calculateAesParticipant paricipantId: " << participantData.participantId()
<< " m_aesItemViews.size()=" << m_aesItemViews.size();
for (const CentralEffectSimulation::AesItemViewUtm &itemView : qAsConst(m_aesItemViews))
{
DEBUG_LOG(m_logger) << " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
DEBUG_LOG(m_logger) << " itemView: " << itemView.aesItemId << ", " << itemView.aesTypeId;
if (leave)
{
QHash<int, QSet<EffectType>> effectTypeHash = m_effectTypeStates.value(itemView.aesItemId);
if ( effectTypeHash.contains(participantData.participantId()))
{
effectTypeHash.remove(participantData.participantId());
}
m_effectTypeStates.insert(itemView.aesItemId, effectTypeHash);
}
switch (itemView.aesTypeId.underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
case AreaEffectSimulation::AesType_def::AtNContamination:
case AreaEffectSimulation::AesType_def::AtDangerArea:
inFormCheck(itemView, participantData);
break;
default:
// nothing
break;
} // switch
} // for
} // onNewOutdoorParticipantPosition
void HandlerNBC::onParticipantDecontaminated(const int participantId)
{
DEBUG_LOG(m_logger) << "onParticipantDecontaminated participantId=" << participantId;
m_participantAes.remove(participantId);
for (auto i = m_effectTypeStates.cbegin(), end = m_effectTypeStates.cend(); i != end; ++i)
{
DEBUG_LOG(m_logger) << "aesItemId=" << i.key();
QHash<int, QSet<EffectType>> value = i.value();
value.remove(participantId);
m_effectTypeStates.insert(i.key(), value);
}
}
void HandlerNBC::onRestoreRadioReadinessChanged(const int participantId)
{
DEBUG_LOG(m_logger) << "HandlerNBC::onRestoreRadioReadinessChanged participantId=" << participantId
<< " m_participantAes.size=" << m_participantAes.size();
if (!m_participantAes.contains(participantId) )
{
DEBUG_LOG(m_logger) << "HandlerNBC::onRestoreRadioReadinessChanged !m_participantAes.contains( participantId=" << participantId << ")";
return;
}
QHash<int, bool> aesIds = m_participantAes.value(participantId);
QHashIterator<int, bool> i(aesIds);
while (i.hasNext())
{
i.next();
DEBUG_LOG(m_logger) << "HandlerNBC::onRestoreRadioReadinessChanged remove aesId=" << i.key();
m_participantAes.remove(i.key());
m_eventStates.remove(i.key());
m_effectTypeStates.remove(i.key());
}
m_participantAes.remove(participantId);
}
// return true, if participant is inside of the bounding Box
bool HandlerNBC::inBoundingBoxCheck(const CentralEffectSimulation::AesItemViewUtm &itemView,
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantData)
{
if (itemView.effectStateId != AreaEffectSimulation::AesEffectState_def::EsActivated)
return false;
// QRectF(topLeft, bottomRight) -> no need to mormalize, QRectF:contains() handles it correct
const QRectF boundingBoxImpact(itemView.boundingBoxBottomLeft,
itemView.boundingBoxTopRight);
const QPointF participantPosUtmPoint = CentralEffectSimulation::geographic2Utm(participantData.pos(), itemView.zone);
if (boundingBoxImpact.contains(participantPosUtmPoint))
{
DEBUG_LOG(m_logger) << "inBoundingBoxCheck Paricipant " << participantData.participantId()
<< " inside AesItemView:" << itemView.aesItemId;
return true;
}
TRACE_LOG(m_logger) << "inBoundingBoxCheck Paricipant " << participantData.participantId()
<< " outside AesItemView:" << itemView.aesItemId;
return false;
}
void HandlerNBC::sendEnterEvent(const int aesItemId, const AreaEffectSimulation::AesType aesTypeId, const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantData, bool isIndoor)
{
AreaEffectSimulation::AesItemView aesItemView;
m_ddsHandler->dtcAes()->aesItemViewFromEntityId(aesItemId,AreaEffectSimulation::AesType::AtUnknown, aesItemView );
DEBUG_LOG(m_logger) << "sendEnterEvent, paricipantId: " << participantData.participantId()
<< ", aesItemId: " << aesItemId
<< ", aesType=" << aesTypeId
<< ", isIndoor=" << isIndoor;
QHash<int, bool> aesIds = m_participantAes.value(participantData.participantId());
aesIds.insert(aesItemId, true);
m_participantAes.insert(participantData.participantId(), aesIds);
int zone = -1;
if ( m_aesItemViews.contains(aesItemId))
zone = m_aesItemViews.value(aesItemId).zone;
else
{
ERROR_LOG(m_logger) << "No m_aesItemViews.contains aesItemId=" << aesItemId;
}
const QPointF participantPosUtmPoint = CentralEffectSimulation::geographic2Utm(participantData.pos(), zone);
switch (aesTypeId.underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
{
// since buildings can only be contaminated by resident bccontaminations
// effectType is EffectType::BCContaminationEnterResident if isIndoor
EffectType effectType = isIndoor ? EffectType::BCContaminationEnterResident : effectTypeForBCContaminationArea(m_aesItemViews.value(aesItemId), participantPosUtmPoint);
// The Hit Event comes later from the participant
sendEffectTypeEvent(aesItemId, participantData, effectType);
break;
}
case AreaEffectSimulation::AesType_def::AtDangerArea:
sendParticipantEvent(aesItemId, participantData, ProjectDataManagement::EventType_def::EnterDangerArea);
break;
case AreaEffectSimulation::AesType_def::AtNContamination:
sendParticipantEvent(aesItemId, participantData, ProjectDataManagement::EventType_def::EnterNuclear);
sendEffectTypeEvent(aesItemId, participantData, effectTypeForNContaminationArea(m_aesItemViews.value(aesItemId), participantPosUtmPoint, participantData.sampleTime(), participantData.insideBuilding()));
break;
case AreaEffectSimulation::AesType_def::AtExplosionArea:
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
case AreaEffectSimulation::AesType_def::AtMineArea:
default:
INFO_LOG(m_logger) << "sendEvent Unhandled AES-Type" << aesTypeId;
break;
}
} // END sendEvent
void HandlerNBC::sendLeaveEvent(const int aesItemId, const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantData)
{
AreaEffectSimulation::AesItemView aesItemView;
m_ddsHandler->dtcAes()->aesItemViewFromEntityId(aesItemId, AreaEffectSimulation::AesType_def::AtUnknown, aesItemView);
DEBUG_LOG(m_logger) << "sendLeaveEvent"
<< " aesId=" << aesItemId
<< " participantId=" << participantData.participantId()
<< " aesTypeId=" << aesItemView.aesTypeId();
switch (aesItemView.aesTypeId().underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
sendEffectTypeEvent(aesItemId, participantData, EffectType::BCContaminationLeave);
break;
case AreaEffectSimulation::AesType_def::AtDangerArea:
sendParticipantEvent(aesItemId, participantData, ProjectDataManagement::EventType_def::LeaveDangerArea);
break;
case AreaEffectSimulation::AesType_def::AtMineArea:
sendParticipantEvent(aesItemId, participantData, ProjectDataManagement::EventType_def::LeaveMineArea);
break;
case AreaEffectSimulation::AesType_def::AtNContamination:
sendParticipantEvent(aesItemId, participantData, ProjectDataManagement::EventType_def::LeaveNuclear);
sendEffectTypeEvent(aesItemId, participantData, EffectType::NContaminationLeave);
break;
case AreaEffectSimulation::AesType_def::AtExplosionArea:
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
default:
break;
} // end switch
}
// return true, if participant is inside of the form of AesItemView
bool HandlerNBC::inFormCheck(const CentralEffectSimulation::AesItemViewUtm &itemView,
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantData)
{
if (itemView.effectStateId != AreaEffectSimulation::AesEffectState_def::EsActivated)
return false;
const QRectF boundingBoxImpact(itemView.boundingBoxBottomLeft,
itemView.boundingBoxTopRight);
const QPointF participantPosUtmPoint = CentralEffectSimulation::geographic2Utm(participantData.pos(), itemView.zone);
const QString participantPosMgrs = CentralEffectSimulation::geographic2mgrs(participantData.pos(), itemView.zone);
TRACE_LOG(m_logger) << "inFormCheck start, paricipantId: " << participantData.participantId()
<< ", aesItemId: " << itemView.aesItemId
<< ", aesTypeId: " << itemView.aesTypeId
<< ", form.size: " << itemView.form.size()
<< ", Mgrs:" << participantPosMgrs
<< ", effectStateId: " << itemView.effectStateId;
if (boundingBoxImpact.contains(participantPosUtmPoint) &&
itemView.form.containsPoint(participantPosUtmPoint, Qt::FillRule::OddEvenFill))
{
DEBUG_LOG(m_logger) << "Participant id=" << participantData.participantId()
<< " inside Area"
<< " inside Building:" << participantData.insideBuilding()
<< " roomId=" << participantData.roomId();
if ( participantData.roomId() > 0 )
{
InfrastructureManagement::StructureElement structureElement;
bool roomFound = m_ddsHandler->dtcIsm()->getStructureElementById(participantData.roomId(), structureElement);
DEBUG_LOG (m_logger) << "Participant id=" << participantData.participantId()
<< " pos.z=" << participantData.pos().z()
<< " upperOffset =" << itemView.upperOffset
<< " lowerOffset=" << itemView.lowerOffset
<< " roomFound=" << roomFound
<< " offsetZ=" << structureElement.relPosition().offsetZ();
if ( (itemView.aesTypeId.underlying() != AreaEffectSimulation::AesType_def::AtNContamination)
&& itemView.offsetIsSet
&& ( ( structureElement.relPosition().offsetZ() + 1.5 > itemView.upperOffset )
|| ( structureElement.relPosition().offsetZ() + 1.5 < itemView.lowerOffset)))
{
DEBUG_LOG (m_logger) << "Participant id=" << participantData.participantId()
<< " pos.z=" << participantData.pos().z()
<< " not between upperOffset =" << itemView.upperOffset
<< " and lowerOffset=" << itemView.lowerOffset
<< "\nreturn false";
sendLeaveEvent(itemView.aesItemId, participantData);
return false;
}
}
sendEnterEvent(itemView.aesItemId, itemView.aesTypeId, participantData);
return true;
} // if inside
sendLeaveEvent(itemView.aesItemId, participantData);
#if 0
if (m_logger.isDebugEnabled())
{
DEBUG_LOG(m_logger) << "inFormCheck: Paricipant " << participantPosition.participantId << " outside AesItemView " << itemView.aesItemId;
DEBUG_LOG(m_logger) << "ParticipantPos = " << debug(participantPosUtmPoint);
for (const auto &itPos : itemView.form)
DEBUG_LOG(m_logger) << "itemView =" << debug(itPos);
}
#endif
return false;
} // END inFormCheck
// Send via TAB-Proxy to battlefield
void HandlerNBC::sendCesHitRequest(const CentralEffectSimulation::AesItemViewUtm &itemView,
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantData,
qint64 effectTime,
int remaining,
int mineFieldBitIndex)
{
if (remaining < 0)
return;
DEBUG_LOG(m_logger) << "sendCesHitRequest Settings::calculateCentralAes="
<< " insideWlsArea=" << std::boolalpha << participantData.insideWlsArea()
<< " isSmartChargeType=" << std::boolalpha << m_ddsHandler->isSmartChargeType(itemView.chargeStruct)
<< " participantId=" << participantData.participantId();
const int equipNo = m_ddsHandler->participantId2EquipNo(participantData.participantId());
DEBUG_LOG(m_logger) << " ftc sendCESHit to Participant participantId = " << participantData.participantId()
<< " equipNo = " << equipNo
<< " aesItemId =" << itemView.aesItemId;
// participantPosition.participantPosition == 0 -> send to all
if (participantData.participantId() != 0 && equipNo <= 0)
{
DEBUG_LOG(m_logger) << "participantPosition.participantId != 0 && equipNo <= 0" ;
return;
}
int32_t originatorParticipantId = m_aesItemId2partIdMap.value(itemView.aesItemId, 0);
const TrainingAreaBase::TabPosition pos(participantData.pos(),
Core::PositionReportingSource_def::Gps, // irrelevant
participantData.buildingId(),
participantData.roomId());
const int originatorEquipNo = m_ddsHandler->participantId2EquipNo(originatorParticipantId);
const ProjectDataManagement::EventType eventType = ProjectDataManagement::EventType_def::Unknown;
TrainingAreaBase::SendCesHitRequest requestTab(
equipNo, // equipmentNumber
participantData.participantId(), // participantId
itemView.chargeStruct.chargeTypeId(), // chargeTypeId
itemView.aesItemId, // aesId
originatorEquipNo, // originatorEquipmentNumber
remaining, // remainEffectPercent ( no protection outside Building )
pos,
effectTime, // effectTime
eventType,
itemView.partyId, // originPartyId
mineFieldBitIndex
);
DEBUG_LOG(m_logger) << " participantId=" << participantData.participantId()
<< " chargeTypeId=" << itemView.chargeStruct.chargeTypeId();
m_sendCesHitRequestQueue.enqueue(requestTab);
if (m_sendCesHitRequestQueue.size() == 1)
{
DEBUG_LOG(m_logger) << "SendCesHitRequest: " << requestTab;
m_ddsHandler->ftcTab()->sendCesHitRequest(requestTab, this);
}
}
void HandlerNBC::sendCesHitRequest(const int aesItemId,
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantData,
qint64 effectTime,
int remaining,
int mineFieldBitIndex,
EffectType effectType)
{
if (remaining < 0)
return;
AreaEffectSimulation::AesItem aesItem;
m_ddsHandler->dtcAes()->aesItemFromId(aesItemId, aesItem);
int32_t legacyChargeTypeId = 0;
int32_t partyId = 0;
if ( aesItem.partyId().is_set())
partyId = aesItem.partyId().get();
legacyChargeTypeId = m_ddsHandler->getLegacyIdFromChargeTypeId(aesItem.chargeStruct());
DEBUG_LOG(m_logger) << "sendCesHitRequest Settings::calculateCentralAes="
<< " insideWlsArea=" << std::boolalpha << participantData.insideWlsArea()
<< " isSmartChargeType=" << std::boolalpha << m_ddsHandler->isSmartChargeType(aesItem.chargeStruct())
<< " participantId=" << participantData.participantId()
<< " partyId=" << partyId
<< " effectType=" << static_cast<int>(effectType)
<< " remaining=" << remaining;
const int equipmentNumber = m_ddsHandler->participantId2EquipNo(participantData.participantId());
DEBUG_LOG(m_logger) << " ftc sendCESHit to Participant participantId = " << participantData.participantId()
<< " equipNo = " << equipmentNumber << " aesItemId =" << aesItemId;
// participantPosition.participantPosition == 0 -> send to all
if (participantData.participantId() != 0 && equipmentNumber <= 0)
{
DEBUG_LOG(m_logger) << "participantPosition.participantId != 0 && equipNo <= 0" ;
return;
} // if
// Check Protection by buildings
else if (effectType == CES_NBC::EffectType::NContaminationEnterArea1)
{
DEBUG_LOG(m_logger) << "NContaminationEnterArea1";
if (participantData.buildingId() > 0)
{
DEBUG_LOG(m_logger) << "NContaminationEnterArea1 Protection by buildings"
<< " remaining vorher=" << remaining
<< " remaining nachher=2";
remaining = 2;
}
else
{
DEBUG_LOG(m_logger) << "NContaminationEnterArea1 NO Protection by buildings"
<< " remaining vorher="<< remaining
<< " remaining nachher=1";
remaining = 1;
}
}
else if (effectType == CES_NBC::EffectType::NContaminationEnterArea2)
{
DEBUG_LOG(m_logger) << "NContaminationEnterArea2 NO Protection by buildings"
<< " remaining vorher="<< remaining
<< " remaining nachher=2";
DEBUG_LOG(m_logger) << "NContaminationEnterArea2";
remaining = 2;
}
int32_t originatorParticipantId = m_aesItemId2partIdMap.value(aesItemId, 0);
const int originatorEquipmentNumber = m_ddsHandler->participantId2EquipNo(originatorParticipantId);
const TrainingAreaBase::TabPosition pos(
participantData.pos(), Core::PositionReportingSource_def::Gps, participantData.buildingId(),
participantData.roomId()
);
const ProjectDataManagement::EventType eventType = ProjectDataManagement::EventType_def::Unknown;
TrainingAreaBase::SendCesHitRequest requestTab(
equipmentNumber, participantData.participantId(), legacyChargeTypeId, aesItemId, originatorEquipmentNumber,
remaining, pos, effectTime, eventType, partyId, mineFieldBitIndex
);
DEBUG_LOG(m_logger) << " participantId=" << participantData.participantId() << " chargeTypeId=" << aesItem.chargeStruct().chargeTypeId()
<< " legacyChargeTypeId=" << legacyChargeTypeId;
m_sendCesHitRequestQueue.enqueue(requestTab);
if (m_sendCesHitRequestQueue.size() == 1)
{
DEBUG_LOG(m_logger) << "SendCesHitRequest: " << requestTab;
m_ddsHandler->ftcTab()->sendCesHitRequest(requestTab, this);
} // if
}
void HandlerNBC::sendParticipantEvent(const int aesItemId,
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantData,
const ProjectDataManagement::EventType eventType)
{
ParticipantManagement::TypeClass typeClass = m_handlerParticipant->typeClassFromTypeId(participantData.participantTypeId());
// can happen since the positions are collected for all participants (no check if it is a SupportEntity or similar)
if (typeClass == ParticipantManagement::TypeClass_def::Unit ||
typeClass == ParticipantManagement::TypeClass_def::SupportUnit ||
typeClass == ParticipantManagement::TypeClass_def::SupportEntity ||
typeClass == ParticipantManagement::TypeClass_def::Aircraft ||
typeClass == ParticipantManagement::TypeClass_def::Vessel ||
typeClass == ParticipantManagement::TypeClass_def::Unknown)
{
DEBUG_LOG(m_logger) << "Participant with id " << participantData.participantId()
<< " has invalid typeClass: " << typeClass
<< " eventType: " << eventType;
return;
}
if (!eventMustBeSend(aesItemId, participantData.participantId(), eventType))
{
if ( m_isInContaminatedRoom.contains(participantData.participantId()) && participantData.roomId() == 0) // Tln leaves Building
{
DEBUG_LOG(m_logger) << "Sending Event because Participant leaves Building";
}
else
{
DEBUG_LOG(m_logger) << "Not sending Event " << eventType << " for participant " << participantData.participantId()
<< " and aes " << aesItemId << " - already sent";
return;
}
}
// send hit events only with central AES Simulation
if (eventType == ProjectDataManagement::EventType_def::HitB
|| eventType == ProjectDataManagement::EventType_def::HitC
|| eventType == ProjectDataManagement::EventType_def::Hit
|| eventType == ProjectDataManagement::EventType_def::HitEffectSimulation
|| eventType == ProjectDataManagement::EventType_def::HitMine
|| eventType == ProjectDataManagement::EventType_def::HitN)
{
DEBUG_LOG(m_logger) << "send hit events only with central AES Simulation participant=" << participantData.participantId();
return;
}
int equipmentNumber = m_ddsHandler->participantId2EquipNo(participantData.participantId());
if (equipmentNumber <= 0)
{
WARNING_LOG(m_logger) << "Not sending Event " << eventType << " for participant " << participantData.participantId()
<< " - participant has no equipment number";
return;
}
DEBUG_LOG(m_logger) << "sendParticipantEvent" << eventType
<< " participantId=" << participantData.participantId()
<< " AesItemId=" << aesItemId;
CentralEffectSimulation::ParticipantEvent pe;
pe.id(m_ddsHandler->getParticipantEventId());
pe.eventTypeId(eventType.underlying());
pe.participantId(participantData.participantId());
pe.eventTime(participantData.sampleTime());
pe.aesItemId(aesItemId);
pe.partyId(participantData.partyId());
if (eventType == ProjectDataManagement::EventType_def::BCContamination)
{
const AreaEffectSimulation::BCContamination &bc = m_ddsHandler->dtcAes()->bCContamination(aesItemId);
pe.aesName(bc.name());
}
else if (eventType == ProjectDataManagement::EventType_def::DangerArea)
{
const AreaEffectSimulation::DangerArea &da = m_ddsHandler->dtcAes()->dangerArea(aesItemId);
pe.aesName(da.name());
}
else if (eventType == ProjectDataManagement::EventType_def::NContamination)
{
const AreaEffectSimulation::NContamination &nc = m_ddsHandler->dtcAes()->nContamination(aesItemId);
pe.aesName(nc.name());
}
pe.equipmentNumber(equipmentNumber);
pe.vulnerability(participantData.vulnerabilityState.underlying());
pe.position(participantData.pos());
AreaEffectSimulation::AesItem aesItem;
m_ddsHandler->dtcAes()->aesItemFromId(aesItemId, aesItem);
// Criterion for friendly Fire:
if (aesItem.partyId() != -1
&& ((eventType == ProjectDataManagement::EventType_def::EnterMineArea
|| eventType == ProjectDataManagement::EventType_def::EnterNuclear
|| eventType == ProjectDataManagement::EventType_def::HitB
|| eventType == ProjectDataManagement::EventType_def::HitC
|| eventType == ProjectDataManagement::EventType_def::Hit
|| eventType == ProjectDataManagement::EventType_def::HitEffectSimulation
|| eventType == ProjectDataManagement::EventType_def::HitMine
|| eventType == ProjectDataManagement::EventType_def::HitN)
&& aesItem.partyId() == participantData.partyId()))
pe.friendlyFire(true);
else
pe.friendlyFire(false);
INFO_LOG(m_logger) << "sendParticipantEvent: " << pe
<< ", currentMSecsSinceEpoch = " << QDateTime::currentMSecsSinceEpoch()
<< ", time difference = " << QDateTime::currentMSecsSinceEpoch() - pe.eventTime();
m_ddsHandler->dtsCes()->publish(pe);
const auto id = pe.id();
QTimer::singleShot(1 * 60 * 1000, this, [id, this]() { m_ddsHandler->dtsCes()->removeParticipantEventByKey(id); });
}
void HandlerNBC::sendEffectTypeEvent(const int aesItemId,
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantData,
EffectType effectType)
{
// Trefferereignis Sekundaerwirkung
int mineFieldBitIndex = 0;
if (!effectTypeMustBeSend(aesItemId,
participantData.participantId(),
effectType))
{
DEBUG_LOG(m_logger) << "Not sending EffectType event " << toString(effectType)
<< ", participant: " << participantData.participantId()
<< ", aesItemId: " << aesItemId
<< " - already sent";
return;
}
const int ctasEffectType = static_cast<int>(effectType) & 0xffff;
DEBUG_LOG(m_logger) << "Sending EffectType event " << toString(effectType)
<< ", participant: " << participantData.participantId()
<< ", aesItemId: " << aesItemId
<< ", ctasEffectType: " << ctasEffectType;
sendCesHitRequest(aesItemId,
participantData,
//effectTime >= 0 ? effectTime : participantPosition.sampleTime(),
QDateTime::currentMSecsSinceEpoch(),
ctasEffectType,
mineFieldBitIndex,
effectType);
}
bool HandlerNBC::eventMustBeSend(int aesItemId,
int participantId,
const ProjectDataManagement::EventType eventType)
{
// end enter-leave only once
QSet<ProjectDataManagement::EventType> &activeEvents = m_eventStates[aesItemId][participantId]; // reference!
// - only send event if it was not already sent
if (activeEvents.contains(eventType))
{
DEBUG_LOG(m_logger) << "activeEvents=" << eventType
<< " return false";
return false;
}
activeEvents.insert(eventType);
// - remove opposite events (e.g remove Enter event when we leave the area)
switch (eventType.underlying())
{
case ProjectDataManagement::EventType_def::EnterDangerArea:
activeEvents.remove(ProjectDataManagement::EventType_def::LeaveDangerArea);
break;
case ProjectDataManagement::EventType_def::LeaveDangerArea:
activeEvents.remove(ProjectDataManagement::EventType_def::EnterDangerArea);
break;
case ProjectDataManagement::EventType_def::EnterMineArea:
activeEvents.remove(ProjectDataManagement::EventType_def::LeaveMineArea);
break;
case ProjectDataManagement::EventType_def::LeaveMineArea:
activeEvents.remove(ProjectDataManagement::EventType_def::EnterMineArea);
break;
case ProjectDataManagement::EventType_def::EnterNuclear:
activeEvents.remove(ProjectDataManagement::EventType_def::LeaveNuclear);
break;
case ProjectDataManagement::EventType_def::LeaveNuclear:
activeEvents.remove(ProjectDataManagement::EventType_def::EnterNuclear);
break;
case ProjectDataManagement::EventType_def::EnterFunctionalArea:
case ProjectDataManagement::EventType_def::LeaveFunctionalArea:
default:
break;
}
DEBUG_LOG(m_logger) << "eventMustBeSend=true";
return true;
}
bool HandlerNBC::effectTypeMustBeSend(int aesItemId,
int participantId,
EffectType effectType)
{
DEBUG_LOG(m_logger) << "effectTypeMustBeSend"
<< " aesItemId= " << aesItemId
<< " participantId=" << participantId
<< " effectType=" << CES_NBC::toString(effectType);
// end enter-leave only once
QSet<EffectType> &activeEffects = m_effectTypeStates[aesItemId][participantId]; // reference!
// - only send event if it was not already sent
if (activeEffects.contains(effectType))
{
//DEBUG_LOG(m_logger) << "effectTypeStates already contains aesItemId " << aesItemId;
return false;
}
if ( (effectType == EffectType::NContaminationEnterArea1)
|| (effectType == EffectType::NContaminationEnterArea2))
{
if (activeEffects.contains(EffectType::NContaminationDetonation))
{
DEBUG_LOG(m_logger) << "effectTypeStates.contains(NContaminationDetonation) " << aesItemId
<< " return false";
return false;
}
}
activeEffects += effectType;
bool bMustBeSend = true;
switch (effectType)
{
case EffectType::NContaminationLeave:
bMustBeSend = false;
bMustBeSend |= activeEffects.remove(EffectType::NContaminationEnterArea1);
bMustBeSend |= activeEffects.remove(EffectType::NContaminationEnterArea2);
bMustBeSend |= activeEffects.remove(EffectType::NContaminationDetonation);
break;
case EffectType::NContaminationEnterArea1:
bMustBeSend = true;
activeEffects.remove(EffectType::NContaminationLeave);
activeEffects.remove(EffectType::NContaminationEnterArea2);
activeEffects.remove(EffectType::NContaminationDetonation);
break;
case EffectType::NContaminationEnterArea2:
bMustBeSend = true;
activeEffects.remove(EffectType::NContaminationLeave);
activeEffects.remove(EffectType::NContaminationEnterArea1);
activeEffects.remove(EffectType::NContaminationDetonation);
break;
case EffectType::NContaminationDetonation:
bMustBeSend = true;
activeEffects.remove(EffectType::NContaminationLeave);
activeEffects.remove(EffectType::NContaminationEnterArea1);
activeEffects.remove(EffectType::NContaminationEnterArea2);
break;
case EffectType::BCContaminationLeave:
bMustBeSend = false;
bMustBeSend |= activeEffects.remove(EffectType::BCContaminationEnterFloating);
bMustBeSend |= activeEffects.remove(EffectType::BCContaminationEnterResident);
bMustBeSend |= activeEffects.remove(EffectType::BCContaminationEnterFloatingArea);
break;
case EffectType::BCContaminationEnterFloating:
bMustBeSend = true;
activeEffects.remove(EffectType::BCContaminationLeave);
activeEffects.remove(EffectType::BCContaminationEnterResident);
activeEffects.remove(EffectType::BCContaminationEnterFloatingArea);
break;
case EffectType::BCContaminationEnterResident:
bMustBeSend = true;
activeEffects.remove(EffectType::BCContaminationLeave);
activeEffects.remove(EffectType::BCContaminationEnterFloating);
activeEffects.remove(EffectType::BCContaminationEnterFloatingArea);
break;
case EffectType::BCContaminationEnterFloatingArea:
bMustBeSend = true;
activeEffects.remove(EffectType::BCContaminationLeave);
activeEffects.remove(EffectType::BCContaminationEnterFloating);
activeEffects.remove(EffectType::BCContaminationEnterResident);
break;
case EffectType::EffectiveMineRangeEnter:
case EffectType::EffectiveMineRangeLeave:
case EffectType::FunctionalAreaLeave:
case EffectType::FunctionalAreaEnter:
case EffectType::ExplosionArea:
case EffectType::ExplosionSingle:
case EffectType::BeStillWarning:
case EffectType::Unknown:
break;
}
return bMustBeSend;
}
// Anmerkung: Im SFM werden Quadrate und keine Kreise genommen. ( Wird hier nach Absprache mit Manfred nicht gemacht)
bool HandlerNBC::inCircle(const QPointF &centerUtm, const double radius, const QPointF &pointUtm)
{
double squareDist = CentralEffectSimulation::getSquareDistance(centerUtm, pointUtm);
double squareRadius = radius * radius;
DEBUG_LOG(m_logger) << "squareDist: " << squareDist << ", squareRadius: " << squareRadius
<< " centerUtm=" << centerUtm.x() << "/" << centerUtm.y()
<< " pointUtm=" << pointUtm.x() << "/" << pointUtm.y()
<< " radius = " << radius
<< " dist=" << sqrt(squareDist);
return (squareDist < squareRadius);
} // inCircle
ProjectDataManagement::EventType HandlerNBC::leaveEventTypeForAesType(AreaEffectSimulation::AesType aesTypeId)
{
switch (aesTypeId.underlying())
{
case AreaEffectSimulation::AesType_def::AtDangerArea:
return ProjectDataManagement::EventType::LeaveDangerArea;
case AreaEffectSimulation::AesType_def::AtMineArea:
return ProjectDataManagement::EventType::LeaveMineArea;
case AreaEffectSimulation::AesType_def::AtNContamination:
return ProjectDataManagement::EventType::LeaveNuclear;
default:
break;
}
return ProjectDataManagement::EventType::Unknown;
}
EffectType HandlerNBC::leaveEffectTypeForAesType(AreaEffectSimulation::AesType aesTypeId)
{
switch (aesTypeId.underlying())
{
case AreaEffectSimulation::AesType_def::AtBCContamination:
return EffectType::BCContaminationLeave;
case AreaEffectSimulation::AesType_def::AtNContamination:
return EffectType::NContaminationLeave;
default:
break;
}
return EffectType::Unknown;
}
EffectType HandlerNBC::effectTypeForNContaminationArea(const CentralEffectSimulation::AesItemViewUtm &itemView,
const QPointF &participantPosUtmPoint,
qint64 partPosSampleTime,
const bool isIndoor)
{
const AreaEffectSimulation::NContamination &nc = m_ddsHandler->dtcAes()->nContamination(itemView.aesItemId);
auto utm = LtsCoordTrans::UtmCoordinate::fromGeographic(nc.impactPosition().lon(), nc.impactPosition().lat(), itemView.zone);
QPointF impactPositionUtm = QPointF(utm.x, utm.y);
DEBUG_LOG(m_logger) << "HandlerNBC::effectTypeForNContaminationArea itemView.radials.size()=" << itemView.radials.size();
if (itemView.radials.size() != 3)
return EffectType::NContaminationEnterArea2; // not yet known, we only know we're inside the area
DEBUG_LOG(m_logger) << "impactPositionUtm=" << impactPositionUtm.x() << "/" << impactPositionUtm.y()
<< " participantPosUtmPoint=" << participantPosUtmPoint.x() << "/" << participantPosUtmPoint.y();
const double squareDist = CentralEffectSimulation::getSquareDistance(impactPositionUtm, participantPosUtmPoint);
if (squareDist <= pow(itemView.radials.at(0), 2))
{
// 5s delay
DEBUG_LOG(m_logger) << "partPosSampleTime: " << partPosSampleTime
<< ", itemView.effectStart: " << itemView.effectStart;
if (partPosSampleTime < itemView.effectStart + 5000)
{
DEBUG_LOG(m_logger) << "return EffectType::NContaminationDetonation";
return EffectType::NContaminationDetonation;
}
DEBUG_LOG(m_logger) << "return EffectType::NContaminationEnterArea2";
return EffectType::NContaminationEnterArea2;
}
DEBUG_LOG(m_logger) << "squareDist=" << squareDist
<< " pow(itemView.radials.at(1), 2)=" << pow(itemView.radials.at(1), 2)
<< " itemView.radials.at(1)=" << itemView.radials.at(1);
// Bereich 1
if (squareDist <= pow(itemView.radials.at(1), 2))
{
DEBUG_LOG(m_logger) << "-------------- NContamination Bereich 1 ---------------------";
if ( isIndoor)
{
DEBUG_LOG(m_logger) << "NContaminationEnterArea1 indoor => NContaminationEnterArea2";
return EffectType::NContaminationEnterArea2;
}
DEBUG_LOG(m_logger) << "NContaminationEnterArea1";
return EffectType::NContaminationEnterArea1;
}
DEBUG_LOG(m_logger) << "squareDist=" << squareDist
<< " Dist=" << sqrt (squareDist )
<< " pow(itemView.radials.at(2), 2)=" << pow(itemView.radials.at(2), 2)
<< " itemView.radials.at(2)=" << itemView.radials.at(2);
// Bereich 2
if (squareDist <= pow(itemView.radials.at(2), 2))
{
DEBUG_LOG(m_logger) << "-------------- NContamination Bereich 2 ---------------------";
if ( isIndoor)
{
DEBUG_LOG(m_logger) << "NContaminationEnterArea2 indoor => NContaminationLeave";
return EffectType::NContaminationLeave;
}
DEBUG_LOG(m_logger) << "NContaminationEnterArea2";
return EffectType::NContaminationEnterArea2;
}
DEBUG_LOG(m_logger) << "NContaminationLeave";
return EffectType::NContaminationLeave;
}
EffectType HandlerNBC::effectTypeForBCContaminationArea(const CentralEffectSimulation::AesItemViewUtm &itemView,
const QPointF &participantPosUtmPoint)
{
if (itemView.radials.size() != 1)
return EffectType::BCContaminationEnterFloating;
// use real start point for non floating!
const auto &bcItem = m_ddsHandler->dtcAes()->bCContamination(itemView.aesItemId);
const auto utmImpcat = CentralEffectSimulation::geographic2Utm(bcItem.impactPosition(), itemView.zone);
const double squareDist = CentralEffectSimulation::getSquareDistance(utmImpcat, participantPosUtmPoint);
if (squareDist <= pow(itemView.radials.at(0), 2))
{
return EffectType::BCContaminationEnterResident; // first circle of resident contamination
}
return EffectType::BCContaminationEnterFloatingArea;
//return EffectType::BCContaminationEnterFloatingArea; // expanding/moving part of the contamination
}
void HandlerNBC::aesItemViewRemoved(int aesItemId)
{
const CentralEffectSimulation::AesItemViewUtm aiv = m_aesItemViews.value(aesItemId);
if (aiv.aesItemId == aesItemId)
{
const auto effectTypLeave = leaveEffectTypeForAesType(aiv.aesTypeId);
if (effectTypLeave != EffectType::Unknown)
{
DEBUG_LOG(m_logger) << "aesItemViewRemoved, leaveEffectType: " << toString(effectTypLeave);
auto it = m_effectTypeStates.find(aesItemId);
if (it != m_effectTypeStates.end())
{
const QHash<int, QSet<EffectType>> &participants = it.value();
DEBUG_LOG(m_logger) << "aesItemViewRemoved, sending leave events to " << participants.size()
<< " participants";
for (auto itP = participants.begin(); itP != participants.end(); ++ itP)
sendEffectTypeEvent(aesItemId, m_handlerParticipant->position(itP.key()), effectTypLeave);
}
}
const auto eventTypeLeave = leaveEventTypeForAesType(aiv.aesTypeId);
if (eventTypeLeave != ProjectDataManagement::EventType::Unknown)
{
DEBUG_LOG(m_logger) << "aesItemViewRemoved, leaveEventType: " << eventTypeLeave;
auto it = m_eventStates.find(aesItemId);
if (it != m_eventStates.end())
{
const QHash<int, QSet<ProjectDataManagement::EventType>> &participants = it.value();
DEBUG_LOG(m_logger) << "aesItemViewRemoved, sending leave events to " << participants.size()
<< " participants";
for (auto itP = participants.begin(); itP != participants.end(); ++ itP)
sendParticipantEvent(aiv.aesItemId, m_handlerParticipant->position(itP.key()), eventTypeLeave);
}
}
}
m_effectTypeStates.remove(aesItemId);
m_aesItemViews.remove(aesItemId);
m_explosionSingleStates.remove(aesItemId);
m_eventStates.remove(aesItemId);
} // END aesItemViewRemoved
// ///////////////////////////////////
// B L D (Buildings)
// ///////////////////////////////////
int HandlerNBC::getContaminationFromBuildingRoom(const int buildingId, const int roomId) const
{
DEBUG_LOG(m_logger) << "getContaminationFromBuildingRoom buildingId=" << buildingId
<< " roomId=" << roomId;
Buildings::BuildingState buildingState = m_ddsHandler->dtcBld()->buildingState(buildingId);
if (buildingState.contaminationStates().size() == 0 )
return 0;
if (buildingState.contaminationStates().size() == 0)
return 0;
for (unsigned int i = 0; i < buildingState.contaminationStates().size(); i++)
{
for (unsigned int j = 0; j < buildingState.contaminationStates()[i].rooms().size(); j++)
{
if (buildingState.contaminationStates()[i].rooms()[j] == roomId)
return buildingState.contaminationStates()[i].aesId();
}
}
return 0;
} // end of getContaminationFromBuildingRoom()
void HandlerNBC::onBuildingStateChanged(const Buildings::BuildingState &data, DataModification modType)
{
if (modType == DataModification::eRemoved)
{
return;
}
DEBUG_LOG(m_logger) << "Got BuildingState originatorParticipantId=" << data.originatorParticipantId()
<< ", aesId = " << data.aesId()
<< ", data.contaminationStates().size()=" << data.contaminationStates().size();
// Check each participant
const QHash<int, CentralEffectSimulation::HandlerParticipant::CesParticipantData> participantsMap = m_handlerParticipant->positions();
for (const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPos : participantsMap)
{
if (m_handlerParticipant->isOutdated(participantPos))
continue;
if (participantPos.buildingId() == 0)
continue;
int aesId = getContaminationFromBuildingRoom(participantPos.buildingId(), participantPos.roomId());
const CentralEffectSimulation::AesItemViewUtm itemView = m_aesItemViews.value(aesId);
QHash<int, bool> aesIds = m_participantAes.value(participantPos.participantId());
aesIds.insert(aesId, true);
m_participantAes.insert(participantPos.participantId(), aesIds);
onNewIndoorParticipantPosition(participantPos);
}
} // END onBuildingStateChanged
void HandlerNBC::onNewIndoorParticipantPosition(const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantData)
{
bool enterBuilding = false;
if ( m_lastRoomId.value(participantData.participantId()) == 0)
{
DEBUG_LOG(m_logger) << "m_lastRoomId Enter Building m_isInContaminatedRoom.contains participantId=" << participantData.participantId()
<< " roomId=" << participantData.roomId()
<< " m_isInContaminatedRoom. \nremove!!!!";
m_isInContaminatedRoom.remove(participantData.participantId());
m_lastRoomId.insert(participantData.participantId(), participantData.roomId());
enterBuilding = true;
}
else
{
DEBUG_LOG(m_logger) << "m_lastRoomId.contains(" << m_lastRoomId.contains(participantData.participantId())
<< " roomId=" << m_lastRoomId.value(participantData.participantId());
}
int aesId = getContaminationFromBuildingRoom(participantData.buildingId(), participantData.roomId());
DEBUG_LOG(m_logger) << "++++++++ onNewIndoorParticipantPosition participantId=" << participantData.participantId()
<< " buildingId=" << participantData.buildingId()
<< " roomId=" << participantData.roomId()
<< " reportingSource=" << participantData.reportingSource()
<< " Raum ist Kontaminiert: aesId=" << aesId;
if ( aesId == 0)
{
onNewOutdoorParticipantPosition(participantData);
return;
}
if (enterBuilding)
{
QHash<int, QSet<EffectType>> effectTypeHash = m_effectTypeStates.value(aesId);
if ( effectTypeHash.contains(participantData.participantId()))
{
effectTypeHash.remove(participantData.participantId());
}
m_effectTypeStates.insert(aesId, effectTypeHash);
}
DEBUG_LOG(m_logger) << "aesId=" << aesId;
if (aesId > 0 && !m_aesItemViews.contains(aesId))
{
DEBUG_LOG(m_logger) << "m_isInContaminatedRoom insert participantId=" << participantData.participantId()
<< " aesId=" << aesId;
m_isInContaminatedRoom.insert(participantData.participantId(), aesId);
}
if (aesId > 0)
{
AreaEffectSimulation::AesItemView aesItemView;
m_ddsHandler->dtcAes()->aesItemViewFromEntityId(aesId,AreaEffectSimulation::AesType::AtUnknown, aesItemView );
AreaEffectSimulation::AesType aesTypeId = aesItemView.aesTypeId();
DEBUG_LOG(m_logger) << "onNewIndoorParticipantPosition sendEnterEvent aesTypeId=" << aesTypeId;
sendEnterEvent(aesId,aesTypeId, participantData, true);
}
else
{
if (m_participantAes.contains(participantData.participantId()))
{
QHash<int, bool> aesIds = m_participantAes.value(participantData.participantId());
// leave aesArea
QHashIterator<int, bool> i(aesIds);
while (i.hasNext())
{
i.next();
CentralEffectSimulation::AesItemViewUtm itemView;
itemView = m_aesItemViews.value(i.key());
if (itemView.aesItemId > 0)
sendLeaveEvent(itemView.aesItemId, participantData);
}
}
}
} // onNewIndoorParticipantPosition
} // namespace CES_NBC