420 lines
17 KiB
C++
Executable File
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
|