1167 lines
49 KiB
C++
Executable File
1167 lines
49 KiB
C++
Executable File
/**
|
|
* Handler for player data
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by gr, SLSE, 2017-02-20
|
|
*/
|
|
|
|
#include "handler_mine_areas.h"
|
|
#include "CentralEffectSimulation/handler_participant.h"
|
|
#include "settings.h"
|
|
|
|
#include <LtsUtilsCore/dds_bitarray.h>
|
|
#include <LtsUtilsCore/qpoint3d.h>
|
|
#include <LtsCoordTrans/lts_coord_trans.h>
|
|
#include <ProjectDataManagement/pdm_enums.hpp>
|
|
|
|
#include <QTimer>
|
|
#include <QDateTime>
|
|
|
|
namespace dds
|
|
{
|
|
namespace core
|
|
{
|
|
inline uint qHash(ProjectDataManagement::EventType et)
|
|
{
|
|
return ::qHash(et.underlying());
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace CesMineAreas
|
|
{
|
|
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));
|
|
}
|
|
|
|
|
|
HandlerMineAreas::HandlerMineAreas(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.MineAreas.HandlerMineAreas"))
|
|
{
|
|
DEBUG_LOG(m_logger) << "HandlerMineAreas::HandlerMineAreas";
|
|
m_aesItemViews.clear();
|
|
} // end of ctor()
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HandlerMineAreas::~HandlerMineAreas()
|
|
{
|
|
|
|
m_aesItemViews.clear();
|
|
m_sendCesHitRequestQueue.clear();
|
|
m_eventStates.clear();
|
|
m_effectTypeStates.clear();
|
|
m_effectTypeBitFieldIndexes.clear();
|
|
|
|
} // end of dtor()
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool HandlerMineAreas::init()
|
|
{
|
|
auto dtcAes = m_ddsHandler->dtcAes();
|
|
dtcAes->waitForHistoricalDataMineArea(2000);
|
|
dtcAes->waitForHistoricalDataMineCorridor(2000);
|
|
|
|
DEBUG_LOG(m_logger) << "HandlerMineAreas::init";
|
|
|
|
dtcAes->enableTriggeredImpacts();
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::triggeredImpactsChanged,
|
|
this, &HandlerMineAreas::onTriggeredImpactsChanged);
|
|
|
|
dtcAes->enableMineArea();
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
dtcAes->waitForHistoricalDataAesItemView(1000);
|
|
connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
|
|
this, &HandlerMineAreas::onAesItemViewChanged);
|
|
|
|
|
|
DEBUG_LOG(m_logger) << " m_aesItemViews.size=" << m_aesItemViews.size();
|
|
// Get 'static' data for all onAesItemView
|
|
{
|
|
auto cb = [this](const AreaEffectSimulation::AesItemView & aiv)
|
|
{
|
|
onAesItemViewChanged(aiv, DataModification::eAdded);
|
|
};
|
|
if (!dtcAes->aesItemViews(cb))
|
|
return false;
|
|
}
|
|
DEBUG_LOG(m_logger) << " m_aesItemViews.size=" << m_aesItemViews.size();
|
|
|
|
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::newOutdoorPosition,
|
|
this, &HandlerMineAreas::onNewOutdoorPosition);
|
|
|
|
connect(m_handlerParticipant.get(), &CentralEffectSimulation::HandlerParticipant::newParticipantState,
|
|
this, &HandlerMineAreas::onNewParticipantState);
|
|
|
|
INFO_LOG(m_logger) << "HandlerParticipantArea::init() finished.";
|
|
return true;
|
|
} // end of init()
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void HandlerMineAreas::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);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HandlerMineAreas::onMineTriggeredReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
if (replyObject.error())
|
|
ERROR_LOG(m_logger) << "Can not send MineTriggerReply: " << replyObject();
|
|
else
|
|
DEBUG_LOG(m_logger) << "MineTriggerReply for id " << replyObject.id() << " success";
|
|
}
|
|
// ///////////////////////////////////
|
|
// A E S (AreaEffectSimulation)
|
|
// ///////////////////////////////////
|
|
void HandlerMineAreas::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType)
|
|
{
|
|
if (data.aesTypeId() != AreaEffectSimulation::AesType_def::AtMineAreaSingleMines
|
|
&& data.aesTypeId() != AreaEffectSimulation::AesType_def::AtMineArea
|
|
&& data.aesTypeId() != AreaEffectSimulation::AesType_def::AtMineCorridor)
|
|
{
|
|
DEBUG_LOG(m_logger) << "AesItemView return";
|
|
return;
|
|
}
|
|
|
|
const AreaEffectSimulation::MineArea &ma = m_ddsHandler->dtcAes()->mineArea(data.aesItemId());
|
|
DEBUG_LOG(m_logger) << "aesItemId=" << data.aesItemId()
|
|
<< " chargeTypeId=" << data.chargeStruct().chargeTypeId()
|
|
<< " isCentral=" << ma.isCentral();
|
|
|
|
// 240 = Verlegemine muss immer berechnet werden.
|
|
if (!ma.isCentral() && (data.chargeStruct().chargeTypeId() != 240))
|
|
return;
|
|
|
|
|
|
if (data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired)
|
|
{
|
|
DEBUG_LOG(m_logger) << "AesItemView expired return id=" << data.aesItemId();
|
|
aesItemViewRemoved(data.aesItemId());
|
|
return;
|
|
}
|
|
|
|
if (m_ddsHandler->isDus(data.chargeStruct()))
|
|
{
|
|
DEBUG_LOG(m_logger) << "isDus aesItemId=" << data.aesItemId()
|
|
<< " chargeTypeId=" << data.chargeStruct().chargeTypeId() << " do not consider";
|
|
return;
|
|
}
|
|
|
|
const int aesItemId = data.aesItemId();
|
|
|
|
DEBUG_LOG(m_logger) << "Got AesItemView id: " << aesItemId
|
|
<< ", type: " << data.aesTypeId()
|
|
<< ", effectState: " << data.effectStateId()
|
|
<< ", modType: " << modType;
|
|
DEBUG_LOG(m_logger) << " m_aesItemViews.size=" << m_aesItemViews.size();
|
|
|
|
if (modType == DataModification::eRemoved)
|
|
{
|
|
DEBUG_LOG(m_logger) << " aesItemViewRemoved aesItemId=" << aesItemId;
|
|
aesItemViewRemoved(aesItemId);
|
|
return;
|
|
}
|
|
|
|
if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtMineAreaSingleMines)
|
|
{
|
|
if (!m_aesItemViews.contains(aesItemId))
|
|
{
|
|
DEBUG_LOG(m_logger) << " !m_aesItemViews.contains aesItemId=" << aesItemId;
|
|
return;
|
|
}
|
|
// build Polygon Mines:
|
|
DEBUG_LOG(m_logger) << " m_aesItemViews.size=" << m_aesItemViews.size();
|
|
auto &formMines = m_aesItemViews[data.aesItemId()].formMines;
|
|
DEBUG_LOG(m_logger) << " m_aesItemViews.size=" << m_aesItemViews.size();
|
|
int &zone = m_aesItemViews[data.aesItemId()].zone;
|
|
DEBUG_LOG(m_logger) << " m_aesItemViews.size=" << m_aesItemViews.size();
|
|
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.chargeStruct());
|
|
DEBUG_LOG(m_logger) << "impactRadius=" << impactRadius;
|
|
switch (effectState.underlying())
|
|
{
|
|
case AreaEffectSimulation::AesEffectState_def::EsPrepared:
|
|
{
|
|
break;
|
|
}
|
|
case AreaEffectSimulation::AesEffectState_def::EsActivated:
|
|
{
|
|
const auto aesItemViewUtm(CentralEffectSimulation::AesItemViewUtm::create(data, m_aesItemViews[data.aesItemId()], impactRadius));
|
|
|
|
DEBUG_LOG(m_logger) << "EsActivated m_aesItemViews.insert data.aesItemId()= " << data.aesItemId()
|
|
<< " m_aesItemViews.size=" << m_aesItemViews.size();
|
|
m_aesItemViews.insert(data.aesItemId(), aesItemViewUtm);
|
|
DEBUG_LOG(m_logger) << " m_aesItemViews.size=" << m_aesItemViews.size();
|
|
|
|
printAesItemViews();
|
|
break;
|
|
|
|
|
|
} // case EsActivated
|
|
case AreaEffectSimulation::AesEffectState_def::EsRemoved:
|
|
case AreaEffectSimulation::AesEffectState_def::EsExpired:
|
|
{
|
|
aesItemViewRemoved(aesItemId);
|
|
break;
|
|
}
|
|
default:
|
|
// do nothing
|
|
break;
|
|
} // switch effectStateId
|
|
DEBUG_LOG(m_logger) << " m_aesItemViews.size=" << m_aesItemViews.size();
|
|
printAesItemViews();
|
|
} // onAesItemViewChanged
|
|
|
|
|
|
|
|
void HandlerMineAreas::onNewOutdoorPosition(const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition)
|
|
{
|
|
if (m_handlerParticipant->isOutdated(participantPosition))
|
|
return;
|
|
|
|
if (m_handlerParticipant->getEquipmentNumber(participantPosition.participantId()) == 0)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Not handle position: participant has no equipment number";
|
|
return;
|
|
}
|
|
|
|
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) << "return New Position Participant with id " << participantPosition.participantId()
|
|
<< " has invalid typeClass: " << typeClass;
|
|
return;
|
|
}
|
|
|
|
int equipmentNumber = m_ddsHandler->participantId2EquipNo(participantPosition.participantId());
|
|
if (equipmentNumber <= 0)
|
|
{
|
|
TRACE_LOG(m_logger) << "return New Position - participant has no equipment number"
|
|
<< " participantId=" << participantPosition.participantId()
|
|
<< " typeClass=" << typeClass;
|
|
return;
|
|
}
|
|
|
|
if (participantPosition.vulnerabilityState == ProjectDataManagement::VulnerabilityState_def::CatastrophicKill)
|
|
{
|
|
DEBUG_LOG(m_logger) << "New Position CatastrophicKill return";
|
|
return;
|
|
}
|
|
|
|
if (m_mineLists.contains(participantPosition.participantId()))
|
|
{
|
|
DEBUG_LOG(m_logger) << "Naechste Mine schicken ohne Bounding-Box-Check... return"
|
|
<< " Anzahl Minen in Liste:" << m_mineLists[participantPosition.participantId()].size()
|
|
<< " cesMaxPeriodForCashedMines=" << Settings::cesPeriodStoredMinesOutdated();
|
|
//DEBUG_LOG(m_logger) << "Settings::cesMaxPeriodForCashedMines() =" << Settings::cesMaxPeriodForCashedMines();
|
|
|
|
if ((m_mineLists[participantPosition.participantId()].size() > 0)
|
|
&& (QDateTime::currentMSecsSinceEpoch() - m_mineLists[participantPosition.participantId()][0].time < Settings::cesPeriodStoredMinesOutdated()))
|
|
{
|
|
DEBUG_LOG(m_logger) << "Send Stored mines";
|
|
// Search mine with the next no distance
|
|
int distance = m_mineLists[participantPosition.participantId()][0].distance;
|
|
int index = 0;
|
|
for (int i = 0; i < m_mineLists[participantPosition.participantId()].size(); i++)
|
|
{
|
|
if (m_mineLists[participantPosition.participantId()][i].distance < distance)
|
|
{
|
|
distance = m_mineLists[participantPosition.participantId()][i].distance;
|
|
index = i;
|
|
}
|
|
}
|
|
//m_mineLists[participantPos.participantId()].value()
|
|
int mineIndex = m_mineLists[participantPosition.participantId()][index].mineIndex;
|
|
int aesItemId = m_mineLists[participantPosition.participantId()][index].aesItemId;
|
|
if (!m_aesItemViews.contains(aesItemId))
|
|
return;
|
|
|
|
sendFtcMineTrigger(aesItemId, mineIndex - 1);
|
|
sendEffectTypeEvent(m_aesItemViews[aesItemId], participantPosition, EffectType::EffectiveMineRangeEnter, mineIndex - 1, -1);
|
|
CentralEffectSimulation::HandlerParticipant::CesParticipantData minePosition = participantPosition;
|
|
// TODO convert minePos to geographic and set minePosGeo
|
|
// DEBUG_LOG(m_logger) << "minePosGeo lat=" << minePosGeo.lat()
|
|
// << " lon=" << minePosGeo.lon()
|
|
// << " z=" << minePosGeo.z();
|
|
sendParticipantEvent(m_aesItemViews[aesItemId], minePosition, ProjectDataManagement::EventType_def::HitMine);
|
|
|
|
m_mineLists[participantPosition.participantId()].remove(index);
|
|
|
|
if (m_mineLists[participantPosition.participantId()].size() == 0)
|
|
{
|
|
m_mineLists[participantPosition.participantId()].clear();
|
|
m_mineLists.remove(participantPosition.participantId());
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << "Stored mines are outdated!"
|
|
<< " actTime=" << QDateTime::currentMSecsSinceEpoch()
|
|
<< " Settings::cesPeriodStoredMinesOutdated()=" << Settings::cesPeriodStoredMinesOutdated();
|
|
m_mineLists[participantPosition.participantId()].clear();
|
|
m_mineLists.remove(participantPosition.participantId());
|
|
}// end if time-check
|
|
}
|
|
|
|
|
|
DEBUG_LOG(m_logger) << "HandlerParticipantArea::calculateAesParticipant paricipantId: " << participantPosition.participantId()
|
|
<< " m_aesItemViews.size=" << m_aesItemViews.size();
|
|
|
|
// const QVector<QPointF> utmStepPoly = m_handlerParticipant->getParticipantStep(participantPos.participantId(), m_zone);
|
|
|
|
for (const CentralEffectSimulation::AesItemViewUtm &itemView : qAsConst(m_aesItemViews))
|
|
{
|
|
int remaining = m_ddsHandler->remainingTasCode(itemView.chargeStruct);
|
|
DEBUG_LOG(m_logger) << " itemView: " << itemView.aesItemId << ", " << itemView.aesTypeId
|
|
<< " remainingTasCode=" << remaining;
|
|
|
|
if (itemView.effectStateId != AreaEffectSimulation::AesEffectState_def::EsActivated)
|
|
continue;
|
|
|
|
if (typeClass == ParticipantManagement::TypeClass_def::Human && remaining > 50)
|
|
{
|
|
DEBUG_LOG(m_logger) << "ParticipantManagement::TypeClass_def::Human && remaining > 50 continue";
|
|
continue;
|
|
}
|
|
|
|
if (typeClass == ParticipantManagement::TypeClass_def::Human && m_ddsHandler->isAtMine(itemView.chargeStruct))
|
|
continue;
|
|
|
|
if (itemView.aesTypeId.underlying() == AreaEffectSimulation::AesType_def::AtMineArea)
|
|
{
|
|
|
|
// checks whether the participant has been positioned in the minefield or across it.
|
|
bool inBoundingBox = inBoundingBoxCheck(itemView, participantPosition);
|
|
if (!inBoundingBox)
|
|
{
|
|
bool intersectsBoundingBox = intersectsBoundingBoxCheck(itemView, participantPosition.participantId());
|
|
if (!intersectsBoundingBox)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Continue nach Bounding BoxCheck itemView: " << itemView.aesItemId << ", "
|
|
<< " paricipantId=" << participantPosition.participantId();
|
|
continue;
|
|
}
|
|
}
|
|
DEBUG_LOG(m_logger) << "Weiter nach Bounding BoxCheck itemView: " << itemView.aesItemId << ", "
|
|
<< " paricipantId=" << participantPosition.participantId();
|
|
|
|
bool inFormCheckResult = inFormCheck(itemView, participantPosition);
|
|
if (!inFormCheckResult)
|
|
{
|
|
DEBUG_LOG(m_logger) << "!inForm";
|
|
if (!intersectFormCheck(itemView, participantPosition.participantId()))
|
|
{
|
|
DEBUG_LOG(m_logger) << "!intersectForm continue";
|
|
continue;
|
|
}
|
|
}
|
|
DEBUG_LOG(m_logger) << "Weiter nach inFormCheck und intersectFormCheck";
|
|
sendParticipantEventEnterLeave(itemView, participantPosition, inFormCheckResult);
|
|
|
|
DEBUG_LOG(m_logger) << "intersectMineRadiusCheck ";
|
|
if (intersectMineRadiusCheck(itemView, participantPosition))
|
|
{
|
|
DEBUG_LOG(m_logger) << "intersectMineRadiusCheck=true return";
|
|
return;
|
|
}
|
|
} // if AtMineArea
|
|
} // for m_aesItemViews
|
|
} // calculateAesParticipant
|
|
|
|
void HandlerMineAreas::onNewParticipantState(const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPos)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onNewParticipantState ";
|
|
if (participantPos.vulnerabilityState == ProjectDataManagement::VulnerabilityState_def::CombatReady)
|
|
{
|
|
DEBUG_LOG(m_logger) << "m_mineLists.contains(participantPos.participantId():" << m_mineLists.contains(participantPos.participantId());
|
|
if (m_mineLists.contains(participantPos.participantId()))
|
|
{
|
|
DEBUG_LOG(m_logger) << "onNewParticipantState CombatReady, loesche Minenliste Eintrag";
|
|
m_mineLists[participantPos.participantId()].clear();
|
|
m_mineLists.remove(participantPos.participantId());
|
|
}
|
|
DEBUG_LOG(m_logger) << "onNewParticipantState CombatReady, loesche Minenliste";
|
|
}
|
|
}
|
|
|
|
// return true, if participant crossed the dangerous area of a mine
|
|
bool HandlerMineAreas::intersectMineRadiusCheck(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition)
|
|
{
|
|
qreal distance = -1.0;
|
|
qreal lastDistance = -1.0;
|
|
QPointF minePos = QPointF();
|
|
|
|
int mineIndex = -1;
|
|
int mineListIndex = -1;
|
|
int mineListItemIndex = -1;
|
|
|
|
|
|
int32_t bitFieldIdx = 0;
|
|
const double impactRadius = m_ddsHandler->chargeTypeRadius(itemView.chargeStruct);
|
|
|
|
const QPolygonF utmStep = m_handlerParticipant->getParticipantStep(participantPosition.participantId(), itemView.zone);
|
|
for (const auto &itPos : itemView.formMines)
|
|
{
|
|
DEBUG_LOG(m_logger) << " itemId=" << itemView.aesItemId
|
|
<< " chargeTypeId=" << itemView.chargeStruct.chargeTypeId()
|
|
<< ", MinePosUtm: " << CentralEffectSimulation::debug(itPos)
|
|
<< " utmStep:" << utmStep[0].x() << utmStep[0].y()
|
|
<< ", " << utmStep[1].x() << utmStep[1].y();
|
|
// Check, if mine is active
|
|
// already triggered (bit is already 0)
|
|
if (m_triggeredImpacts.contains(itemView.aesItemId))
|
|
{
|
|
const AreaEffectSimulation::TriggeredImpacts &triggeredImpact = m_triggeredImpacts[itemView.aesItemId];
|
|
if (!LtsUtils::BitArray::testBit(triggeredImpact.bitfield(), bitFieldIdx))
|
|
{
|
|
++bitFieldIdx;
|
|
DEBUG_LOG(m_logger) << "Mine is active continue bitFieldIdx=" << 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
|
|
distance = crossCircle(itPos, impactRadius, participantPosition.participantId(), itemView.zone);
|
|
DEBUG_LOG(m_logger) << "distance=" << distance;
|
|
if (distance < 0.0)
|
|
{
|
|
DEBUG_LOG(m_logger) << "distance < 0.0 continue";
|
|
++bitFieldIdx;
|
|
continue;
|
|
}
|
|
if (lastDistance < 0.0)
|
|
lastDistance = distance + 1.0;
|
|
|
|
MineListItem mineListItem;
|
|
mineListItem.aesItemId = itemView.aesItemId;
|
|
mineListItem.distance = distance;
|
|
mineListItem.mineIndex = mineIdx;
|
|
mineListItem.minePos = minePos;
|
|
mineListItem.time = QDateTime::currentMSecsSinceEpoch();
|
|
m_mineLists[participantPosition.participantId()].append(mineListItem);
|
|
mineListIndex++;
|
|
DEBUG_LOG(m_logger) << " m_mineLists[" << participantPosition.participantId()
|
|
<< "].length=" << m_mineLists[participantPosition.participantId()].length();
|
|
|
|
if (distance < lastDistance)
|
|
{
|
|
DEBUG_LOG(m_logger) << " distance < lastDistance crossCircle for aesItemId: " << itemView.aesItemId
|
|
<< ", mineIdx: " << mineIdx
|
|
<< ", impactRadius:" << impactRadius
|
|
<< ", participantId: " << participantPosition.participantId()
|
|
<< ", lastDistance:" << lastDistance
|
|
<< ", distance:" << distance;
|
|
minePos = itPos;
|
|
mineIndex = mineIdx;
|
|
lastDistance = distance;
|
|
mineListItemIndex = mineListIndex;
|
|
}
|
|
bitFieldIdx++;
|
|
} // for each mine
|
|
|
|
DEBUG_LOG(m_logger) << "End of for-loop participantId=" << participantPosition.participantId()
|
|
<< " mineIndex=" << mineIndex
|
|
<< " lastDistance=" << lastDistance;
|
|
if (lastDistance > 0)
|
|
{
|
|
DEBUG_LOG(m_logger) << "sendEffectTypeEvent participantId=" << participantPosition.participantId()
|
|
<< " mineIndex=" << mineIndex;
|
|
// TODO Minenposition fuer den Event nehmen und nicht die Participant-Position
|
|
sendFtcMineTrigger(itemView.aesItemId, mineIndex - 1);
|
|
sendEffectTypeEvent(itemView, participantPosition, EffectType::EffectiveMineRangeEnter, mineIndex - 1, -1);
|
|
CentralEffectSimulation::HandlerParticipant::CesParticipantData minePosition = participantPosition;
|
|
// TODO convert minePos to geographic and set minePosGeo
|
|
// DEBUG_LOG(m_logger) << "minePosGeo lat=" << minePosGeo.lat()
|
|
// << " lon=" << minePosGeo.lon()
|
|
// << " z=" << minePosGeo.z();
|
|
sendParticipantEvent(itemView, minePosition, ProjectDataManagement::EventType_def::HitMine);
|
|
// aktuell verarbeitete Mine aus der Liste entfernen.
|
|
m_mineLists[participantPosition.participantId()].remove(mineListItemIndex);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// return true, if participant is inside of the bounding Box
|
|
bool HandlerMineAreas::intersectsBoundingBoxCheck(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const int participantId)
|
|
{
|
|
bool result = false;
|
|
DEBUG_LOG(m_logger) << "intersectsBoundingBoxCheck participantId=" << participantId
|
|
<< " itemViewId=" << itemView.aesItemId
|
|
<< " zone=" << itemView.zone;
|
|
const QPolygonF stepPoly = m_handlerParticipant->getParticipantStep(participantId, itemView.zone);
|
|
if (stepPoly.size() < 2)
|
|
return false;
|
|
|
|
DEBUG_LOG(m_logger) << "utmStep von=" << stepPoly.at(0).x() << "/" << stepPoly.at(0).y()
|
|
<< " bis=" << stepPoly.at(1).x() << "/" << stepPoly.at(1).y()
|
|
<< " zone=" << itemView.zone;
|
|
DEBUG_LOG(m_logger) << "ItemView Bounding Box BottomLeft=" << itemView.boundingBoxBottomLeft.x() << "/" << itemView.boundingBoxBottomLeft.y()
|
|
<< " boundingBoxTopRight=" << itemView.boundingBoxTopRight.x() << "/" << itemView.boundingBoxTopRight.y();
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5,10,0)
|
|
result = itemView.boundingBox.intersected(stepPoly).size() > 0;
|
|
#else
|
|
result = itemView.boundingBox.intersects(stepPoly);
|
|
#endif
|
|
DEBUG_LOG(m_logger) << "HandlerMineAreas::intersectsBoundingBoxCheck result =" << result;
|
|
return result;
|
|
|
|
}
|
|
|
|
// return true, if participant is inside of the bounding Box
|
|
bool HandlerMineAreas::inBoundingBoxCheck(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition)
|
|
{
|
|
const double impactRadius = m_ddsHandler->chargeTypeRadius(itemView.chargeStruct);
|
|
|
|
qreal boundingBoxBottomLeftX = itemView.boundingBoxBottomLeft.x() - impactRadius;
|
|
qreal boundingBoxBottomLeftY = itemView.boundingBoxBottomLeft.y() + impactRadius;
|
|
|
|
qreal boundingBoxTopRightX = itemView.boundingBoxTopRight.x() + impactRadius;
|
|
qreal boundingBoxTopRightY = itemView.boundingBoxTopRight.y() - impactRadius;
|
|
|
|
|
|
QPointF boundingBoxBottomLeft = QPointF(boundingBoxBottomLeftX, boundingBoxBottomLeftY);
|
|
QPointF boundingBoxTopRight = QPointF(boundingBoxTopRightX, boundingBoxTopRightY);
|
|
|
|
DEBUG_LOG(m_logger) << " impactRadius=" << impactRadius
|
|
<< " itemView.boundingBoxBottomLeft" << itemView.boundingBoxBottomLeft.x() << "/" << itemView.boundingBoxBottomLeft.y()
|
|
<< " itemView.boundingBoxTopRight" << itemView.boundingBoxTopRight.x() << "/" << itemView.boundingBoxTopRight.y()
|
|
<< " boundingBoxBottomLeft=" << boundingBoxBottomLeft.x() << "/" << boundingBoxBottomLeft.y()
|
|
<< " boundingBoxTopRight=" << boundingBoxTopRight.x() << "/" << boundingBoxTopRight.y();
|
|
|
|
|
|
const QRectF boundingBoxImpact(boundingBoxBottomLeft,
|
|
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";
|
|
return true;
|
|
}
|
|
DEBUG_LOG(m_logger) << "inBoundingBoxCheck Paricipant " << participantPosition.participantId()
|
|
<< " outside AesItemView:" << itemView.aesItemId << " return false";
|
|
return false;
|
|
}
|
|
|
|
// return true, if participant is inside of the form of AesItemView
|
|
bool HandlerMineAreas::inFormCheck(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition)
|
|
{
|
|
|
|
const QPointF participantPosUtmPoint = CentralEffectSimulation::geographic2Utm(participantPosition.pos(), itemView.zone);
|
|
DEBUG_LOG(m_logger) << "inFormCheck start, paricipantId: " << participantPosition.participantId()
|
|
<< ", aesItemId: " << itemView.aesItemId
|
|
<< ", aesTypeId: " << itemView.aesTypeId
|
|
<< ", form.size: " << itemView.form.size();
|
|
|
|
if (itemView.form.containsPoint(participantPosUtmPoint, Qt::FillRule::OddEvenFill))
|
|
{
|
|
DEBUG_LOG(m_logger) << "inside AES form, paricipantId: " << participantPosition.participantId()
|
|
<< ", aesItemId: " << itemView.aesItemId;
|
|
return true;
|
|
} // if inside
|
|
|
|
return inExtededFormCheck(itemView, participantPosition);
|
|
}
|
|
|
|
// return true, if participant is inside of the form of AesItemView
|
|
bool HandlerMineAreas::intersectFormCheck(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const int participantId)
|
|
{
|
|
const QPolygonF utmStep = m_handlerParticipant->getParticipantStep(participantId, itemView.zone);
|
|
|
|
DEBUG_LOG(m_logger) << "intersectFormCheck start, paricipantId: " << participantId
|
|
<< ", aesItemId: " << itemView.aesItemId
|
|
<< ", aesTypeId: " << itemView.aesTypeId
|
|
<< ", form.size: " << itemView.form.size();
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5,10,0)
|
|
if (itemView.form.intersected(utmStep).size() > 0)
|
|
#else
|
|
if (itemView.form.intersects(utmStep))
|
|
#endif
|
|
{
|
|
DEBUG_LOG(m_logger) << "intersect AES form, paricipantId: " << participantId
|
|
<< ", aesItemId: " << itemView.aesItemId;
|
|
return true;
|
|
} // if inside
|
|
|
|
return false;
|
|
}
|
|
|
|
void HandlerMineAreas::onTriggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType)
|
|
{
|
|
if (modType != DataModification::eAdded &&
|
|
modType != DataModification::eModified)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << "Got TriggeredImpacts: ";
|
|
switch (data.aesTypeId().underlying())
|
|
{
|
|
case AreaEffectSimulation::AesType_def::AtExplosionArea:
|
|
case AreaEffectSimulation::AesType_def::AtExplosionSingle:
|
|
//case AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions: Plugin Artillery
|
|
// 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
|
|
|
|
// Check for all participants wheter he is in the explosion area
|
|
void HandlerMineAreas::calculateImpacts(const AreaEffectSimulation::TriggeredImpacts &data)
|
|
{
|
|
|
|
if ((data.aesTypeId() == AreaEffectSimulation::AesType_def::AtExplosionAreaSingleExplosions)
|
|
|| (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtExplosionClusterSingleExplosions))
|
|
return;
|
|
|
|
|
|
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)
|
|
{
|
|
DEBUG_LOG(m_logger) << "pos participantId=" << pPos.participantId()
|
|
<< " buildingId=" << pPos.buildingId()
|
|
<< " insideBuilding=" << pPos.insideBuilding()
|
|
<< " positionValid=" << pPos.positionValid;
|
|
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 HandlerMineAreas::calculateImpacts(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const QVector<int> &impactsToCheck,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition)
|
|
{
|
|
|
|
// get radius of munition
|
|
const double impactRadius = m_ddsHandler->chargeTypeRadius(itemView.chargeStruct);
|
|
const QPointF participantPosUtmPoint = CentralEffectSimulation::geographic2Utm(participantPosition.pos(), itemView.zone);
|
|
|
|
for (int bitFieldIdx : impactsToCheck)
|
|
{
|
|
if (itemView.form.size() <= bitFieldIdx)
|
|
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 HandlerMineAreas::sendCesHitRequest(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition,
|
|
qint64 effectTime,
|
|
int mineFieldBitIndex)
|
|
{
|
|
int remaining = m_ddsHandler->remainingTasCode(itemView.chargeStruct);
|
|
|
|
DEBUG_LOG(m_logger) << "sendCesHitRequest "
|
|
<< " insideWlsArea=" << std::boolalpha << participantPosition.insideWlsArea()
|
|
<< " participantId=" << participantPosition.participantId();
|
|
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);
|
|
|
|
const ProjectDataManagement::EventType eventType = ProjectDataManagement::EventType_def::Unknown;
|
|
|
|
TrainingAreaBase::SendCesHitRequest requestTab(
|
|
equipNo, // equipmentNumber
|
|
participantPosition.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=" << participantPosition.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 HandlerMineAreas::sendCesHitRequest(const AreaEffectSimulation::AesItemView &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition,
|
|
qint64 effectTime,
|
|
int mineFieldBitIndex)
|
|
{
|
|
int remaining = m_ddsHandler->remainingTasCode(itemView.chargeStruct());
|
|
|
|
int32_t legacyChargeTypeId = 0;
|
|
legacyChargeTypeId = m_ddsHandler->getLegacyIdFromChargeTypeId(itemView.chargeStruct());
|
|
DEBUG_LOG(m_logger) << "sendCesHitRequest"
|
|
<< " insideWlsArea=" << std::boolalpha << participantPosition.insideWlsArea()
|
|
<< " 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()
|
|
);
|
|
const ProjectDataManagement::EventType eventType = ProjectDataManagement::EventType_def::Unknown;
|
|
|
|
TrainingAreaBase::SendCesHitRequest requestTab(
|
|
equipmentNumber, participantPosition.participantId(), legacyChargeTypeId, itemView.aesItemId(), originatorEquipmentNumber,
|
|
remaining, pos, effectTime, eventType, itemView.partyId().get(), mineFieldBitIndex
|
|
);
|
|
DEBUG_LOG(m_logger) << " participantId=" << participantPosition.participantId() << " chargeTypeId=" << itemView.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 HandlerMineAreas::sendParticipantEventEnterLeave(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition,
|
|
const bool inFormCheckResult)
|
|
{
|
|
|
|
const ProjectDataManagement::EventType &lastEvent = m_eventStates[itemView.aesItemId][participantPosition.participantId()];
|
|
|
|
|
|
ProjectDataManagement::EventType eventType = ProjectDataManagement::EventType_def::EnterMineArea;
|
|
|
|
|
|
if (inFormCheckResult)
|
|
{
|
|
if (lastEvent == ProjectDataManagement::EventType_def::EnterMineArea)
|
|
return;
|
|
else
|
|
{
|
|
eventType = ProjectDataManagement::EventType_def::EnterMineArea;
|
|
m_eventStates[itemView.aesItemId][participantPosition.participantId()] = ProjectDataManagement::EventType_def::EnterMineArea;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (lastEvent == ProjectDataManagement::EventType_def::LeaveMineArea)
|
|
return;
|
|
else
|
|
{
|
|
eventType = ProjectDataManagement::EventType_def::LeaveMineArea;
|
|
m_eventStates[itemView.aesItemId][participantPosition.participantId()] = ProjectDataManagement::EventType_def::LeaveMineArea;
|
|
}
|
|
}
|
|
|
|
sendParticipantEvent(itemView, participantPosition, eventType);
|
|
|
|
}
|
|
|
|
void HandlerMineAreas::sendParticipantEvent(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition,
|
|
const ProjectDataManagement::EventType eventType)
|
|
{
|
|
|
|
|
|
DEBUG_LOG(m_logger) << "sendParticipantEvent " << itemView.aesItemId
|
|
<< " participantId=" << participantPosition.participantId()
|
|
<< " eventType=" << eventType
|
|
<< " pos=" << participantPosition.pos().lat()
|
|
<< "/" << participantPosition.pos().lon()
|
|
<< "/" << participantPosition.pos().z();
|
|
|
|
int equipmentNumber = m_ddsHandler->participantId2EquipNo(participantPosition.participantId());
|
|
const AreaEffectSimulation::MineArea &ma = m_ddsHandler->dtcAes()->mineArea(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(ma.name());
|
|
pe.equipmentNumber(equipmentNumber);
|
|
pe.vulnerability(participantPosition.vulnerabilityState.underlying());
|
|
pe.position(participantPosition.pos());
|
|
|
|
m_ddsHandler->dtsCes()->publish(pe);
|
|
|
|
const auto id = pe.id();
|
|
QTimer::singleShot(1 * 60 * 1000, this, [id, this]() { m_ddsHandler->dtsCes()->removeParticipantEventByKey(id); });
|
|
}
|
|
|
|
|
|
void HandlerMineAreas::sendFtcMineTrigger(int aesItemId, int mineIndex)
|
|
{
|
|
const AreaEffectSimulation::MineArea &ma = m_ddsHandler->dtcAes()->mineArea(aesItemId);
|
|
|
|
auto ftcAes = m_ddsHandler->ftcAes();
|
|
AreaEffectSimulation::MineTriggeredRequest tr;
|
|
tr.mineAreaId(aesItemId);
|
|
tr.mineId(mineIndex);
|
|
tr.chargeTypeId(ma.chargeStruct().chargeTypeId());
|
|
DEBUG_LOG(m_logger) << "send sendFtcMineTrigger: aesItemId=" << tr.mineAreaId()
|
|
<< " MineIndex=" << tr.mineId();
|
|
ftcAes->mineTriggeredRequest(tr, this);
|
|
}
|
|
|
|
void HandlerMineAreas::sendEffectTypeEvent(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition,
|
|
EffectType effectType,
|
|
int mineFieldBitIndex,
|
|
qint64 effectTime)
|
|
{
|
|
DEBUG_LOG(m_logger) << "sendEffectTypeEvent aesItemId=" << itemView.aesItemId
|
|
<< " participantId=" << participantPosition.participantId()
|
|
<< " effectType=" << effectTime
|
|
<< " mineFieldBitIndex=" << mineFieldBitIndex;
|
|
Q_UNUSED(effectTime);
|
|
// Trefferereignis Sekundaerwirkung
|
|
|
|
|
|
QByteArray mfb;
|
|
if (mineFieldBitIndex >= 0)
|
|
mfb = ", mineFieldBitIndex: " + QByteArray::number(mineFieldBitIndex);
|
|
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(),
|
|
mineFieldBitIndex);
|
|
}
|
|
|
|
// Anmerkung: Im SFM werden Quadrate und keine Kreise genommen. ( Wird hier nach Absprache mit Manfred nicht gemacht)
|
|
qreal HandlerMineAreas::crossCircle(const QPointF ¢erUtm, const double radius, const int participantId, int zone)
|
|
{
|
|
qreal result = -1.0;
|
|
|
|
QPointF p1 = QPointF(centerUtm.x() + radius, centerUtm.y() + radius);
|
|
QPointF p2 = QPointF(centerUtm.x() + radius, centerUtm.y() - radius);
|
|
QPointF p3 = QPointF(centerUtm.x() - radius, centerUtm.y() - radius);
|
|
QPointF p4 = QPointF(centerUtm.x() - radius, centerUtm.y() + radius);
|
|
|
|
|
|
QPolygonF boundingBoxPolyMine;
|
|
boundingBoxPolyMine << p1 << p2 << p3 << p4 << p1;
|
|
|
|
|
|
const QPolygonF stepPoly = m_handlerParticipant->getParticipantStep(participantId, zone);
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5,10,0)
|
|
if (boundingBoxPolyMine.intersected(stepPoly).size() > 0)
|
|
#else
|
|
if (boundingBoxPolyMine.intersects(stepPoly))
|
|
#endif
|
|
{
|
|
QLineF line;
|
|
line.setP1(stepPoly[0]);
|
|
line.setP2(centerUtm);
|
|
DEBUG_LOG(m_logger) << "crossCircle distance =" << line.length();
|
|
return line.length();
|
|
}
|
|
return result;
|
|
} // inCircle
|
|
|
|
|
|
// Anmerkung: Im SFM werden Quadrate und keine Kreise genommen. ( Wird hier nach Absprache mit Manfred nicht gemacht)
|
|
bool HandlerMineAreas::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
|
|
|
|
void HandlerMineAreas::aesItemViewRemoved(int aesItemId)
|
|
{
|
|
DEBUG_LOG(m_logger) << "HandlerMineAreas::aesItemViewRemoved aesItemId=" << aesItemId;
|
|
|
|
m_effectTypeStates.remove(aesItemId);
|
|
m_effectTypeBitFieldIndexes.remove(aesItemId);
|
|
m_aesItemViews.remove(aesItemId);
|
|
m_eventStates.remove(aesItemId);
|
|
}
|
|
|
|
void HandlerMineAreas::printAesItemViews()
|
|
{
|
|
|
|
QHashIterator<int, CentralEffectSimulation::AesItemViewUtm> i(m_aesItemViews);
|
|
while (i.hasNext())
|
|
{
|
|
i.next();
|
|
DEBUG_LOG(m_logger) << "printAesItemViews key=" << i.key() << ": "
|
|
<< " aesItemId=" << i.value().aesItemId
|
|
<< " aesTypeId=" << i.value().aesTypeId;
|
|
}
|
|
}
|
|
|
|
bool HandlerMineAreas::inExtededFormCheck(const CentralEffectSimulation::AesItemViewUtm &itemView,
|
|
const CentralEffectSimulation::HandlerParticipant::CesParticipantData &participantPosition) const
|
|
{
|
|
const double distance = m_ddsHandler->chargeTypeRadius(itemView.chargeStruct);
|
|
const QPointF participantPosUtmPoint = CentralEffectSimulation::geographic2Utm(participantPosition.pos(), itemView.zone);
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Check whether the position is within an expanded form //
|
|
///////////////////////////////////////////////////////////
|
|
DEBUG_LOG(m_logger) << "itemView.form.size=" << itemView.form.size();
|
|
for (int i = 0; i < itemView.form.size() ; i++)
|
|
{
|
|
int nextPoint = i + 1;
|
|
if (i == itemView.form.size() - 1)
|
|
nextPoint = 0;
|
|
|
|
const QPointF l1(itemView.form[i].x(), itemView.form[i].y());
|
|
const QPointF l2(itemView.form[nextPoint].x(), itemView.form[nextPoint].y());
|
|
double distancePointLineValue = distancePointLine(participantPosUtmPoint, l1, l2);
|
|
DEBUG_LOG(m_logger) << "distancePointLineValue=" << distancePointLineValue
|
|
<< " ParticipantPos =" << participantPosUtmPoint.x() << "/" << participantPosUtmPoint.y()
|
|
<< " Line=" << l1.x() << "/" << l1.y()
|
|
<< " " << l2.x() << "/" << l2.y();
|
|
if (distancePointLineValue < distance)
|
|
{
|
|
DEBUG_LOG(m_logger) << "posInExtendedForm return true";
|
|
return true;
|
|
}
|
|
}
|
|
DEBUG_LOG(m_logger) << "posInExtendedForm return false";
|
|
return false;
|
|
}
|
|
|
|
double HandlerMineAreas::distancePointLine(const QPointF &p, const QPointF &l1,
|
|
const QPointF &l2) const
|
|
{
|
|
const double u = (((p.x() - l1.x()) * (l2.x() - l1.x())) +
|
|
((p.y() - l1.y()) * (l2.y() - l1.y()))) / squareLen(l2, l1);
|
|
|
|
if ((u < 0.0f) || (u > 1.0f))
|
|
{
|
|
QLineF pToP1(p, l1);
|
|
QLineF pToP2(p, l2);
|
|
qreal length1 = pToP1.length();
|
|
qreal length2 = pToP2.length();
|
|
if (length1 < length2)
|
|
{
|
|
DEBUG_LOG(m_logger) << "a distancePointLine p=" << p.x() << "/" << p.y()
|
|
<< " line: p1=" << l1.x() << "/" << l1.y()
|
|
<< " p2=" << l2.x() << "/" << l2.y()
|
|
<< " distance=" << length1
|
|
<< ", return=" << length1;
|
|
return length1;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << "b distancePointLine p=" << p.x() << "/" << p.y()
|
|
<< " line: p1=" << l1.x() << "/" << l1.y()
|
|
<< " p2=" << l2.x() << "/" << l2.y()
|
|
<< " distance=" << length2
|
|
<< ", return=" << length2;
|
|
return length2;
|
|
}
|
|
}
|
|
|
|
QPointF intersectPnt(l1.x() + u * (l2.x() - l1.x()),
|
|
l1.y() + u * (l2.y() - l1.y()));
|
|
|
|
/* double distance = sqrt(squareLen(p, intersectPnt));
|
|
|
|
DEBUG_LOG(m_logger) << "c distancePointLine p=" << p.x() << "/" << p.y()
|
|
<< " line: p1=" << l1.x() << "/" << l1.y()
|
|
<< " p2=" << l2.x() << "/" << l2.y()
|
|
<< " distance=" << distance;
|
|
return distance;*/
|
|
return 0;
|
|
}
|
|
|
|
double HandlerMineAreas::squareLen(const QPointF &p1, const QPointF &p2) const
|
|
{
|
|
double vx = p2.x() - p1.x();
|
|
double vy = p2.y() - p1.y();
|
|
return vx * vx + vy * vy;
|
|
}
|
|
|
|
} // namespace CesMineAreas
|