Files
qt5-legatus-legacy/Lts/Plugins/AreaEffectSimulation/Gui/NContamination/aes_ncontamination_edit.cpp
T
2026-08-13 18:33:10 +02:00

420 lines
17 KiB
C++
Executable File

/**
* @RDE_HEADER@
* AreaEffectSimulation - NContamination Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-07-07
*/
#include "aes_ncontamination_edit.h"
#include "ui_aes_ncontamination_edit.h"
#include <LtsSession/lts_session_data.h>
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_gui_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <AreaEffectSimulation/aes_translation.h>
#include <QDoubleSpinBox>
namespace AreaEffectSimulation
{
double NContaminationEdit::s_minRadiusKm;
double NContaminationEdit::s_maxRadiusKm;
double NContaminationEdit::s_stepRadiusKm;
double NContaminationEdit::s_minBorderLengthInnerKm;
double NContaminationEdit::s_maxBorderLengthInnerKm;
double NContaminationEdit::s_stepBorderLengthInnerKm;
double NContaminationEdit::s_minBorderLengthOuterKm;
double NContaminationEdit::s_maxBorderLengthOuterKm;
double NContaminationEdit::s_stepBorderLengthOuterKm;
double NContaminationEdit::s_minSpanAngle;
double NContaminationEdit::s_maxSpanAngle;
double NContaminationEdit::s_minYield;
double NContaminationEdit::s_maxYield;
double NContaminationEdit::s_stepYield;
int NContaminationEdit::s_minDurationMinutes;
int NContaminationEdit::s_maxDurationMinutes;
int NContaminationEdit::s_stepDurationMinutes;
NContaminationEdit::NContaminationEdit(const QString &menuGroup, QWidget *parent)
: BaseEdit(menuGroup, QLatin1String("NContaminationEdit"), parent)
, m_ui(new Ui::NContaminationEdit)
, m_previewCircleRadius(0.0)
{
m_ui->setupUi(this);
s_minRadiusKm = 0.050;
s_maxRadiusKm = 5.000;
s_stepRadiusKm = 0.010;
s_minBorderLengthInnerKm = 0.000;
s_maxBorderLengthInnerKm = 65.000;
s_stepBorderLengthInnerKm = 0.010;
s_minBorderLengthOuterKm = 0.000;
s_maxBorderLengthOuterKm = 65.000;
s_stepBorderLengthOuterKm = 0.010;
s_minSpanAngle = 10.0;
s_maxSpanAngle = 90.0;
s_minYield = 0.0;
s_maxYield = 99999.9;
s_stepYield = 0.01;
s_minDurationMinutes = 0.0;
s_maxDurationMinutes = 10000.0;
s_stepDurationMinutes = 10.0;
m_ui->rotationAngleEdit->initAngleEditWidget(2); // radial spinbox 1&2
m_ui->cbWeather->setCurrentIndex(AesWeatherSource::AwsNone);
m_ui->sbRadiusKm->setMinimum(s_minRadiusKm);
m_ui->sbRadiusKm->setMaximum(s_maxRadiusKm);
m_ui->sbRadiusKm->setSingleStep(s_stepRadiusKm);
m_ui->sbRange1Km->setMinimum(s_minBorderLengthInnerKm);
m_ui->sbRange1Km->setMaximum(s_maxBorderLengthInnerKm);
m_ui->sbRange1Km->setSingleStep(s_stepBorderLengthInnerKm);
m_ui->sbRange2Km->setMinimum(s_minBorderLengthOuterKm);
m_ui->sbRange2Km->setMaximum(s_maxBorderLengthOuterKm);
m_ui->sbRange2Km->setSingleStep(s_stepBorderLengthOuterKm);
m_ui->sbYield->setMinimum(s_minYield);
m_ui->sbYield->setMaximum(s_maxYield);
m_ui->sbYield->setSingleStep(s_stepYield);
m_ui->stackedWidget->addWidget(m_ui->lbRadials);
m_ui->stackedWidget->addWidget(m_ui->lbAngle);
// m_ui->sbDuration->setMinimum(s_minDurationMinutes);
// m_ui->sbDuration->setMaximum(s_maxDurationMinutes);
// m_ui->sbDuration->setSingleStep(s_stepDurationMinutes);
m_uiRequirements->addRequirement({m_ui->lblPosition, [this]() { return (!m_ui->positionEdit->coordinate().isNull()); }});
m_uiRequirements->addRequirement({m_ui->lblIdentifier, [this]() { return (!m_ui->leIdentifier->text().isEmpty()); }});
m_uiRequirements->addRequirement({m_ui->lblEffectStart, [this]() { return hasValidEffectStart(m_ui->dteEffectStart); }});
m_uiRequirements->addRequirement({m_ui->lbRadials, [this]() { return ((spanAngle() >= s_minSpanAngle) && (spanAngle() <= s_maxSpanAngle)); }});
m_uiRequirements->addRequirement({m_ui->lbAngle, [this]() { return (m_ui->rotationAngleEdit->getAngle(0) >= 0);}} );//m_ui->sbRadials1->value()
m_uiRequirements->addRequirement({m_ui->lblChargeType, [this]() { return (m_ui->cbChargeType->currentData().toInt() > 0); }});
connect(m_ui->sbRadiusKm, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this, &NContaminationEdit::onRadiusChanged);
connect(m_ui->cbWeather, QOverload<int>::of(&LtsWidgets::LtsComboBox::currentIndexChanged),
this, &NContaminationEdit::onWeatherChanged);
connect(m_ui->pbClear, &QPushButton::clicked, m_ui->positionEdit, &LtsCoordWidget::LtsCoordWidget::clear);
// connect(m_ui->sbRadials1, &QDoubleSpinBox::editingFinished, this, &NContaminationEdit::correctSpinBoxValue);
// connect(m_ui->sbRadials2, &QDoubleSpinBox::editingFinished, this, &NContaminationEdit::correctSpinBoxValue);
connect(m_ui->sbRadiusKm, &QDoubleSpinBox::editingFinished, this, &NContaminationEdit::correctSpinBoxValue);
connect(m_ui->sbRange1Km, &QDoubleSpinBox::editingFinished, this, &NContaminationEdit::correctSpinBoxValue);
connect(m_ui->sbRange2Km, &QDoubleSpinBox::editingFinished, this, &NContaminationEdit::correctSpinBoxValue);
connect(m_ui->sbYield, &QDoubleSpinBox::editingFinished, this, &NContaminationEdit::correctSpinBoxValue);
m_ui->cbWeather->addItem(toString(AesWeatherSource::AwsNone), AesWeatherSource::AwsNone);
m_ui->cbWeather->addItem(toString(AesWeatherSource::AwsStatic), AesWeatherSource::AwsStatic);
m_ui->cbWeather->addItem(toString(AesWeatherSource::AwsDynamic), AesWeatherSource::AwsDynamic);
m_ui->lblChargeType->hide();
m_ui->cbChargeType->hide();
enaDisa();
setOnlineHelpFilename(QStringLiteral("Situation-Add_N-Contamination"));
}
void NContaminationEdit::retranslate()
{
translate(m_ui, m_aesItem, tr("N-Contamination"));
}
void NContaminationEdit::onRadiusChanged(double radiusKm)
{
m_ui->sbRange1Km->setMinimum(radiusKm);
}
void NContaminationEdit::onPresetChanged(int id)
{
if (id == 0)
return;
ProjectDataManagement::NuclearPreset ps = m_presets.value(id);
if (ps.id() != id)
return;
m_ui->sbYield->setValue(ps.detonationValue());
m_ui->sbRadiusKm->setValue(ps.impactRadius() / 1000.0);
m_ui->sbRange1Km->setValue(ps.borderLengthInner() / 1000.0);
m_ui->sbRange2Km->setValue(ps.borderLengthOuter() / 1000.0);
}
void NContaminationEdit::showPreviewObject()
{
if (!m_sitMapGuiIfc)
return;
if (m_previewCircleCenter.isNull())
return;
m_sitMapGuiIfc->displayPreviewObject(this, m_previewCircleCenter, m_previewCircleRadius);
}
void NContaminationEdit::onWeatherChanged(int index )
{
Q_UNUSED(index);
AreaEffectSimulation::AesWeatherSource weather = static_cast<AreaEffectSimulation::AesWeatherSource::inner_enum>(m_ui->cbWeather->currentData().toInt());
if (weather == AreaEffectSimulation::AesWeatherSource_def::AwsDynamic ||
weather == AreaEffectSimulation::AesWeatherSource_def::AwsStatic)
{
m_ui->rotationAngleEdit->showSpinbox(1, false); //sbRadials2
m_ui->stackedWidget->setCurrentWidget(m_ui->lbAngle);
}
else
{
m_ui->rotationAngleEdit->showSpinbox(1, true); //sbRadials2
m_ui->stackedWidget->setCurrentWidget(m_ui->lbRadials);
}
}
NContaminationEdit::~NContaminationEdit()
{
delete m_ui;
}
void NContaminationEdit::setRadials(double direction, double spanAngle)
{
double radial1 = direction - (fabs(spanAngle) / 2.0);
double radial2 = direction + (fabs(spanAngle) / 2.0);
AreaEffectSimulation::AesWeatherSource weather = static_cast<AreaEffectSimulation::AesWeatherSource::inner_enum>(m_ui->cbWeather->currentData().toInt());
if (weather == AreaEffectSimulation::AesWeatherSource_def::AwsDynamic ||
weather == AreaEffectSimulation::AesWeatherSource_def::AwsStatic)
{
radial1 = spanAngle;
}
radial1 = fmod(radial1, 360.0);
radial2 = fmod(radial2, 360.0);
m_ui->rotationAngleEdit->setValue(radial1, LtsAngleEditBase::AngleUnitType::Deg, 0); // 0 für index 0
m_ui->rotationAngleEdit->setValue(radial2, LtsAngleEditBase::AngleUnitType::Deg, 1); // 1 für index 1
}
double NContaminationEdit::spanAngle() const
{
double radial1 = m_ui->rotationAngleEdit->getAngleConverted(m_ui->rotationAngleEdit->getAngle(0), LtsAngleEditBase::AngleUnitType::Deg,
m_ui->rotationAngleEdit->getAngleCurrentUnit()); //m_ui->sbRadials1->value();
double radial2 = m_ui->rotationAngleEdit->getAngleConverted(m_ui->rotationAngleEdit->getAngle(1), LtsAngleEditBase::AngleUnitType::Deg,
m_ui->rotationAngleEdit->getAngleCurrentUnit()); //m_ui->sbRadials2->value();
if (m_ui->cbWeather->currentData().toInt() != AreaEffectSimulation::AesWeatherSource_def::AwsNone)
return radial1;
double spanAngle = radial2 - radial1;
if (spanAngle < 0)
spanAngle += 360.0;
return spanAngle;
}
double NContaminationEdit::rotatianAngle() const
{
if (m_ui->cbWeather->currentData().toInt() != AreaEffectSimulation::AesWeatherSource_def::AwsNone)
return 0.0;
double radial1 = m_ui->rotationAngleEdit->getAngleConverted(m_ui->rotationAngleEdit->getAngle(0), LtsAngleEditBase::AngleUnitType::Deg,
m_ui->rotationAngleEdit->getAngleCurrentUnit()); //m_ui->sbRadials1->value();
double radial2 = m_ui->rotationAngleEdit->getAngleConverted(m_ui->rotationAngleEdit->getAngle(1), LtsAngleEditBase::AngleUnitType::Deg,
m_ui->rotationAngleEdit->getAngleCurrentUnit()); //m_ui->sbRadials2->value();
double direction = (radial2 + radial1) / 2.0;
if (radial1 > radial2)
direction += 180.0;
return fmod(direction, 360.0);
}
void NContaminationEdit::enableUiElements(bool enable)
{
m_ui->leIdentifier->setMaxLength(30);
m_ui->rotationAngleEdit->setEnabled(enable);
m_ui->cbStandardValues->setEnabled(enable);
m_ui->sbRadiusKm->setEnabled(enable);
m_ui->sbRange1Km->setEnabled(enable);
m_ui->sbRange2Km->setEnabled(enable);
m_ui->sbYield->setEnabled(enable);
m_ui->cbChargeType->setEnabled(enable);
setEffectStartEnabled(m_ui->dteEffectStart, enable);
m_ui->pbPosition->setEnabled(m_sitMapGuiIfc && enable);
m_ui->positionEdit->setEnabled(enable);
m_ui->pbClear->setEnabled(enable);
m_ui->leIdentifier->setEnabled(enable || isOnlyNameModifiable());
m_ui->cbWeather->setEnabled(enable);
if (m_aesItem.effectStateId() == AesEffectState_def::EsExpired)
{
m_ui->leIdentifier->setText(QString::fromStdString(m_aesItem.name()));
__unchange__();
}
if (m_aesItem.effectStateId() == AesEffectState_def::EsActivated)
{
QString name = m_ui->leIdentifier->text();
auto baseData = m_dtc->nContamination(m_aesItem.id());
setData(baseData, false);
__unchange__();
if (name != m_ui->leIdentifier->text())
m_ui->leIdentifier->setText(name);
}
}
bool NContaminationEdit::init(int aesItemId, bool copy,
LtsSession::LtsSession *session)
{
if (!BaseEdit::init(aesItemId, session))
return false;
bool editable = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::NContaminationsEdit) ||
m_session->app() == LtsAppDescriptor::App::OC;
bool readable = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::NContaminationsShow);
if (!readable && !editable)
return false;
std::shared_ptr<ProjectDataManagement::ForeignGuiInterface> pdmGuiIfc;
if (!m_session->getForeignGuiInterface<ProjectDataManagement::ForeignGuiInterface>(pdmGuiIfc))
return false;
m_ui->cbStandardValues->addItem(QLatin1String("---"), 0);
std::shared_ptr<ProjectDataManagement::Interface::Dtc> pdmDtc;
if (m_session->getDtc<ProjectDataManagement::DataInterface>(pdmDtc))
{
m_presets = pdmDtc->nuclearPresets();
for (const ProjectDataManagement::NuclearPreset &preset : qAsConst(m_presets))
m_ui->cbStandardValues->addItem(pdmDtc->trNuclearPresetName(preset.id()), preset.id());
connect(m_ui->cbStandardValues, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &NContaminationEdit::onPresetChanged);
}
else
INFO_LOG(m_logger) << "Could not fetch Presets from PDM.";
m_ui->dteEffectStart->setMinimumTimeMSec(m_session->partitionTime());
m_ui->dteEffectStart->setRetrieveCurrentTimeCallback([this]() { return m_session->partitionTime(); });
if (m_sitMapGuiIfc)
connect(m_ui->pbPosition, &QPushButton::clicked, this, &NContaminationEdit::getPosition);
else
m_ui->pbPosition->setEnabled(false);
pdmGuiIfc->fillNComboBox(m_ui->cbChargeType);
if (aesItemId > 0)
{
auto baseData = m_dtc->nContamination(aesItemId);
setData(baseData, copy);
// Note: @GUEZ, SpanAngle, RotationAngle, Name and Range Lengths are modifiable
// even, when it is active! Not possible here (yet)!
}
enableUiElements(editable && isModifiable() && !isOnlyNameModifiable());
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::nContaminationChanged,
this, &BaseEdit::onAreaChanged);
return true;
}
void NContaminationEdit::setData(const NContamination &contamination, bool copy)
{
m_aesItem = contamination;
if (copy)
{
m_aesItem.id(0);
m_aesItem.effectStateId(AreaEffectSimulation::AesEffectState_def::get_default());
}
m_ui->leIdentifier->setText(QString::fromStdString(contamination.name()));
m_ui->dteEffectStart->setMsecsSinceEpoch(contamination.effectStart().is_set() ? contamination.effectStart().get() : 0);
m_ui->cbChargeType->setCurrentIndex(m_ui->cbChargeType->findData(contamination.chargeStruct().chargeTypeId()));
m_ui->cbWeather->setCurrentIndex(m_ui->cbWeather->findData(contamination.weatherSource().underlying()));
const QPointF pos(contamination.impactPosition().lon(), contamination.impactPosition().lat());
if (!pos.isNull())
m_ui->positionEdit->setCoordinate(pos);
m_ui->sbYield->setValue(contamination.detonationValue());
m_ui->sbRange1Km->setValue(contamination.borderLengthInner() / 1000.0);
m_ui->sbRange2Km->setValue(contamination.borderLengthOuter() / 1000.0);
m_ui->sbRadiusKm->setValue(contamination.impactRadius() / 1000.0);
setRadials(contamination.rotationAngle(), contamination.spanAngle());
}
void NContaminationEdit::getPosition()
{
if (!has2DMap())
return;
// Todo: Correct Rubberband!
m_sitMapGuiIfc->getCircle(this
, SLOT(onCircleData(QPointF, double))
, nullptr
, s_minRadiusKm * 1000.0 //min
, s_maxRadiusKm * 1000.0 //max
, m_ui->positionEdit->coordinate()
, m_ui->sbRadiusKm->value() * 1000); //max
}
void NContaminationEdit::onCircleData(const QPointF &position, double radius)
{
m_previewCircleCenter = position;
m_ui->positionEdit->setCoordinate(position);
m_ui->sbRadiusKm->setValue(radius/1000.0);
// SB corrects value if SingleStep is set
m_previewCircleRadius = m_ui->sbRadiusKm->value()*1000;
if( m_ui->sbRadiusKm->value() > m_ui->sbRange1Km->value())
m_ui->sbRange1Km->setValue(radius/1000.0);
showPreviewObject();
}
bool NContaminationEdit::apply()
{
std::string name = m_ui->leIdentifier->text().toStdString();
qint64 effectStart = m_ui->dteEffectStart->msecsSinceEpoch();
int duration = 0; // Infinite
double borderInner = m_ui->sbRange1Km->value() * 1000.0;
double borderOuter = m_ui->sbRange2Km->value() * 1000.0;
double impactRadius = m_ui->sbRadiusKm->value() * 1000.0;
int chargeType = m_ui->cbChargeType->currentData().toInt();
double sAngle = spanAngle();
double rAngle = rotatianAngle();
double detonationValue = m_ui->sbYield->value();
int partyId = 0;
int playerId = 0;
AesWeatherSource weatherSourceId = static_cast<AesWeatherSource::inner_enum>(m_ui->cbWeather->currentData().toInt());
const QPointF p(m_ui->positionEdit->coordinate());
const Core::GeoPosition2D pos(p.x(), p.y());
const NContaminationModifyRequest req(m_aesItem.id(),
name,
LtsUtils::toOptional(effectStart),
duration,
chargeType,
pos,
borderInner,
borderOuter,
impactRadius,
sAngle,
rAngle,
detonationValue,
weatherSourceId,
LtsUtils::toOptional(partyId),
LtsUtils::toOptional(playerId),
dds::core::optional<rti::core::int64>());
return m_requestHelper->startSingleRequest([this, req]()
{
return m_ftc->nContaminationModifyRequest(req, this);
});
}
} // namespace AreaEffectSimulation