/** * 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 "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 : qAsConst(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().is_set()) { 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::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_def::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().is_set()) { 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_def::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().underlying()), 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::FunctionalArea); state.sampleTime(data.sampleTime()); state.vulnerabilityState(ProjectDataManagement::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