/** * @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 #include #include #include #include #include #include #include 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::of(&QDoubleSpinBox::valueChanged), this, &NContaminationEdit::onRadiusChanged); connect(m_ui->cbWeather, QOverload::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(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(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 pdmGuiIfc; if (!m_session->getForeignGuiInterface(pdmGuiIfc)) return false; m_ui->cbStandardValues->addItem(QLatin1String("---"), 0); std::shared_ptr pdmDtc; if (m_session->getDtc(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(&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(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()); return m_requestHelper->startSingleRequest([this, req]() { return m_ftc->nContaminationModifyRequest(req, this); }); } } // namespace AreaEffectSimulation