764 lines
27 KiB
C++
Executable File
764 lines
27 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* AreaEffectSimulation - Explosions Edit Dialog
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Steve Tougnia, SLTE, 2023-09-05
|
|
*/
|
|
|
|
#include "aes_explosions_edit_adler.h"
|
|
// #include "aes_explosions_edit_helper.h"
|
|
#include "aes_effector.h"
|
|
#include "ui_aes_explosions_edit_adler.h"
|
|
|
|
#include <Proxies/TrainingAreaBase/Plugins/AdlerJson/telegrams.h>
|
|
|
|
#include <LtsSession/lts_session_data.h>
|
|
#include <PluginInterfaces/gui_plugin_interface.h>
|
|
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
|
|
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_base_model.h>
|
|
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
|
|
#include <Services/AreaEffectSimulation/Utils/aes_helper.h>
|
|
#include <Services/AreaEffectSimulation/Utils/polygons.h>
|
|
#include <Services/ParticipantManagement/ppm_translation.h>
|
|
|
|
#include <LtsUtilsSettings/settings.h>
|
|
#include <Services/AreaEffectSimulation/settings.h>
|
|
|
|
#include <Plugins/AdvancedSymbology/asb_data_plugin_interface.h>
|
|
#include <Plugins/ParticipantManagement/Gui/ParticipantSelection/participant_selection.h>
|
|
|
|
#include <AreaEffectSimulation/aes_translation.h>
|
|
#include <LtsCoordTrans/lts_coord_trans.h>
|
|
#include <ProjectDataManagement/pdm_translation.h>
|
|
#include <Trajectory/trajectory_generator.h>
|
|
#include <Trajectory/trajectory_helper.h>
|
|
|
|
#include <AssetManagement/asm_data_plugin_interface.h>
|
|
#include <ExerciseManagement/exm_data_plugin_interface.h>
|
|
#include <LtsElevation/lts_elevation_manager.h>
|
|
|
|
#include <QButtonGroup>
|
|
#include <QDateTime>
|
|
#include <QHash>
|
|
#include <QJsonDocument>
|
|
#include <QSpinBox>
|
|
#include <QTimer>
|
|
|
|
namespace AreaEffectSimulation
|
|
{
|
|
|
|
static const char *const VALUE_VALID_PROPERTY_NAME = "VALUE_VALID";
|
|
|
|
/*!
|
|
* \brief ExplosionsEditAdler::ExplosionsEditAdler
|
|
* \param menuGroup
|
|
* \param parent
|
|
*/
|
|
QString ExplosionsEditAdler::toString(ExplosionsEditAdler::FlighDurationOrPeakHeight val)
|
|
{
|
|
switch (val)
|
|
{
|
|
case ExplosionsEditAdler::FlighDurationOrPeakHeight::FDPH_flightDuration:
|
|
return QStringLiteral("FDPH_flightDuration");
|
|
break;
|
|
case ExplosionsEditAdler::FlighDurationOrPeakHeight::FDPH_peakHeight:
|
|
return QStringLiteral("FDPH_peakHeight");
|
|
break;
|
|
default:
|
|
return QStringLiteral("PHFD_Unknow");
|
|
break;
|
|
}
|
|
return QStringLiteral("PHFD_Unknow");
|
|
}
|
|
|
|
// Maximaler Winkel fuer untere Winkelgruppe
|
|
static double maxAngleUW = 45.0;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// class ExplosionsEditAdler
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
ExplosionsEditAdler::ExplosionsEditAdler(const QString &menuGroup, QWidget *parent)
|
|
: BaseEdit(menuGroup, QStringLiteral("ExplosionsEditAdler"), parent)
|
|
, m_ui(new Ui::ExplosionsEditAdler)
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
|
|
m_ui->setupUi(this);
|
|
|
|
m_geometrieButtonGroup = new QButtonGroup(this);
|
|
m_geometrieButtonGroup->addButton(m_ui->geometrieAimPointBtn, static_cast<int>(AreaEffectSimulation::AesExplosionGeometry_def::EgAimPoint));
|
|
m_geometrieButtonGroup->addButton(m_ui->geometrieAreaBtn, static_cast<int>(AreaEffectSimulation::AesExplosionGeometry_def::EgArea));
|
|
m_geometrieButtonGroup->addButton(m_ui->geometrieLineBtn, static_cast<int>(AreaEffectSimulation::AesExplosionGeometry_def::EgLine));
|
|
m_geometrieButtonGroup->addButton(m_ui->geometriePointBtn, static_cast<int>(AreaEffectSimulation::AesExplosionGeometry_def::EgPoint));
|
|
m_geometrieButtonGroup->addButton(m_ui->geometrieRadialBtn, static_cast<int>(AreaEffectSimulation::AesExplosionGeometry_def::EgRadial));
|
|
m_geometrieButtonGroup->setExclusive(true);
|
|
|
|
m_gearClassFilter = {ProjectDataManagement::GearClass::Artillery, ProjectDataManagement::GearClass::Mortar};
|
|
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
|
|
const bool enableRocket = ps->value(QStringLiteral("aes"), QStringLiteral("enableRocket"), false).toBool();
|
|
if (enableRocket)
|
|
m_gearClassFilter += ProjectDataManagement::GearClass::Rocket;
|
|
|
|
m_uiRequirements->addRequirement(
|
|
{m_ui->lbxActors,
|
|
[this]() { return ((m_ui->gbEffectMarkingInTa->isChecked() && m_ui->cbActors->currentData().toInt() > 0) || !m_ui->gbEffectMarkingInTa->isChecked()); }});
|
|
|
|
connect(m_ui->pbClear, &QPushButton::clicked, m_ui->positionEdit, &LtsCoordWidget::LtsCoordWidget::clear);
|
|
|
|
// "Einschießen" is hidden for now
|
|
m_ui->lblFire->hide();
|
|
m_ui->einschlJaBtn->hide();
|
|
m_ui->einschlNoBtn->hide();
|
|
|
|
// "Wirkungsfeuer" is hidden for now
|
|
m_ui->lblFire_2->hide();
|
|
m_ui->wirkungJaBtn->hide();
|
|
m_ui->wirkungNoBtn->hide();
|
|
|
|
// DMF EffectMarkingInTa hide currently always true
|
|
// m_ui->cbEffectMarkingInTa->hide();
|
|
|
|
m_ui->rbAngleGroupLower->setChecked(true);
|
|
// disable Tab Additional/Charge for now
|
|
m_ui->tabWidget->setTabEnabled(1, false);
|
|
m_ui->tabWidget->setTabEnabled(2, false);
|
|
|
|
m_ui->pbStateChange->hide();
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
|
|
}
|
|
|
|
/*!
|
|
* \brief ExplosionsEditAdler::~ExplosionsEditAdler
|
|
*/
|
|
ExplosionsEditAdler::~ExplosionsEditAdler()
|
|
{
|
|
if (m_sitMapGuiIfc)
|
|
m_sitMapGuiIfc->removeObjectIndicator();
|
|
delete m_ui;
|
|
}
|
|
|
|
/*!
|
|
* \brief AreaEffectSimulation::ExplosionsEditAdler::init
|
|
* \param aesItemId
|
|
* \param session
|
|
* \return
|
|
*/
|
|
bool ExplosionsEditAdler::init(int aesItemId, bool copy, LtsSession::LtsSession *session)
|
|
{
|
|
|
|
Q_UNUSED(copy)
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " START";
|
|
if (!BaseEdit::init(aesItemId, session))
|
|
return false;
|
|
|
|
if (!m_session->getForeignDataInterface<AdvancedSymbology::DataInterface>(m_asbIfc))
|
|
return false;
|
|
|
|
if (!session->getForeignGuiInterface(m_esmActorCbx))
|
|
return false;
|
|
|
|
// P _D_ M
|
|
if (!m_session->getDtc<ProjectDataManagement::DataInterface>(m_pdmDtc))
|
|
{
|
|
ERROR_LOG(m_logger) << " failed to get pdmDtc";
|
|
return false;
|
|
}
|
|
|
|
if (!m_session->getForeignGuiInterface<ProjectDataManagement::ForeignGuiInterface>(m_pdmCbx))
|
|
return false;
|
|
|
|
m_pdmDtc->waitForHistoricalDataChargeType(1000);
|
|
m_pdmDtc->waitForHistoricalDataGearType(1000);
|
|
m_pdmDtc->waitForHistoricalDataGearTypeChargeType(1000);
|
|
m_dtc->waitForHistoricalDataExplosionCluster(1000);
|
|
m_ftc->enableAcknowledgeExternalAesItem();
|
|
|
|
// P _P_ M
|
|
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
|
|
{
|
|
ERROR_LOG(m_logger) << " failed to get ppmDtc";
|
|
return false;
|
|
}
|
|
|
|
if (aesItemId > 0)
|
|
{
|
|
const EffectCluster &ecData = m_dtc->effectCluster(aesItemId);
|
|
DEBUG_LOG(m_logger) << "chargeTypeId: " << ecData.chargeStruct().chargeTypeId();
|
|
m_effectClusterData = ecData;
|
|
setEffectClusterData(ecData);
|
|
|
|
setPbStateChangeName();
|
|
m_ui->gbEffectMarkingInTa->setChecked(m_aesItem.effectMarkingInTa()); // always true for explosion cluster
|
|
}
|
|
|
|
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::effectClusterChanged, this, &ExplosionsEditAdler::onEffectClusterChanged, Qt::UniqueConnection);
|
|
|
|
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::effectorChanged, this, &ExplosionsEditAdler::onEffectorChanged);
|
|
|
|
connect(m_ui->pbStateChange, &QPushButton::clicked, this, &ExplosionsEditAdler::onPbStateChangeClicked);
|
|
setOnlineHelpFilename(QStringLiteral("Situation-Add_Cluster_Artillery_AdlerVerbund.md"));
|
|
|
|
m_initDone = true;
|
|
|
|
enableUiElements();
|
|
m_ui->dteEffectStart->setEnabled(false);
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
* \brief ExplosionsEditAdlerStandAlone::showPreviewObject
|
|
*/
|
|
void ExplosionsEditAdler::showPreviewObject()
|
|
{
|
|
if (!has2DMap(false)) // showMsgBoxIfNot2D
|
|
return;
|
|
|
|
switch (m_currentGeometry.underlying())
|
|
{
|
|
case AreaEffectSimulation::AesExplosionGeometry_def::EgArea:
|
|
if (m_previewPolygon.isEmpty())
|
|
return;
|
|
|
|
m_sitMapGuiIfc->displayPreviewObject(this, m_previewPolygon, true);
|
|
return;
|
|
case AreaEffectSimulation::AesExplosionGeometry_def::EgAimPoint:
|
|
case AreaEffectSimulation::AesExplosionGeometry_def::EgPoint:
|
|
if (m_previewCircleCenter.isNull())
|
|
return;
|
|
|
|
m_sitMapGuiIfc->displayPreviewObject(this, m_previewPolygon, false);
|
|
return;
|
|
case AreaEffectSimulation::AesExplosionGeometry_def::EgRadial:
|
|
if (m_previewCircleCenter.isNull())
|
|
return;
|
|
|
|
m_sitMapGuiIfc->displayPreviewObject(this, m_previewCircleCenter, m_previewCircleRadius);
|
|
return;
|
|
default:
|
|
WARNING_LOG(m_logger) << " Unknown Geometry!";
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool ExplosionsEditAdler::isDataSufficiant()
|
|
{
|
|
// identifier:
|
|
if (m_ui->lblZpNumber->text().isEmpty())
|
|
return false;
|
|
|
|
// originator:
|
|
bool hasParticipant = !m_ui->lblParticipantUnits->text().isEmpty();
|
|
if (!hasParticipant)
|
|
return false;
|
|
|
|
// target:
|
|
bool bHasTargetArea = !m_coord.isNull();
|
|
switch (m_currentGeometry.underlying())
|
|
{
|
|
case AreaEffectSimulation::AesExplosionGeometry_def::EgArea:
|
|
bHasTargetArea &= m_ui->lblDimensionYDepth->text().toInt() > 0;
|
|
bHasTargetArea &= m_ui->lblWidthRadius->text().toInt() > 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (!bHasTargetArea)
|
|
return false;
|
|
|
|
// ammo
|
|
const bool bHasAmmo = !m_ui->lblChargeType->text().isEmpty();
|
|
if (!bHasAmmo)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void ExplosionsEditAdler::setEffectClusterData(const EffectCluster &ecData)
|
|
{
|
|
m_aesItem = ecData;
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " START, ecData=" << ecData;
|
|
|
|
m_ui->lblZpNumber->setText(QString::fromStdString(ecData.name()));
|
|
|
|
qint64 effectStart = 0;
|
|
|
|
if (ecData.effectStart().is_set())
|
|
{
|
|
const QJsonObject propsObj(QJsonDocument::fromJson(QByteArray::fromStdString(ecData.properties())).object());
|
|
const FiringType firingType = static_cast<FiringType::inner_enum>(propsObj[AdlerJson::JsonKeys::ABFEUERUNGSART()].toInt());
|
|
|
|
effectStart = ecData.effectStart().get();
|
|
|
|
if (firingType == FiringType::FireWithIndicationTTF)
|
|
effectStart -= ecData.effectors().size() ? ecData.effectors().at(0).flightTime() : 0;
|
|
}
|
|
|
|
m_ui->dteEffectStart->setMsecsSinceEpoch(effectStart);
|
|
|
|
// Geometry/Area
|
|
const AreaEffectSimulation::AesExplosionGeometry_def::type geometryType = ecData.explosionGeometry().underlying();
|
|
switch (geometryType)
|
|
{
|
|
case AreaEffectSimulation::AesExplosionGeometry_def::EgAimPoint:
|
|
m_ui->geometrieAimPointBtn->setChecked(true);
|
|
break;
|
|
case AreaEffectSimulation::AesExplosionGeometry_def::EgPoint:
|
|
m_ui->geometriePointBtn->setChecked(true);
|
|
break;
|
|
case AreaEffectSimulation::AesExplosionGeometry_def::EgArea:
|
|
m_ui->geometrieAreaBtn->setChecked(true);
|
|
break;
|
|
case AreaEffectSimulation::AesExplosionGeometry_def::EgLine:
|
|
m_ui->geometrieLineBtn->setChecked(true);
|
|
break;
|
|
case AreaEffectSimulation::AesExplosionGeometry_def::EgRadial:
|
|
m_ui->geometrieRadialBtn->setChecked(true);
|
|
break;
|
|
default:
|
|
// empty
|
|
break;
|
|
} // switch
|
|
|
|
if (ecData.effectDuration() == DEFAULT_EFFECT_DURATION)
|
|
m_ui->lblDuration->setText(QStringLiteral("---"));
|
|
else
|
|
m_ui->lblDuration->setText(QString::number(ecData.effectDuration() / 1000)); // msecs -> secs
|
|
|
|
// 1st GearClass
|
|
ProjectDataManagement::GearClass gc = m_pdmDtc->gearClassFromChargeTypeId(ecData.chargeStruct().chargeTypeId());
|
|
m_ui->lblGearClass->setText(ProjectDataManagement::toString(gc));
|
|
|
|
// 2nd Party
|
|
if (ecData.partyId().is_set())
|
|
m_ui->lblParty->setText(ParticipantManagement::trPartyName(m_ppmDtc->party(ecData.partyId().get()).name()));
|
|
|
|
// 3rd Originator
|
|
if (ecData.participantId().is_set())
|
|
m_ui->lblParticipantUnits->setText(QString::fromStdString(m_ppmDtc->participant(ecData.participantId().get()).name()));
|
|
|
|
m_ui->lblChargeType->setText(m_pdmDtc->adlerChargeTypeName(ecData.chargeStruct().chargeTypeId()));
|
|
m_ui->lblIgniterType->setText(m_pdmDtc->adlerIgniterTypeName(ecData.chargeStruct().igniterTypeId()));
|
|
m_ui->lblIgniterFunction->setText(m_pdmDtc->adlerIgniterFunctionName(ecData.chargeStruct().igniterFunctionId()));
|
|
|
|
int impactCount = 0;
|
|
|
|
// delete existing widgets
|
|
QLayoutItem *item = nullptr;
|
|
while((item = m_ui->layoutEffectors->takeAt(0)) != nullptr)
|
|
{
|
|
if (item->widget())
|
|
delete item->widget();
|
|
delete item;
|
|
}
|
|
for (const auto &effectorData : ecData.effectors())
|
|
{
|
|
setEffector(effectorData.participantId(), m_dtc->effector(effectorData.participantId()).effectorState());
|
|
impactCount += effectorData.chargeAmount();
|
|
}
|
|
|
|
m_ui->layoutEffectors->setColumnStretch(m_effectorNumber + 1 % m_maxColumns, 1);
|
|
m_ui->lblCannons->setText(QString::number(impactCount));
|
|
m_ui->lblFirePurpose->setText(m_pdmDtc->trFirePurposeName(ecData.firePurposeId()));
|
|
|
|
m_ui->lblZog->setText(QString::number(ecData.tla())); // tla == zog
|
|
|
|
const AreaEffectSimulation::Area &areaRef = ecData.area();
|
|
const QPointF bottomLeft(areaRef.cornerBottomLeft().lon(), areaRef.cornerBottomLeft().lat());
|
|
const QPointF centerpoint = Polygons::bottomLeft2CenterPoint(bottomLeft, areaRef.width(), areaRef.height(), areaRef.rotation());
|
|
if (!bottomLeft.isNull())
|
|
{
|
|
m_ui->positionEdit->setCoordinate(centerpoint);
|
|
m_coord = centerpoint;
|
|
const Core::GeoPosition coordGeo(centerpoint.x(), centerpoint.y(), 0);
|
|
bool isSmoke = m_pdmDtc->isSmoke(ecData.chargeStruct().chargeTypeId(), ecData.chargeStruct().igniterTypeId(), ecData.chargeStruct().igniterFunctionId());
|
|
m_esmActorCbx->fillActorComboBox(m_ui->cbActors, coordGeo, isSmoke, 0);
|
|
m_esmActorCbx->fillActorComboBox(m_ui->cbActors_2, coordGeo, isSmoke, 0);
|
|
}
|
|
|
|
if (ecData.explosionGeometry().underlying() == AreaEffectSimulation::AesExplosionGeometry_def::EgRadial)
|
|
{
|
|
m_ui->lblDimensionYDepth->setText(QString::number(static_cast<int>(std::round(areaRef.height() / 2))));
|
|
m_ui->lblWidthRadius->setText(QString::number(static_cast<int>(std::round(areaRef.width() / 2))));
|
|
m_ui->lblAimingAxis->setText(QString::number(0));
|
|
}
|
|
else
|
|
{
|
|
m_ui->lblDimensionYDepth->setText(QString::number(static_cast<int>(std::round(areaRef.height()))));
|
|
m_ui->lblWidthRadius->setText(QString::number(static_cast<int>(std::round(areaRef.width()))));
|
|
m_ui->lblAimingAxis->setText(QString::number(static_cast<int>(std::round(fmod((areaRef.rotation()) * 6400 / 360, 6400)))));
|
|
}
|
|
setEffectClusterDataFromJson(ecData.properties());
|
|
if (!ecData.esmParticipantIds().empty())
|
|
{
|
|
m_ui->cbActors->setCurrentIndex(m_ui->cbActors->findData(ecData.esmParticipantIds().at(0)));
|
|
if (ecData.esmParticipantIds().size() > 1)
|
|
m_ui->cbActors_2->setCurrentIndex(m_ui->cbActors_2->findData(ecData.esmParticipantIds().at(1)));
|
|
}
|
|
if (ecData.effectors().size())
|
|
setOWUWFromTrajectory(ecData.effectors().at(0).trajectoryRelative());
|
|
|
|
// enable second Actor if possible
|
|
const int amountFireMarker = m_pdmDtc->getAmountFireMarkers(ecData.firePurposeId());
|
|
m_ui->cbActors_2->setEnabled(amountFireMarker > 1);
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " END";
|
|
}
|
|
|
|
void ExplosionsEditAdler::setEffector(int participantId, const AreaEffectSimulation::AesEffectorState &effectorState)
|
|
{
|
|
const ParticipantManagement::Participant &part = m_ppmDtc->participant(participantId);
|
|
|
|
auto *effectorWidget = new AesEffector(this);
|
|
effectorWidget->init(participantId, QString::fromStdString(part.tacticalIdentifier()), QString::fromStdString(part.name()), effectorState);
|
|
effectorWidget->setStateButtonVisible(false);
|
|
|
|
const int row = m_effectorNumber / m_maxColumns;
|
|
const int col = m_effectorNumber % m_maxColumns;
|
|
m_ui->layoutEffectors->addWidget(effectorWidget, row, col);
|
|
m_effectorNumber++;
|
|
}
|
|
|
|
/*!
|
|
* \brief ExplosionsEditAdler::dialogIdentifier
|
|
* \return
|
|
*/
|
|
QString ExplosionsEditAdler::dialogIdentifier() const
|
|
{
|
|
DEBUG_LOG(m_logger) << "dialogIdentifier";
|
|
return m_aesItem.id() <= 0 ? QStringLiteral("AddExplosionsArtillery") : QStringLiteral("EditExplosionsArtillery%1").arg(m_aesItem.id());
|
|
}
|
|
|
|
void ExplosionsEditAdler::onAcknowledgeExternalAesItemReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
DEBUG_LOG(m_logger) << " GOIT REPLY for onAcknowledgeExternalAesItemReply";
|
|
m_requestHelper->requestReply(replyObject);
|
|
}
|
|
|
|
void ExplosionsEditAdler::onEffectClusterChanged(const EffectCluster &ecData, DataModification modType)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onExplosionClusterChanged";
|
|
if (ecData.id() != m_aesItem.id())
|
|
return;
|
|
|
|
BaseEdit::onAreaChanged(ecData, modType);
|
|
|
|
if (modType == DataModification::eRemoved)
|
|
{
|
|
m_effectClusterData = EffectCluster();
|
|
return;
|
|
}
|
|
|
|
m_effectClusterData = ecData;
|
|
m_currentGeometry = m_effectClusterData.explosionGeometry();
|
|
|
|
setEffectClusterData(ecData);
|
|
setPbStateChangeName();
|
|
|
|
if (m_effectClusterData.effectDuration() == DEFAULT_EFFECT_DURATION)
|
|
m_ui->lblDuration->setText(QStringLiteral("---"));
|
|
else
|
|
m_ui->lblDuration->setText(QString::number(m_effectClusterData.effectDuration() / 1000)); // msec -> sec
|
|
|
|
enableUiElements();
|
|
if (unchangeable())
|
|
{
|
|
m_ui->pbStateChange->setEnabled(false);
|
|
m_ui->gbEffectMarkingInTa->setEnabled(false);
|
|
}
|
|
}
|
|
|
|
QPointF ExplosionsEditAdler::centerOfFiringUnitGeo(int particpantUnitId)
|
|
{
|
|
DEBUG_LOG(m_logger) << "centerOfFiringUnitGeo";
|
|
if (!m_sitMapGuiIfc || !m_ppmDtc)
|
|
return {};
|
|
if (particpantUnitId <= 0)
|
|
return {};
|
|
|
|
std::vector<Core::GeoPosition> singlePositionsOut_unused;
|
|
const LtsUtils::QPoint3D ¢erCoordGeo = Polygons::calculateFiringUnitCenterNonRecursive(m_ppmDtc, particpantUnitId, singlePositionsOut_unused, m_logger);
|
|
if (centerCoordGeo.isNull() || std::isnan(centerCoordGeo.x()))
|
|
{
|
|
// may happen in real life: so WARNING_LOG to DEBUG_LOG
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " calculateFiringUnitCenterNonRecursive failed, particpantUnitId = " << particpantUnitId;
|
|
return {};
|
|
}
|
|
return centerCoordGeo.toPointF();
|
|
}
|
|
|
|
void ExplosionsEditAdler::showCenterOfFiringUnit(int particpantUnitId)
|
|
{
|
|
DEBUG_LOG(m_logger) << "showCenterOfFiringUnit";
|
|
|
|
if (!m_sitMapGuiIfc || !m_ppmDtc)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " START particpantUnitId: " << particpantUnitId;
|
|
if (particpantUnitId <= 0)
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " showCenterOfFiringUnit: " << particpantUnitId << ", removeObjectIndicator";
|
|
m_sitMapGuiIfc->removeObjectIndicator();
|
|
return;
|
|
}
|
|
|
|
const QPointF ¢erFiringUnitGeo = centerOfFiringUnitGeo(particpantUnitId);
|
|
|
|
if (centerFiringUnitGeo.isNull())
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " showCenterOfFiringUnit: " << particpantUnitId << ", removeObjectIndicator due to invalid position";
|
|
m_sitMapGuiIfc->removeObjectIndicator();
|
|
return;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " END particpantUnitId: " << particpantUnitId;
|
|
m_sitMapGuiIfc->objectIndicatorToPoint(centerFiringUnitGeo); // you can provide a duration: lifetimeMsec = -1
|
|
}
|
|
|
|
/*!
|
|
* \brief ExplosionsEditAdler::retranslate
|
|
*/
|
|
void ExplosionsEditAdler::retranslate()
|
|
{
|
|
QString title = tr("ADLER Artillery");
|
|
|
|
translate(m_ui, m_aesItem, title);
|
|
|
|
if (unchangeable())
|
|
{
|
|
m_ui->pbStateChange->setEnabled(false);
|
|
m_ui->gbEffectMarkingInTa->setEnabled(false);
|
|
}
|
|
}
|
|
|
|
void ExplosionsEditAdler::enableUiElements() { enableUiElements(false); }
|
|
|
|
void ExplosionsEditAdler::enableUiElements(bool enable)
|
|
{
|
|
m_ui->pbPosition->setEnabled(m_sitMapGuiIfc && enable);
|
|
m_ui->pbPosition_2->setEnabled(m_sitMapGuiIfc && enable);
|
|
m_ui->positionEdit->setEnabled(enable);
|
|
m_ui->positionEdit_2->setEnabled(enable);
|
|
m_ui->pbClear->setEnabled(enable);
|
|
m_ui->pbClear_2->setEnabled(enable);
|
|
|
|
m_ui->geometrieAimPointBtn->setEnabled(enable);
|
|
m_ui->geometrieAreaBtn->setEnabled(enable);
|
|
m_ui->geometriePointBtn->setEnabled(enable);
|
|
m_ui->geometrieLineBtn->setEnabled(enable);
|
|
m_ui->geometrieRadialBtn->setEnabled(enable);
|
|
m_ui->rbAngleGroupLower->setEnabled(enable);
|
|
m_ui->rbAngleGroupUpper->setEnabled(enable);
|
|
|
|
if (m_aesItem.effectStateId() == AesEffectState_def::EsReceived)
|
|
m_ui->pbStateChange->setEnabled(true);
|
|
else
|
|
m_ui->pbStateChange->setEnabled(m_effectClusterData.effectorState() != AreaEffectSimulation::AesEffectorState::EsReadyToFire);
|
|
}
|
|
|
|
/*!
|
|
* \brief ExplosionsEditAdler::apply
|
|
* \return
|
|
*/
|
|
bool ExplosionsEditAdler::apply()
|
|
{
|
|
// DMF (Actors)
|
|
int esmParticipantId1 = m_ui->cbActors->currentData().toInt(); // participant ID
|
|
int esmParticipantId2 = m_ui->cbActors_2->currentData().toInt(); // participant ID
|
|
|
|
EffectClusterModifyActorRequest request;
|
|
request.aesId(m_aesItem.id());
|
|
DEBUG_LOG(m_logger) << "currentIndex: " << m_ui->cbActors->currentIndex() << ", currentText: " << m_ui->cbActors->currentText()
|
|
<< ", participantId1: " << esmParticipantId1;
|
|
|
|
if (esmParticipantId1 > 0 || esmParticipantId2 > 0)
|
|
{
|
|
request.esmParticipantIds().reserve(2);
|
|
if (esmParticipantId1 > 0)
|
|
request.esmParticipantIds().push_back(esmParticipantId1);
|
|
if (esmParticipantId2 > 0 && esmParticipantId1 != esmParticipantId2 && m_ui->cbActors_2->isEnabled())
|
|
request.esmParticipantIds().push_back(esmParticipantId2);
|
|
}
|
|
|
|
m_requestHelper->addRequest([this, request]() { return m_ftc->effectClusterModifyActorRequest(request, this); });
|
|
|
|
return m_requestHelper->startRequests();
|
|
}
|
|
//
|
|
void ExplosionsEditAdler::setPbStateChangeName()
|
|
{
|
|
DEBUG_LOG(m_logger) << "onPbStateChangeName: AesEffectState: " << m_aesItem.effectStateId();
|
|
|
|
if ((m_aesItem.effectStateId() != AesEffectState::EsReceived && m_aesItem.effectStateId() != AesEffectState::EsCreated) || m_aesItem.id() <= 0)
|
|
return;
|
|
|
|
m_ui->pbStateChange->show();
|
|
|
|
if (m_aesItem.effectStateId() == AesEffectState_def::EsReceived)
|
|
m_ui->pbStateChange->setText(tr("Acknowledge"));
|
|
else
|
|
{
|
|
m_ui->pbStateChange->setText(tr("Ready to fire"));
|
|
m_ui->pbStateChange->setEnabled(m_effectClusterData.effectorState() != AreaEffectSimulation::AesEffectorState::EsReadyToFire);
|
|
}
|
|
}
|
|
|
|
void ExplosionsEditAdler::onPbStateChangeClicked()
|
|
{
|
|
if ((m_aesItem.effectStateId() != AesEffectState::EsReceived && m_aesItem.effectStateId() != AesEffectState::EsCreated) || m_aesItem.id() <= 0)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << " onPbStateChangeClicked: AesEffectState = " << m_aesItem.effectStateId();
|
|
|
|
m_ui->pbStateChange->setDisabled(true);
|
|
|
|
if (m_ui->gbEffectMarkingInTa->isChecked())
|
|
apply();
|
|
|
|
// Re-Enable PB, so we can call it another time, if it does not react...
|
|
QTimer::singleShot(2000, [this]() { m_ui->pbStateChange->setEnabled(m_effectClusterData.effectorState() != AreaEffectSimulation::AesEffectorState::EsReadyToFire); });
|
|
|
|
if (m_aesItem.effectStateId() == AesEffectState_def::EsReceived)
|
|
{
|
|
AreaEffectSimulation::AcknowledgeExternalAesItemRequest request;
|
|
request.aesId(m_aesItem.id());
|
|
DEBUG_LOG(m_logger) << "Send acknowledgeExternalAesItemRequest with aesId: " << request.aesId();
|
|
m_requestHelper->addRequest([this, request]() { return m_ftc->acknowledgeExternalAesItemRequest(request, this); });
|
|
}
|
|
else
|
|
{
|
|
AreaEffectSimulation::SetAesItemEffectorStateRequest request;
|
|
request.aesId(m_aesItem.id());
|
|
request.newEffectorState(AesEffectorState::EsReadyToFire);
|
|
DEBUG_LOG(m_logger) << "Send setAesItemEffectorStateRequest with aesId: " << request.aesId() << ", AesEffectorState: " << request.newEffectorState();
|
|
m_requestHelper->addRequest([this, request]() { return m_ftc->setAesItemEffectorStateRequest(request, this); });
|
|
}
|
|
|
|
m_requestHelper->startRequests();
|
|
}
|
|
|
|
void ExplosionsEditAdler::onEffectorChanged(const AreaEffectSimulation::Effector &data, DataModification modType)
|
|
{
|
|
if (data.aesItemId() != m_aesItem.id())
|
|
return;
|
|
|
|
for (int i = 0; i < m_ui->layoutEffectors->count(); ++i)
|
|
{
|
|
QLayoutItem *item = m_ui->layoutEffectors->itemAt(i);
|
|
if (QWidget *widget = item->widget())
|
|
{
|
|
if (AesEffector *effectorWidget = qobject_cast<AesEffector *>(widget))
|
|
{
|
|
if (effectorWidget->effectorId() != data.id())
|
|
continue;
|
|
|
|
effectorWidget->setState(data.effectorState());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (modType == DataModification::eAdded)
|
|
setEffector(data.participantId(), data.effectorState());
|
|
}
|
|
|
|
bool ExplosionsEditAdler::isOnlyNameModifiable() const
|
|
{
|
|
// BaseClass::isOnlyNameModifiable() -> EsPaused || EsActivated
|
|
// m_effectClusterData.isObjectModifiable -> since PreStart and s_calculationOffsetMSec
|
|
const bool ret = BaseClass::isOnlyNameModifiable() || !m_effectClusterData.isObjectModifiable();
|
|
return ret;
|
|
}
|
|
|
|
void ExplosionsEditAdler::resetTempAndAnnotationStr()
|
|
{
|
|
INFO_LOG(m_logger) << " RESET resetTempAndAnnotationStr";
|
|
m_temporaryData.reset();
|
|
// updateAnnotationStr();
|
|
}
|
|
|
|
void ExplosionsEditAdler::addAnnotationStr(const QString &newAnno)
|
|
{
|
|
m_temporaryData.m_annotationString4Dlg += newAnno;
|
|
updateAnnotationStr();
|
|
}
|
|
|
|
void ExplosionsEditAdler::setOWUWFromTrajectory(const std::vector<Core::RelativePositionRelativeTime> &vecGeometry)
|
|
{
|
|
if (vecGeometry.size() < 2)
|
|
return;
|
|
|
|
const double dz = vecGeometry.at(1).offsetZ() - vecGeometry.at(0).offsetZ();
|
|
const QLineF line(vecGeometry.at(0).offsetX(), vecGeometry.at(0).offsetY(),
|
|
vecGeometry.at(1).offsetX(), vecGeometry.at(1).offsetY());
|
|
|
|
double angleArc = std::atan2(dz, line.length());
|
|
double angleDegree = angleArc * (180.0 / M_PI);
|
|
angleDegree = std::fmod(angleDegree + 360.0, 360.0);
|
|
DEBUG_LOG(m_logger) << "distance: " << line.length() << ", height: " << dz << ", angleDegree: " << angleDegree;
|
|
|
|
if (angleDegree > maxAngleUW)
|
|
m_ui->rbAngleGroupUpper->setChecked(true);
|
|
else
|
|
m_ui->rbAngleGroupLower->setChecked(true);
|
|
}
|
|
|
|
void ExplosionsEditAdler::updateAnnotationStr()
|
|
{
|
|
QStringList sl;
|
|
if (!m_temporaryData.m_annotationStringFiring4Dlg.isEmpty())
|
|
sl.append(m_temporaryData.m_annotationStringFiring4Dlg);
|
|
if (!m_temporaryData.m_annotationString4Dlg.isEmpty())
|
|
sl.append(m_temporaryData.m_annotationString4Dlg);
|
|
if (!m_temporaryData.m_remainingTimeStr.isEmpty())
|
|
sl.append(m_temporaryData.m_remainingTimeStr);
|
|
|
|
if (sl.isEmpty())
|
|
m_ui->lblAnnotationStringContent->setText(QStringLiteral("-"));
|
|
else if (sl.size() == 1)
|
|
m_ui->lblAnnotationStringContent->setText(sl.first());
|
|
else
|
|
m_ui->lblAnnotationStringContent->setText(sl.join(QStringLiteral(" ; ")));
|
|
}
|
|
|
|
void ExplosionsEditAdler::setEffectClusterDataFromJson(const std::string &properties)
|
|
{
|
|
const QJsonObject propsObj(QJsonDocument::fromJson(QByteArray::fromStdString(properties)).object());
|
|
DEBUG_LOG(m_logger) << "ecData json: " << properties;
|
|
|
|
const int elemente = propsObj[AdlerJson::JsonKeys::ELEMENTE()].toInt();
|
|
if (elemente > 0)
|
|
m_ui->lblElement->setText(QString::number(elemente));
|
|
|
|
const int loadTypeId = propsObj[AdlerJson::JsonKeys::LADUNG()].toInt();
|
|
if (loadTypeId > 0)
|
|
m_ui->lblLoadType->setText(m_pdmDtc->trLoadTypeShortName(loadTypeId));
|
|
|
|
const int loadNumber = propsObj[AdlerJson::JsonKeys::LADUNGSNUMMER()].toInt(-1);
|
|
if (loadNumber >= 0)
|
|
m_ui->lblLoadNumber->setText(QString::number(loadNumber));
|
|
|
|
const int targetTypeId = propsObj[AdlerJson::JsonKeys::TYP()].toInt();
|
|
if (targetTypeId > 0)
|
|
m_ui->lblTargetType->setText(m_pdmDtc->trTargetTypeName(targetTypeId));
|
|
|
|
const int targetSubTypeId = propsObj[AdlerJson::JsonKeys::SUB_TYP()].toInt();
|
|
if (targetSubTypeId > 0)
|
|
m_ui->lblTargetSubType->setText(m_pdmDtc->trTargetSubTypeName(targetSubTypeId));
|
|
|
|
const int angleGroup = propsObj[AdlerJson::JsonKeys::WINKELGRUPPE()].toInt();
|
|
if (angleGroup == ProjectDataManagement::L43_AngleGroup::Lower)
|
|
m_ui->rbAngleGroupLower->setChecked(true);
|
|
else
|
|
m_ui->rbAngleGroupUpper->setChecked(true);
|
|
|
|
const FiringType &firingType = static_cast<FiringType::inner_enum>(propsObj[AdlerJson::JsonKeys::ABFEUERUNGSART()].toInt());
|
|
m_ui->lblFiringType->setText(AreaEffectSimulation::toString(firingType));
|
|
}
|
|
|
|
} // namespace AreaEffectSimulation
|