/** * Handler for the HMI language * $Id$ * $HeadURL$ * $Author$ */ #include "object_bccontamination.h" #include "meteo_data_provider.h" #include "special_area_provider.h" #include "Utils/polygons.h" #include #include namespace AreaEffectSimulation { ObjectBCContamination::ObjectBCContamination(MainHandler *mainHandler, QObject *parent) : ObjectBaseTmpl(mainHandler, QStringLiteral("BCContamination"), parent) , m_weatherTimer(new QTimer(this)) , m_aivUpdateTimer(new QTimer(this)) { m_weatherTimer->setInterval(20 * 60 * 1000); // 20 min - weather change in TA max every 15 min m_weatherTimer->setTimerType(Qt::VeryCoarseTimer); connect(m_weatherTimer, &QTimer::timeout, this, &ObjectBCContamination::onUpdateWeatherData); m_aivUpdateTimer->setInterval(1 * 1000); // every second - really needed? m_aivUpdateTimer->setTimerType(Qt::VeryCoarseTimer); connect(m_aivUpdateTimer, &QTimer::timeout, this, &ObjectBCContamination::onUpdateAiv); } ObjectBCContamination::~ObjectBCContamination() { removeTopics(); } Core::FunctionReplyObject ObjectBCContamination::createObject(const Database::AesBCContamination &data) { Core::FunctionReplyObject ret = ObjectBaseTmpl::createObject(data); if (data.weatherSourceId != AesWeatherSource::AwsNoUpdate) // on OC-Laptop, we use the given weather information, therefore no update { onUpdateWeatherData(); m_weatherTimer->start(); } return ret; } Core::FunctionReplyObject ObjectBCContamination::updateObject(const Database::AesBCContamination &data) { Core::FunctionReplyObject ret = ObjectBaseTmpl::updateObject(data); if (ret.error() || (isOnlyObjectNameModifiable() && (data.id > 0))) // data.id > 0 -> negative values from oc always get a full update) return ret; // only allow some fields Database::AesBCContamination tmpData(m_data); tmpData.id = std::abs(data.id); tmpData.name = data.name; tmpData.effectStart = data.effectStart; tmpData.effectDuration = data.effectDuration; tmpData.impactPosition = data.impactPosition; tmpData.impactRadius = data.impactRadius; tmpData.windSpeed = data.windSpeed; tmpData.propagationDirection = data.propagationDirection; tmpData.weatherSourceId = data.weatherSourceId; tmpData.participantId = data.participantId; tmpData.partyId = data.partyId; tmpData.chargeTypeId = data.chargeTypeId; tmpData.weatherPosition = data.impactPosition; // initial tmpData.effectStateId = data.effectStateId; // overwrite for oc tmpData.upperOffset = data.upperOffset; tmpData.lowerOffset = data.lowerOffset; tmpData.properties = data.properties; if (!m_mainHandler->db()->update(tmpData)) return Core::FunctionReplyObject(data.id, tr_lts("dds", "Error updating B/C contamination with id %1 in database.")).arg(m_data.id); m_data = std::move(tmpData); m_publishDataTimer->start(); checkEnterNewState(); return Core::FunctionReplyObject(data.id); // data not m_data for the possible negative id in the oc-laptop } bool ObjectBCContamination::removeObjectFromDb() { return m_mainHandler->db()->removeAesBCContamination(m_data.id); } void ObjectBCContamination::setEffectState(AesEffectState newState) { if (newState == AesEffectState::EsActivated) { m_aivUpdateTimer->start(); } else m_aivUpdateTimer->stop(); if (newState == AesEffectState::EsExpired || newState == AesEffectState::EsRemoved) m_weatherTimer->stop(); ObjectBaseTmpl::setEffectState(newState); } ProjectDataManagement::VolatilityType ObjectBCContamination::volatilityType() const { return m_mainHandler->dds()->pdmDtc()->volatilityTypeId(m_data.chargeTypeId, m_data.igniterTypeId, m_data.igniterFunctionId); } double ObjectBCContamination::expansionFactor() const { return m_mainHandler->dds()->pdmDtc()->expansionFactor(m_data.chargeTypeId, m_data.igniterTypeId, m_data.igniterFunctionId); } void ObjectBCContamination::onUpdateWeatherData() { if (effectState() == AesEffectState::EsExpired || effectState() == AesEffectState::EsRemoved) return; // calculate current center point double distance; QPointF curCenterPointGeographic; Polygons::bcCurrentCenterPoint(m_data, volatilityType(), partitionTime(), curCenterPointGeographic, distance); // check if weather data changed MeteoDataManagement::MeteoData md; if (m_data.weatherSourceId == AesWeatherSource::AwsDynamic) md = m_mainHandler->meteoData()->getNearestWeather(Core::GeoPosition2D(curCenterPointGeographic.x(), curCenterPointGeographic.y())); else md = m_mainHandler->meteoData()->getStaticWeather(); if (qFuzzyCompare(md.windDirection(), fmod(m_data.propagationDirection + 180.0, 360.0)) && qFuzzyCompare(md.windSpeed(), m_data.windSpeed)) { DEBUG_LOG(m_logger) << id() << " weather for " << m_typeName << " did not change - no need to publish new data"; return; } DEBUG_LOG(m_logger) << id() << " updating weather for " << m_typeName; m_data.propagationDirection = fmod(md.windDirection() + 180.0, 360.0); m_data.windSpeed = md.windSpeed(); m_data.weatherTimestamp = partitionTime() > m_data.effectStart ? partitionTime() : m_data.effectStart; m_data.weatherPosition = curCenterPointGeographic; m_publishDataTimer->start(); return; } void ObjectBCContamination::onUpdateAiv() { if (effectState() != AesEffectState::EsActivated) { m_aivUpdateTimer->stop(); return; } publishAiv(); } void ObjectBCContamination::onPublishData() { ObjectBaseTmpl::onPublishData(); if (!m_mainHandler->db()->update(m_data)) ERROR_LOG(m_logger) << "Error updating AesBcContamination-data in database"; BCContamination ddsData(m_data.id, m_data.name.toStdString(), effectState() == AesEffectState::EsRemoved, false, partitionTimeMSec(), {m_data.chargeTypeId,0,0}, m_data.effectDuration, toOptional(toMSec(m_data.effectStart)), m_data.effectStateId, m_data.effectSourceId, toOptional(m_data.partyId), toOptional(m_data.participantId), m_data.effectMarkingInTa, m_data.externalId, m_data.isCentral, m_data.properties.toStdString(), Core::GeoPosition2D(m_data.impactPosition.x(), m_data.impactPosition.y()), m_data.impactRadius, m_data.weatherSourceId, m_data.propagationDirection, m_data.windSpeed, toMSec(m_data.weatherTimestamp), Core::GeoPosition2D(m_data.weatherPosition.x(), m_data.weatherPosition.y()), m_data.upperOffset, m_data.lowerOffset ); m_mainHandler->dds()->dts()->publish(ddsData); publishAiv(); } void ObjectBCContamination::publishAiv() { { const QPolygonF poly = Polygons::bcContamination(m_data, volatilityType(), expansionFactor(), partitionTime()); const QRectF bounds(poly.boundingRect()); AesItemView aiv(m_aiv); aiv.aesItemId(m_data.id); aiv.effectStart(toMSec(m_data.effectStart)); aiv.chargeStruct().chargeTypeId(m_data.chargeTypeId); ddsVecFromPoly(poly, aiv.form()); aiv.boundingBoxBottomLeft(Core::GeoPosition2D(bounds.bottomLeft().x(), bounds.bottomLeft().y())); aiv.boundingBoxTopRight(Core::GeoPosition2D(bounds.topRight().x(), bounds.topRight().y())); aiv.aesTypeId(AesType::AtBCContamination); aiv.effectStateId(data().effectStateId); aiv.id(1000 * m_data.id + AesType::AtBCContamination); // Check if aiv is in special area // effectStart needs to be set checkIsCentralAndPublish(aiv.form(), m_aiv.form(), m_data.isCentral); if (m_data.partyId != 0) aiv.partyId(m_data.partyId); if (aiv != m_aiv) { aiv.sampleTime(partitionTimeMSec()); m_aiv = aiv; m_mainHandler->dds()->dts()->publish(aiv); emit newAiv(m_aiv); } } // adding danger area.. #if GUEZ_MODE // { // QPolygonF dangerAreaPoly = Polygons::dangerAreaPentagon(m_data.impactPosition, 100); // AesItemView aiv2(m_aiv2); // aiv2.aesItemId(m_data.id); // aiv2.chargeTypeId(m_data.chargeTypeId); // aiv2.effectStart(toMSec(m_data.effectStart)); // ddsVecFromPoly(dangerAreaPoly, aiv2.form()); // const QRectF bounds(dangerAreaPoly.boundingRect()); // aiv2.boundingBoxBottomLeft(Core::GeoPosition2D(bounds.bottomLeft().x(), bounds.bottomLeft().y())); // aiv2.boundingBoxTopRight(Core::GeoPosition2D(bounds.topRight().x(), bounds.topRight().y())); // aiv2.aesTypeId(AesType::AtDangerArea); // aiv2.effectStateId(effectState()); // aiv2.id(1000 * m_data.id + AesType::AtDangerArea); // aiv2.partyId(0); // checkIsCentralAndPublish(aiv2.form(), m_aiv2.form(), m_data.isCentral); // if (aiv2 != m_aiv2) // { // aiv2.sampleTime(partitionTimeMSec()); // m_aiv2 = aiv2; // m_mainHandler->dds()->dts()->publish(aiv2); // //emit newAiv(aiv2); // } // } #endif } void ObjectBCContamination::removeTopics() { auto dts = m_mainHandler->dds()->dts(); m_aivUpdateTimer->stop(); m_weatherTimer->stop(); dts->removeBCContaminationByKey(m_data.id); dts->removeAesItemViewByKey(1000 * m_data.id + AesType::AtBCContamination); emit removeAiv(m_data.id); } QPolygonF ObjectBCContamination::generateForm() { return Polygons::bcContamination(m_data, volatilityType(), expansionFactor(), partitionTime()); } } // Namespace AreaEffectSimulation