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