/** * Handler for player data * $Id$ * $HeadURL$ * $Author$ * Created by hjl, SLSE, 2017-02-20 */ #include "handler_contamination.h" #include #include #include #include namespace CesBuildings { HandlerContamination::HandlerContamination(const std::shared_ptr &ddsHandler, QObject *parent) : QObject(parent) , m_ddsHandler(ddsHandler) , m_logger(CentralEffectSimulation::getLogger("Plugin.Buildings.Buildings")) { } // end of ctor() //----------------------------------------------------------------------------- HandlerContamination::~HandlerContamination() { } // end of dtor() //----------------------------------------------------------------------------- bool HandlerContamination::init() { auto dtcAes = m_ddsHandler->dtcAes(); auto ftcBld = m_ddsHandler->ftcBld(); auto dtcBld = m_ddsHandler->dtcBld(); ftcBld->enableSetBuildingContaminationState(); //////////////////////////// /// \brief Get 'static' data for all BCContaminations /// dtcAes->waitForHistoricalDataBCContamination(1000); connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::bCContaminationChanged, this, &HandlerContamination::onBCContaminationChanged); // Get 'static' data for all BCContaminations { auto cb = [this](const AreaEffectSimulation::BCContamination & bcc) { onBCContaminationChanged(bcc, DataModification::eAdded); }; if (!dtcAes->bCContaminations(cb)) return false; } //////////////////////////// /// \brief Get 'static' data for all AesItemView /// dtcAes->waitForHistoricalDataAesItemView(1000); connect(dtcAes.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged, this, &HandlerContamination::onAesItemViewChanged); // Get 'static' data for all AesItemView { auto cb = [this](const AreaEffectSimulation::AesItemView & aiv) { onAesItemViewChanged(aiv, DataModification::eAdded); }; if (!dtcAes->aesItemViews(cb)) return false; } //////////////////////////// /// \brief Get data for all Building States /// dtcBld->waitForHistoricalDataBuildingState(1000); connect(dtcBld.get(), &Buildings::Interface::Dtc::buildingStateChanged, this, &HandlerContamination::onBuildingStateChanged); // Get 'static' data for all buildingStates { auto cb = [this](const Buildings::BuildingState & bs) { onBuildingStateChanged(bs, DataModification::eAdded); }; if (!dtcBld->buildingStates(cb)) return false; } return true; } // end of init() //----------------------------------------------------------------------------- // /////////////////////////////////// // A E S (AreaEffectSimulation) // /////////////////////////////////// void HandlerContamination::onAesItemViewChanged(const AreaEffectSimulation::AesItemView &data, DataModification modType) { if (modType != DataModification::eAdded && modType != DataModification::eModified) return; DEBUG_LOG(m_logger) << "Got AesItemView: " << data.effectStateId() << " data.aesItemId()" << data.aesItemId() << " data.aesTypeId()" << data.aesTypeId(); switch (data.effectStateId().underlying()) { case AreaEffectSimulation::AesEffectState_def::EsActivated: { double chargeHeight; // Alle Stockwerke beruecksichtigen double chargeDepression; // Alle Kellerraeume beruecksichtigen if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtNContamination) { chargeHeight = 500.0; // Alle Stockwerke beruecksichtigen chargeDepression = -1000.0; // Alle Kellerraeume beruecksichtigen DEBUG_LOG(m_logger) << "AtNContamination: chargeHeight=" << chargeHeight << " chargeDepression=" << chargeDepression; } else { chargeHeight = m_aesBCContaminations.value(data.aesItemId()).upperOffset(); chargeDepression = m_aesBCContaminations.value(data.aesItemId()).lowerOffset(); DEBUG_LOG(m_logger) << "BCContaminations: chargeHeight=" << chargeHeight << " chargeDepression=" << chargeDepression; } if (data.aesTypeId() != AreaEffectSimulation::AesType_def::AtBCContamination && data.aesTypeId() != AreaEffectSimulation::AesType_def::AtNContamination) { DEBUG_LOG(m_logger) << "return1: AesItemView: " << data.effectStateId(); return; } // Gebaeude die von einem sesshaften Kampfstoff betroffen sind, müssen als kontaminiert gelten. const ProjectDataManagement::VolatilityType volatilityType = m_ddsHandler->volatilityTypeId(data.chargeStruct()); if (volatilityType != ProjectDataManagement::VolatilityType_def::Resident && data.aesTypeId() != AreaEffectSimulation::AesType_def::AtNContamination) { DEBUG_LOG(m_logger) << "return2: AesItemView: " << data.effectStateId(); return; } DEBUG_LOG(m_logger) << "HandlerContamination::onAesItemViewChanged data.aesItemId=" << data.aesItemId(); auto dtcIsm = m_ddsHandler->dtcIsm(); // Form in UTM-Polygon wandeln int exerciseId = m_ddsHandler->getExerciseId(); QPolygonF polygonGeo; // Convert Form to UTM for (unsigned int i = 0; i < data.form().size(); i++) polygonGeo.append(QPointF(data.form()[i].lon(), data.form()[i].lat())); bool completeEnclosed = true; bool isGroundLevel = false; const QVector &buildingIds = dtcIsm.get()->getBuildingByPolygon(exerciseId, polygonGeo, completeEnclosed, isGroundLevel); DEBUG_LOG(m_logger) << "buildingIds.size=" << buildingIds.size(); for (int buildingId : qAsConst(buildingIds)) { calculateBuilding(buildingId, data, chargeHeight, chargeDepression); } // break; } default: break; } } void HandlerContamination::calculateBuilding(int buildingId, const AreaEffectSimulation::AesItemView &data, double chargeHeight, double chargeDepression) { auto dtcIsm = m_ddsHandler->dtcIsm(); QVector effectedRooms; QVector effectedFloors; if (data.aesTypeId() != AreaEffectSimulation::AesType_def::AtBCContamination && data.aesTypeId() != AreaEffectSimulation::AesType_def::AtNContamination) { DEBUG_LOG(m_logger) << "return: NO BC-Contamination AesItemView: " << data.effectStateId(); return; } const ProjectDataManagement::VolatilityType volatilityType = m_ddsHandler->volatilityTypeId(data.chargeStruct()); if ( volatilityType != ProjectDataManagement::VolatilityType_def::Resident && data.aesTypeId() != AreaEffectSimulation::AesType_def::AtNContamination) return; DEBUG_LOG(m_logger) << "buildingId=" << buildingId; effectedRooms.clear(); effectedFloors = getEffectedFloors(buildingId, chargeHeight, chargeDepression); for (int effectedFloor : qAsConst(effectedFloors)) effectedRooms += dtcIsm.get()->getRoomIdsFromFloorId(buildingId, effectedFloor); if (!effectedRooms.empty()) { DEBUG_LOG(m_logger) << "effectedRooms.size=" << effectedRooms.size(); ProjectDataManagement::VulnerabilityState vulnerabilityState = ProjectDataManagement::VulnerabilityState::CombatReady; // [GUEZE-2752] N-Contamination: Only Contamionation inside Range1 if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtNContamination && !isInsideRange1(buildingId, data.aesItemId())) { DEBUG_LOG(m_logger) << "!isInsideRange1 buildingId=" << buildingId; return; } if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtBCContamination && !isInsideBCContamination(buildingId, data.aesItemId())) { DEBUG_LOG(m_logger) << "AtBCContamination !isInsideRange buildingId=" << buildingId << "return"; return; } if (data.aesTypeId() == AreaEffectSimulation::AesType_def::AtNContamination && isInsideInnerCircle(buildingId, data.aesItemId())) { constexpr int TIME_2_SECONDS = 2000; // Only actual explosion not old N-Fields if ( m_ddsHandler->dtcCore()->partitionTime().timeStamp() < (data.effectStart() + TIME_2_SECONDS)) { DEBUG_LOG(m_logger) << "VulnerabilityState=CatastrophicKill"; vulnerabilityState = ProjectDataManagement::VulnerabilityState::CatastrophicKill; } } DEBUG_LOG(m_logger) << "setBuildingContaminationStateRequest buildingId=" << buildingId << " data.aesTypeId()=" << data.aesTypeId() << " isInsideInnerCircle(buildingId, data.aesItemId()=" << isInsideInnerCircle(buildingId, data.aesItemId()); { DEBUG_LOG(m_logger) << "isInsideInnerCircle buildingId=" << buildingId; setBuildingContaminationStateRequest(buildingId, data.aesItemId(), vulnerabilityState, effectedRooms); } } } // /////////////////////////////////// // B L D (Buildings) // /////////////////////////////////// void HandlerContamination::onBuildingStateChanged(const Buildings::BuildingState &data, DataModification modType) { if (modType != DataModification::eAdded && modType != DataModification::eModified) return; INFO_LOG(m_logger) << "onBuildingStateChanged" << " id=" << data.id() << " aesId=" << data.aesId() << " contaminationStates().size=" << data.contaminationStates().size(); // Reset: if (data.contaminationStates().empty()) m_contaminationState.remove(data.id()); // If a building is reset in an area where there is an active nuclear weapon, it will not be recontaminated -> in this case, // regular checks should be carried out to see if the building needs to be contaminated // Buildings that have been reset or decontaminated will be recontaminated as long as the nuclear weapon is still present const auto aesItemViews = m_ddsHandler->dtcAes()->aesItemViews(); for (const auto &aesItemView : qAsConst(aesItemViews)) { if (aesItemView.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated) { DEBUG_LOG(m_logger) << "Wirkfeld aesItemView.id()=" << aesItemView.id() << " aesItemView.aesItemId()=" << aesItemView.aesItemId() << " fuer Gebaeude " << data.id() << " neu berechnen"; double chargeHeight = 0.0; double chargeDepression = 0.0; if (aesItemView.aesTypeId() == AreaEffectSimulation::AesType_def::AtNContamination) { chargeHeight = 500.0; // Alle Stockwerke beruecksichtigen chargeDepression = -1000.0; // Alle Kellerraeume beruecksichtigen DEBUG_LOG(m_logger) << "AtNContamination: chargeHeight=" << chargeHeight << " chargeDepression=" << chargeDepression; } else { if ( m_aesBCContaminations.contains(aesItemView.aesItemId())) { chargeHeight = m_aesBCContaminations.value(aesItemView.aesItemId()).upperOffset(); chargeDepression = m_aesBCContaminations.value(aesItemView.aesItemId()).lowerOffset(); DEBUG_LOG(m_logger) << "BCContaminations: chargeHeight=" << chargeHeight << " chargeDepression=" << chargeDepression; } else { DEBUG_LOG(m_logger) << "BCContaminations: m_aesBCContaminations not contains:"<< aesItemView.aesItemId(); } } // [GUEZE-2527] Fehler bei A-Waffen und Dekontaminierung auto dtcIsm = m_ddsHandler->dtcIsm(); int exerciseId = m_ddsHandler->getExerciseId(); QPolygonF polygonGeo; polygonGeo.reserve(aesItemView.form().size()); // Convert Form to UTM for (const auto point : aesItemView.form()) polygonGeo.append(QPointF(point.lon(), point.lat())); bool completeEnclosed = true; bool isGroundLevel = false; const QVector &buildingIds = dtcIsm.get()->getBuildingByPolygon(exerciseId, polygonGeo, completeEnclosed, isGroundLevel); if (buildingIds.contains(data.id() )) calculateBuilding(data.id(), aesItemView, chargeHeight, chargeDepression); else DEBUG_LOG(m_logger) << "Building not in Area BuildingId=" << data.id(); } } } void HandlerContamination::setBuildingContaminationStateRequest(int buildingId, int aesId, ProjectDataManagement::VulnerabilityState vulnerabilityState, QVector rooms) { Buildings::ContaminationState contaminationState; contaminationState.aesId(aesId); contaminationState.vulnerabilityState(vulnerabilityState); // contaminationState.vulne DEBUG_LOG(m_logger) << "setBuildingContaminationStateRequest" << " buildingId=" << buildingId << " aesId=" << aesId << " vulnerabilityState=" << vulnerabilityState << " rooms.size=" << rooms.size(); contaminationState.rooms().resize(rooms.size()); for (int i = 0; i < rooms.size(); i++) { contaminationState.rooms()[i] = rooms[i]; contaminationState.vulnerabilityState(vulnerabilityState); DEBUG_LOG(m_logger) << " room[" << i << "]=" << rooms[i]; } Buildings::SetBuildingContaminationStateRequest requestContamination( buildingId, contaminationState ); // Senden, wenn fuer das Gebaeude noch keine Contamination vorhanden ist. if (!m_contaminationState.contains(buildingId)) { DEBUG_LOG(m_logger) << "Neue Kontamination BuildingId=" << buildingId << " requestContamination aesId=" << requestContamination.contaminationState().aesId(); m_ddsHandler->ftcBld()->setBuildingContaminationStateRequest(requestContamination, this); m_contaminationState.insert(buildingId, requestContamination); return; } // Senden, wenn sich die Kontamination geaendert hat. Buildings::SetBuildingContaminationStateRequest lastRequestContamination = m_contaminationState.value(buildingId); if (lastRequestContamination != requestContamination) { DEBUG_LOG(m_logger) << "Änderung der Kontamination BuildingId=" << buildingId << " aesId=" << requestContamination.contaminationState().aesId(); m_ddsHandler->ftcBld()->setBuildingContaminationStateRequest(requestContamination, this); m_contaminationState.insert(buildingId, requestContamination); return; } DEBUG_LOG(m_logger) << "Keine Änderung der Kontamination BuildingId=" << buildingId; } QVector HandlerContamination::getEffectedFloors(const int buildingId, const int chargeHeight, const int depression) { auto dtcIsm = m_ddsHandler->dtcIsm(); DEBUG_LOG(m_logger) << "Contaminated-Building=" << buildingId << " chargeHeight=" << chargeHeight << " depression=" << depression; const QVector &floorIds = dtcIsm->getFloorIdsFromBuilding(buildingId); QVector effectedFloorIds; effectedFloorIds.reserve(floorIds.size()); for (int floorId : qAsConst(floorIds)) { double halfFloorHeight = dtcIsm->getHalfFloorHeight(buildingId, floorId); DEBUG_LOG(m_logger) << " floorId=" << floorId << " halfFloorHeight=" << halfFloorHeight << " chargeHeight=" << chargeHeight << " depression=" << depression; if (depression < 0) // Kellerraeme beruecksichtigen { if (halfFloorHeight > depression) DEBUG_LOG(m_logger) << "Checke Obergrenze"; else { DEBUG_LOG(m_logger) << "halfFloorHeight > depression floorId=" << floorId << " continue"; continue; } } else { if (halfFloorHeight < 0) // Kellerraeume nicht beruecksichtigen { DEBUG_LOG(m_logger) << "depression ist nicht < 0" << " Kelleretagen nicht beruecksichtigen floorId=" << floorId << " continue"; continue; } } if (halfFloorHeight < chargeHeight) effectedFloorIds.append(floorId); } return effectedFloorIds; } void HandlerContamination::onSetBuildingContaminationStateReply(const Core::FunctionReplyObject &replyObject) { if (replyObject.error()) WARNING_LOG(m_logger) << "Can not send ContaminationStates on building to building service: " << replyObject(); else DEBUG_LOG(m_logger) << "onSetBuildingContaminationStateReply for id " << replyObject.id() << " success\n" << " replyObject.str() = " << replyObject.str(); } void HandlerContamination::onBCContaminationChanged(const AreaEffectSimulation::BCContamination &data, DataModification modType) { if ((modType == DataModification::eRemoved) || data.isDeleted()) m_aesBCContaminations.remove(data.id()); else m_aesBCContaminations.insert(data.id(), data); } // Returns true if the building is in the inner circle at the time of impact and should fail as a result. // Liefert true, wenn sich das Gebaeude beim Einschlag im inneren Kreis befindet und daraufhin ausfallen soll. bool HandlerContamination::isInsideInnerCircle(int buildingId, int aesId) { InfrastructureManagement::MainStructureElement mse = m_ddsHandler->dtcIsm()->mainStructureElement(buildingId); AreaEffectSimulation::NContamination nContamination = m_ddsHandler->dtcAes()->nContamination(aesId); DEBUG_LOG(m_logger) << "isInsideInnerCircle borderLengthInner=" << nContamination.borderLengthInner() << " borderLengthOuter=" << nContamination.borderLengthOuter() << " impactRadius=" << nContamination.impactRadius(); int zone = -1; const QPointF impactPositionUtm = CentralEffectSimulation::geographic2Utm(nContamination.impactPosition(), zone); DEBUG_LOG(m_logger) << "impactPositionUtm=" << impactPositionUtm.x() << "/" << impactPositionUtm.y() << " zone=" << zone; const QPointF buildingPositionUtm = CentralEffectSimulation::geographic2Utm(mse.geoPosition(), zone); DEBUG_LOG(m_logger) << "buildingPositionUtm=" << buildingPositionUtm.x() << "/" << buildingPositionUtm.y(); double squareDistance = CentralEffectSimulation::getSquareDistance(impactPositionUtm, buildingPositionUtm); if (squareDistance < nContamination.impactRadius() * nContamination.impactRadius()) { DEBUG_LOG(m_logger) << "isInsideInnerCircle return true"; return true; } else { DEBUG_LOG(m_logger) << "isInsideInnerCircle return false"; return false; } } // Returns true if the building is in the inner circle at the time of impact and should fail as a result. // Liefert true, wenn sich das Gebaeude beim Einschlag im inneren Kreis befindet und daraufhin ausfallen soll. bool HandlerContamination::isInsideBCContamination(int buildingId, int aesId) { InfrastructureManagement::MainStructureElement mse = m_ddsHandler->dtcIsm()->mainStructureElement(buildingId); //AreaEffectSimulation::NContamination nContamination = m_ddsHandler->dtcAes()->nContamination(aesId); AreaEffectSimulation::BCContamination bcContamination = m_ddsHandler->dtcAes()->bCContamination(aesId); DEBUG_LOG(m_logger) << " impactRadius=" << bcContamination.impactRadius(); int zone = -1; const QPointF impactPositionUtm = CentralEffectSimulation::geographic2Utm(bcContamination.impactPosition(), zone); DEBUG_LOG(m_logger) << "impactPositionUtm=" << impactPositionUtm.x() << "/" << impactPositionUtm.y() << " zone=" << zone; const QPointF buildingPositionUtm = CentralEffectSimulation::geographic2Utm(mse.geoPosition(), zone); DEBUG_LOG(m_logger) << "buildingPositionUtm=" << buildingPositionUtm.x() << "/" << buildingPositionUtm.y(); double squareDistance = CentralEffectSimulation::getSquareDistance(impactPositionUtm, buildingPositionUtm); if (squareDistance < bcContamination.impactRadius() * bcContamination.impactRadius()) { DEBUG_LOG(m_logger) << "isInsideInnerCircle return true"; return true; } else { DEBUG_LOG(m_logger) << "isInsideInnerCircle return false"; return false; } } // Returns true if the building is located in range 1 at the time of impact and is to be contaminated as a result. // Liefert true, wenn sich das Gebaeude beim Einschlag im Bereich 1 befindet und daraufhin kontaminiert werden soll. bool HandlerContamination::isInsideRange1(int buildingId, int aesId) { InfrastructureManagement::MainStructureElement mse = m_ddsHandler->dtcIsm()->mainStructureElement(buildingId); AreaEffectSimulation::NContamination nContamination = m_ddsHandler->dtcAes()->nContamination(aesId); DEBUG_LOG(m_logger) << "isInsideRange1 borderLengthInner=" << nContamination.borderLengthInner() << " borderLengthOuter=" << nContamination.borderLengthOuter() << " impactRadius=" << nContamination.impactRadius(); int zone = -1; const QPointF impactPositionUtm = CentralEffectSimulation::geographic2Utm(nContamination.impactPosition(), zone); DEBUG_LOG(m_logger) << "impactPositionUtm=" << impactPositionUtm.x() << "/" << impactPositionUtm.y() << " zone=" << zone; const QPointF buildingPositionUtm = CentralEffectSimulation::geographic2Utm(mse.geoPosition(), zone); DEBUG_LOG(m_logger) << "buildingPositionUtm=" << buildingPositionUtm.x() << "/" << buildingPositionUtm.y(); double squareDistance = CentralEffectSimulation::getSquareDistance(impactPositionUtm, buildingPositionUtm); if (squareDistance < nContamination.borderLengthInner() * nContamination.borderLengthInner()) { DEBUG_LOG(m_logger) << "isInsideRange1 return true"; return true; } else { DEBUG_LOG(m_logger) << "isInsideRange1 return false"; return false; } } } // namespace CesBuildings