/** * The ParticipantHandler class manages all participant related function topics and holds classes for * further participant data. * $Id$ * $HeadURL$ * $Author$ * Created by Hannes Baeuerle, SLSE, 2016-05-12 */ #include "participant_handler.h" #include #include "participant.h" #include "ppm_common.h" #include "settings.h" #include "unit_position_calculator.h" #include #include #include namespace ParticipantManagement { namespace ParticipantHandling { // // ParticipantHandler // ParticipantHandler::ParticipantHandler(BaseDataProvider *bdp, const char *loggerName) : QObject(), m_hitLineId(0), m_bdp(bdp), m_logger(getLogger(loggerName)) {} ParticipantHandler::~ParticipantHandler() { if (m_unitPositionCalculator) m_unitPositionCalculator->stopCalculation(); clearParticipants(); } void ParticipantHandler::clearParticipants() { // clear maps for (auto it = m_hitLineInfoMap.cbegin(); it != m_hitLineInfoMap.cend(); ++it) dts()->removeHitLineInfoByKey(it.value().id); m_hitLineInfoMap.clear(); for (auto p : std::as_const(m_participants)) { p->removeFromDds(); delete p; } m_participants.clear(); } bool ParticipantHandler::init() { clearParticipants(); m_unitPositionCalculator.reset(new UnitPositionCalculator(this)); m_webSocketHandler = std::make_shared(this); if (!m_webSocketHandler->init(Settings::getWebSocketServerPortRange(2))) { ERROR_LOG(m_logger) << "could not init websockethandler"; return false; } return true; } void ParticipantHandler::setEquipmentNumberForParticipant(int oldEqNo, int newEqNo, int participantId) { DEBUG_LOG(m_logger) << "setEquipmentNumberForParticipant, old: " << oldEqNo << ", new: " << newEqNo << ", participant: " << participantId; if (oldEqNo > 0) m_equipNumber2ParticipantId.remove(oldEqNo); if (newEqNo > 0) { int &val = m_equipNumber2ParticipantId[newEqNo]; if (val != 0 && val != participantId) WARNING_LOG(m_logger) << "Another participant (" << val << ") already has the equipment number " << newEqNo << " - overriding it with participant " << participantId; val = participantId; } } Participant *ParticipantHandler::participantById(int32_t participantId) const { return m_participants.value(participantId); } Participant *ParticipantHandler::participantByEquipmentNumber(int32_t equipmentNumber) { const int participantId = m_equipNumber2ParticipantId.value(equipmentNumber); DEBUG_LOG(m_logger) << " >>>>>> [ParticipantHandler] participantByEquipmentNumber participantId: " << participantId << " | equipNumb: " << equipmentNumber; return participantById(participantId); } void ParticipantHandler::onNewGearEvent(const TrainingAreaBase::EquipmentGearEvent &gearEvent) { if (isTelegramInFuture(gearEvent)) { WARNING_LOG(m_logger) << "Got an EquipmentGearEvent which has a timestamp in the future: " << gearEvent.sampleTime; return; } // NOTE: gearEvent.chargeAmount() is not used because there is no usecase for this value ... atm Participant *participantToBeChanged = participantByEquipmentNumber(gearEvent.equipmentNumber); if (!participantToBeChanged) { WARNING_LOG(m_logger) << "Got gear charge state for unknown equipment number " << gearEvent.equipmentNumber; return; } participantToBeChanged->setGearCharge(gearEvent.charge, gearEvent.sampleTime); participantToBeChanged->publishDynamicData(); // publish gear event dts()->publish( ParticipantGearEvent(participantToBeChanged->id(), gearEvent.sampleTime, gearEvent.chargeAmount, GearCharge(gearEvent.charge.gearId, gearEvent.charge.gearTypeId, gearEvent.charge.chargeTypeId, gearEvent.charge.remain))); } void ParticipantHandler::onNewGearChargeStateFromProxy(const TrainingAreaBase::EquipmentGearChargeState &chargeState) { if (isTelegramInFuture(chargeState)) { WARNING_LOG(m_logger) << "Got an EquipmentGearChargeState which has a timestamp in the future: " << chargeState.sampleTime; return; } const int equipNo = chargeState.equipmentNumber; Participant *participantToBeChanged = equipNo < 0 ? participantById(-equipNo) : participantByEquipmentNumber(equipNo); if (!participantToBeChanged) { WARNING_LOG(m_logger) << "Got gear charge state for unknown equipment number " << chargeState.equipmentNumber; return; } for (const TrainingAreaBase::GearCharge &charge : chargeState.charge) participantToBeChanged->setGearCharge(charge, chargeState.sampleTime); participantToBeChanged->publishDynamicData(); emit gearChargeChanged(participantToBeChanged->id(), participantToBeChanged->partyId()); } void ParticipantHandler::onNewGearAssignmentFromProxy(const TrainingAreaBase::EquipmentGearAssignment &gearAssignment) { if (isTelegramInFuture(gearAssignment)) { WARNING_LOG(m_logger) << "Got an EquipmentGearAssignment which has a timestamp in the future: " << gearAssignment.sampleTime; return; } Participant *participantToBeChanged = participantByEquipmentNumber(gearAssignment.equipmentNumber); if (!participantToBeChanged) { WARNING_LOG(m_logger) << "Got gear assignment for unknown equipment number " << gearAssignment.equipmentNumber; return; } participantToBeChanged->setGear(gearAssignment); participantToBeChanged->publishDynamicData(); } void ParticipantHandler::onNewStateFromProxy(const TrainingAreaBase::EquipmentState &data) { if (isTelegramInFuture(data)) { WARNING_LOG(m_logger) << "Got an EquipmentState which has a timestamp in the future: " << data.sampleTime; return; } // 1. handle included EquipmentPosition: TrainingAreaBase::EquipmentPosition pos; pos.equipmentNumber = data.equipmentNumber; pos.sampleTime = data.sampleTime; if (data.position.has_value()) { pos.position = data.position.get(); onNewPositionFromProxy(pos); } // 2. handle EquipmentState Participant *participantToBeChanged = participantByEquipmentNumber(data.equipmentNumber); if (!participantToBeChanged) { WARNING_LOG(m_logger) << "Got equipment state for unknown equipment number " << data.equipmentNumber; return; } // convert eqNo to participantId if originator was a participant and data.originatorId() is an equipment number int originatorId = data.originatorId; Participant *originParticipant = nullptr; if (data.originatorType == ProjectDataManagement::StateChangeOriginator::StateChangeOriginator_Participant) { originParticipant = participantByEquipmentNumber(data.originatorId); if (originParticipant) originatorId = originParticipant->id(); else originatorId = -originatorId; } // Make Laser Designations to Laser Designations auto dtcPdm = m_bdp->pdmDtc(); if (dtcPdm && dtcPdm->getChargeTypeSpecialProperty(data.originatorChargeTypeId, 0, 0) == ProjectDataManagement::ChargeTypeProperty::LTD && originParticipant) { QSet ldGearTypes{1043}; // Need Property for LTD... DynamicParticipantData dpd = originParticipant->dynamicParticipantData(); auto it = std::find_if(dpd.gear.cbegin(), dpd.gear.cend(), [ldGearTypes](const GearInformation &gi) { return ldGearTypes.contains(gi.gearTypeId); }); if (it != dpd.gear.cend()) { for (auto &ld : dpd.designations) { if (ld.gearId != it->gearId) continue; ld.spotLocation = pos.position.position; ld.outputPower = 1.0; originParticipant->setDynamicData(dpd); originParticipant->publishDynamicData(); break; } } } if (!participantToBeChanged->setState(data, originatorId)) return; // outdated - ignore participantToBeChanged->publishDynamicData(); createHitlineInfo(originatorId, originParticipant, participantToBeChanged, pos, data.originatorChargeTypeId, data.sampleTime); } void ParticipantHandler::createHitlineInfo(int, Participant *, Participant *, const TrainingAreaBase::EquipmentPosition &, int, qint64) { // replay participant is filled with setHitlineInfoFromReplay return; } void ParticipantHandler::onNewPositionFromProxy(const TrainingAreaBase::EquipmentPosition &position) { if (isTelegramInFuture(position)) { WARNING_LOG(m_logger) << "Got an EquipmentPosition which has a timestamp in the future: " << position.sampleTime; return; } if (isTelegramOutdated(position) && position.position.reportingSource != Core::PositionReportingSource::SetByOperator) { INFO_LOG(m_logger) << "position is outdated: " << position; return; } DEBUG_LOG(m_logger) << "Got new position from proxy: " << position; const int equipNo = position.equipmentNumber; // negative - treat as participantId Participant *participantWithNewPosition = equipNo < 0 ? participantById(-equipNo) : participantByEquipmentNumber(equipNo); if (!participantWithNewPosition) { WARNING_LOG(m_logger) << "Got EquipmentPosition " << position << " for unknown equipment number: " << equipNo; return; } if (participantWithNewPosition->setPosition(position)) participantWithNewPosition->publishPosition(); } void ParticipantHandler::onNewEquipmentOperationalStateFromProxy(const TrainingAreaBase::EquipmentOperationalState &operationalState) { if (isTelegramInFuture(operationalState)) { WARNING_LOG(m_logger) << "Got an EquipmentOperationalState which has a timestamp in the future: " << operationalState.sampleTime; return; } Participant *participantToUpdate = participantByEquipmentNumber(operationalState.equipmentNumber); if (!participantToUpdate) { WARNING_LOG(m_logger) << "Got EquipmentOperationalState for unknown equipment number: " << operationalState; return; } participantToUpdate->setOperationalState(operationalState); participantToUpdate->publishDynamicData(); } void ParticipantHandler::onNewBiteFromProxy(const TrainingAreaBase::EquipmentBite &bite) { if (isTelegramInFuture(bite)) { WARNING_LOG(m_logger) << "Got an EquipmentBite which has a timestamp in the future: " << bite.sampleTime; return; } if (isTelegramOutdated(bite)) { WARNING_LOG(m_logger) << "Got an EquipmentBite which has a timestamp in the past: " << bite.sampleTime; return; } Bite biteData; Participant *p = participantByEquipmentNumber(bite.equipmentNumber); biteData.participantId = p ? p->id() : -1; biteData.equipmentNumber = bite.equipmentNumber; biteData.sampleTime = bite.sampleTime; biteData.registerType = bite.registerType; biteData.biteState = bite.biteState; biteData.configState = bite.configState; biteData.batteryState = bite.batteryState; biteData.configError = bite.configError; biteData.biteErrors.reserve(bite.biteErrors.size()); for (const TrainingAreaBase::EquipmentBiteError &error : bite.biteErrors) biteData.biteErrors.emplace_back(error.errorNumber, error.canDeviceNumber, error.subdeviceNumber, error.uniqueId); dts()->publish(biteData); } void ParticipantHandler::onNewCtaDataErrorFromProxy(const TrainingAreaBase::CtaDataError &error) { CtaError ctasErrorData; ctasErrorData.equipmentNumber = error.equipmentNumber; ctasErrorData.timeReceipt = currentTimeMSec(); ctasErrorData.timePlayerUnit = error.sampleTime; ctasErrorData.errorReason = error.reason; ctasErrorData.telegramId = error.originTelegramId; dts()->publish(ctasErrorData); } void ParticipantHandler::onNewParticipantModeReport(const TrainingAreaBase::ParticipantModeReport &report) { if (isTelegramInFuture(report)) { WARNING_LOG(m_logger) << "Got a ParticipantModeReport which has a timestamp in the future: " << report.sampleTime; return; } if (isTelegramOutdated(report)) { WARNING_LOG(m_logger) << "Got a ParticipantModeReport which has a timestamp in the past: " << report.sampleTime; return; } Participant *participant = participantByEquipmentNumber(report.equipmentNumber); if (!participant) { ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << report.equipmentNumber; return; } ParticipantMode ddsData; ddsData.participantId = participant->id(); ddsData.language = report.language; ddsData.opMode = report.operationMode; ddsData.reactivationDecontamination = report.reactivationDetoxication; ddsData.reactivationMaintenance = report.reactivationMaintenance; ddsData.reactivationMedic = report.reactivationMedic; ddsData.modeVest = report.protectionModeVest; ddsData.modeHelmet = report.protectionModeHelmet; ddsData.modePersonalProtection = report.personellProtectionMode; ddsData.protectionLevel = report.protectionLevel; ddsData.handgrenadeSearchMode = report.handgrenadeSearchMode; ddsData.internationalMode = report.internationalMode; ddsData.abcProtectionMode = report.abcProtectionMode; ddsData.sampleTime = report.sampleTime; participant->setMode(ddsData); participant->publishMode(); } void ParticipantHandler::onNewSpecialSensorData(const TrainingAreaBase::SpecialSensorData &data) { if (isTelegramInFuture(data)) { WARNING_LOG(m_logger) << "Got a SpecialSensorData which has a timestamp in the future: " << data.sampleTime; return; } if (isTelegramOutdated(data)) { WARNING_LOG(m_logger) << "Got a SpecialSensorData which has a timestamp in the past: " << data.sampleTime; return; } Participant *participant = data.equipmentNumber < 0 ? participantById(-data.equipmentNumber) : participantByEquipmentNumber(data.equipmentNumber); if (!participant) { ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber; return; } TrainingAreaBase::EquipmentPosition pos; pos.equipmentNumber = data.equipmentNumber; pos.sampleTime = data.sampleTime; if (data.position.has_value()) { Core::GeoPosition geoPos(data.position.get().lon, data.position.get().lat, 0); pos.position.position = geoPos; if (participant->setPosition(pos)) participant->publishPosition(); } participant->setSpecialSensorData(data); participant->publishDynamicData(); } void ParticipantHandler::onNewLaserDesignation(const TrainingAreaBase::LaserDesignation &data) { DEBUG_LOG(m_logger) << "New Laser Designation: " << "Code: " << data.code << ", GearID: " << data.gearId << ", EqNo: " << data.equipmentNumber << ", Lon: " << data.spotLocation.lon << ", Lat: " << data.spotLocation.lat << ", Power: " << data.outputPower; Participant *participant = participantByEquipmentNumber(data.equipmentNumber); if (!participant) { ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber; return; } DynamicParticipantData dpd = participant->dynamicParticipantData(); DEBUG_LOG(m_logger) << "Begin Update Laser Designation: "; updateLaserDesignation(dpd, data); DEBUG_LOG(m_logger) << "End Update Laser Designation: "; DEBUG_LOG(m_logger) << "Set DPD and publish "; participant->setDynamicData(dpd); participant->publishDynamicData(); } void ParticipantHandler::onLaserDesignationRemoved(int equipmentNumber, int gearId) { DEBUG_LOG(m_logger) << "On Remove Laser Designation: "; Participant *participant = participantByEquipmentNumber(equipmentNumber); if (!participant) { ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << equipmentNumber; return; } DynamicParticipantData dpd = participant->dynamicParticipantData(); DEBUG_LOG(m_logger) << "Begin Remove Laser Designation: "; removeLaserDesignation(dpd, gearId); DEBUG_LOG(m_logger) << "End Remove Laser Designation: "; DEBUG_LOG(m_logger) << "Set DPD and publish "; participant->setDynamicData(dpd); participant->publishDynamicData(); } void ParticipantHandler::onBuildingHitLineInfo(const Buildings::BuildingHitLineInfo &data) { DEBUG_LOG(m_logger) << "onBuildingHitLineInfo " << "BuildingId=" << data.buildingId << " originatorParticipantId=" << data.originatorParticipantId; auto dtcPdm = m_bdp->pdmDtc(); // NOTE: igniterTypeId/IgniterFunction = 0 as long as BuildingHitLineInfo does not contain values if (dtcPdm->getChargeTypeSpecialProperty(data.chargeTypeId, 0, 0) != ProjectDataManagement::ChargeTypeProperty::LTD) return; Participant *participant = participantById(data.originatorParticipantId); if (!participant) { ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with participantId: " << data.originatorParticipantId; return; } DynamicParticipantData dpd = participant->dynamicParticipantData(); DEBUG_LOG(m_logger) << "Begin Update Laser Designation: "; updateLaserDesignation(dpd, data); DEBUG_LOG(m_logger) << "End Update Laser Designation: "; DEBUG_LOG(m_logger) << "setDynamicData"; participant->setDynamicData(dpd); DEBUG_LOG(m_logger) << "publishDynamicData" << " dpd.designations().size()=" << dpd.designations.size(); participant->publishDynamicData(); } void ParticipantHandler::onSanitaryMaterialStockReport(const TrainingAreaBase::ParticipantSanitaryMaterialStockReport &data) { DEBUG_LOG(m_logger) << "onSanitaryMaterialStockReport"; Participant *participant = participantByEquipmentNumber(data.equipmentNumber); if (!participant) { ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber; return; } if (data.qualification == TrainingAreaBase::Qualification::NotDefined) { DEBUG_LOG(m_logger) << "!!! Clear Materials : equipment number " << data.equipmentNumber; DEBUG_LOG(m_logger) << "!!! Clear Materials : sample time " << data.sampleTime; participant->setSanitationMaterial(0, std::vector(), data.uniqueId, data.sampleTime, Qualification::NotAssigned, data.originatorEquipmentNumber); // this is a deassociation so clear material } else { DEBUG_LOG(m_logger) << "!!! Set Materials : equipment number " << data.equipmentNumber; DEBUG_LOG(m_logger) << "!!! Set Materials : sample time " << data.sampleTime; participant->setSanitationMaterial(data.sanitaryMaterialCount, data.sanitaryMaterialStock, data.uniqueId, data.sampleTime, static_cast(data.qualification), data.originatorEquipmentNumber); } participant->publishDynamicData(); } void ParticipantHandler::onParticipantSanitation(const TrainingAreaBase::ParticipantSanitation &data) { Participant *participant = participantByEquipmentNumber(data.equipmentNumber); Participant *participantOrig = participantByEquipmentNumber(data.originatorEquipmentNumber); if (!participant) { ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber; return; } int participantOrigId = data.originatorEquipmentNumber; if (participantOrig) participantOrigId = participantOrig->id(); if (data.qualification == TrainingAreaBase::Qualification::NotDefined && data.proceduresTaken == 0) { DEBUG_LOG(m_logger) << "!!! Clear Sanitation = " << data.sampleTime; DEBUG_LOG(m_logger) << "!!! Clear Sanitation: equipNo = " << data.equipmentNumber; participant->setSanitationMaterial(0, std::vector(), 0, data.sampleTime, Qualification::NotAssigned, 0); // this is a deassociation so clear material } else { DEBUG_LOG(m_logger) << "!!! SetSanitation: sample time = " << data.sampleTime; DEBUG_LOG(m_logger) << "!!! SetSanitation: equipNo = " << data.equipmentNumber; participant->setSanitation(data.proceduresTaken, data.sanitationResult, data.sanitationEvaluation, participantOrigId, data.qualification, data.sampleTime); } participant->publishDynamicData(); } void ParticipantHandler::onOperatorAction(const TrainingAreaBase::OperatorAction &data) { // maybe use other commands later?! if (data.action != 8 && data.action != 35) return; Participant *participant = participantByEquipmentNumber(data.equipmentNumber); if (!participant) { ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber; return; } if (participant->setOperatorAction(data.action, data.operatorId, data.sampleTime)) participant->publishDynamicData(); } void ParticipantHandler::onEquipmentEvent(const TrainingAreaBase::EquipmentEvent &data) { // maybe use other commands later?! if (data.source.subDeviceId != 14 || data.source.equipmentFunctionId != 5) return; if (data.code == 1 || data.code == 2) // 1: 9Liner 2: Transport { Participant *participant = participantByEquipmentNumber(data.equipmentNumber); if (!participant) return; if (participant->setEquipmentEvent(data.code, data.sampleTime)) participant->publishDynamicData(); } } void ParticipantHandler::onNewFunctionalAreaEntryChanged(const TrainingAreaBase::FunctionalAreaEntry &data) { Participant *participant = participantByEquipmentNumber(data.equipmentNumber); if (!participant) { ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with equipment number " << data.equipmentNumber; return; } TrainingAreaBase::EquipmentPosition pos; pos.equipmentNumber = data.equipmentNumber; pos.sampleTime = data.sampleTime; Core::GeoPosition geoPos(data.position.lon, data.position.lat, 0); pos.position.position = geoPos; if (participant->setPosition(pos)) participant->publishPosition(); StateInformation oldState = youngestStateInformation(participant->dynamicParticipantData().stateHistory, false); TrainingAreaBase::EquipmentState state; state.equipmentNumber = data.equipmentNumber; state.originatorId = data.aesItemId; state.originatorType = ProjectDataManagement::StateChangeOriginator::StateChangeOriginator_FunctionalArea; state.sampleTime = data.sampleTime; state.vulnerabilityState = ProjectDataManagement::VulnerabilityState::VulnerabilityState_HitWithNoEffect; // no effect - it's an entry into a functional area state.vulnerabilityBits = oldState.vulnerabilityBits; state.vulnerabilityKindId = oldState.vulnerabilityKindId; state.vitality = oldState.vitality; participant->setState(state, data.aesItemId); participant->publishDynamicData(); } inline bool isOutdated(qint64 curTime, qint64 posTime) { // maxDisplayDuration = 2min -> use 3min return curTime > (posTime + 3 * 60 * 1000); } void ParticipantHandler::onHitLineInfoTimeout() { const qint64 tNow = currentTimeMSec(); auto it = m_hitLineInfoMap.begin(); while (it != m_hitLineInfoMap.end()) { if (!isOutdated(tNow, it.value().sampleTime)) break; dts()->removeHitLineInfoByKey(it.value().id); it = m_hitLineInfoMap.erase(it); } } void ParticipantHandler::setPosition(const ParticipantManagement::ParticipantPosition &data) { Participant *participant = participantById(data.participantId); if (!participant) { ERROR_LOG(m_logger) << LOGFUNCTION << "Could not find participant with id " << data.participantId; return; } participant->setPosition(data, true); } void ParticipantHandler::setHitlineInfoFromReplay(const HitLineInfo &data) { if (!dts()->publish(data)) return; m_hitLineInfoMap.insert(data.id, data); } void ParticipantHandler::setUASFromReplay(const UAS &data) { dts()->publish(data); } bool ParticipantHandler::isSupportTypeClass(const ParticipantManagement::TypeClass &typeClass) { return (typeClass == TypeClass::SupportUnit || typeClass == TypeClass::SupportEntity); } bool ParticipantHandler::isSampleTimeOutdated(qint64 sampleTime) const { const qint64 curTime = currentTimeMSec(); return sampleTime < curTime - 11 * 60 * 1000; } bool ParticipantHandler::isSampleTimeInFuture(qint64 sampleTime) const { const qint64 curTime = currentTimeMSec(); return sampleTime > curTime + 1 * 60 * 1000; } std::shared_ptr ParticipantHandler::dts() const { return m_bdp->dts(); } qint64 ParticipantHandler::currentTimeMSec() const { return m_bdp->currentTimeMSec(); } quint16 ParticipantHandler::getWebSocketPort() const { return m_webSocketHandler->listenPort(); } void ParticipantHandler::updateLaserDesignation(DynamicParticipantData &data, const TrainingAreaBase::LaserDesignation &newLaserDesignation) { LOGGER_T m_logger = getLogger("ParticipantHandler.Laser"); DEBUG_LOG(m_logger) << "-Update Laser Designation - Start "; for (LaserDesignation &laserDesignation : data.designations) { if (laserDesignation.gearId != newLaserDesignation.gearId) continue; DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << laserDesignation.gearId << " found in designations"; laserDesignation.code = newLaserDesignation.code; if (!qFuzzyIsNull(laserDesignation.outputPower) && !qFuzzyIsNull(newLaserDesignation.spotLocation.lat) && !qFuzzyIsNull(newLaserDesignation.spotLocation.lon)) laserDesignation.spotLocation = Core::GeoPosition(newLaserDesignation.spotLocation.lon, newLaserDesignation.spotLocation.lat, 0.0); // If Laser was on before and now is turned off, we have to reset spot Location if (!qFuzzyIsNull(laserDesignation.outputPower) && qFuzzyIsNull(newLaserDesignation.outputPower)) laserDesignation.spotLocation = Core::GeoPosition(0.0, 0.0, 0.0); laserDesignation.outputPower = newLaserDesignation.outputPower; DEBUG_LOG(m_logger) << "-Update Laser Designation - Data updated, returning"; return; } DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << newLaserDesignation.gearId << " NOT found in designations"; int gearId = newLaserDesignation.gearId; auto it = std::find_if(data.gear.cbegin(), data.gear.cend(), [gearId](const GearInformation &gi) { return gearId == gi.gearId; }); if (it == data.gear.cend()) // No gear, no designation... { DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << newLaserDesignation.gearId << " NOT found in Gears"; return; } DEBUG_LOG(m_logger) << "-Update Laser Designation - Gear with id " << newLaserDesignation.gearId << " found in Gears"; DEBUG_LOG(m_logger) << "-Update Laser Designation - Adding new designation"; data.designations.emplace_back(newLaserDesignation.gearId, Core::GeoPosition(newLaserDesignation.spotLocation.lon, newLaserDesignation.spotLocation.lat, 0.0), newLaserDesignation.code, newLaserDesignation.outputPower); } void ParticipantHandler::updateLaserDesignation(DynamicParticipantData &dataInOut, const Buildings::BuildingHitLineInfo &newLaserDesignation) { LOGGER_T m_logger = getLogger("ParticipantHandler.Laser"); // Todo: Die erste vorhandene LaserDesignation wird angepasst. Ein Laser On muss vorher gekommen sein, damit das Element da ist. // Mehrere Designatoren pro Teilnehmer werden nicht unterstützt. DEBUG_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info"; for (LaserDesignation &laserDesignation : dataInOut.designations) { DEBUG_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info - Updating (first) Designation with GearId " << laserDesignation.gearId; laserDesignation.outputPower = 1.0; laserDesignation.spotLocation = newLaserDesignation.buildingPos; return; } QSet ldGearTypes{1043}; // Need Property for LTD... auto it = std::find_if(dataInOut.gear.cbegin(), dataInOut.gear.cend(), [ldGearTypes](const GearInformation &gi) { return ldGearTypes.contains(gi.gearTypeId); }); if (it != dataInOut.gear.cend()) { LaserDesignation ld; ld.gearId = it->gearId; ld.code = 0; ld.spotLocation = newLaserDesignation.buildingPos; ld.outputPower = 1.0; dataInOut.designations.emplace_back(ld); ERROR_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info - Added Designation"; } ERROR_LOG(m_logger) << "-Update Laser Designation by Building Hitline Info - No laserDesignation available participantId=" << newLaserDesignation.originatorParticipantId; } void ParticipantHandler::removeLaserDesignation(DynamicParticipantData &data, qint32 gearId) { LOGGER_T m_logger = getLogger("ParticipantHandler.Laser"); DEBUG_LOG(m_logger) << "-Remove Laser Designation: Start"; auto validationFunction = [gearId](ParticipantManagement::LaserDesignation laserDesignation) { return laserDesignation.gearId == gearId; }; auto eraseIterator = std::find_if(data.designations.begin(), data.designations.end(), validationFunction); if (eraseIterator == data.designations.end()) { DEBUG_LOG(m_logger) << "-Remove Laser Designation: GearId NOT found"; return; } DEBUG_LOG(m_logger) << "-Remove Laser Designation: Removing Designation"; data.designations.erase(eraseIterator); } } // namespace ParticipantHandling } // namespace ParticipantManagement