1538 lines
65 KiB
C++
Executable File
1538 lines
65 KiB
C++
Executable File
/**
|
|
* Handler for player data
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by gr, SLSE, 2017-02-20
|
|
*/
|
|
|
|
#include "handler_participant_area.h"
|
|
#include "settings.h"
|
|
#include "CentralEffectSimulation/handler_participant.h"
|
|
|
|
|
|
#include <LtsUtilsCore/dds_bitarray.h>
|
|
#include <LtsCoordTrans/lts_coord_trans.h>
|
|
#include <ProjectDataManagement/pdm_enums.hpp>
|
|
#include <cmath>
|
|
|
|
#include <QTimer>
|
|
#include <QDateTime>
|
|
|
|
namespace dds
|
|
{
|
|
namespace core
|
|
{
|
|
inline uint qHash(ProjectDataManagement::EventType et)
|
|
{
|
|
return ::qHash(et.underlying());
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace Ces2D
|
|
{
|
|
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));
|
|
}
|
|
|
|
|
|
HandlerParticipantArea::HandlerParticipantArea(const std::shared_ptr<CentralEffectSimulation::DdsHandler> &ddsHandler,
|
|
const std::shared_ptr<CentralEffectSimulation::HandlerParticipant> &participantHandler,
|
|
const std::shared_ptr<HandlerAesData> &aesDataHandler,
|
|
const std::shared_ptr<HandlerBuildingModel> &buildingModelHandler,
|
|
QObject *parent)
|
|
: QObject(parent)
|
|
, m_ddsHandler(ddsHandler)
|
|
, m_handlerParticipant(participantHandler)
|
|
, m_handlerAesData(aesDataHandler)
|
|
, m_handlerBuildingModel(buildingModelHandler)
|
|
, m_logger(getLogger("HandlerParticipantArea"))
|
|
{
|
|
} // end of ctor()
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HandlerParticipantArea::~HandlerParticipantArea()
|
|
{
|
|
} // end of dtor()
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool HandlerParticipantArea::init()
|
|
{
|
|
auto dtcAes = m_ddsHandler->dtcAes();
|
|
|
|
DEBUG_LOG(m_logger) << "Settings::calculateCentralAes() =" << Settings::calculateCentralAes();
|
|
|
|
dtcAes->enableBCContamination();
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::bCContaminationChanged,
|
|
this, &HandlerParticipantArea::onBCContaminationChanged);
|
|
|
|
dtcAes->enableNContamination();
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::nContaminationChanged,
|
|
this, &HandlerParticipantArea::onNContaminationChanged);
|
|
|
|
dtcAes->enableTriggeredImpacts();
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::triggeredImpactsChanged,
|
|
this, &HandlerParticipantArea::onTriggeredImpactsChanged);
|
|
|
|
dtcAes->enableExplosionArea();
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::explosionAreaChanged,
|
|
this, &HandlerParticipantArea::onExplosionAreaChanged);
|
|
|
|
dtcAes->enableExplosionSingle();
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::explosionSingleChanged,
|
|
this, &HandlerParticipantArea::onExplosionSingleChanged);
|
|
|
|
dtcAes->enableExplosionSingleCentral();
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::explosionSingleCentralChanged,
|
|
this, &HandlerParticipantArea::onExplosionSingleCentralChanged);
|
|
|
|
dtcAes->enableAesItemView();
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
|
|
this, &HandlerParticipantArea::onAesItemViewChanged);
|
|
|
|
dtcAes->enableDusSingleMine();
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::dusSingleMineChanged,
|
|
this, &HandlerParticipantArea::onDusSingleMineChanged);
|
|
|
|
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::newIndoorPosition,
|
|
this, &HandlerParticipantArea::calculateAesParticipant);
|
|
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::newOutdoorPosition,
|
|
this, &HandlerParticipantArea::calculateAesParticipant);
|
|
|
|
// 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 explosionAreas
|
|
{
|
|
auto cb = [this](const AreaEffectSimulation::NContamination & nc)
|
|
{
|
|
onNContaminationChanged(nc, DataModification::eAdded);
|
|
};
|
|
if (!dtcAes->nContaminations(cb))
|
|
return false;
|
|
}
|
|
|
|
// Get 'static' data for all explosionSingle
|
|
{
|
|
auto cb = [this](const AreaEffectSimulation::ExplosionSingle & es)
|
|
{
|
|
onExplosionSingleChanged(es, DataModification::eAdded);
|
|
};
|
|
if (!dtcAes->explosionSingles(cb))
|
|
return false;
|
|
}
|
|
|
|
// Get 'static' data for all explosionSingleCentral
|
|
{
|
|
auto cb = [this](const AreaEffectSimulation::ExplosionSingleCentral & esc)
|
|
{
|
|
onExplosionSingleCentralChanged(esc, DataModification::eAdded);
|
|
};
|
|
if (!dtcAes->explosionSingleCentrals(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;
|
|
}
|
|
|
|
// Get 'static' data for all DusSingleMines
|
|
{
|
|
auto cb = [this](const AreaEffectSimulation::DusSingleMine & fa)
|
|
{
|
|
onDusSingleMineChanged(fa, DataModification::eAdded);
|
|
};
|
|
if (!dtcAes->dusSingleMines(cb))
|
|
return false;
|
|
}
|
|
// Get 'static' data for all explosionAreas
|
|
{
|
|
auto cb = [this](const AreaEffectSimulation::ExplosionArea & ea)
|
|
{
|
|
onExplosionAreaChanged(ea, DataModification::eAdded);
|
|
};
|
|
if (!dtcAes->explosionAreas(cb))
|
|
return false;
|
|
}
|
|
|
|
INFO_LOG(m_logger) << "HandlerParticipantArea::init() finished.";
|
|
return true;
|
|
} // end of init()
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void HandlerParticipantArea::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 FunctionsArea 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 HandlerParticipantArea::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
|
|
{
|
|
// not needed, handled through HandlerParticipantGasPipe
|
|
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtGasPipe)
|
|
return;
|
|
|
|
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtUnknown)
|
|
return;
|
|
|
|
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtBoobyTrap)
|
|
return;
|
|
|
|
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtOffRouteMine)
|
|
return;
|
|
|
|
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary)
|
|
return;
|
|
|
|
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtMineArea)
|
|
return;
|
|
|
|
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtMineCorridor)
|
|
return;
|
|
|
|
if (m_ddsHandler->isSmartChargeType(data.chargeTypeId()))
|
|
{
|
|
DEBUG_LOG(m_logger) << "isSmartType = TRUE";
|
|
return;
|
|
}
|
|
|
|
const int aesItemId = data.aesItemId();
|
|
DEBUG_LOG(m_logger) << "Got AesItemView id: " << aesItemId
|
|
<< ", type: " << data.aesTypeId()
|
|
<< ", effectState: " << data.effectStateId()
|
|
<< ", modType: " << modType;
|
|
|
|
if (modType == DataModification::eRemoved)
|
|
{
|
|
aesItemViewRemoved(aesItemId);
|
|
return;
|
|
}
|
|
|
|
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtMineAreaSingleMines)
|
|
{
|
|
// build Polygon Mines:
|
|
auto &formMines = m_aesItemViews[data.aesItemId()].formMines;
|
|
int &zone = m_aesItemViews[data.aesItemId()].zone;
|
|
formMines.clear();
|
|
formMines.reserve(data.form().size());
|
|
for (const Core::GeoPosition2D &pointGeo : data.form())
|
|
formMines.push_back(CentralEffectSimulation::geographic2Utm(pointGeo, &zone));
|
|
return;
|
|
}
|
|
|
|
const AreaEffectSimulation::AesEffectState &effectState = data.effectStateId();
|
|
const double impactRadius = m_ddsHandler->chargeTypeRadius(data.chargeTypeId());
|
|
DEBUG_LOG(m_logger) << "impactRadius=" << impactRadius;
|
|
switch (effectState.underlying())
|
|
{
|
|
case AreaEffectSimulation::AesEffectState_def::EsPrepared:
|
|
{
|
|
m_aesItemViews.insert(data.aesItemId(), CentralEffectSimulation::AesItemViewUtm::create(data, m_aesItemViews[data.aesItemId()], impactRadius));
|
|
break;
|
|
}
|
|
case AreaEffectSimulation::AesEffectState_def::EsActivated:
|
|
{
|
|
const auto aesItemViewUtm(CentralEffectSimulation::AesItemViewUtm::create(data, m_aesItemViews[data.aesItemId()], impactRadius));
|
|
|
|
switch (data.aesTypeId().underlying())
|
|
{
|
|
case AreaEffectSimulation::AesType_def::AtExplosionArea:
|
|
case AreaEffectSimulation::AesType_def::AtExplosionSingle:
|
|
case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions:
|
|
case AreaEffectSimulation::AesType_def::AtMineArea:
|
|
case AreaEffectSimulation::AesType_def::AtAirSupportImpact:
|
|
m_aesItemViews.insert(data.aesItemId(), aesItemViewUtm);
|
|
break;
|
|
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);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
|
|
case AreaEffectSimulation::AesType_def::AtDangerArea:
|
|
calculateFunctionArea(aesItemViewUtm);
|
|
m_aesItemViews.insert(data.aesItemId(), aesItemViewUtm);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtUnknown:
|
|
case AreaEffectSimulation::AesType_def::AtMineCorridor:
|
|
case AreaEffectSimulation::AesType_def::AtBorderline:
|
|
case AreaEffectSimulation::AesType_def::AtReconArea:
|
|
case AreaEffectSimulation::AesType_def::AtTechnicalArea:
|
|
case AreaEffectSimulation::AesType_def::AtDusSingleMine:
|
|
case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines:
|
|
case AreaEffectSimulation::AesType_def::AtGasPipe:
|
|
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentral:
|
|
case AreaEffectSimulation::AesType_def::AtExplosionSingleCentralTrajectory:
|
|
case AreaEffectSimulation::AesType_def::AtBoobyTrap:
|
|
case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary:
|
|
case AreaEffectSimulation::AesType_def::AtOffRouteMine:
|
|
case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary:
|
|
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 HandlerParticipantArea::onDusSingleMineChanged(const AreaEffectSimulation::DusSingleMine &data, DataModification modType)
|
|
{
|
|
switch (modType)
|
|
{
|
|
case DataModification::eRemoved:
|
|
break;
|
|
case DataModification::eAdded:
|
|
case DataModification::eModified:
|
|
switch (data.effectStateId().underlying())
|
|
{
|
|
case AreaEffectSimulation::AesEffectState_def::EsActivated:
|
|
{
|
|
//DEBUG_LOG(m_logger) << "Got onDusSingleMineChanged data.id()=" << data.id();
|
|
CentralEffectSimulation::AesItemViewUtm itemView;
|
|
itemView.aesItemId = data.id();
|
|
itemView.chargeTypeId = data.chargeTypeId();
|
|
itemView.partyId = data.partyId().is_set() ? data.partyId().get() : -1;
|
|
itemView.aesTypeId = AreaEffectSimulation::AesType_def::AtDusSingleMine;
|
|
itemView.effectStart = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch();
|
|
itemView.formMines.push_back(CentralEffectSimulation::geographic2Utm(data.position(), &itemView.zone));
|
|
itemView.dusMineId = data.mineId();
|
|
m_aesItemViews[itemView.aesItemId] = itemView;
|
|
AreaEffectSimulation::TriggeredImpacts ti;
|
|
ti.aesItemId(itemView.aesItemId);
|
|
ti.bitfield().resize(1, 0xff);
|
|
m_triggeredImpacts[itemView.aesItemId] = ti;
|
|
break;
|
|
}
|
|
case AreaEffectSimulation::AesEffectState_def::EsPrepared:
|
|
case AreaEffectSimulation::AesEffectState_def::EsExpired:
|
|
case AreaEffectSimulation::AesEffectState_def::EsRemoved:
|
|
m_aesItemViews.remove(data.id());
|
|
break;
|
|
default:
|
|
// Nothing
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void HandlerParticipantArea::onBCContaminationChanged(const AreaEffectSimulation::BCContamination &data, DataModification modType)
|
|
{
|
|
switch (modType)
|
|
{
|
|
case DataModification::eRemoved:
|
|
break;
|
|
case DataModification::eAdded:
|
|
case DataModification::eModified:
|
|
switch (data.effectStateId().underlying())
|
|
{
|
|
case AreaEffectSimulation::AesEffectState_def::EsReceived:
|
|
case AreaEffectSimulation::AesEffectState_def::EsCreated:
|
|
case AreaEffectSimulation::AesEffectState_def::EsPrepared:
|
|
case AreaEffectSimulation::AesEffectState_def::EsActivated:
|
|
{
|
|
CentralEffectSimulation::AesItemViewUtm &ref = m_aesItemViews[data.id()];
|
|
const auto dtcPdm = m_ddsHandler->dtcPdm();
|
|
if (dtcPdm->volatilityTypeId(data.chargeTypeId()) == ProjectDataManagement::VolatilityType_def::Resident)
|
|
{
|
|
ref.radials = {data.impactRadius()};
|
|
ref.center = CentralEffectSimulation::geographic2Utm(data.impactPosition(), &ref.zone);
|
|
}
|
|
else
|
|
ref.radials.clear();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerParticipantArea::onNContaminationChanged(const AreaEffectSimulation::NContamination &data, DataModification modType)
|
|
{
|
|
switch (modType)
|
|
{
|
|
case DataModification::eRemoved:
|
|
break;
|
|
case DataModification::eAdded:
|
|
case DataModification::eModified:
|
|
switch (data.effectStateId().underlying())
|
|
{
|
|
case AreaEffectSimulation::AesEffectState_def::EsReceived:
|
|
case AreaEffectSimulation::AesEffectState_def::EsCreated:
|
|
case AreaEffectSimulation::AesEffectState_def::EsPrepared:
|
|
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);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerParticipantArea::calculateBcContamination(const CentralEffectSimulation::AesItemViewUtm &itemView)
|
|
{
|
|
DEBUG_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)) // Participant Position is not valid Todo Magic Number
|
|
continue;
|
|
inFormCheck(itemView, participantPos);
|
|
} // for
|
|
} // calculateBcContamination
|
|
|
|
void HandlerParticipantArea::calculateFunctionArea(const CentralEffectSimulation::AesItemViewUtm &itemView)
|
|
{
|
|
DEBUG_LOG(m_logger) << "HandlerParticipantArea::calculateFunctionArea aesItemId =" << itemView.aesItemId;
|
|
const auto partPosMap = m_handlerParticipant->positions();
|
|
for (const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPos : partPosMap)
|
|
{
|
|
if (m_handlerParticipant->isOutdated(participantPos))
|
|
continue;
|
|
inFormCheck(itemView, participantPos);
|
|
}
|
|
} // calculateFunctionArea
|
|
|
|
void HandlerParticipantArea::deleteFunctionalArea(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)
|
|
{
|
|
if (m_handlerParticipant->isOutdated(participantPos))
|
|
continue;
|
|
// Same as leave FunctionArea
|
|
if (itemView.aesTypeId == AreaEffectSimulation::AesType_def::AtFunctionalArea)
|
|
{
|
|
sendParticipantEvent(itemView, participantPos, ProjectDataManagement::EventType_def::LeaveFunctionalArea);
|
|
sendEffectTypeEvent(itemView, participantPos, EffectType::FunctionalAreaLeave, -1, -1);
|
|
}
|
|
else
|
|
sendParticipantEvent(itemView, participantPos, ProjectDataManagement::EventType_def::LeaveDangerArea);
|
|
DEBUG_LOG(m_logger) << "Participant inside id=" << participantPos.participantId();
|
|
} // for all Participants
|
|
} // deleteFunctionalArea
|
|
|
|
void HandlerParticipantArea::calculateAesParticipant(const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPos)
|
|
{
|
|
if (m_handlerParticipant->isOutdated(participantPos))
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "HandlerParticipantArea::calculateAesParticipant paricipantId: " << participantPos.participantId();
|
|
for (const CentralEffectSimulation::AesItemViewUtm &itemView : qAsConst(m_aesItemViews))
|
|
{
|
|
DEBUG_LOG(m_logger) << " itemView: " << itemView.aesItemId << ", " << itemView.aesTypeId;
|
|
switch (itemView.aesTypeId.underlying())
|
|
{
|
|
case AreaEffectSimulation::AesType_def::AtMineArea:
|
|
if (inFormCheck(itemView, participantPos))
|
|
// Check, if Participant is in a circle of mine
|
|
inMineRadiusCheck(itemView, participantPos);
|
|
else
|
|
// no longer in mine area - reset all EffectiveMineRangeEnter mineIndexes
|
|
m_effectTypeBitFieldIndexes[itemView.aesItemId][participantPos.participantId()].clear();
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines:
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtDusSingleMine:
|
|
inMineRadiusCheck(itemView, participantPos);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtBCContamination:
|
|
case AreaEffectSimulation::AesType_def::AtNContamination:
|
|
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
|
|
case AreaEffectSimulation::AesType_def::AtDangerArea:
|
|
inFormCheck(itemView, participantPos);
|
|
break;
|
|
default:
|
|
// nothing
|
|
break;
|
|
} // switch
|
|
} // for
|
|
} // calculateAesParticipant
|
|
|
|
|
|
|
|
// return true, if participant is inside of the dangerous area of a mine
|
|
bool HandlerParticipantArea::inMineRadiusCheck(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition)
|
|
{
|
|
int32_t bitFieldIdx = 0;
|
|
const double impactRadius = m_ddsHandler->chargeTypeRadius(itemView.chargeTypeId);
|
|
const AreaEffectSimulation::TriggeredImpacts &triggeredImpact = m_triggeredImpacts[itemView.aesItemId];
|
|
const QPointF participantPosUtmPoint = CentralEffectSimulation::geographic2Utm(participantPosition.pos(), itemView.zone);
|
|
bool bOutOfBounds = false;
|
|
for (const auto &itPos : itemView.formMines)
|
|
{
|
|
DEBUG_LOG(m_logger) << "participantPositionUtm: " << CentralEffectSimulation::debug(participantPosUtmPoint)
|
|
<< ", MinePosUtm: " << CentralEffectSimulation::debug(itPos);
|
|
// Check, if mine is active
|
|
// already triggered (bit is already 0)
|
|
if (!LtsUtils::BitArray::testBit(triggeredImpact.bitfield(), bitFieldIdx) && !bOutOfBounds)
|
|
{
|
|
++bitFieldIdx;
|
|
continue;
|
|
}
|
|
|
|
const int mineIdx = (itemView.aesTypeId == AreaEffectSimulation::AesType_def::AtDusSingleMine)
|
|
? itemView.dusMineId : bitFieldIdx + 1; // mineIdx in minefield starts at 1
|
|
|
|
// Check, if participant is inside danger-radius of the mine
|
|
if (inCircle(itPos, impactRadius, participantPosUtmPoint))
|
|
{
|
|
DEBUG_LOG(m_logger) << "Mine Hit for aesItemId: " << itemView.aesItemId
|
|
<< ", mineIdx: " << mineIdx
|
|
<< ", participantId: " << participantPosition.participantId();
|
|
sendEffectTypeEvent(itemView, participantPosition, EffectType::EffectiveMineRangeEnter, mineIdx, -1);
|
|
}
|
|
else
|
|
sendEffectTypeEvent(itemView, participantPosition, EffectType::EffectiveMineRangeLeave, mineIdx, -1);
|
|
bitFieldIdx++;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// return true, if participant is inside of the bounding Box
|
|
bool HandlerParticipantArea::inBoundingBoxCheck(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition)
|
|
{
|
|
if (itemView.effectStateId != AreaEffectSimulation::AesEffectState_def::EsActivated)
|
|
return false;
|
|
|
|
if (m_handlerParticipant->isOutdated(participantPosition)) // Participant Position is not valid Todo Magic Number
|
|
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(participantPosition.pos(), itemView.zone);
|
|
if (boundingBoxImpact.contains(participantPosUtmPoint))
|
|
{
|
|
DEBUG_LOG(m_logger) << "inBoundingBoxCheck Paricipant " << participantPosition.participantId()
|
|
<< " inside AesItemView:" << itemView.aesItemId;
|
|
return true;
|
|
}
|
|
TRACE_LOG(m_logger) << "inBoundingBoxCheck Paricipant " << participantPosition.participantId()
|
|
<< " outside AesItemView:" << itemView.aesItemId;
|
|
return false;
|
|
}
|
|
|
|
// return true, if participant is inside of the form of AesItemView
|
|
bool HandlerParticipantArea::inFormCheck(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition)
|
|
{
|
|
if (itemView.effectStateId != AreaEffectSimulation::AesEffectState_def::EsActivated)
|
|
return false;
|
|
|
|
if (m_handlerParticipant->isOutdated(participantPosition)) // Participant Position is not valid
|
|
return false;
|
|
|
|
const QRectF boundingBoxImpact(itemView.boundingBoxBottomLeft,
|
|
itemView.boundingBoxTopRight);
|
|
const QPointF participantPosUtmPoint = CentralEffectSimulation::geographic2Utm(participantPosition.pos(), itemView.zone);
|
|
const QString participantPosMgrs = CentralEffectSimulation::geographic2mgrs(participantPosition.pos(), itemView.zone);
|
|
DEBUG_LOG(m_logger) << "inFormCheck start, paricipantId: " << participantPosition.participantId()
|
|
<< ", aesItemId: " << itemView.aesItemId
|
|
<< ", aesTypeId: " << itemView.aesTypeId
|
|
<< ", form.size: " << itemView.form.size()
|
|
<< ", Mgrs:" << participantPosMgrs;
|
|
|
|
if (boundingBoxImpact.contains(participantPosUtmPoint) &&
|
|
itemView.form.containsPoint(participantPosUtmPoint, Qt::FillRule::OddEvenFill))
|
|
{
|
|
DEBUG_LOG(m_logger) << "inside AES form, paricipantId: " << participantPosition.participantId()
|
|
<< ", aesItemId: " << itemView.aesItemId;
|
|
switch (itemView.aesTypeId.underlying())
|
|
{
|
|
case AreaEffectSimulation::AesType_def::AtBCContamination:
|
|
sendEffectTypeEvent(itemView, participantPosition, effectTypeForBCContaminationArea(itemView, participantPosUtmPoint), -1, -1);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtDangerArea:
|
|
sendParticipantEvent(itemView, participantPosition, ProjectDataManagement::EventType_def::EnterDangerArea);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtExplosionArea:
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
|
|
sendParticipantEvent(itemView, participantPosition, ProjectDataManagement::EventType_def::EnterFunctionalArea);
|
|
sendEffectTypeEvent(itemView, participantPosition, EffectType::FunctionalAreaEnter, -1, -1);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtMineArea:
|
|
sendParticipantEvent(itemView, participantPosition, ProjectDataManagement::EventType_def::EnterMineArea);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtNContamination:
|
|
sendParticipantEvent(itemView, participantPosition, ProjectDataManagement::EventType_def::EnterNuclear);
|
|
sendEffectTypeEvent(itemView, participantPosition, effectTypeForNContaminationArea(itemView, participantPosUtmPoint, participantPosition.sampleTime()), -1, -1);
|
|
break;
|
|
default:
|
|
INFO_LOG(m_logger) << "inFormCheck Unhandled AES-Type" << itemView.aesTypeId;
|
|
break;
|
|
}
|
|
return true;
|
|
} // if inside
|
|
|
|
// outside
|
|
switch (itemView.aesTypeId.underlying())
|
|
{
|
|
case AreaEffectSimulation::AesType_def::AtBCContamination:
|
|
sendEffectTypeEvent(itemView, participantPosition, EffectType::BCContaminationLeave, -1, -1);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtDangerArea:
|
|
sendParticipantEvent(itemView, participantPosition, ProjectDataManagement::EventType_def::LeaveDangerArea);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtExplosionArea:
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
|
|
sendParticipantEvent(itemView, participantPosition, ProjectDataManagement::EventType_def::LeaveFunctionalArea);
|
|
sendEffectTypeEvent(itemView, participantPosition, EffectType::FunctionalAreaLeave, -1, -1);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtMineArea:
|
|
sendParticipantEvent(itemView, participantPosition, ProjectDataManagement::EventType_def::LeaveMineArea);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtNContamination:
|
|
sendParticipantEvent(itemView, participantPosition, ProjectDataManagement::EventType_def::LeaveNuclear);
|
|
sendEffectTypeEvent(itemView, participantPosition, EffectType::NContaminationLeave, -1, -1);
|
|
break;
|
|
default:
|
|
break;
|
|
} // end switch
|
|
#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;
|
|
}
|
|
|
|
|
|
void HandlerParticipantArea::onTriggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType)
|
|
{
|
|
if (modType != DataModification::eAdded &&
|
|
modType != DataModification::eModified)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "Got TriggeredImpacts: " << data;
|
|
switch (data.aesTypeId().underlying())
|
|
{
|
|
case AreaEffectSimulation::AesType_def::AtExplosionArea:
|
|
case AreaEffectSimulation::AesType_def::AtExplosionSingle:
|
|
case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions:
|
|
// explosion at the position of participant
|
|
calculateImpacts(data);
|
|
break;
|
|
case AreaEffectSimulation::AesType_def::AtMineAreaSingleMines:
|
|
case AreaEffectSimulation::AesType_def::AtMineArea:
|
|
// participant run on mine
|
|
// => store Mine-State and take into account when a participant runs to one of this mines
|
|
m_triggeredImpacts.insert(data.aesItemId(), data);
|
|
break;
|
|
default:
|
|
//nothigng
|
|
break;
|
|
}
|
|
} // onTriggeredImpactsChanged
|
|
|
|
void HandlerParticipantArea::onExplosionAreaChanged(const AreaEffectSimulation::ExplosionArea &data, DataModification modType)
|
|
{
|
|
if (modType != DataModification::eAdded &&
|
|
modType != DataModification::eModified)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "Got ExplosionArea, m_aesItemId2partIdMap.insert " << data.id() << " / " << data.participantId();
|
|
if (data.participantId().is_set())
|
|
m_aesItemId2partIdMap.insert(data.id(), data.participantId().get());
|
|
else
|
|
m_aesItemId2partIdMap.remove(data.id());
|
|
} // onExplosionAreaChanged
|
|
|
|
|
|
void HandlerParticipantArea::onExplosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType)
|
|
{
|
|
|
|
bool handleExplosion = false;
|
|
|
|
if (m_ddsHandler->isSmartChargeType(data.chargeTypeId()))
|
|
{
|
|
DEBUG_LOG(m_logger) << "isSmartType = TRUE";
|
|
return;
|
|
}
|
|
|
|
if (modType != DataModification::eAdded &&
|
|
modType != DataModification::eModified)
|
|
return;
|
|
|
|
if (data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsRemoved)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Remove SingleExplosion";
|
|
m_explosionSingleStates.remove(data.id());
|
|
return;
|
|
}
|
|
// Only handle transitions from prepared or fired to activated
|
|
if ((m_explosionSingleStates.value(data.id()) == AreaEffectSimulation::AesEffectState_def::EsPrepared ||
|
|
m_explosionSingleStates.value(data.id()) == AreaEffectSimulation::AesEffectState_def::EsFired) &&
|
|
data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Handle SingleExplosion";
|
|
handleExplosion = true;
|
|
}
|
|
m_explosionSingleStates.insert(data.id(), data.effectStateId());
|
|
|
|
if (!handleExplosion)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "isSmartType = " << m_ddsHandler->isSmartChargeType(data.chargeTypeId());
|
|
if (m_ddsHandler->isSmartChargeType(data.chargeTypeId()))
|
|
{
|
|
DEBUG_LOG(m_logger) << "isSmartType = TRUE";
|
|
}
|
|
else
|
|
{
|
|
int impactPosZone = -1;
|
|
const QPointF impactPos(CentralEffectSimulation::geographic2Utm(data.impactPosition(), &impactPosZone));
|
|
const CentralEffectSimulation::AesItemViewUtm itemView = m_aesItemViews.value(data.id());
|
|
const double impactRadius = m_ddsHandler->chargeTypeRadius(data.chargeTypeId());
|
|
DEBUG_LOG(m_logger) << "Handle ExplosionSingle (EsActivated)";
|
|
const auto participantPositions = m_handlerParticipant->positions();
|
|
for (const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition : participantPositions)
|
|
{
|
|
if (participantPosition.insideBuilding())
|
|
continue;
|
|
|
|
if (m_handlerParticipant->isOutdated(participantPosition))
|
|
continue;
|
|
|
|
const QPointF participantPosUtm = CentralEffectSimulation::geographic2Utm(participantPosition.pos(), impactPosZone);
|
|
DEBUG_LOG(m_logger) << "impact pos: " << CentralEffectSimulation::debug(impactPos)
|
|
<< " with radius " << impactRadius
|
|
<< " and participant position " << CentralEffectSimulation::debug(participantPosUtm);
|
|
if (inCircle(impactPos, impactRadius, participantPosUtm))
|
|
{
|
|
DEBUG_LOG(m_logger) << "participantId = " << participantPosition.participantId() << " inCircle = true";
|
|
sendEffectTypeEvent(itemView, participantPosition, EffectType::ExplosionSingle, -1, QDateTime::currentMSecsSinceEpoch());
|
|
}
|
|
else
|
|
DEBUG_LOG(m_logger) << "participantId = " << participantPosition.participantId() << " inCircle = false";
|
|
}
|
|
}
|
|
} // onExplosionSingleChanged
|
|
|
|
void HandlerParticipantArea::onExplosionSingleCentralChanged(const AreaEffectSimulation::ExplosionSingleCentral &data, DataModification modType)
|
|
{
|
|
if (modType != DataModification::eAdded && modType != DataModification::eModified)
|
|
return;
|
|
|
|
if (data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsRemoved) // EsExpired? EsError? EsUnknown?
|
|
{
|
|
DEBUG_LOG(m_logger) << "Remove ExplosionSingleCentral with aesId = " << data.id();
|
|
m_explosionSingleCentralStates.remove(data.id());
|
|
return;
|
|
} // if
|
|
|
|
if ((m_explosionSingleCentralStates.value(data.id()) != AreaEffectSimulation::AesEffectState_def::EsPrepared &&
|
|
m_explosionSingleCentralStates.value(data.id()) != AreaEffectSimulation::AesEffectState_def::EsFired) ||
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsActivated)
|
|
{
|
|
m_explosionSingleCentralStates.insert(data.id(), data.effectStateId());
|
|
return;
|
|
} // if
|
|
|
|
m_explosionSingleCentralStates.insert(data.id(), data.effectStateId());
|
|
DEBUG_LOG(m_logger) << "Handle ExplosionSingleCentral with aesId = " << data.id();
|
|
|
|
// pre-calculate geometric data
|
|
const AreaEffectSimulation::AesItemView &itemView = m_handlerAesData->itemView(data.id());
|
|
const Core::GeoPosition ¢erGeo = itemView.form().front();
|
|
const LtsCoordTrans::UtmCoordinate centerUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(centerGeo.lon(), centerGeo.lat());
|
|
const LtsUtils::QPoint3D center(centerUtm.x, centerUtm.y, centerGeo.z());
|
|
const Core::GeoPosition &pointOnSphereGeo = itemView.form().back();
|
|
const LtsCoordTrans::UtmCoordinate pointOnSphereUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(pointOnSphereGeo.lon(), pointOnSphereGeo.lat());
|
|
const LtsUtils::QPoint3D pointOnSphere(pointOnSphereUtm.x, pointOnSphereUtm.y, pointOnSphereGeo.z());
|
|
const double radiusSquared = (center - pointOnSphere).lengthSquared();
|
|
|
|
const int effectType = static_cast<int>(EffectType::ExplosionSingle) & 0xffff;
|
|
const QMap<int, BuildingModel *> buildingModels = m_handlerBuildingModel->buildingModels();
|
|
const QList<CentralEffectSimulation::HandlerParticipant::CesParticipantData> participantPositions = m_handlerParticipant->positions().values();
|
|
for (const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition : qAsConst(participantPositions))
|
|
{
|
|
if (participantPosition.insideBuilding())
|
|
continue;
|
|
|
|
if (m_handlerParticipant->isOutdated(participantPosition))
|
|
continue;
|
|
|
|
const LtsCoordTrans::UtmCoordinate positionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(participantPosition.lastGeoPosition.lon(), participantPosition.lastGeoPosition.lat());
|
|
const LtsUtils::QPoint3D position(positionUtm.x, positionUtm.y, participantPosition.lastGeoPosition.z());
|
|
const double distanceSquared = (center - position).lengthSquared();
|
|
if (distanceSquared > radiusSquared)
|
|
continue;
|
|
|
|
bool isCovered = false;
|
|
for (auto it = buildingModels.constBegin(); it != buildingModels.constEnd(); ++it)
|
|
{
|
|
const BuildingModel *buildingModel = it.value();
|
|
if (buildingModel->hasIntersection(centerGeo, participantPosition.lastGeoPosition))
|
|
{
|
|
DEBUG_LOG(m_logger) << "Participant " << participantPosition.participantId() << " is covered by building " << it.key();
|
|
isCovered = true;
|
|
break;
|
|
} // if
|
|
} // for
|
|
|
|
if (isCovered)
|
|
continue;
|
|
|
|
DEBUG_LOG(m_logger) << "Participant " << participantPosition.participantId() << " is hit";
|
|
sendCesHitRequest(itemView, participantPosition, QDateTime::currentMSecsSinceEpoch(), effectType, -1);
|
|
} // for
|
|
}
|
|
|
|
// Check for all participants wheter he is in the explosion area
|
|
void HandlerParticipantArea::calculateImpacts(const AreaEffectSimulation::TriggeredImpacts &data)
|
|
{
|
|
auto it = m_aesItemViews.find(data.aesItemId());
|
|
if (it == m_aesItemViews.end())
|
|
{
|
|
WARNING_LOG(m_logger) << "Could not find item view for aes with id " << data.aesItemId();
|
|
return;
|
|
}
|
|
CentralEffectSimulation::AesItemViewUtm &aesItemView = *it;
|
|
|
|
// older then 10sec? ignore
|
|
if (data.sampleTime() < m_ddsHandler->currentPartitionTime() - 10 * 1000)
|
|
{
|
|
if (aesItemView.sampleTimeHandledImpacts < data.sampleTime())
|
|
{
|
|
aesItemView.sampleTimeHandledImpacts = data.sampleTime();
|
|
aesItemView.handledImpacts = data.bitfield();
|
|
}
|
|
return;
|
|
}
|
|
|
|
QVector<int> bitsToCheck;
|
|
aesItemView.handledImpacts.resize(data.bitfield().size(), 0xFF);
|
|
for (int bitFieldIdx = 0; bitFieldIdx < data.impactCount(); ++bitFieldIdx)
|
|
{
|
|
// not yet triggered (bit is still 1)
|
|
if (LtsUtils::BitArray::testBit(data.bitfield(), bitFieldIdx))
|
|
continue;
|
|
|
|
// already checked (bit is already 0)
|
|
if (!LtsUtils::BitArray::testBit(aesItemView.handledImpacts, bitFieldIdx))
|
|
continue;
|
|
DEBUG_LOG(m_logger) << "New impact at idx " << bitFieldIdx;
|
|
bitsToCheck += bitFieldIdx;
|
|
}
|
|
|
|
// remember handled impacts
|
|
aesItemView.sampleTimeHandledImpacts = data.sampleTime();
|
|
aesItemView.handledImpacts = data.bitfield();
|
|
|
|
const auto participantPositions = m_handlerParticipant->positions();
|
|
for (const CentralEffectSimulation::HandlerParticipant::CesParticipantData &pPos : participantPositions)
|
|
{
|
|
if (pPos.vulnerabilityState == ProjectDataManagement::VulnerabilityState_def::CatastrophicKill)
|
|
continue;
|
|
if (pPos.insideBuilding())
|
|
continue;
|
|
if (!inBoundingBoxCheck(aesItemView, pPos))
|
|
continue;
|
|
calculateImpacts(aesItemView, bitsToCheck, pPos);
|
|
}
|
|
|
|
} // calculateImpacts
|
|
|
|
// calculate all impacts of the field for a participant
|
|
void HandlerParticipantArea::calculateImpacts(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const QVector<int> &impactsToCheck,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition)
|
|
{
|
|
const bool bIsSmartChargeType = m_ddsHandler->isSmartChargeType(itemView.chargeTypeId);
|
|
|
|
DEBUG_LOG(m_logger) << "calculateImpacts, isSMart: " << bIsSmartChargeType;
|
|
|
|
// get radius of munition
|
|
const double impactRadius = m_ddsHandler->chargeTypeRadius(itemView.chargeTypeId);
|
|
const QPointF participantPosUtmPoint = CentralEffectSimulation::geographic2Utm(participantPosition.pos(), itemView.zone);
|
|
|
|
for (int bitFieldIdx : impactsToCheck)
|
|
{
|
|
if (itemView.form.size() <= bitFieldIdx)
|
|
continue;
|
|
if (bIsSmartChargeType)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// get position of impact to corresponding bit
|
|
const QPointF &impactPos = itemView.form.value(bitFieldIdx);
|
|
if (inCircle(impactPos, impactRadius, participantPosUtmPoint))
|
|
sendEffectTypeEvent(itemView, participantPosition, EffectType::ExplosionArea, bitFieldIdx, QDateTime::currentMSecsSinceEpoch());
|
|
|
|
} // foreach Impact
|
|
|
|
} // calculateImpacts
|
|
|
|
// Send via TAB-Proxy to battlefield
|
|
void HandlerParticipantArea::sendCesHitRequest(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition,
|
|
qint64 effectTime,
|
|
int remaining,
|
|
int mineFieldBitIndex)
|
|
{
|
|
int32_t legacyChargeTypeId = 0;
|
|
legacyChargeTypeId = m_ddsHandler->getLegacyIdFromChargeTypeId(itemView.chargeTypeId);
|
|
|
|
if (remaining < 0)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "sendCesHitRequest Settings::calculateCentralAes=" << std::boolalpha << Settings::calculateCentralAes()
|
|
<< " insideWlsArea=" << std::boolalpha << participantPosition.insideWlsArea()
|
|
<< " isSmartChargeType=" << std::boolalpha << m_ddsHandler->isSmartChargeType(itemView.chargeTypeId)
|
|
<< " participantId=" << participantPosition.participantId();
|
|
if (!m_ddsHandler->isSmartChargeType(itemView.chargeTypeId))
|
|
{
|
|
DEBUG_LOG(m_logger) << "don't sendCesHitRequest Smart Type return";
|
|
return;
|
|
}
|
|
const int equipNo = m_ddsHandler->participantId2EquipNo(participantPosition.participantId());
|
|
DEBUG_LOG(m_logger) << " ftc sendCESHit to Participant participantId = " << participantPosition.participantId()
|
|
<< " equipNo = " << equipNo
|
|
<< " aesItemId =" << itemView.aesItemId;
|
|
|
|
// participantPosition.participantPosition == 0 -> send to all
|
|
if (participantPosition.participantId() != 0 && equipNo <= 0)
|
|
{
|
|
DEBUG_LOG(m_logger) << "participantPosition.participantId != 0 && equipNo <= 0" ;
|
|
return;
|
|
}
|
|
if (participantPosition.participantId() != 0 &&
|
|
participantPosition.vulnerabilityState == ProjectDataManagement::VulnerabilityState_def::CatastrophicKill)
|
|
{
|
|
DEBUG_LOG(m_logger) << "participantPosition.participantId != 0 CatastrophicKill)";
|
|
return;
|
|
}
|
|
|
|
int32_t originatorParticipantId = m_aesItemId2partIdMap.value(itemView.aesItemId, 0);
|
|
|
|
const TrainingAreaBase::TabPosition pos(participantPosition.pos(),
|
|
Core::PositionReportingSource_def::Gps, // irrelevant
|
|
participantPosition.buildingId(),
|
|
participantPosition.roomId());
|
|
const int originatorEquipNo = m_ddsHandler->participantId2EquipNo(originatorParticipantId);
|
|
|
|
|
|
TrainingAreaBase::SendCesHitRequest requestTab(
|
|
equipNo, // equipmentNumber
|
|
participantPosition.participantId(), // participantId
|
|
itemView.chargeTypeId, // chargeTypeId
|
|
itemView.aesItemId, // aesId
|
|
originatorEquipNo, // originatorEquipmentNumber
|
|
remaining, // remainEffectPercent ( no protection outside Building )
|
|
pos,
|
|
effectTime, // effectTime
|
|
itemView.partyId, // originPartyId
|
|
mineFieldBitIndex
|
|
);
|
|
DEBUG_LOG(m_logger) << " participantId=" << participantPosition.participantId()
|
|
<< " chargeTypeId=" << itemView.chargeTypeId
|
|
<< " legacyChargeTypeId=" << legacyChargeTypeId;
|
|
|
|
m_sendCesHitRequestQueue.enqueue(requestTab);
|
|
if (m_sendCesHitRequestQueue.size() == 1)
|
|
{
|
|
DEBUG_LOG(m_logger) << "SendCesHitRequest: " << requestTab;
|
|
m_ddsHandler->ftcTab()->sendCesHitRequest(requestTab, this);
|
|
}
|
|
}
|
|
|
|
void HandlerParticipantArea::sendCesHitRequest(const AreaEffectSimulation::AesItemView &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition,
|
|
qint64 effectTime,
|
|
int remaining,
|
|
int mineFieldBitIndex)
|
|
{
|
|
if (remaining < 0)
|
|
return;
|
|
|
|
int32_t legacyChargeTypeId = 0;
|
|
legacyChargeTypeId = m_ddsHandler->getLegacyIdFromChargeTypeId(itemView.chargeTypeId());
|
|
DEBUG_LOG(m_logger) << "sendCesHitRequest Settings::calculateCentralAes=" << std::boolalpha << Settings::calculateCentralAes()
|
|
<< " insideWlsArea=" << std::boolalpha << participantPosition.insideWlsArea()
|
|
<< " isSmartChargeType=" << std::boolalpha << m_ddsHandler->isSmartChargeType(itemView.chargeTypeId())
|
|
<< " participantId=" << participantPosition.participantId();
|
|
|
|
const int equipmentNumber = m_ddsHandler->participantId2EquipNo(participantPosition.participantId());
|
|
DEBUG_LOG(m_logger) << " ftc sendCESHit to Participant participantId = " << participantPosition.participantId()
|
|
<< " equipNo = " << equipmentNumber << " aesItemId =" << itemView.aesItemId();
|
|
|
|
// participantPosition.participantPosition == 0 -> send to all
|
|
if (participantPosition.participantId() != 0 && equipmentNumber <= 0)
|
|
{
|
|
DEBUG_LOG(m_logger) << "participantPosition.participantId != 0 && equipNo <= 0" ;
|
|
return;
|
|
} // if
|
|
|
|
if (participantPosition.participantId() != 0 &&
|
|
participantPosition.vulnerabilityState == ProjectDataManagement::VulnerabilityState_def::CatastrophicKill)
|
|
{
|
|
DEBUG_LOG(m_logger) << "participantPosition.participantId != 0 CatastrophicKill)";
|
|
return;
|
|
} // if
|
|
|
|
int32_t originatorParticipantId = m_aesItemId2partIdMap.value(itemView.aesItemId(), 0);
|
|
const int originatorEquipmentNumber = m_ddsHandler->participantId2EquipNo(originatorParticipantId);
|
|
const TrainingAreaBase::TabPosition pos(
|
|
participantPosition.pos(), Core::PositionReportingSource_def::Gps, participantPosition.buildingId(),
|
|
participantPosition.roomId()
|
|
);
|
|
TrainingAreaBase::SendCesHitRequest requestTab(
|
|
equipmentNumber, participantPosition.participantId(), legacyChargeTypeId, itemView.aesItemId(), originatorEquipmentNumber,
|
|
remaining, pos, effectTime, itemView.partyId().get(), mineFieldBitIndex
|
|
);
|
|
DEBUG_LOG(m_logger) << " participantId=" << participantPosition.participantId() << " chargeTypeId=" << itemView.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 HandlerParticipantArea::sendParticipantEvent(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition,
|
|
const ProjectDataManagement::EventType eventType)
|
|
{
|
|
bool calculateAes = false;
|
|
ParticipantManagement::TypeClass typeClass = m_handlerParticipant->typeClassFromTypeId(participantPosition.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 " << participantPosition.participantId()
|
|
<< " has invalid typeClass: " << typeClass
|
|
<< " eventType: " << eventType;
|
|
return;
|
|
}
|
|
|
|
|
|
if (!eventMustBeSend(itemView.aesItemId, participantPosition.participantId(), eventType))
|
|
{
|
|
DEBUG_LOG(m_logger) << "Not sending Event " << eventType << " for participant " << participantPosition.participantId()
|
|
<< " and aes " << itemView.aesItemId << " - already sent";
|
|
return;
|
|
}
|
|
switch (Settings::calculateCentralAes())
|
|
{
|
|
case Settings::NO_AES_CALCUALTION:
|
|
calculateAes = false;
|
|
break;
|
|
case Settings::AES_CALCUALTION:
|
|
calculateAes = true;
|
|
break;
|
|
case Settings::AES_CALCUALTION_ONLY_IN_WLS_AREA:
|
|
if (participantPosition.insideWlsArea())
|
|
calculateAes = true;
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << "!participantPosition.insideWlsArea()";
|
|
calculateAes = false;
|
|
}
|
|
}
|
|
// send hit events only with central AES Simulation
|
|
if (calculateAes
|
|
&& (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=" << participantPosition.participantId();
|
|
return;
|
|
}
|
|
|
|
int equipmentNumber = m_ddsHandler->participantId2EquipNo(participantPosition.participantId());
|
|
if (equipmentNumber <= 0)
|
|
{
|
|
WARNING_LOG(m_logger) << "Not sending Event " << eventType << " for participant " << participantPosition.participantId()
|
|
<< " - participant has no equipment number";
|
|
return;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "sendParticipantEvent" << eventType
|
|
<< " participantId=" << participantPosition.participantId()
|
|
<< " AesItemId=" << itemView.aesItemId;
|
|
|
|
CentralEffectSimulation::ParticipantEvent pe;
|
|
pe.id(m_ddsHandler->getParticipantEventId());
|
|
|
|
pe.eventTypeId(eventType.underlying());
|
|
pe.participantId(participantPosition.participantId());
|
|
pe.eventTime(participantPosition.sampleTime());
|
|
pe.aesItemId(itemView.aesItemId);
|
|
pe.partyId(participantPosition.partyId());
|
|
//pe.aesName(m_handlerAesData->aesName(itemView.aesItemId));
|
|
pe.equipmentNumber(equipmentNumber);
|
|
pe.vulnerability(participantPosition.vulnerabilityState.underlying());
|
|
pe.position(participantPosition.pos());
|
|
|
|
// Criterion for friendly Fire:
|
|
if (itemView.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)
|
|
&& itemView.partyId == participantPosition.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 HandlerParticipantArea::sendEffectTypeEvent(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition,
|
|
EffectType effectType,
|
|
int mineFieldBitIndex,
|
|
qint64 effectTime)
|
|
{
|
|
Q_UNUSED(effectTime);
|
|
// Trefferereignis Sekundaerwirkung
|
|
switch (Settings::calculateCentralAes())
|
|
{
|
|
case Settings::NO_AES_CALCUALTION:
|
|
return;
|
|
case Settings::AES_CALCUALTION:
|
|
break;
|
|
case Settings::AES_CALCUALTION_ONLY_IN_WLS_AREA:
|
|
if (!participantPosition.insideWlsArea())
|
|
{
|
|
DEBUG_LOG(m_logger) << "!participantPosition.insideWlsArea()";
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*if (!participantPosition.insideWlsArea())
|
|
{
|
|
// forget all enter/leave - the TNE calculates on its own
|
|
m_effectTypeStates[itemView.aesItemId][participantPosition.participantId()].clear();
|
|
m_effectTypeBitFieldIndexes[itemView.aesItemId][participantPosition.participantId()].clear();
|
|
return;
|
|
}*/
|
|
|
|
QByteArray mfb;
|
|
if (mineFieldBitIndex >= 0)
|
|
mfb = ", mineFieldBitIndex: " + QByteArray::number(mineFieldBitIndex);
|
|
if (!effectTypeMustBeSend(itemView.aesItemId,
|
|
participantPosition.participantId(),
|
|
effectType, mineFieldBitIndex,
|
|
participantPosition.insideBuilding()))
|
|
{
|
|
DEBUG_LOG(m_logger) << "Not sending EffectType event " << toString(effectType)
|
|
<< ", participant: " << participantPosition.participantId()
|
|
<< ", aesItemId: " << itemView.aesItemId
|
|
<< mfb
|
|
<< " - already sent";
|
|
return;
|
|
}
|
|
const int ctasEffectType = static_cast<int>(effectType) & 0xffff;
|
|
DEBUG_LOG(m_logger) << "Sending EffectType event " << toString(effectType)
|
|
<< ", participant: " << participantPosition.participantId()
|
|
<< ", aesItemId: " << itemView.aesItemId
|
|
<< mfb
|
|
<< ", ctasEffectType: " << ctasEffectType;
|
|
sendCesHitRequest(itemView,
|
|
participantPosition,
|
|
//effectTime >= 0 ? effectTime : participantPosition.sampleTime(),
|
|
QDateTime::currentMSecsSinceEpoch(),
|
|
ctasEffectType,
|
|
mineFieldBitIndex);
|
|
}
|
|
|
|
bool HandlerParticipantArea::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;
|
|
}
|
|
|
|
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::EnterFunctionalArea:
|
|
activeEvents.remove(ProjectDataManagement::EventType_def::LeaveFunctionalArea);
|
|
break;
|
|
case ProjectDataManagement::EventType_def::LeaveFunctionalArea:
|
|
activeEvents.remove(ProjectDataManagement::EventType_def::EnterFunctionalArea);
|
|
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;
|
|
default:
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool HandlerParticipantArea::effectTypeMustBeSend(int aesItemId,
|
|
int participantId,
|
|
EffectType effectType,
|
|
int mineFieldBitIndex,
|
|
bool insideBuilding)
|
|
{
|
|
// 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;
|
|
}
|
|
activeEffects += effectType;
|
|
|
|
bool bMustBeSend = true;
|
|
switch (effectType)
|
|
{
|
|
case EffectType::EffectiveMineRangeEnter:
|
|
{
|
|
activeEffects.remove(EffectType::EffectiveMineRangeLeave);
|
|
activeEffects.remove(EffectType::EffectiveMineRangeEnter); // must check per bit, not per area
|
|
QSet<int> &mineFieldBits = m_effectTypeBitFieldIndexes[aesItemId][participantId];
|
|
if (mineFieldBits.contains(mineFieldBitIndex) || insideBuilding)
|
|
bMustBeSend = false;
|
|
else
|
|
{
|
|
mineFieldBits.insert(mineFieldBitIndex);
|
|
bMustBeSend = true;
|
|
}
|
|
break;
|
|
}
|
|
case EffectType::EffectiveMineRangeLeave:
|
|
{
|
|
activeEffects.remove(EffectType::EffectiveMineRangeEnter);
|
|
activeEffects.remove(EffectType::EffectiveMineRangeLeave); // must check per bit, not per area
|
|
|
|
QSet<int> &mineFieldBits = m_effectTypeBitFieldIndexes[aesItemId][participantId];
|
|
mineFieldBits.remove(mineFieldBitIndex);
|
|
bMustBeSend = false; // no need to send leave to CTAS
|
|
break;
|
|
}
|
|
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::FunctionalAreaLeave:
|
|
bMustBeSend = activeEffects.remove(EffectType::FunctionalAreaEnter);
|
|
break;
|
|
case EffectType::FunctionalAreaEnter:
|
|
activeEffects.remove(EffectType::FunctionalAreaLeave);
|
|
break;
|
|
case EffectType::ExplosionArea:
|
|
activeEffects.remove(EffectType::ExplosionArea);
|
|
bMustBeSend = true;
|
|
break;
|
|
case EffectType::ExplosionSingle:
|
|
bMustBeSend = true;
|
|
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::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 HandlerParticipantArea::inCircle(const QPointF ¢erUtm, const double radius, const QPointF &pointUtm)
|
|
{
|
|
double squareDist = CentralEffectSimulation::getSquareDistance(centerUtm, pointUtm);
|
|
double squareRadius = radius * radius;
|
|
DEBUG_LOG(m_logger) << "squareDist: " << squareDist << ", squareRadius: " << squareRadius;
|
|
return (squareDist < squareRadius);
|
|
} // inCircle
|
|
|
|
ProjectDataManagement::EventType HandlerParticipantArea::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;
|
|
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
|
|
return ProjectDataManagement::EventType::LeaveFunctionalArea;
|
|
default:
|
|
break;
|
|
}
|
|
return ProjectDataManagement::EventType::Unknown;
|
|
}
|
|
|
|
EffectType HandlerParticipantArea::leaveEffectTypeForAesType(AreaEffectSimulation::AesType aesTypeId)
|
|
{
|
|
switch (aesTypeId.underlying())
|
|
{
|
|
case AreaEffectSimulation::AesType_def::AtBCContamination:
|
|
return EffectType::BCContaminationLeave;
|
|
case AreaEffectSimulation::AesType_def::AtNContamination:
|
|
return EffectType::NContaminationLeave;
|
|
case AreaEffectSimulation::AesType_def::AtFunctionalArea:
|
|
return EffectType::FunctionalAreaLeave;
|
|
default:
|
|
break;
|
|
}
|
|
return EffectType::Unknown;
|
|
}
|
|
|
|
EffectType HandlerParticipantArea::effectTypeForNContaminationArea(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const QPointF &participantPosUtmPoint,
|
|
qint64 partPosSampleTime)
|
|
{
|
|
if (itemView.radials.size() != 3)
|
|
return EffectType::NContaminationEnterArea2; // not yet known, we only know we're inside the area
|
|
|
|
const double squareDist = CentralEffectSimulation::getSquareDistance(itemView.center, 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)
|
|
return EffectType::NContaminationDetonation;
|
|
return EffectType::NContaminationEnterArea1;
|
|
}
|
|
if (squareDist <= pow(itemView.radials.at(1), 2))
|
|
return EffectType::NContaminationEnterArea1;
|
|
if (squareDist <= pow(itemView.radials.at(2), 2))
|
|
return EffectType::NContaminationEnterArea2;
|
|
return EffectType::NContaminationLeave;
|
|
}
|
|
|
|
EffectType HandlerParticipantArea::effectTypeForBCContaminationArea(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const QPointF &participantPosUtmPoint)
|
|
{
|
|
if (itemView.radials.size() != 1)
|
|
return EffectType::BCContaminationEnterFloating;
|
|
|
|
const double squareDist = CentralEffectSimulation::getSquareDistance(itemView.center, participantPosUtmPoint);
|
|
if (squareDist <= pow(itemView.radials.at(0), 2))
|
|
return EffectType::BCContaminationEnterResident; // first circle of resident contamination
|
|
return EffectType::BCContaminationEnterFloatingArea; // expanding/moving part of the contamination
|
|
}
|
|
|
|
|
|
void HandlerParticipantArea::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(aiv, m_handlerParticipant->position(itP.key()), effectTypLeave, -1, -1);
|
|
}
|
|
}
|
|
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, m_handlerParticipant->position(itP.key()), eventTypeLeave);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_effectTypeStates.remove(aesItemId);
|
|
m_effectTypeBitFieldIndexes.remove(aesItemId);
|
|
m_aesItemViews.remove(aesItemId);
|
|
m_explosionSingleStates.remove(aesItemId);
|
|
m_eventStates.remove(aesItemId);
|
|
}
|
|
|
|
|
|
} // namespace Ces2D
|