Files
qt5-legatus-legacy/Lts/Services/AreaEffectSimulation/object_bccontamination.cpp
T
2026-08-13 18:33:10 +02:00

293 lines
10 KiB
C++
Executable File

/**
* 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 <QPolygonF>
#include <QTimer>
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