Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

@@ -0,0 +1,116 @@
#
# $Id: CMakeLists.txt 63121 2024-06-21 07:06:23Z karwat $
# $HeadURL: svn://slssvn/TDS/branches/product/features/24_adler/Lts/Plugins/AreaEffectSimulation/Gui/Explosion/CMakeLists.txt $
# $Author: karwat $
# Created by Christian Ehrlicher, SLSE, 2016-02-29
#
#
# LIBRARY for AesEffectClusterModel (which is used at AirSupportPlugin)
#
SET(AesEffectCluster_SRCS
aes_effect_cluster_model.cpp
aes_effect_cluster_model.h
aes_effector.h
aes_effector.cpp
aes_effector.ui
)
NGL_ADD_LIBRARY2(WS AesEffectClusterModel SHARED ${AesEffectCluster_SRCS})
NGL_TARGET_LINK_LIBRARIES(AesEffectClusterModel
PRIVATE
AesBaseGui
svcAesClient
ngltools
PUBLIC
NGLLogger
Qt5::Core
)
NGL_TARGET_INCLUDE_DIRECTORIES(AesEffectClusterModel
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/..
)
NGL_INSTALL_TARGET(AesEffectClusterModel)
##
##
##
ADD_INTERFACE_LIBRARY(
AesExplosionGuiPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/aes_explosion_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/..
PdmDataPluginInterface
)
SET(aes_explosion_gui_SRCS
aes_explosion_gui_plugin.cpp
aes_explosion_gui_plugin.h
aes_explosion_edit.cpp
aes_explosion_edit.h
aes_explosions_edit.cpp
aes_explosions_edit.h
aes_explosions_edit_adler.cpp
aes_explosions_edit_adler.h
aes_explosions_edit_adler_standalone.cpp
aes_explosions_edit_adler_standalone.h
aes_explosion_list.cpp
aes_explosion_list.h
aes_explosions_area_model.cpp
aes_explosions_area_model.h
# aes_effect_cluster_model.cpp
# aes_effect_cluster_model.h
aes_explosions_single_model.cpp
aes_explosions_single_model.h
aes_effector.cpp
aes_effector.h
aes_rocket_utility.cpp
aes_rocket_utility.h
CustomView/aes_explosion.h
CustomView/aes_explosion.cpp
)
NGL_WRAP_UI(aes_explosion_gui_SRCS
aes_explosion_edit.ui
aes_explosions_edit.ui
aes_explosions_edit_adler.ui
aes_explosions_edit_adler_standalone.ui
aes_effector.ui
CustomView/aes_explosion.ui
)
NGL_ADD_LIBRARY(WS AesExplosionGuiPlugin MODULE ${aes_explosion_gui_SRCS})
NGL_TARGET_LINK_LIBRARIES(AesExplosionGuiPlugin
AesBaseGui
ngltools
NGLLogger
LtsSessionData
AesDataPluginInterface
AesExplosionGuiPluginInterface
AesEffectClusterModel
PdmGuiPluginInterface
PpmDataPluginInterface
PpmParticipantSelectionGui
SituationMapGuiPluginInterface
Qt5::Widgets
LtsWidgets
LtsDataView
LtsUtilsGuiDds
LtsUtilsCore
LtsUtilsSettings
LtsElevation
Trajectory
LtsSessionData
AsmDataPluginInterface
ExmDataPluginInterface
saaTelegrams
)
NGL_INSTALL_TARGET(AesExplosionGuiPlugin)
@@ -0,0 +1,116 @@
/**
* @RDE_HEADER@
* CustomView for AES Explosion
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-04-08
*/
#include "aes_explosion.h"
#include "ui_aes_explosion.h"
#include "aes_explosions_area_model.h"
#include "aes_explosions_single_model.h"
#include <Services/AreaEffectSimulation/Utils/polygons.h>
#include <ProjectDataManagement/pdm_data_plugin_interface.h>
namespace AreaEffectSimulation
{
CustomViewExplosion::CustomViewExplosion(LtsSession::LtsSession *session, QWidget *parent)
: AbstractDisplayWidget(parent)
, m_session(session)
, m_ui(new Ui::CustomViewExplosion)
{
m_ui->setupUi(this);
}
CustomViewExplosion::~CustomViewExplosion()
{
delete m_ui;
}
bool CustomViewExplosion::init(const QModelIndex &idx)
{
if (!idx.isValid())
return false;
m_ui->lbName->setText(rowData(idx, AreaEffectSimulation::ExplosionsAreaModel::BcName).toString());
m_ui->lbEffectState->setText(rowData(idx, AreaEffectSimulation::ExplosionsAreaModel::BcEffectState).toString());
m_ui->lbEffectStart->setText(rowData(idx, AreaEffectSimulation::ExplosionsAreaModel::BcEffectStart).toString());
m_ui->lbChargeType->setText(rowData(idx, AreaEffectSimulation::ExplosionsAreaModel::BcChargeType).toString());
QString durationString = rowData(idx, AreaEffectSimulation::ExplosionsAreaModel::BcEffectDuration).toString();
if (!durationString.isEmpty() && durationString != QLatin1String("0"))
{
m_ui->lbEffectDuration->setText(durationString);
}
else
{
m_ui->label_4->hide();
m_ui->lbEffectDuration->hide();
}
m_ui->lblIcon->clear();
m_ui->lblIcon->setAutoFillBackground(true);
const AesItemSortFilterProxyModel *sfpm = qobject_cast<const AesItemSortFilterProxyModel*>(idx.model());
if (!sfpm)
return false;
const auto srcIdx = sfpm->mapToSource(idx);
const ExplosionsAreaModel *aesModelArea = qobject_cast<const ExplosionsAreaModel*>(sfpm->sourceModel());
if (aesModelArea)
{
ExplosionArea ea = aesModelArea->getRowData(srcIdx.row());
calculateIcon(ea, sfpm->partyColor(idx.row()));
return true;
}
else
{
const ExplosionsSingleModel *aesModelSingle = qobject_cast<const ExplosionsSingleModel*>(sfpm->sourceModel());
if (aesModelSingle)
{
ExplosionSingle es = aesModelSingle->getRowData(srcIdx.row());
calculateIcon(es, sfpm->partyColor(idx.row()));
return true;
}
}
return false;
}
bool CustomViewExplosion::calculateIcon(const ExplosionArea &area, const QColor &color)
{
Database::AesExplosionArea ea;
ea.impactPosition = QPointF(area.area().cornerBottomLeft().lon(),
area.area().cornerBottomLeft().lat());
ea.rotationAngle = area.area().rotation();
ea.impactWidth = area.area().width();
ea.impactLength = area.area().height(); // Todo: Correct?
QPolygonF poly = AreaEffectSimulation::Polygons::explosionArea(ea);
Qt::BrushStyle bStyle = PixmapLabel::checkForBrushStyle(area.effectStateId());
const auto pix = Polygons::pixmapFromPolygon(PixmapLabel::geographic2Utm(poly), color, ICON_RESOLUTION, bStyle);
m_ui->lblIcon->setPixmap(pix);
return true;
}
bool CustomViewExplosion::calculateIcon(const ExplosionSingle &single, const QColor &color)
{
Database::AesExplosionSingle es;
es.impactPosition = QPointF(single.impactPosition().lon(), single.impactPosition().lat());
std::shared_ptr<ProjectDataManagement::Interface::Dtc> pdmDtc;
if (!m_session->getDtc<ProjectDataManagement::DataInterface>(pdmDtc))
return false;
double radius = pdmDtc->impactRadius(single.chargeStruct().chargeTypeId(),
single.chargeStruct().igniterTypeId(),
single.chargeStruct().igniterFunctionId());
QPolygonF poly = AreaEffectSimulation::Polygons::explosionSingle(es, radius);
Qt::BrushStyle bStyle = PixmapLabel::checkForBrushStyle(single.effectStateId());
const auto pix = Polygons::pixmapFromPolygon(PixmapLabel::geographic2Utm(poly), color, ICON_RESOLUTION, bStyle);
m_ui->lblIcon->setPixmap(pix);
return true;
}
} // namespace AreaEffectSimulation
@@ -0,0 +1,39 @@
/**
* @RDE_HEADER@
* CustomView for AES Explosion
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2016-04-08
*/
#pragma once
#include <Viewer/LtsDataView/abstract_display_widget.h>
#include <LtsSession/lts_session.h>
namespace Ui
{
class CustomViewExplosion;
}
namespace AreaEffectSimulation
{
class ExplosionArea;
class ExplosionSingle;
class CustomViewExplosion final : public LtsDataView::AbstractDisplayWidget
{
Q_OBJECT
public:
explicit CustomViewExplosion(LtsSession::LtsSession *session, QWidget *parent = nullptr);
~CustomViewExplosion();
bool init(const QModelIndex &idx) override final;
private:
bool calculateIcon(const AreaEffectSimulation::ExplosionArea &area, const QColor &color);
bool calculateIcon(const AreaEffectSimulation::ExplosionSingle &single, const QColor &color);
LtsSession::LtsSession *m_session;
Ui::CustomViewExplosion *m_ui;
};
} // namespace AreaEffectSimulation
@@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CustomViewExplosion</class>
<widget class="QWidget" name="CustomViewExplosion">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>350</width>
<height>200</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="true"/>
</property>
<property name="toolTip">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="lbName">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string/>
</property>
<property name="text">
<string notr="true">Name</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbChargeType">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string/>
</property>
<property name="text">
<string notr="true">Type</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>State:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbEffectState">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string notr="true">State</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="AreaEffectSimulation::PixmapLabel" name="lblIcon">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">icon</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lbEffectStart">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string notr="true">Time</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string notr="true">for</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbEffectDuration">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string notr="true">Duration</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>AreaEffectSimulation::PixmapLabel</class>
<extends>QLabel</extends>
<header>AreaEffectSimulation/Gui/Base/aes_pixmap_label.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,30 @@
/**
* @RDE_HEADER@
* AreaEffectManangement - Explosion Single Overview Dialog Model
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-09-26
*/
#include "aes_explosions_single_central_model.h"
namespace AreaEffectSimulation
{
bool ExplosionsSingleCentralModel::initModel(LtsSession::LtsSession *session)
{
if (!AesGuiBaseModel::initModel(session))
return false;
connect(m_aesDtc.get(), &Interface::Dtc::explosionSingleCentralChanged,
this, &ExplosionsSingleCentralModel::onDataChanged);
fillAvailableChargeIds(m_gearClass);
m_aesDtc->explosionSingleCentrals([this](const ExplosionSingleCentral &item) { insertRow(item); });
return true;
}
} // namespace AreaEffectSimulation
@@ -0,0 +1,38 @@
/**
* @RDE_HEADER@
* ExplosionManangement - Explosion Single Overview Dialog Model
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-09-26
*/
#pragma once
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_base_model.h>
namespace AreaEffectSimulation
{
/************ Class for Artillery and Mortar Explosion Single ***************/
class ExplosionsSingleCentralModel : public AesGuiBaseModel<ExplosionSingleCentral>
{
Q_OBJECT
public:
ExplosionsSingleCentralModel(ProjectDataManagement::GearClass gc, QObject *parent)
: AesGuiBaseModel<ExplosionSingleCentral>(parent)
, m_gearClass(gc)
{}
bool initModel(LtsSession::LtsSession *session);
ProjectDataManagement::GearClass gearClass() const { return m_gearClass; }
protected:
ProjectDataManagement::GearClass m_gearClass;
};
} //namespace AreaEffectSimulation
@@ -0,0 +1,310 @@
/**
* @RDE_HEADER@
* AreaEffectManangement - Explosion Cluster Overview Dialog Model
* $Id$
* $HeadURL$
* $Author$
*
* Created by Norbert Thoden, SLSE, 2023-12-15
*/
#include "aes_effect_cluster_model.h"
#include <LtsCoordTrans/lts_coord_trans.h>
#include <ProjectDataManagement/pdm_dtc.h>
#include <ProjectDataManagement/pdm_translation.h>
namespace AreaEffectSimulation
{
EffectClusterModel::EffectClusterModel(const QVector<ProjectDataManagement::GearClass> &gcs, QObject *parent)
: AesGuiBaseModel<EffectCluster>(parent,
{tr("GearType"),
tr("Fuse Type"),
tr("FiringPosition"),
tr("ExplosionGeometry"),
tr("ZOG"), // TLA ZOG
tr("MeanHitPoints"),
tr("MhpRotation"),
tr("Impact Count"),
tr("AnnotationString"),
tr("Element"),
tr("Original Flight Duration"),
tr("Original Peak Height"),
tr("Calculated Flight Duration"),
tr("Calculated Peak Height"),
tr("Calculated Firing Speed [m/s]"),
tr("Launch Velocity [m/s]"),
tr("Launch Angle [degree]"),
tr("Drop Angle [degree]"),
tr("TapTimepoint"),
tr("Laser Code Prf"),
tr("Laser Code Termination"),
tr("Cloud Base")})
, m_gearClasses(gcs)
{
}
bool EffectClusterModel::initModel(LtsSession::LtsSession *session)
{
updateEffectStateComboboxFilterData(true);
if (!AesGuiBaseModel::initModel(session))
return false;
connect(m_aesDtc.get(), &Interface::Dtc::effectClusterChanged, this, &EffectClusterModel::onDataChanged);
connect(m_aesDtc.get(), &Interface::Dtc::explosionClusterChanged, this, &EffectClusterModel::onExplosionClusterDataChanged);
fillAvailableChargeIds(m_gearClasses);
// fillAvailableChargeIds({ProjectDataManagement::GearClass_def::Artillery, ProjectDataManagement::GearClass_def::Mortar});
m_aesDtc->effectClusters([this](const EffectCluster &item) { insertRow(item); });
m_aesDtc->explosionClusters([this](const ExplosionCluster &item) { insertRow(toEffectCluster(item)); });
m_pdmDtc->enableGearTypeChargeType();
return true;
}
EffectCluster EffectClusterModel::toEffectCluster(const ExplosionCluster &data)
{
EffectCluster ec;
ec.id(data.id());
ec.name(data.name());
ec.effectSourceId(data.effectSourceId());
ec.effectStateId(data.effectStateId());
ec.chargeStruct(data.chargeStruct());
ec.effectDuration(data.effectDuration());
ec.effectStart(data.effectStart());
ec.area(data.area());
ec.esmParticipantIds(data.esmParticipantIds());
ec.explosionGeometry(data.explosionGeometry());
ec.element(data.element());
ec.firePurposeId(data.firePurposeId());
ec.firingPosition(data.firingPosition());
ec.fireRequestTime(data.fireRequestTime());
ec.tla(data.tla());
ec.sampleTime(data.sampleTime());
ec.effectMarkingInTa(data.effectMarkingInTa());
ec.externalId(data.externalId());
ec.remainExplosionNumber(data.remainExplosionNumber());
ec.participantId(data.participantId());
ec.partyId(data.partyId());
ec.properties(data.properties());
ec.isCentral(data.isCentral());
ec.isDeleted(data.isDeleted());
ec.isUsed(data.isUsed());
return ec;
}
void EffectClusterModel::onExplosionClusterDataChanged(const ExplosionCluster &data, const DataModification &mod) { onDataChanged(toEffectCluster(data), mod); }
void EffectClusterModel::toolTipHelper(const EffectClusterModel *model, const QModelIndex &idx, int col, QString &toolTipStringInOut) const
{
const QString &hdr = model->headerData(col, Qt::Horizontal, Qt::DisplayRole).toString();
const QModelIndex &idxTemp = idx.siblingAtColumn(col);
toolTipStringInOut.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, model->data(idxTemp, Qt::DisplayRole).toString()));
}
QVariant EffectClusterModel::data(const QModelIndex &idx, int role) const
{
if (!indexIsValid(idx))
return QVariant();
const EffectCluster &ec = m_vecData.at(idx.row());
// const dds::core::optional<AreaEffectSimulation::FlightCurve>& flightCurveRef = ec.flightCurve();
// const dds::core::optional<AreaEffectSimulation::LaserGuiding>& laserGuidingRef = ec.laserGuiding();
if (role == Qt::DisplayRole)
{
switch (idx.column())
{
case ColGearType:
{
const int chargeTypeId = ec.chargeStruct().chargeTypeId();
// There might be several gears for the same charge and we take the first one knowingly.
const int gearTypeId = m_pdmDtc->gearTypeIdFromChargeTypeId(chargeTypeId).value(0, 0);
return m_pdmDtc->trGearTypeName(gearTypeId);
}
break;
case ColIgniterType:
return m_pdmDtc->trIgniterTypeShortName(ec.chargeStruct().igniterTypeId());
break;
case ColFiringPosition:
{
const Core::GeoPosition &firingPositionRef = ec.firingPosition();
QString mgrs = LtsCoordTrans::mgrsFromGeographic(firingPositionRef.lon(), firingPositionRef.lat());
if (!qFuzzyIsNull(firingPositionRef.z()))
mgrs.append(QStringLiteral(" ") + QString::number(firingPositionRef.z(), 'f', 2));
return mgrs;
}
break;
case ColExplosionGeometry:
return AreaEffectSimulation::toString(ec.explosionGeometry());
break;
case ColTlaZog:
return ec.tla();
break;
// case ColMhPointCount:
// return static_cast<int>(ec.mhPoints().size());
// break;
// case ColMhpRotationCount:
// return std::ceil(ec.mhpRotation() * 100) / 100;
// break;
// case ColImpactCount:
// return ec.impactCount();
// break;
case ColAnnotationString:
return QString::fromStdString(ec.annotationString());
break;
case ColZpElement:
return QString::fromStdString(ec.element());
break;
/* Might be used again if needed
// FlightCurve
case ColOriginalFlightDuration:
if (flightCurveRef.is_set())
return std::ceil(flightCurveRef.get().requestedFlightDuration() * 100) / 100;
else
return QStringLiteral("-");
break;
case ColOriginalPeakHeight:
if (flightCurveRef.is_set())
return flightCurveRef.get().requestedRelativePeakHeight();
else
return QStringLiteral("-");
break;
case ColCalculatedFlightDuration:
if (flightCurveRef.is_set())
return flightCurveRef.get().calculatedFlightDuration();
else
return QStringLiteral("-");
break;
case ColCalculatedPeakHeight:
if (flightCurveRef.is_set())
return std::ceil(flightCurveRef.get().calculatedPeakHeightAbs() * 100) / 100;
else
return QStringLiteral("-");
break;
case ColCalculatedFiringSpeed:
if (flightCurveRef.is_set())
return std::ceil(flightCurveRef.get().calculatedFiringSpeed() * 100) / 100;
else
return QStringLiteral("-");
break;
case ColLaunchVelocity:
if (flightCurveRef.is_set())
return std::ceil(flightCurveRef.get().launchVelocity() * 100) / 100;
else
return QStringLiteral("-");
break;
case ColLaunchAngleDeg:
if (flightCurveRef.is_set())
return std::ceil(flightCurveRef.get().launchAngle() * 100) / 100;
else
return QStringLiteral("-");
break;
case ColDropAngle:
if (flightCurveRef.is_set())
return std::ceil(flightCurveRef.get().dropAngle() * 100) / 100;
else
return QStringLiteral("-");
break;
// LaserGuiding
case ColTapTimepoint:
if (laserGuidingRef.is_set())
return DTG::toStringMSec(laserGuidingRef.get().tapTime());
else
return QStringLiteral("-");
break;
case ColLcAttack_Prf:
if (laserGuidingRef.is_set())
return laserGuidingRef.get().lcAttack();
else
return QStringLiteral("-");
break;
case ColLcTermination:
if (laserGuidingRef.is_set())
return laserGuidingRef.get().lcTermination();
else
return QStringLiteral("-");
break;
case ColCloudBase:
if (laserGuidingRef.is_set())
return laserGuidingRef.get().cloudBase();
else
return QStringLiteral("-");
break;
*/
default:
return AesGuiBaseModel::data(idx, role);
break;
} // switch
}
else if (role == Qt::ToolTipRole)
{
switch (idx.column())
{
case ColAnnotationString:
// return QString::fromStdString(ec.annotationString());
break;
default:
{
QString tooltip(QStringLiteral("<html>"));
const QString &hdr = this->headerData(BcName, Qt::Horizontal, Qt::DisplayRole).toString();
tooltip.append(QStringLiteral("<p>%1: %2</p>").arg(hdr, QString::fromStdString(ec.name())));
bool bIsArtilleryOrMortar = m_gearClasses.contains(ProjectDataManagement::GearClass_def::Artillery)
|| m_gearClasses.contains(ProjectDataManagement::GearClass_def::Mortar)
|| m_gearClasses.contains(ProjectDataManagement::GearClass_def::Rocket);
toolTipHelper(this, idx, ColGearType, tooltip);
if (bIsArtilleryOrMortar)
{
toolTipHelper(this, idx, BcChargeType, tooltip);
toolTipHelper(this, idx, ColIgniterType, tooltip);
}
// Origin
toolTipHelper(this, idx, ColFiringPosition, tooltip);
// target
if (bIsArtilleryOrMortar)
{
toolTipHelper(this, idx, ColExplosionGeometry, tooltip);
toolTipHelper(this, idx, ColTlaZog, tooltip);
toolTipHelper(this, idx, ColMhPointCount, tooltip);
toolTipHelper(this, idx, ColImpactCount, tooltip);
toolTipHelper(this, idx, ColCalculatedFlightDuration, tooltip);
toolTipHelper(this, idx, ColCalculatedPeakHeight, tooltip);
toolTipHelper(this, idx, ColCalculatedFiringSpeed, tooltip);
toolTipHelper(this, idx, ColLaunchAngleDeg, tooltip);
toolTipHelper(this, idx, ColDropAngle, tooltip);
toolTipHelper(this, idx, ColTapTimepoint, tooltip);
toolTipHelper(this, idx, ColLcAttack_Prf, tooltip);
toolTipHelper(this, idx, ColLcTermination, tooltip);
toolTipHelper(this, idx, ColCloudBase, tooltip);
}
tooltip.append(QStringLiteral("</html>"));
return tooltip;
}
break;
} // switch
}
return AesGuiBaseModel::data(idx, role);
}
} // namespace AreaEffectSimulation
@@ -0,0 +1,69 @@
/**
* @RDE_HEADER@
* AreaEffectManangement - Explosion Cluster Overview Dialog Model
* $Id$
* $HeadURL$
* $Author$
*
* Created by Norbert Thoden, SLSE, 2023-12-15
*/
#pragma once
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_base_model.h>
#include <Plugins/AreaEffectSimulation/Gui/Explosion/aeseffectclustermodel_export.h>
namespace AreaEffectSimulation
{
//
// Model for ExplosionsCluster (Artillery and/or Mortar and/or AirSupport
//
class AESEFFECTCLUSTERMODEL_EXPORT EffectClusterModel : public AesGuiBaseModel<EffectCluster>
{
Q_OBJECT
public:
enum AdditionalColumns
{
ColGearType = BcCount,
ColIgniterType = BcCount + 1,
ColFiringPosition = BcCount + 2,
ColExplosionGeometry = BcCount + 3,
ColTlaZog = BcCount + 4,
ColMhPointCount = BcCount + 5,
ColMhpRotationCount = BcCount + 6,
ColImpactCount = BcCount + 7,
ColAnnotationString = BcCount + 8,
ColZpElement = BcCount + 9,
ColOriginalFlightDuration = BcCount + 10, // origional...
ColOriginalPeakHeight = BcCount + 11, // origional...
ColCalculatedFlightDuration = BcCount + 12, // calculated...
ColCalculatedPeakHeight = BcCount + 13,
ColCalculatedFiringSpeed = BcCount + 14,
ColLaunchVelocity = BcCount + 15, // more or less requested velocity, value is transfered to calculatedFiringSpeed
ColLaunchAngleDeg = BcCount + 16,
ColDropAngle = BcCount + 17,
ColTapTimepoint = BcCount + 18,
ColLcAttack_Prf = BcCount + 19,
ColLcTermination = BcCount + 20,
ColCloudBase = BcCount + 21,
}; // origional...
EffectClusterModel(const QVector<ProjectDataManagement::GearClass> &gcs, QObject *parent);
bool initModel(LtsSession::LtsSession *session) override;
QVariant data(const QModelIndex &idx, int role) const override;
public slots:
void onExplosionClusterDataChanged(const ExplosionCluster &data, const DataModification &mod);
protected:
void toolTipHelper(const EffectClusterModel *model, const QModelIndex &idx, int col, QString &toolTipStringInOut) const;
EffectCluster toEffectCluster(const ExplosionCluster &data);
QVector<ProjectDataManagement::GearClass> m_gearClasses;
};
} // namespace AreaEffectSimulation
@@ -0,0 +1,117 @@
/**
* @RDE_HEADER@
* AreaEffectSimulation - Effector
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, ESZS, 2026-02-18
*/
#include "aes_effector.h"
#include "ui_aes_effector.h"
#include <QtCore/QTimer>
namespace AreaEffectSimulation
{
AesEffector::AesEffector(QWidget *parent)
: QWidget(parent)
, m_ui(new Ui::AesEffector)
{
m_ui->setupUi(this);
connect(m_ui->pbTriggerNextState, &QPushButton::clicked, this, &AesEffector::onPbNextStateClicked);
}
AesEffector::~AesEffector()
{
delete m_ui;
}
bool AesEffector::init(int effectorId, const QString &verEin, const QString &name, AreaEffectSimulation::AesEffectorState state)
{
m_effectorId = effectorId;
m_ui->lblVerEin->setText(verEin);
m_ui->gbEffector->setTitle(verEin);
m_ui->lblName->setText(name);
setState(state);
return true;
}
void AesEffector::setStateButtonVisible( bool visible)
{
m_ui->pbTriggerNextState->setVisible(visible);
}
AreaEffectSimulation::AesEffectorState AesEffector::getState() const
{
return m_state;
}
void AesEffector::setState(const AreaEffectSimulation::AesEffectorState &newState)
{
m_state = newState;
switch(newState.underlying())
{
case AreaEffectSimulation::AesEffectorState::EsNotReadyToFire:
m_ui->lblState->setText(tr("Not ready to fire"));
m_ui->pbTriggerNextState->setText(tr("Ready to Fire"));
break;
case AreaEffectSimulation::AesEffectorState::EsReadyToFire:
m_ui->lblState->setText(tr("Ready to fire"));
m_ui->pbTriggerNextState->setText(tr("Fire"));
break;
case AreaEffectSimulation::AesEffectorState::EsReceivedOrder:
m_ui->lblState->setText(tr("Fire command received"));
m_ui->pbTriggerNextState->setText(tr("Fire"));
break;
case AreaEffectSimulation::AesEffectorState::EsReportedFired:
m_ui->lblState->setText(tr("Fired reported"));
m_ui->pbTriggerNextState->setText(tr("Report Ready to Fire"));
break;
case AreaEffectSimulation::AesEffectorState::EsFired:
m_ui->lblState->setText(tr("Fired"));
m_ui->pbTriggerNextState->setText(tr("Report Fired"));
break;
default:
// this shouldn't happen...
break;
}
}
void AesEffector::onPbNextStateClicked()
{
switch (m_state.underlying()) {
case AreaEffectSimulation::AesEffectorState::EsFired:
emit reportFired();
break;
case AreaEffectSimulation::AesEffectorState::EsReportedFired:
emit reportReadyToFire();
break;
case AreaEffectSimulation::AesEffectorState::EsNotReadyToFire:
emit reportReadyToFire();
break;
case AreaEffectSimulation::AesEffectorState::EsReadyToFire:
emit fire();
break;
case AreaEffectSimulation::AesEffectorState::EsReceivedOrder:
break;
emit fire();
default:
break;
}
m_ui->pbTriggerNextState->setDisabled(true);
// Re-Enable PB, so we can call it another time, if it does not react...
QTimer::singleShot(2000, [this](){m_ui->pbTriggerNextState->setEnabled(true);});
}
int AesEffector::effectorId() const
{
return m_effectorId;
}
} // namespace AreaEffectSimulation
@@ -0,0 +1,52 @@
/**
* @RDE_HEADER@
* AreaEffectSimulation - Effector
* $Id$
* $HeadURL$
* $Author$
* Created by Hanna E. Rathje, ESZS, 2026-02-18
*/
#pragma once
#include <QWidget>
#include <AreaEffectSimulation/aes_enums.hpp>
namespace Ui {
class AesEffector;
}
namespace AreaEffectSimulation
{
class AesEffector : public QWidget
{
Q_OBJECT
public:
explicit AesEffector(QWidget *parent = nullptr);
~AesEffector();
bool init(int effectorId, const QString &verEin, const QString &name, AreaEffectSimulation::AesEffectorState state);
AreaEffectSimulation::AesEffectorState getState() const;
void setState(const AreaEffectSimulation::AesEffectorState &newState);
void setStateButtonVisible(bool visible);
int effectorId() const;
private slots:
void onPbNextStateClicked();
signals:
void reportFired();
void reportReadyToFire();
void fire();
private:
Ui::AesEffector *m_ui;
int m_effectorId;
AreaEffectSimulation::AesEffectorState m_state;
};
} // namespace AreaEffectSimulation
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AesEffector</class>
<widget class="QWidget" name="AesEffector">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>282</width>
<height>458</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QGroupBox" name="gbEffector">
<property name="title">
<string>Effector</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="QLabel" name="lblName">
<property name="text">
<string>XXX Name</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lblVerEin">
<property name="text">
<string>XXX 12345</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>240</width>
<height>2</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lbxVerEin">
<property name="text">
<string>VerEin:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lbxName">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QPushButton" name="pbTriggerNextState">
<property name="text">
<string>TriggerNextState</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lbxState">
<property name="text">
<string>State:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="lblState">
<property name="text">
<string>XXX Fired</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,880 @@
/**
* @RDE_HEADER@
* AreaEffectSimulation - Explosion Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-07-05
*/
#include "aes_explosion_edit.h"
#include "ui_aes_explosion_edit.h"
#include <LtsCoordTrans/lts_coord_trans.h>
#include <LtsSession/lts_session_data.h>
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Services/AreaEffectSimulation/Utils/polygons.h>
#include <QJsonDocument>
#include <LtsUtilsSettings/settings.h>
#include <Plugins/AdvancedSymbology/asb_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/Gui/ParticipantSelection/participant_selection.h>
#include <QSpinBox>
namespace AreaEffectSimulation
{
double ExplosionEdit::s_minWidth;
double ExplosionEdit::s_maxWidth;
double ExplosionEdit::s_stepWidth;
double ExplosionEdit::s_minHeight;
double ExplosionEdit::s_maxHeight;
double ExplosionEdit::s_stepHeight;
double ExplosionEdit::s_minRadius;
double ExplosionEdit::s_maxRadius;
double ExplosionEdit::s_stepRadius;
int ExplosionEdit::s_maxChargeUsage;
double ExplosionEdit::s_minAltitude;
double ExplosionEdit::s_maxAltitude;
qint64 ExplosionEdit::s_maxDurationSeconds;
static int s_lastChargeTypeA = 0;
static int s_lastChargeTypeM = 0;
ExplosionEdit::ExplosionEdit(const QString &menuGroup, ExplosionType type, ProjectDataManagement::GearClass gc, QWidget *parent)
: BaseEdit(menuGroup, QLatin1String("ExplosionEdit"), parent)
, m_type(type)
, m_editable(false)
, m_gearClass(gc)
, m_previewCircleRadius(0.0)
, m_ui(new Ui::ExplosionEdit)
{
m_ui->setupUi(this);
// Todo: Get these values
s_minWidth = 5;
s_maxWidth = 1275;
s_stepWidth = 5;
s_minHeight = 5;
s_maxHeight = 1275;
s_minRadius = 5;
s_maxRadius = 255;
s_stepRadius = 1;
s_stepHeight = 5;
s_minAltitude = 0;
s_maxAltitude = 1000;
s_maxChargeUsage = 1000;
s_maxDurationSeconds = 1800; // 30 Minutes
m_ui->sbDimensionX->setMinimum(s_minWidth);
m_ui->sbDimensionX->setMaximum(s_maxWidth);
m_ui->sbDimensionX->setSingleStep(s_stepWidth);
m_ui->sbDimensionY->setMinimum(s_minHeight);
m_ui->sbDimensionY->setMaximum(s_maxHeight);
m_ui->sbDimensionY->setSingleStep(s_stepHeight);
m_ui->sbAltitude->setMinimum(s_minAltitude);
m_ui->sbAltitude->setMaximum(s_maxAltitude);
m_ui->sbCannons->setMinimum(1);
m_ui->sbCannons->setMaximum(s_maxChargeUsage);
m_ui->sbRounds->setMinimum(1);
m_ui->sbRounds->setMaximum(s_maxChargeUsage);
m_ui->sbDurationSeconds->setMinimum(1);
m_ui->sbDurationSeconds->setMaximum(s_maxDurationSeconds);
m_ui->sbAimingAxis->setMaximum(6400);
m_ui->lblDesignator->clear();
m_ui->lblIcon->clear();
m_ui->lblTactIdentifier->clear();
m_uiRequirements->addRequirement({m_ui->lblPosition, [this]() { return (!m_ui->positionEdit->coordinate().isNull()); }});
m_uiRequirements->addRequirement({m_ui->lblName, [this]() { return (!m_ui->leIdentifier->text().isEmpty()); }});
m_uiRequirements->addRequirement({m_ui->lblChargeType, [this]() { return (!m_ui->cbChargeType->currentData().isNull()); }});
// either no effect start is set or effect start is greater than request time
m_uiRequirements->addRequirement({m_ui->lblEffectStart, [this]()
{
return (hasValidEffectStart(m_ui->dteEffectStart) ||
m_ui->dteEffectStart->msecsSinceEpoch() >= m_ui->dteRequestTime->msecsSinceEpoch());
}});
if (m_type != etArea)
{
m_ui->lblAimingAxis->hide();
m_ui->sbAimingAxis->hide();
m_ui->lblDuration->hide();
m_ui->sbDurationSeconds->hide();
m_ui->sbDimensionX->setEnabled(false);
m_ui->lblOperatorA->hide();
m_ui->sbDimensionY->hide();
m_ui->sbDimensionX->setMinimum(s_minRadius);
m_ui->sbDimensionX->setMaximum(s_maxRadius);
m_ui->sbDimensionX->setSingleStep(s_stepRadius);
m_ui->sbCannons->setEnabled(false);
m_ui->sbCannons->hide();
m_ui->lblOperatorB->hide();
m_ui->sbRounds->setEnabled(false);
}
else
{
m_ui->sbDurationSeconds->setValue(60);
m_ui->sbCannons->setValue(4);
m_ui->sbRounds->setValue(9);
}
if (m_type != etSingleCentral)
{
m_ui->lbxFiringAngle->hide();
m_ui->sbFiringAngle->hide();
m_ui->lbxIgniterType->hide();
m_ui->cbIgniterType->hide();
m_ui->lbxParticipant->hide();
m_ui->lblDesignator->hide();
m_ui->lblIcon->hide();
m_ui->lblTactIdentifier->hide();
m_ui->pbParticipant->hide();
m_ui->cbParty->setEnabled(false);
}
else
m_uiRequirements->addRequirement({m_ui->lbxParticipant, [this]() { return (m_participant.id() != 0); }});
enaDisa();
connect(m_ui->cbParty, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &ExplosionEdit::onPartyChanged);
connect(m_ui->cbChargeType, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &ExplosionEdit::onChargeTypeChanged);
connect(m_ui->sbDimensionX, &QSpinBox::editingFinished, this, &ExplosionEdit::correctSpinBoxValue);
connect(m_ui->sbDimensionY, &QSpinBox::editingFinished, this, &ExplosionEdit::correctSpinBoxValue);
connect(m_ui->sbAltitude, &QSpinBox::editingFinished, this, &ExplosionEdit::correctSpinBoxValue);
// Not yet needed (no singleStep defined)
// connect(m_ui->sbAimingAxis, &QSpinBox::editingFinished, this, &ExplosionEdit::correctSpinBoxValue);
// connect(m_ui->sbCannons, &QSpinBox::editingFinished, this, &ExplosionEdit::correctSpinBoxValue);
// connect(m_ui->sbRounds, &QSpinBox::editingFinished, this, &ExplosionEdit::correctSpinBoxValue);
// connect(m_ui->sbDurationSeconds, &QSpinBox::editingFinished, this, &ExplosionEdit::correctSpinBoxValue);
connect(m_ui->sbCannons, QOverload<int>::of(&QSpinBox::valueChanged),
this, [this](int val) { onCannonsChanged(val); });
connect(m_ui->sbRounds, QOverload<int>::of(&QSpinBox::valueChanged),
this, [this](int val) { onRoundsChanged(val); });
connect(m_ui->pbFire, &QPushButton::clicked,
this, &ExplosionEdit::onFireClicked);
connect(m_ui->pbClear, &QPushButton::clicked,
m_ui->positionEdit, &LtsCoordWidget::LtsCoordWidget::clear);
connect(m_ui->pbParticipant, &QPushButton::clicked,
this, &ExplosionEdit::onParticipantClicked);
m_symbolWatcher = new AdvancedSymbology::SymbolResultWatcherLabel(m_ui->lblIcon);
}
ExplosionEdit::~ExplosionEdit()
{
delete m_ui;
}
void ExplosionEdit::retranslate()
{
QString title;
switch (m_gearClass.underlying())
{
case ProjectDataManagement::GearClass::Artillery:
if (m_type == etSingle)
title = tr("Single Artillery");
else if (m_type == etArea)
title = tr("Area Artillery");
else
title = tr ("Single Artillery Central");
break;
case ProjectDataManagement::GearClass::Mortar:
if (m_type == etSingle)
title = tr("Single Mortar");
else if (m_type == etArea)
title = tr("Area Mortar");
else
title = tr ("Single Mortar Central");
break;
default:
Q_ASSERT(false);
}
translate(m_ui, m_aesItem, title);
if (m_type != etArea)
{
m_ui->sbCannons->setValue(1);
m_ui->sbRounds->setValue(1);
m_ui->lblRounds->setText(tr("Rounds:"));
m_ui->lblDimension->setText(tr("Diameter [m]:"));
}
else
{
m_ui->lblRounds->setText(tr("Cannons x Rounds:"));
m_ui->lblDimension->setText(tr("Dimension [m]:"));
}
setFireButton(m_aesItem.effectStateId());
updateMaxLabel(false);
}
void ExplosionEdit::onCannonsChanged(int cannons, bool modifiedFromExternal)
{
updateMaxLabel(modifiedFromExternal);
if (cannons == 0 || maxAvailableRounds() == 0)
return;
m_ui->sbRounds->setMaximum(maxAvailableRounds() / cannons);
updateMaxLabel(modifiedFromExternal);
}
void ExplosionEdit::onRoundsChanged(int rounds, bool modifiedFromExternal)
{
updateMaxLabel(modifiedFromExternal);
if (rounds == 0 || maxAvailableRounds() == 0)
return;
m_ui->sbCannons->setMaximum(maxAvailableRounds() / rounds);
updateMaxLabel(modifiedFromExternal);
}
void ExplosionEdit::enableUiElements(bool enable)
{
ERROR_LOG(m_logger) << " enableUiElements enable=" << enable;
m_ui->leIdentifier->setMaxLength(30);
m_ui->cbChargeType->setEnabled(enable);
m_ui->sbDurationSeconds->setEnabled(enable);
m_ui->cbParty->setEnabled(enable && m_type != etSingleCentral); // Set via Participant
setEffectStartEnabled(m_ui->dteEffectStart, enable);
m_ui->dteRequestTime->setEnabled(enable);
m_ui->pbPosition->setEnabled(m_sitMapGuiIfc && enable);
m_ui->positionEdit->setEnabled(enable);
m_ui->sbAltitude->setEnabled(enable);
m_ui->sbDimensionX->setEnabled(enable && m_type == etArea);
m_ui->sbDimensionY->setEnabled(enable);
m_ui->sbAimingAxis->setEnabled(enable);
m_ui->cbPurpose->setEnabled(enable);
m_ui->sbCannons->setEnabled(enable && m_type == etArea);
m_ui->sbRounds->setEnabled(enable && m_type == etArea);
m_ui->cbEffectMarkingInTa->setEnabled(enable);
m_ui->leIdentifier->setEnabled(enable || isOnlyNameModifiable());
m_ui->pbClear->setEnabled(enable);
m_ui->sbFiringAngle->setEnabled(enable);
m_ui->pbParticipant->setEnabled(enable);
m_ui->cbIgniterType->setEnabled(enable);
if (!enable)
{
bool hasChanges = hasUnsavedChanges();
m_ui->sbDurationSeconds->setValue(m_aesItem.effectDuration() / 1000); // ms -> s
if (!hasChanges)
__unchange__();
}
setFireButton(m_aesItem.effectStateId());
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();
AesItem baseData;
if (m_type == etSingle)
{
ExplosionSingle singleData = m_dtc->explosionSingle(m_aesItem.id());
setSingleData(singleData);
baseData = singleData;
}
else if (m_type == etArea)
{
ExplosionArea areaData = m_dtc->explosionArea(m_aesItem.id());
setAreaData(areaData);
baseData = areaData;
}
setBaseData(baseData, false);
setFireButton(baseData.effectStateId());
__unchange__();
if (name != m_ui->leIdentifier->text())
m_ui->leIdentifier->setText(name);
}
if (m_aesItem.effectStateId() == AesEffectState_def::EsPaused)
__unchange__();
}
int ExplosionEdit::maxAvailableRounds() const
{
int mapMax = m_chargeTypeMap[m_ui->cbChargeType->currentData().toInt()].available[m_ui->cbParty->currentData().toInt()];
return mapMax > s_maxChargeUsage ? s_maxChargeUsage : mapMax;
}
void ExplosionEdit::setBaseData(const AesItem &baseData, bool copy)
{
m_aesItem = baseData;
if (copy)
{
m_aesItem.id(0);
m_aesItem.effectStateId(AreaEffectSimulation::AesEffectState_def::get_default());
}
m_ui->leIdentifier->setText(QString::fromUtf8(baseData.name().c_str()));
int idx = m_ui->cbChargeType->findData(baseData.chargeStruct().chargeTypeId());
if (idx < 0)
{
auto ct = m_chargeTypeMap[baseData.chargeStruct().chargeTypeId()].chargeType;
m_ui->cbChargeType->addItem(m_pdmDtc->trChargeTypeShortName(ct.id(), true), ct.id());
idx = m_ui->cbChargeType->findData(ct.id());
}
m_ui->cbChargeType->setCurrentIndex(idx);
m_ui->dteEffectStart->setMsecsSinceEpoch(baseData.effectStart().is_set() ? baseData.effectStart().get() : 0);
m_ui->sbDurationSeconds->setValue(baseData.effectDuration() / 1000); // ms -> s
m_ui->cbParty->setCurrentIndex(m_ui->cbParty->findData(partyForItem(baseData)));
m_ui->cbEffectMarkingInTa->setChecked(baseData.effectMarkingInTa());
m_editable = m_editable && isModifiable() && !isOnlyNameModifiable() && m_session->app() != LtsAppDescriptor::App::OC;
}
bool ExplosionEdit::init(int aesItemId, bool copy,
LtsSession::LtsSession *session)
{
if (!BaseEdit::init(aesItemId, session))
return false;
if (!m_session->getForeignDataInterface<AdvancedSymbology::DataInterface>(m_asbIfc))
return false;
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
{
ERROR_LOG(m_logger) << " failed to get ppmDtc";
return false;
}
if (!m_session->getForeignGuiInterface<ProjectDataManagement::ForeignGuiInterface>(m_pdmCbx))
return false;
bool readable = false;
switch (m_gearClass.underlying())
{
case ProjectDataManagement::GearClass::Artillery:
m_editable = (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SingleExplosionsEditArtillery) && m_type == etSingle) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::AreaExplosionsEditArtillery) && m_type == etArea) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SingleExplosionsCentralEditArtillery) && m_type == etSingleCentral) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::ExplosionEditCluster) && m_type == etArea) ;
readable = (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SingleExplosionsShowArtillery) && m_type == etSingle) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::AreaExplosionsShowArtillery) && m_type == etArea) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SingleExplosionsCentralEditArtillery) && m_type == etSingleCentral) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::ExplosionShowCluster) && m_type == etArea);
if (m_type == etSingle) // Single Artillery
setOnlineHelpFilename(QStringLiteral("Situation-Add_Single_Artillery"));
else if (m_type == etArea) // Area Artillery
setOnlineHelpFilename(QStringLiteral("Situation-Add_Area_Artillery"));
else if (m_type == etSingleCentral) // Single Central Artillery
setOnlineHelpFilename(QStringLiteral("Situation-Add_Single_Central_Artillery"));
break;
case ProjectDataManagement::GearClass::Mortar:
m_editable = (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SingleExplosionsEditMortar) && m_type == etSingle) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::AreaExplosionsEditMortar) && m_type == etArea) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SingleExplosionsCentralEditMortar) && m_type == etSingleCentral) ;
readable = (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SingleExplosionsShowMortar) && m_type == etSingle) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::AreaExplosionsShowMortar) && m_type == etArea) ||
(LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SingleExplosionsCentralShowMortar) && m_type == etSingleCentral) ;
if (m_type == etSingle) // Single Artillery
setOnlineHelpFilename(QStringLiteral("Situation-Add_Single_Mortar"));
else if (m_type == etArea) // Area Artillery
setOnlineHelpFilename(QStringLiteral("Situation-Add_Area_Mortar"));
else if (m_type == etSingleCentral) // Single Central Artillery
setOnlineHelpFilename(QStringLiteral("Situation-Add_Single_Central_Mortar"));
break;
default:
Q_ASSERT(false);
break;
}
if (!readable && !m_editable)
return false;
if (!m_session->getDtc<ProjectDataManagement::DataInterface>(m_pdmDtc))
return false;
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
return false;
m_ui->dteEffectStart->setMinimumTimeMSec(m_session->partitionTime());
m_ui->dteEffectStart->setRetrieveCurrentTimeCallback([this]() { return m_session->partitionTime(); });
m_ui->dteRequestTime->setRetrieveCurrentTimeCallback([this]() { return m_session->partitionTime(); });
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
const bool enableEffectShowManagement = ps->value(QStringLiteral("esm"),
QStringLiteral("enableEffectShowManagement")).toBool();
m_ui->cbEffectMarkingInTa->setVisible(enableEffectShowManagement &&
((m_session->app() == LtsAppDescriptor::App::Situation ||
m_session->app() == LtsAppDescriptor::App::SituationTablet) &&
(!m_session->isReplayPartition())));
if (m_sitMapGuiIfc)
connect(m_ui->pbPosition, &QPushButton::clicked, this, &ExplosionEdit::getPosition);
else
m_ui->pbPosition->setEnabled(false);
const auto firePurposes = m_pdmDtc->firePurposes();
for (const auto &firePurpose : firePurposes)
m_ui->cbPurpose->addItem(m_pdmDtc->trFirePurposeName(firePurpose.id()), firePurpose.id());
const auto chargesForGearClass =
m_pdmDtc->chargesForGearClass(m_gearClass);
for (const ProjectDataManagement::ChargeType &chargeType : chargesForGearClass)
m_chargeTypeMap[chargeType.id()].chargeType = chargeType;
const auto chargeAdmins = m_dtc->chargeAdministrations();
for (const ChargeAdministration &val : chargeAdmins)
{
if (!m_chargeTypeMap.contains(val.chargeTypeId()))
continue;
m_chargeTypeMap[val.chargeTypeId()].available.insert(val.partyId(), val.amount() - val.planned());
}
m_ppmGuiCbxIfc->fillPartyComboBox(m_ui->cbParty);
onPartyChanged();
if (aesItemId > 0)
{
AesItem baseData;
if (m_type == etSingle)
{
ExplosionSingle singleData = m_dtc->explosionSingle(aesItemId);
setSingleData(singleData);
baseData = singleData;
}
else if (m_type == etArea)
{
ExplosionArea areaData = m_dtc->explosionArea(aesItemId);
setAreaData(areaData, copy);
baseData = areaData;
}
setBaseData(baseData, copy);
setFireButton(baseData.effectStateId());
}
else
setFireButton(AreaEffectSimulation::AesEffectState::EsUnknown);
enableUiElements(m_editable);
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::chargeAdministrationChanged,
this, &ExplosionEdit::onChargeCountChanged);
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionAreaChanged,
this, &BaseEdit::onAreaChanged);
onChargeTypeChanged();
return true;
}
QString ExplosionEdit::dialogIdentifier() const
{
switch (m_gearClass.underlying())
{
case ProjectDataManagement::GearClass::Artillery:
if (m_type == etSingle)
return m_aesItem.id() <= 0 ? QStringLiteral("AddExplosionSingleArtillery") : QStringLiteral("EditExplosionSingleArtillery%1").arg(m_aesItem.id());
else if (m_type == etArea)
return m_aesItem.id() <= 0 ? QStringLiteral("AddExplosionAreaArtillery") : QStringLiteral("EditExplosionAreaArtillery%1").arg(m_aesItem.id());
else
return m_aesItem.id() <= 0 ? QStringLiteral("AddExplosionSingleCentralArtillery") : QStringLiteral("EditExplosionSingleCentralArtillery%1").arg(m_aesItem.id());
case ProjectDataManagement::GearClass::Mortar:
if (m_type == etSingle)
return m_aesItem.id() <= 0 ? QStringLiteral("AddExplosionSingleMortar") : QStringLiteral("EditExplosionSingleMortar%1").arg(m_aesItem.id());
else if (m_type == etArea)
return m_aesItem.id() <= 0 ? QStringLiteral("AddExplosionAreaMortar") : QStringLiteral("EditExplosionAreaMortar%1").arg(m_aesItem.id());
else
return m_aesItem.id() <= 0 ? QStringLiteral("AddExplosionSingleCentralMortar") : QStringLiteral("EditExplosionSingleCentralMortar%1").arg(m_aesItem.id());
default:
Q_ASSERT(false);
break;
}
return QString();
}
void ExplosionEdit::onChargeCountChanged(const AreaEffectSimulation::ChargeAdministration &data, DataModification modType)
{
// All relevant Charge Types are in Map. So we can just skip the others.
if (!m_chargeTypeMap.contains(data.chargeTypeId()))
return;
if (modType == DataModification::eRemoved || data.amount() - data.planned() <= 0)
m_chargeTypeMap[data.chargeTypeId()].available.remove(data.partyId());
else
m_chargeTypeMap[data.chargeTypeId()].available.insert(data.partyId(), data.amount() - data.planned());
onPartyChanged();
updateCannonsRounds(true);
updateMaxLabel(true);
}
void ExplosionEdit::showPreviewObject()
{
if (!m_sitMapGuiIfc)
return;
if (m_previewCircleCenter.isNull() && m_previewPolygon.isEmpty())
return;
if (m_previewCircleCenter.isNull())
m_sitMapGuiIfc->displayPreviewObject(this, m_previewPolygon, true);
else
m_sitMapGuiIfc->displayPreviewObject(this, m_previewCircleCenter, m_previewCircleRadius);
}
void ExplosionEdit::setFireButton(AreaEffectSimulation::AesEffectState effectState)
{
if (effectState == AesEffectState::EsActivated)
{
m_ui->pbFire->setText(tr("Pause"));
m_ui->pbFire->setIcon(QIcon(QStringLiteral("icon:avm_pause.svg")));
}
else
{
m_ui->pbFire->setText(tr("Start"));
m_ui->pbFire->setIcon(QIcon(QStringLiteral("icon:avm_start.svg")));
}
if ((effectState == AesEffectState::EsActivated ||
effectState == AesEffectState::EsPrepared ||
effectState == AesEffectState::EsCreated ||
effectState == AesEffectState::EsPaused)
&& m_aesItem.id() > 0)
m_ui->pbFire->setEnabled(true);
else
m_ui->pbFire->setEnabled(false);
}
void ExplosionEdit::updateCannonsRounds(bool modifiedFromExternal)
{
// If Cannons are already more than availRounds, Reset both to One
if (m_ui->sbCannons->value() > maxAvailableRounds() && m_editable && m_aesItem.id() <= 0)
{
m_ui->sbCannons->setValue(1);
m_ui->sbRounds->setValue(1);
}
// setMaximum on one or both.
onCannonsChanged(m_ui->sbCannons->value(), modifiedFromExternal);
onRoundsChanged(m_ui->sbRounds->value(), modifiedFromExternal);
}
void ExplosionEdit::updateMaxLabel(bool modifiedFromExternal)
{
QString text = tr("= %1 (avail: %2%3)").arg(m_ui->sbCannons->value() * m_ui->sbRounds->value())
.arg(maxAvailableRounds() == s_maxChargeUsage ? QLatin1String(">=") : QString())
.arg(maxAvailableRounds());
if (modifiedFromExternal) // Todo: Use palette
text = QStringLiteral("<span style=\"color:#aa0000;\">%1</span>").arg(text);
if (text == m_ui->lblMaxCount->text())
return;
m_ui->lblMaxCount->setText(text);
m_ui->lblMaxCount->setToolTip(modifiedFromExternal ? tr("Cannons / Rounds potentially modified by external source!") : QString());
}
quint32 ExplosionEdit::partyForItem(const AesItem &aesItem) const
{
if (aesItem.participantId().is_set())
{
if (m_participant.id() == aesItem.participantId().get())
return m_participant.partyId();
else
return m_ppmDtc->participant(aesItem.participantId().get()).partyId();
}
else if (aesItem.partyId().is_set())
return aesItem.partyId().get();
return {};
}
void ExplosionEdit::setSingleData(const ExplosionSingle &singleData)
{
QPointF impactPosition(singleData.impactPosition().lon(), singleData.impactPosition().lat());
if (!impactPosition.isNull())
m_ui->positionEdit->setCoordinate(impactPosition);
m_ui->dteRequestTime->setMsecsSinceEpoch(singleData.fireRequestTime());
m_ui->cbPurpose->setCurrentText(QString::fromUtf8(singleData.purpose().c_str()));
m_ui->sbAltitude->setValue(singleData.altitude());
if (m_aesItem.id() > 0)
m_chargeTypeMap[singleData.chargeStruct().chargeTypeId()].available[partyForItem(singleData)] += 1;
const double radius = m_pdmDtc->impactRadius(singleData.chargeStruct().chargeTypeId(),singleData.chargeStruct().igniterTypeId(), singleData.chargeStruct().igniterFunctionId());
m_ui->sbDimensionX->setValue(2 * radius);
}
void ExplosionEdit::setAreaData(const ExplosionArea &areaData, bool copy)
{
const Area &area = areaData.area();
if (!qFuzzyCompare(area.cornerBottomLeft().lon(), 0) ||
!qFuzzyCompare(area.cornerBottomLeft().lat(), 0))
{
QPointF bottomLeft(area.cornerBottomLeft().lon(), area.cornerBottomLeft().lat());
m_ui->positionEdit->setCoordinate(Polygons::bottomLeft2CenterPoint(bottomLeft, area.width(), area.height(), area.rotation()));
}
m_ui->sbDimensionX->setValue(area.width());
m_ui->sbDimensionY->setValue(area.height());
m_ui->sbAimingAxis->setValue(fmod((90.0 + area.rotation()) * 6400 / 360, 6400));
m_ui->sbCannons->setValue(areaData.cannonCount() == 0 ? 4 : areaData.cannonCount());
m_ui->sbRounds->setValue(areaData.cannonRounds() == 0 ? 9 : areaData.cannonRounds());
if (m_aesItem.id() > 0 && !copy)
{
if (!m_chargeTypeMap.contains(areaData.chargeStruct().chargeTypeId()))
ERROR_LOG(m_logger) << "SetAreaData called with a charge Type, that has doesn't match. Id " << areaData.chargeStruct().chargeTypeId() << "is not in m_chargeTypeMap";
if (!areaData.partyId().is_set())
ERROR_LOG(m_logger) << "SetAreaData called without a party set. m_chargeTypeMap might be corrupted.";
m_chargeTypeMap[areaData.chargeStruct().chargeTypeId()].available[areaData.partyId().get()] += areaData.cannonCount() * areaData.cannonRounds();
}
m_ui->dteRequestTime->setMsecsSinceEpoch(areaData.fireRequestTime());
m_ui->cbPurpose->setCurrentText(QString::fromUtf8(areaData.purpose().c_str()));
m_ui->sbAltitude->setValue(areaData.altitude());
}
//slots
void ExplosionEdit::getPosition()
{
if (!has2DMap())
return;
bool isNull = qFuzzyCompare(m_ui->positionEdit->coordinate().x(), 0) && qFuzzyCompare(m_ui->positionEdit->coordinate().y(), 0);
QPointF p(Polygons::centerPoint2BottomLeft(m_ui->positionEdit->coordinate(), m_ui->sbDimensionX->value(), m_ui->sbDimensionY->value(), (m_ui->sbAimingAxis->value() - 1600) / 6400. * 360));
if (m_type != etArea)
m_sitMapGuiIfc->getCoordinate(this, SLOT(onCoordinate(QPointF)), nullptr);
else
m_sitMapGuiIfc->getRectangle(this,
SLOT(onMapRecData(QPointF,double,double,double,QPolygonF)),
nullptr,
s_minWidth,
s_maxWidth,
s_minHeight,
s_maxHeight,
isNull ? m_ui->positionEdit->coordinate() : p,
m_ui->sbDimensionX->value(),
m_ui->sbDimensionY->value(),
(m_ui->sbAimingAxis->value() - 1600) / 6400. * 360);
}
void ExplosionEdit::onCoordinate(const QPointF &centerPoint)
{
m_previewPolygon.clear();
m_previewCircleCenter = centerPoint;
m_previewCircleRadius = 0.5 * m_ui->sbDimensionX->value();
m_ui->positionEdit->setCoordinate(centerPoint);
showPreviewObject();
}
void ExplosionEdit::onMapRecData(const QPointF &bottomLeft, double width, double height, double angleDegNorth, const QPolygonF &bufferOutlinePolygon)
{
m_previewCircleCenter = QPointF();
m_previewPolygon = bufferOutlinePolygon;
m_ui->positionEdit->setCoordinate(Polygons::bottomLeft2CenterPoint(bottomLeft, width, height, angleDegNorth));
m_ui->sbDimensionX->setValue(round(width));
m_ui->sbDimensionY->setValue(round(height));
m_ui->sbAimingAxis->setValue(fmod((90.0 + angleDegNorth) * 6400 / 360, 6400));
showPreviewObject();
}
void ExplosionEdit::onChargeTypeChanged()
{
int chargeTypeId =m_ui->cbChargeType->currentData().toInt();
// update comboBox IgniterType:
m_pdmCbx->fillIgniterComboBox(m_ui->cbIgniterType, chargeTypeId);
updateCannonsRounds();
if (m_type == etArea)
return;
// NOTE: igniterType/IgniterFunciton = 0 as long as ExplosionEdit does not contain values
double impactRadius = m_pdmDtc->impactRadius(m_ui->cbChargeType->currentData().toInt(), 0, 0);
m_ui->sbDimensionX->setValue(2 * impactRadius);
}
void ExplosionEdit::onPartyChanged()
{
int partyId = m_ui->cbParty->currentData().toInt();
int chargeTypeId = m_ui->cbChargeType->currentData().toInt();
if (chargeTypeId <= 0)
chargeTypeId = m_gearClass == ProjectDataManagement::GearClass::Artillery ? s_lastChargeTypeA : s_lastChargeTypeM;
QSignalBlocker sb(m_ui->cbChargeType);
m_ui->cbChargeType->clear();
for (const Charges &charge : qAsConst(m_chargeTypeMap))
{
if (charge.available.contains(partyId) && charge.available[partyId] > 0)
m_ui->cbChargeType->addItem(m_pdmDtc->trChargeTypeShortName(charge.chargeType.id(), true), charge.chargeType.id());
}
m_ui->cbChargeType->setCurrentIndex(m_ui->cbChargeType->findData(chargeTypeId) < 0 ? 0 : m_ui->cbChargeType->findData(chargeTypeId));
sb.unblock();
updateCannonsRounds();
}
bool ExplosionEdit::apply()
{
std::string name = m_ui->leIdentifier->text().toStdString();
qint64 effectStart = m_ui->dteEffectStart->msecsSinceEpoch();
int chargeType = m_ui->cbChargeType->currentData().toInt();
if (m_gearClass == ProjectDataManagement::GearClass::Artillery)
s_lastChargeTypeA = chargeType;
else
s_lastChargeTypeM = chargeType;
int partyId = m_ui->cbParty->currentData().toInt();
// int playerId = m_participant.id();
int cannons = m_ui->sbCannons->value();
int rounds = m_ui->sbRounds->value();
int duration = m_ui->sbDurationSeconds->value() * 1000; // secs --> msecs
// Area:
QPointF bottomLeft(Polygons::centerPoint2BottomLeft(m_ui->positionEdit->coordinate(), m_ui->sbDimensionX->value(), m_ui->sbDimensionY->value(), (m_ui->sbAimingAxis->value() - 1600) * 360.0 / 6400));
const Core::GeoPosition2D bottomLeftGeo(bottomLeft.x(), bottomLeft.y());
const Area area(bottomLeftGeo, m_ui->sbDimensionX->value(), m_ui->sbDimensionY->value(), (m_ui->sbAimingAxis->value() - 1600) * 360.0 / 6400);
// Single:
const Core::GeoPosition2D pos(m_ui->positionEdit->coordinate().x(), m_ui->positionEdit->coordinate().y());
const Core::GeoPosition pos3D(m_ui->positionEdit->coordinate().x(), m_ui->positionEdit->coordinate().y(), 0.0);
qint64 fireRequestTime = m_ui->dteRequestTime->msecsSinceEpoch();
int altitude = m_ui->sbAltitude->value();
std::string purpose = m_ui->cbPurpose->currentText().toStdString();
if (m_type == etSingle)
{
const ExplosionSingleModifyRequest req(m_aesItem.id(),
name,
LtsUtils::toOptional(effectStart),
m_aesItem.effectSourceId(),
chargeType,
pos,
LtsUtils::toOptional(partyId),
LtsUtils::toOptional(0), // PlayerId
fireRequestTime,
altitude,
purpose,
m_ui->cbEffectMarkingInTa->isChecked(),
dds::core::optional<rti::core::int64>());
m_requestHelper->addRequest([this, req]()
{
return m_ftc->explosionSingleModifyRequest(req, this);
});
}
else if (m_type == etArea) // area
{
const ExplosionAreaModifyRequest req(m_aesItem.id(),
name,
LtsUtils::toOptional(effectStart),
duration,
m_aesItem.effectSourceId(),
chargeType,
area,
LtsUtils::toOptional(partyId),
LtsUtils::toOptional(0), // PlayerId
cannons,
rounds,
fireRequestTime,
altitude,
purpose,
m_ui->cbEffectMarkingInTa->isChecked(),
dds::core::optional<rti::core::int64>());
m_requestHelper->addRequest([this, req]()
{
return m_ftc->explosionAreaModifyRequest(req, this);
});
}
return m_requestHelper->startRequests();
}
void ExplosionEdit::onFireClicked()
{
m_ui->pbFire->setEnabled(false);
if ((m_aesItem.effectStateId() != AesEffectState_def::EsActivated &&
m_aesItem.effectStateId() != AesEffectState_def::EsPaused &&
m_aesItem.effectStateId() != AesEffectState_def::EsCreated &&
m_aesItem.effectStateId() != AesEffectState_def::EsPrepared)
|| m_aesItem.id() <= 0)
return;
// Catches all single fires...
if (m_aesItem.effectStateId() == AesEffectState_def::EsCreated ||
m_aesItem.effectStateId() == AesEffectState_def::EsPrepared)
{
m_ui->dteEffectStart->setMsecsSinceEpoch(m_session->partitionTime() + 3000);
m_ui->dteEffectStart->setChecked(true);
// Todo: Triggering by simulated button press is a little awkward...
if (m_uiRequirements->checkRequirements(this))
this->m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->click();
else
m_ui->pbFire->setEnabled(true);
return;
}
// No more single fires handled here...
m_requestHelper->addRequest([ = ]()
{
return m_ftc->explosionAreaPauseResumeRequest(ExplosionAreaPauseResumeRequest(m_aesItem.id(),
m_aesItem.effectStateId() != AesEffectState_def::EsActivated,
dds::core::optional<rti::core::int64>(),
dds::core::optional<int32_t>(),
dds::core::optional<int32_t>())
, this);
});
m_requestHelper->startRequests();
}
void ExplosionEdit::onParticipantClicked()
{
ParticipantManagement::ParticipantSelection *ps = new ParticipantManagement::ParticipantSelection(m_session, this);
ps->init();
ps->setParticipantSelected(m_participant.partyId(), m_participant.id());
connect(ps, &ParticipantManagement::ParticipantSelection::selectedParticipants, this, &ExplosionEdit::onParticipant);
ps->exec();
}
void ExplosionEdit::onParticipant(const QVector<int> &participants)
{
if (participants.isEmpty())
return;
if (participants[0] == m_participant.id())
return;
m_participant = m_ppmDtc->participant(participants[0]);
m_symbolWatcher->setSymbolResult(m_asbIfc->findImage(m_participant));
m_ui->lblDesignator->setText(QString::fromStdString(m_participant.designator()));
m_ui->lblTactIdentifier->setText(QString::fromStdString(m_participant.tacticalIdentifier()));
// m_ui->lblParticipant->setText(participant.equipmentNumber().is_set() ? QString::number(participant.equipmentNumber().get()) : tr("Id: %1").arg(participant.id()));
m_ui->cbParty->setCurrentIndex(m_ui->cbParty->findData(m_participant.partyId()));
slotChangesMade();
}
} // namespace AreaEffectSimulation
@@ -0,0 +1,134 @@
/**
* @RDE_HEADER@
* AreaEffectSimulation - Explosion Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-07-05
*/
#pragma once
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_base_edit.h>
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_gui_plugin_interface.h>
#include <AreaEffectSimulation/aes_ftc.h>
#include <ProjectDataManagement/pdm.hpp>
namespace Ui
{
class ExplosionEdit;
}
class QSpinBox;
namespace AdvancedSymbology {
class SymbolResultWatcherLabel;
class ForeignDataInterface;
}
namespace AreaEffectSimulation
{
class ExplosionEdit final
: public BaseEdit
, protected AreaEffectSimulation::Interface::Ftc::ExplosionAreaModifyReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::ExplosionSingleModifyReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::ExplosionAreaPauseResumeReplyHandler
{
Q_OBJECT
public:
enum ExplosionType
{
etSingle,
etArea,
etSingleCentral
};
explicit ExplosionEdit(const QString &menuGroup, ExplosionType type, ProjectDataManagement::GearClass gc, QWidget *parent = nullptr);
~ExplosionEdit();
bool init(int aesItemId, bool copy, LtsSession::LtsSession *session);
QString dialogIdentifier() const override;
void onExplosionAreaModifyReply(const Core::FunctionReplyObject &replyObject) override final { onAesItemModifyReply(replyObject); }
void onExplosionSingleModifyReply(const Core::FunctionReplyObject &replyObject) override final { onAesItemModifyReply(replyObject); }
void onExplosionAreaPauseResumeReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void setFireButton(AesEffectState effectState);
private:
void retranslate() override;
static double s_minWidth;
static double s_maxWidth;
static double s_stepWidth;
static double s_minHeight;
static double s_maxHeight;
static double s_stepHeight;
static double s_minRadius;
static double s_maxRadius;
static double s_stepRadius;
static int s_maxChargeUsage;
static double s_minAltitude;
static double s_maxAltitude;
static qint64 s_maxDurationSeconds;
void setBaseData(const AesItem &baseData, bool copy);
void setSingleData(const ExplosionSingle &singleData);
void setAreaData(const ExplosionArea &areaData, bool copy = false);
void enableUiElements(bool enable) override;
int maxAvailableRounds() const;
void updateCannonsRounds(bool modifiedFromExternal = false);
void updateMaxLabel(bool modifiedFromExternal = false);
quint32 partyForItem(const AesItem &aesItem) const;
private Q_SLOTS:
void getPosition();
void onMapRecData(const QPointF &bottomLeft, double width, double height, double angleDegNorth, const QPolygonF &bufferOutlinePolygon);
void onCoordinate(const QPointF &centerPoint);
void onChargeTypeChanged();
void onPartyChanged();
bool apply() override final;
void onFireClicked();
void onParticipantClicked();
void onCannonsChanged(int cannons, bool modifiedFromExternal = false);
void onRoundsChanged(int rounds, bool modifiedFromExternal = false);
void onChargeCountChanged(const AreaEffectSimulation::ChargeAdministration &data, DataModification modType);
void showPreviewObject() override;
void onParticipant(const QVector<int> &participants);
private:
struct Charges
{
ProjectDataManagement::ChargeType chargeType;
QMap<int, int> available; // PartyId
Charges() {}
explicit Charges(const ProjectDataManagement::ChargeType &type) : chargeType(type) {}
};
ExplosionType m_type;
bool m_editable;
ProjectDataManagement::GearClass m_gearClass;
QPointF m_previewCircleCenter;
double m_previewCircleRadius;
QPolygonF m_previewPolygon;
QMap<qint32, Charges> m_chargeTypeMap; // ChargeTypeId
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asbIfc;
std::shared_ptr<ProjectDataManagement::ForeignGuiInterface> m_pdmCbx;
AdvancedSymbology::SymbolResultWatcherLabel *m_symbolWatcher;
ParticipantManagement::Participant m_participant;
Ui::ExplosionEdit *m_ui;
};
} //namespace AreaEffectSimulation
@@ -0,0 +1,506 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExplosionEdit</class>
<widget class="QWidget" name="ExplosionEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>962</width>
<height>322</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Aes Explosion Edit</string>
</property>
<property name="toolTip">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="7" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QSpinBox" name="sbCannons">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblOperatorB">
<property name="text">
<string notr="true">x</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sbRounds">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblMaxCount">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string notr="true"/>
</property>
<property name="text">
<string>=0 (avail: 0)</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1" colspan="4">
<widget class="LtsWidgets::LtsDateTimeEdit" name="dteRequestTime" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
<property name="withButtons" stdset="0">
<bool>false</bool>
</property>
<property name="withSlider" stdset="0">
<bool>false</bool>
</property>
<property name="withReset" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblAltitude">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Altitude [m]:</string>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="lblChargeType">
<property name="toolTip">
<string>Only charges with available stock are visible</string>
</property>
<property name="text">
<string>Charge Type:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="sbAimingAxis"/>
</item>
<item row="1" column="8">
<widget class="QCheckBox" name="cbEffectMarkingInTa">
<property name="text">
<string>Fire marker</string>
</property>
</widget>
</item>
<item row="6" column="4">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="7">
<widget class="LtsWidgets::LtsComboBox" name="cbChargeType">
<property name="toolTip">
<string/>
</property>
<property name="currentText">
<string notr="true"/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblFireRequest">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Fire Request:</string>
</property>
</widget>
</item>
<item row="3" column="6">
<widget class="QLabel" name="lblEffectStart">
<property name="text">
<string>Impact Time:</string>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QComboBox" name="cbPurpose"/>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="sbAltitude"/>
</item>
<item row="4" column="7">
<widget class="QSpinBox" name="sbDurationSeconds">
<property name="toolTip">
<string/>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1800</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblParty">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Firing Party:</string>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QLabel" name="lblRounds">
<property name="text">
<string>Cannons x Rounds:</string>
</property>
</widget>
</item>
<item row="4" column="8">
<widget class="QPushButton" name="pbFire">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Fire</string>
</property>
<property name="icon">
<iconset>
<normaloff>:/style/avm_start.svg</normaloff>:/style/avm_start.svg</iconset>
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QLabel" name="lblName">
<property name="text">
<string>Identifier:</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="lblDimension">
<property name="text">
<string>Dimension [m]:</string>
</property>
</widget>
</item>
<item row="3" column="7" colspan="2">
<widget class="LtsWidgets::LtsDateTimeEdit" name="dteEffectStart" native="true">
<property name="toolTip">
<string/>
</property>
<property name="checkable" stdset="0">
<bool>true</bool>
</property>
<property name="withReset" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="9">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lblAimingAxis">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Aiming Axis [mil]:</string>
</property>
</widget>
</item>
<item row="3" column="4">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="LtsWidgets::LtsSpinBox" name="sbDimensionX"/>
</item>
<item>
<widget class="QLabel" name="lblOperatorA">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">x</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="LtsWidgets::LtsSpinBox" name="sbDimensionY"/>
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="LtsWidgets::LtsComboBox" name="cbParty">
<property name="toolTip">
<string/>
</property>
<property name="currentText">
<string notr="true"/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblPosition">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>Position:</string>
</property>
</widget>
</item>
<item row="4" column="6">
<widget class="QLabel" name="lblDuration">
<property name="text">
<string>Duration [s]:</string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLabel" name="lblPurpose">
<property name="text">
<string>Purpose:</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="LtsCoordWidget::LtsCoordWidget" name="positionEdit" native="true"/>
</item>
<item>
<widget class="QPushButton" name="pbPosition">
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset>
<normaloff>:/style/position.svg</normaloff>:/style/position.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbClear">
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset>
<normaloff>:/style/remove.svg</normaloff>:/style/remove.svg</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="7" colspan="2">
<widget class="QLineEdit" name="leIdentifier">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string/>
</property>
</widget>
</item>
<item row="2" column="5">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="2">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lbxFiringAngle">
<property name="text">
<string>Firing Angle:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDoubleSpinBox" name="sbFiringAngle">
<property name="maximum">
<double>98.989999999999995</double>
</property>
</widget>
</item>
<item row="5" column="3">
<widget class="QLabel" name="lbxIgniterType">
<property name="text">
<string>IgniterType</string>
</property>
</widget>
</item>
<item row="5" column="4">
<widget class="QComboBox" name="cbIgniterType"/>
</item>
<item row="5" column="6">
<widget class="QLabel" name="lbxParticipant">
<property name="text">
<string>Firing Participant:</string>
</property>
</widget>
</item>
<item row="5" column="7">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="lblDesignator">
<property name="text">
<string notr="true">DESIG</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblIcon">
<property name="text">
<string notr="true">XXX</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblTactIdentifier">
<property name="text">
<string notr="true">TACT_ID</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="8">
<widget class="QPushButton" name="pbParticipant">
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsCoordWidget::LtsCoordWidget</class>
<extends>QWidget</extends>
<header>LtsCoordTrans/lts_coord_widget.h</header>
</customwidget>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
<customwidget>
<class>LtsWidgets::LtsSpinBox</class>
<extends>QSpinBox</extends>
<header>LtsWidgets/lts_spinbox.h</header>
</customwidget>
<customwidget>
<class>LtsWidgets::LtsDateTimeEdit</class>
<extends>QWidget</extends>
<header>LtsWidgets/lts_date_time_edit.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>cbParty</tabstop>
<tabstop>dteRequestTime</tabstop>
<tabstop>positionEdit</tabstop>
<tabstop>pbPosition</tabstop>
<tabstop>pbClear</tabstop>
<tabstop>sbAltitude</tabstop>
<tabstop>sbDimensionX</tabstop>
<tabstop>sbDimensionY</tabstop>
<tabstop>sbAimingAxis</tabstop>
<tabstop>cbPurpose</tabstop>
<tabstop>sbCannons</tabstop>
<tabstop>sbRounds</tabstop>
<tabstop>cbChargeType</tabstop>
<tabstop>cbEffectMarkingInTa</tabstop>
<tabstop>leIdentifier</tabstop>
<tabstop>dteEffectStart</tabstop>
<tabstop>sbDurationSeconds</tabstop>
<tabstop>pbFire</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,385 @@
/**
* @RDE_HEADER@
* GUI Plugin for AreaEffectSimulation - Explosions
* $Id: aes_explosion_gui_plugin.cpp 64799 2025-04-02 12:19:43Z kemayou_s $
* $HeadURL: svn://slssvn/TDS/branches/product/features/24_adler/Lts/Plugins/AreaEffectSimulation/Gui/Explosion/aes_explosion_gui_plugin.cpp $
* $Author: kemayou_s $
* Created by Patric Karwat, SLSE, 2016-07-05
*/
#include "aes_explosion_gui_plugin.h"
#include "aes_explosion_edit.h"
#include "aes_explosion_list.h"
#include "aes_explosions_edit.h"
#include "aes_explosions_edit_adler.h"
#include "aes_explosions_edit_adler_standalone.h"
#include <QApplication>
#include <AreaEffectSimulation/aes_operator_rights.h>
#include <LtsSession/lts_session.h>
#include <LtsUtilsSettings/settings.h>
#include <LtsWidgets/lts_base_layout_widget.h>
#include <LtsWidgets/lts_events.h>
#include <ProjectDataManagement/pdm_enums.hpp>
namespace AreaEffectSimulation
{
const QString InterfaceImpl::s_ExplosionGuiScheme = QStringLiteral("ExplosionGui");
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session) { return std::make_shared<InterfaceImpl>(session); }
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: AesBaseInterface(session, getLogger("Plugins.Gui.Explosion"))
, ForeignGuiInterface()
{
qApp->installEventFilter(this); // for link events
}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> ret;
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
const bool enableSingleExplosionArtillery = ps->value(QStringLiteral("aes"), QStringLiteral("enableSingleExplosionArtillery")).toBool();
const bool enableCentralExplosionArtillery = ps->value(QStringLiteral("aes"), QStringLiteral("enableCentralExplosionArtillery")).toBool();
if (enableSingleExplosionArtillery)
{
// Single Explosion Artillery
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Single Artillery"),
QLatin1String("ShowExplosionSingleArtillery"),
QIcon(QLatin1String("icon:arti_ammunition_firings_single.svg")),
[this](QWidget *parent) { return onShowExplosionListDialog(true, false, ProjectDataManagement::GearClass::Artillery, parent); },
OperatorRights::SingleExplosionsShowArtillery,
LtsWidgets::ExercisePart::eExecution));
if (m_session->isExercisePartition() && appId() != LtsAppDescriptor::App::OC)
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Add Single Artillery"),
QLatin1String("AddExplosionSingleArtillery"),
QIcon(QLatin1String("icon:arti_ammunition_firings_single_add.svg")),
[this](QWidget *parent) { return onShowAddExplosionDialog(true, false, ProjectDataManagement::GearClass::Artillery, parent); },
OperatorRights::SingleExplosionsShowArtillery,
LtsWidgets::ExercisePart::eExecution,
LtsWidgets::ExerciseState::eCreated | LtsWidgets::ExerciseState::eStarted | LtsWidgets::ExerciseState::ePaused));
// Single Explosion Central Artillery
if (enableCentralExplosionArtillery)
{
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Single Artillery Central"),
QLatin1String("ShowExplosionSingleCentralArtillery"),
QIcon(QLatin1String("icon:arti_ammunition_firings_single.svg")),
[this](QWidget *parent) { return onShowExplosionListDialog(true, true, ProjectDataManagement::GearClass::Artillery, parent); },
// OperatorRights::SingleExplosionsCentralShowArtillery,
OperatorRights::SingleExplosionsShowArtillery,
LtsWidgets::ExercisePart::eExecution));
if (m_session->isExercisePartition() && appId() != LtsAppDescriptor::App::OC)
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Add Single Artillery Central"),
QLatin1String("AddExplosionSingleCentralArtillery"),
QIcon(QLatin1String("icon:arti_ammunition_firings_single_add.svg")),
[this](QWidget *parent) { return onShowAddExplosionDialog(true, true, ProjectDataManagement::GearClass::Artillery, parent); },
// OperatorRights::SingleExplosionsCentralShowArtillery,
OperatorRights::SingleExplosionsShowArtillery,
LtsWidgets::ExercisePart::eExecution,
LtsWidgets::ExerciseState::eCreated | LtsWidgets::ExerciseState::eStarted | LtsWidgets::ExerciseState::ePaused));
}
}
const bool enableSingleExplosionMortar = ps->value(QStringLiteral("aes"), QStringLiteral("enableSingleExplosionMortar")).toBool();
if (enableSingleExplosionMortar)
{
// Single Explosion Mortar
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Single Mortar"),
QLatin1String("ShowExplosionSingleMortar"),
QIcon(QLatin1String("icon:mortar_ammunition_firings.svg")),
[this](QWidget *parent) { return onShowExplosionListDialog(true, false, ProjectDataManagement::GearClass::Mortar, parent); },
OperatorRights::SingleExplosionsShowMortar,
LtsWidgets::ExercisePart::eExecution));
if (m_session->isExercisePartition() && appId() != LtsAppDescriptor::App::OC)
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Add Single Mortar"),
QLatin1String("AddExplosionSingleMortar"),
QIcon(QLatin1String("icon:add_mortar_ammunition_firings_single.svg")),
[this](QWidget *parent) { return onShowAddExplosionDialog(true, false, ProjectDataManagement::GearClass::Mortar, parent); },
OperatorRights::SingleExplosionsEditMortar,
LtsWidgets::ExercisePart::eExecution,
LtsWidgets::ExerciseState::eCreated | LtsWidgets::ExerciseState::eStarted | LtsWidgets::ExerciseState::ePaused));
}
// Air Support single fire (for GUEZ Nasat)
if (m_logger.isDebugEnabled())
{
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Single NASAT Impacts"),
QLatin1String("ShowExplosionSingleAerial"),
QIcon(QLatin1String("icon:mortar_ammunition_firings.svg")),
[this](QWidget *parent) { return onShowExplosionListDialog(true, false, ProjectDataManagement::GearClass::AirSupport, parent); },
OperatorRights::AirSupportShow,
LtsWidgets::ExercisePart::eExecution));
}
const bool enableAreaExplosionArtillery = ps->value(QStringLiteral("aes"), QStringLiteral("enableAreaExplosionArtillery")).toBool();
if (enableAreaExplosionArtillery)
{
// Area Explosion Artillery
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Area Artillery"),
QLatin1String("ShowExplosionAreaArtillery"),
QIcon(QLatin1String("icon:arti_ammunition_firings.svg")),
[this](QWidget *parent) { return onShowExplosionListDialog(false, false, ProjectDataManagement::GearClass::Artillery, parent); },
OperatorRights::AreaExplosionsShowArtillery,
LtsWidgets::ExercisePart::eExecution));
if (m_session->isExercisePartition() && appId() != LtsAppDescriptor::App::OC)
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Add Area Artillery"),
QLatin1String("AddExplosionAreaArtillery"),
QIcon(QLatin1String("icon:arti_ammunition_firings_add.svg")),
[this](QWidget *parent) { return onShowAddExplosionDialog(false, false, ProjectDataManagement::GearClass::Artillery, parent); },
OperatorRights::AreaExplosionsEditArtillery,
LtsWidgets::ExercisePart::eExecution,
LtsWidgets::ExerciseState::eCreated | LtsWidgets::ExerciseState::eStarted | LtsWidgets::ExerciseState::ePaused));
}
const bool enableAreaExplosionMortar = ps->value(QStringLiteral("aes"), QStringLiteral("enableAreaExplosionMortar")).toBool();
if (enableAreaExplosionMortar)
{
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Area Mortar"),
QLatin1String("ShowExplosionAreaMortar"),
QIcon(QLatin1String("icon:mortar_ammunition_firings.svg")),
[this](QWidget *parent) { return onShowExplosionListDialog(false, false, ProjectDataManagement::GearClass::Mortar, parent); },
OperatorRights::AreaExplosionsShowMortar,
LtsWidgets::ExercisePart::eExecution));
if (m_session->isExercisePartition() && appId() != LtsAppDescriptor::App::OC)
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Add Area Mortar"),
QLatin1String("AddExplosionAreaMortar"),
QIcon(QLatin1String("icon:add_mortar_ammunition_firings.svg")),
[this](QWidget *parent) { return onShowAddExplosionDialog(false, false, ProjectDataManagement::GearClass::Mortar, parent); },
OperatorRights::AreaExplosionsEditMortar,
LtsWidgets::ExercisePart::eExecution,
LtsWidgets::ExerciseState::eCreated | LtsWidgets::ExerciseState::eStarted | LtsWidgets::ExerciseState::ePaused));
}
const bool enableExplosionCluster = ps->value(QStringLiteral("aes"), QStringLiteral("enableExplosionCluster")).toBool();
if (enableExplosionCluster)
{
DEBUG_LOG(m_logger) << "ShowExplosionClusterArtillery";
// Explosions / ExplosionCluster
// ListView:
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Artillery"),
QStringLiteral("ShowExplosionClusterArtillery"),
QIcon(QStringLiteral("icon:mortar_ammunition_firings.svg")),
[this](QWidget *parent) { return onShowExplosionClusterListDialog(parent); },
OperatorRights::ExplosionShowCluster,
LtsWidgets::ExercisePart::eExecution));
if (m_session->isExercisePartition() && appId() != LtsAppDescriptor::App::OC)
{
DEBUG_LOG(m_logger) << "onShowAddExplosionClusterDialog";
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Add Artillery"),
QStringLiteral("AddExplosionClusterArtillery"),
QIcon(QStringLiteral("icon:arti_ammunition_firings_add.svg")),
[this](QWidget *parent) { return onShowAddExplosionClusterDialog(parent); },
OperatorRights::ExplosionEditCluster,
LtsWidgets::ExercisePart::eExecution,
LtsWidgets::ExerciseState::eCreated | LtsWidgets::ExerciseState::eStarted | LtsWidgets::ExerciseState::ePaused));
DEBUG_LOG(m_logger) << "onShowAddExplosionAdlerDialog";
ret.append(LtsWidgets::PluginData(
menuGroup(),
tr("Add ADLER Artillery"),
QStringLiteral("AddAdlerArtillery"),
QIcon(QStringLiteral("icon:arti_ammunition_firings_add.svg")),
[this](QWidget *parent) { return onShowAddExplosionAdlerStandAloneDialog(parent); },
OperatorRights::AdlerExplosionClusterEdit,
LtsWidgets::ExercisePart::eExecution,
LtsWidgets::ExerciseState::eCreated | LtsWidgets::ExerciseState::eStarted | LtsWidgets::ExerciseState::ePaused));
}
}
return ret;
}
AreaEffectSimulation::BaseEdit *InterfaceImpl::showEditWindow(int aesEntityId, bool isSingle, bool isCentral, ProjectDataManagement::GearClass gc, QWidget *parent)
{
ExplosionEdit *editWidget
= new ExplosionEdit(menuGroup(), isSingle ? (isCentral ? ExplosionEdit::etSingleCentral : ExplosionEdit::etSingle) : ExplosionEdit::etArea, gc, parent);
if (editWidget->init(aesEntityId, false, m_session))
return editWidget;
delete editWidget;
return nullptr;
}
BaseEdit *InterfaceImpl::showEditWindow(int aesEntityId, ProjectDataManagement::EffectSource effectSource, QWidget *parent)
{
switch (effectSource.underlying())
{
case ProjectDataManagement::EffectSource::ES_ADLER_STANDALONE:
{
ExplosionsEditAdlerStandAlone *editWidget = new ExplosionsEditAdlerStandAlone(menuGroup(), parent);
if (editWidget->init(aesEntityId, false, m_session))
return editWidget;
delete editWidget;
return nullptr;
break;
}
case ProjectDataManagement::EffectSource::ES_ADLER:
{
ExplosionsEditAdler *editWidget = new ExplosionsEditAdler(menuGroup(), parent);
if (editWidget->init(aesEntityId, false, m_session))
return editWidget;
delete editWidget;
return nullptr;
break;
}
case ProjectDataManagement::EffectSource::ES_Internal:
case ProjectDataManagement::EffectSource::ES_HLA:
{
ExplosionsEdit *editWidget = new ExplosionsEdit(menuGroup(), parent);
if (editWidget->init(aesEntityId, false, m_session))
return editWidget;
delete editWidget;
return nullptr;
break;
}
case ProjectDataManagement::EffectSource::ES_Unknown:
{
ERROR_LOG(m_logger) << "Unknow EffectSource";
break;
}
}
return nullptr;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowAddExplosionDialog(bool isSingle, bool isCentral, ProjectDataManagement::GearClass gc, QWidget *parent)
{
ExplosionEdit *editWidget
= new ExplosionEdit(menuGroup(), isSingle ? (isCentral ? ExplosionEdit::etSingleCentral : ExplosionEdit::etSingle) : ExplosionEdit::etArea, gc, parent);
if (editWidget->init(0, false, m_session))
return editWidget;
delete editWidget;
return nullptr;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowExplosionListDialog(bool isSingle, bool /*isCentral*/, ProjectDataManagement::GearClass gc, QWidget *parent)
{
ExplosionList *listWidget;
if (isSingle)
listWidget = new ExplosionSingleList(menuGroup(), gc, parent);
else
listWidget = new ExplosionAreaList(menuGroup(), gc, parent);
if (listWidget->init(m_session))
return listWidget;
delete listWidget;
return nullptr;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowAddExplosionClusterDialog(QWidget *parent)
{
ExplosionsEdit *editWidget = new ExplosionsEdit(menuGroup(), parent);
if (editWidget->init(0, false, m_session))
return editWidget;
delete editWidget;
return nullptr;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowAddExplosionAdlerStandAloneDialog(QWidget *parent)
{
DEBUG_LOG(m_logger) << "onShowAddExplosionAdlerStandAloneDialog";
ExplosionsEditAdlerStandAlone *editWidget = new ExplosionsEditAdlerStandAlone(menuGroup(), parent);
if (editWidget->init(0, false, m_session))
return editWidget;
delete editWidget;
return nullptr;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowExplosionClusterListDialog(QWidget *parent)
{
ExplosionList *listWidget;
listWidget = new ExplosionClusterList(menuGroup(),
{ProjectDataManagement::GearClass_def::Artillery,
ProjectDataManagement::GearClass_def::Mortar,
ProjectDataManagement::GearClass_def::Rocket},
parent);
if (listWidget->init(m_session))
return listWidget;
delete listWidget;
return nullptr;
}
bool InterfaceImpl::eventFilter(QObject *obj, QEvent *event) // show dialogs dialog on clicked link
{
if (obj == qApp && !event->isAccepted() && event->type() == LtsWidgets::LtsLinkEvent::eventTypeId())
{
auto ev = static_cast<LtsWidgets::LtsLinkEvent *>(event);
const auto isChildOfSession = [this](QWidget *w)
{
if (!w)
return true;
auto baseLayout = m_session->baseLayout();
return baseLayout->isAncestorOf(w);
};
if (isChildOfSession(ev->sourceBaseLayoutWidget()) && ev->url().host() == s_ExplosionGuiScheme.toLower())
{
bool ok = false;
ERROR_LOG(m_logger) << ev->url().path();
const QStringList params = ev->url().path().split(QStringLiteral("/"));
if (params.size() < 2)
return QObject::eventFilter(obj, event);
ERROR_LOG(m_logger) << "DIalog Name " << params.at(1) << " aesId " << params.at(2);
QString dialogName = params.at(1);
int aesId = params.at(2).toInt(&ok);
if (ok)
{
ExplosionsEditAdler *dlg = new ExplosionsEditAdler(menuGroup(), m_session->baseLayout());
if (dlg->init(aesId, false, m_session))
m_session->addWidget(dlg, menuGroup(), dlg->dialogIdentifier(), LtsWidgets::LayoutArea::eDialogTab);
event->accept();
return true;
}
}
}
return QObject::eventFilter(obj, event);
}
} // namespace AreaEffectSimulation
@@ -0,0 +1,63 @@
/**
* @RDE_HEADER@
* Gui Plugin for AreaEffectSimuation - Explosions
* $Id: aes_explosion_gui_plugin.h 62538 2024-04-23 06:13:45Z karwat $
* $HeadURL: svn://slssvn/TDS/branches/product/features/24_adler/Lts/Plugins/AreaEffectSimulation/Gui/Explosion/aes_explosion_gui_plugin.h $
* $Author: karwat $
* Created by Patric Karwat, SLSE, 2016-07-05
*/
#pragma once
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_base_gui_plugin.h>
#include "aes_explosion_gui_plugin_interface.h"
namespace AreaEffectSimulation
{
class GuiPlugin final : public AesBaseGuiPlugin
{
Q_PLUGIN_METADATA(IID "gui:3:aes.explosions")
Q_OBJECT
public:
GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return QStringLiteral("AreaEffectSimuationExplosionGui"); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return partition == IDL::PartitionType::Exercise ||
partition == IDL::PartitionType::Replay;
}
};
class InterfaceImpl final : public AesBaseInterface, public AesExplosion::ForeignGuiInterface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
QVector<LtsWidgets::PluginData> getActions() override;
AreaEffectSimulation::BaseEdit *showEditWindow(int aesEntityId, bool isSingle, bool isCentral, ProjectDataManagement::GearClass gc, QWidget *parent) override;
AreaEffectSimulation::BaseEdit *showEditWindow(int aesEntityId, ProjectDataManagement::EffectSource effectSource, QWidget *parent) override; // ExplosionCluster
private:
LtsWidgets::LtsDialog *onShowAddExplosionDialog(bool isSingle, bool isCentral, ProjectDataManagement::GearClass gc, QWidget *parent);
LtsWidgets::LtsDialog *onShowExplosionListDialog(bool isSingle, bool, ProjectDataManagement::GearClass gc, QWidget *parent);
LtsWidgets::LtsDialog *onShowAddExplosionClusterDialog(QWidget *parent);
LtsWidgets::LtsDialog *onShowExplosionClusterListDialog(QWidget *parent);
LtsWidgets::LtsDialog *onShowAddExplosionAdlerStandAloneDialog(QWidget *parent);
bool eventFilter(QObject *obj, QEvent *event) override; // show dialogs dialog on clicked link
static const QString s_ExplosionGuiScheme;
};
} // namespace AreaEffectSimulation
@@ -0,0 +1,33 @@
/**
* @RDE_HEADER@
* HMI Plugin for AreaEffectSimulation (Interface for access from other Plugins)
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-07-01
*/
#pragma once
#include <ProjectDataManagement/pdm_enums.hpp>
class QWidget;
namespace AreaEffectSimulation
{
class BaseEdit;
}
namespace AesExplosion
{
class ForeignGuiInterface
{
public:
ForeignGuiInterface() = default;
virtual ~ForeignGuiInterface() = default;
virtual AreaEffectSimulation::BaseEdit *showEditWindow(int aesEntityId, bool isSingle, bool isCentral, ProjectDataManagement::GearClass gc, QWidget *parent) = 0;
virtual AreaEffectSimulation::BaseEdit *showEditWindow(int aesEntityId, ProjectDataManagement::EffectSource effectSource, QWidget *parent) = 0; // ExplosionCluster
};
} // namespace AesExplosion
@@ -0,0 +1,340 @@
/**
* @RDE_HEADER@
* AreaEffectSimulation - Explosion Overview Dialog
* $Id: aes_explosion_list.cpp 64525 2025-02-14 12:35:41Z fritsche_h $
* $HeadURL: svn://slssvn/TDS/branches/product/features/24_adler/Lts/Plugins/AreaEffectSimulation/Gui/Explosion/aes_explosion_list.cpp $
* $Author: fritsche_h $
*
* Created by Mike Wille, SLSE, 2016-09-26
*/
#include "aes_explosion_list.h"
#include "CustomView/aes_explosion.h"
#include "aes_effect_cluster_model.h"
#include "aes_explosion_edit.h"
#include "aes_explosions_area_model.h"
#include "aes_explosions_edit.h"
#include "aes_explosions_edit_adler.h"
#include "aes_explosions_edit_adler_standalone.h"
#include "aes_explosions_single_model.h"
#include <LtsSession/lts_session_data.h>
namespace AreaEffectSimulation
{
ExplosionList::ExplosionList(const QString &menuGroup, ExplosionType type, ProjectDataManagement::GearClass gc, QWidget *parent)
: AesItemList(menuGroup, parent), m_type(type), m_gearClass(gc)
{
}
bool ExplosionList::init(LtsSession::LtsSession *session)
{
if (!AesItemList::init(session))
return false;
m_bHasAddEditOperatorRights = false;
switch (m_gearClass.underlying())
{
case ProjectDataManagement::GearClass::Artillery:
// switch per m_type :
switch (m_type)
{
case etSingle:
m_bHasAddEditOperatorRights = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SingleExplosionsEditArtillery);
setOnlineHelpFilename(QStringLiteral("Situation-Single_Artillery"));
m_windowTitle = tr("Single Artillery");
break;
case etArea:
m_bHasAddEditOperatorRights = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::AreaExplosionsEditArtillery);
setOnlineHelpFilename(QStringLiteral("Situation-Area_Artillery"));
m_windowTitle = tr("Area Artillery");
break;
case etExplosionCluster:
{
m_bHasAddAdlerOperatorRights = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::AdlerExplosionClusterEdit);
m_bHasAddEditOperatorRights = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::ExplosionEditCluster);
setOnlineHelpFilename(QStringLiteral("Situation-Cluster_Artillery"));
m_windowTitle = tr("Artillery");
if (m_bHasAddAdlerOperatorRights)
{
m_buttonBox->connectButton(LtsWidgets::DialogButton::Load, this, &ExplosionList::onAddAdlerAes);
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setVisible(m_bHasAddAdlerOperatorRights);
}
break;
}
default:
// empty
break;
} // switch
// : switch per m_type
break;
case ProjectDataManagement::GearClass::Mortar:
m_bHasAddEditOperatorRights = (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::SingleExplosionsEditMortar) && m_type == etSingle)
|| (LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::AreaExplosionsEditMortar) && m_type == etArea);
if (m_type == etSingle) // Single Mortar
{
setOnlineHelpFilename(QStringLiteral("Situation-Single_Mortar"));
m_windowTitle = tr("Single Mortar");
}
else if (m_type == etArea) // Area Mortar
{
setOnlineHelpFilename(QStringLiteral("Situation-Area_Mortar"));
m_windowTitle = tr("Area Mortar");
}
break;
case ProjectDataManagement::GearClass::AirSupport:
Q_ASSERT(m_type == etSingle);
// NLDEVCTRL-1727
// aes_explosion_gui_plugin.cpp:118 -> just debug -> no setOnlineHelpFilename required:
// just debug: setOnlineHelpFilename(QStringLiteral("Situation-Single_Fire_Air_Support")); // former Situation-Single Aerial Ordnance
m_windowTitle = tr("Single Fire Air Support");
break;
default:
Q_ASSERT(false);
break;
}
setDataViewModel(model(), [this]() { return new CustomViewExplosion(m_session, this); });
#ifndef LTS_DEBUG
hideColumn(ExplosionsSingleModel::BcId);
#endif
hideColumn(ExplosionsSingleModel::BcParticipant);
setSortIndicator(ExplosionsSingleModel::BcName);
enaDisa();
return true;
}
void ExplosionList::onAddAesItem()
{
if (m_type == etExplosionCluster)
{
ExplosionsEdit *dialog = new ExplosionsEdit(menuGroup(), this);
const int aesItemId = model()->aesId(currentRow());
if (dialog->init(aesItemId, aesItemId > 0, m_session))
addDialog(dialog, m_menuGroup, dialog->dialogIdentifier(), LtsWidgets::LayoutArea::eDialogTab);
else
delete dialog;
}
else
{
ExplosionEdit *dialog = new ExplosionEdit(m_menuGroup, static_cast<ExplosionEdit::ExplosionType>(m_type), m_gearClass, this);
const int aesItemId = model()->aesId(currentRow());
if (dialog->init(aesItemId, aesItemId > 0, m_session))
addDialog(dialog, m_menuGroup, dialog->dialogIdentifier(), LtsWidgets::LayoutArea::eDialogTab);
else
delete dialog;
}
}
void ExplosionList::onAddAdlerAes()
{
ExplosionsEditAdlerStandAlone *dialog = new ExplosionsEditAdlerStandAlone(m_menuGroup, this);
const int aesItemId = model()->aesId(currentRow());
if (dialog->init(aesItemId, aesItemId > 0, m_session))
addDialog(dialog, m_menuGroup, dialog->dialogIdentifier(), LtsWidgets::LayoutArea::eDialogTab);
else
delete dialog;
}
void ExplosionList::onEditAesItem()
{
DEBUG_LOG(m_logger) << "\n\nonEditAesItem ExplosionsEdit und ExplosionsEditAdler************************";
const int aesItemId = model()->aesId(currentRow());
if (aesItemId <= 0)
return;
ProjectDataManagement::EffectSource effectSource = model()->aesEffectSourceId(currentRow());
DEBUG_LOG(m_logger) << "current Aes Item Id: " << aesItemId;
DEBUG_LOG(m_logger) << "current EffectSource " << effectSource;
if (m_type == etExplosionCluster)
{
if (effectSource == ProjectDataManagement::EffectSource::ES_ADLER)
{
DEBUG_LOG(m_logger) << "Dialog ExplosionsEditAdler";
ExplosionsEditAdler *dialog = new ExplosionsEditAdler(m_menuGroup, this);
if (dialog->init(aesItemId, false, m_session))
addDialog(dialog, m_menuGroup, dialog->dialogIdentifier(), LtsWidgets::LayoutArea::eDialogTab);
else
delete dialog;
}
else if (effectSource == ProjectDataManagement::EffectSource::ES_ADLER_STANDALONE)
{
DEBUG_LOG(m_logger) << "new ExplosionsEditAdlerStandAlone *************************************";
ExplosionsEditAdlerStandAlone *dialogAdler = new ExplosionsEditAdlerStandAlone(m_menuGroup, this);
if (dialogAdler->init(aesItemId, false, m_session))
{
QString identifier = dialogAdler->dialogIdentifier();
identifier.append(QStringLiteral("Adler StandAlone"));
DEBUG_LOG(m_logger) << "addDialog identifier=" << identifier;
addDialog(dialogAdler, m_menuGroup, identifier, LtsWidgets::LayoutArea::eDialogTab);
}
else
delete dialogAdler;
}
else
{
ExplosionsEdit *dialog = new ExplosionsEdit(m_menuGroup, this);
if (dialog->init(aesItemId, false, m_session))
addDialog(dialog, m_menuGroup, dialog->dialogIdentifier(), LtsWidgets::LayoutArea::eDialogTab);
else
delete dialog;
}
}
else
{
ExplosionEdit *dialog = new ExplosionEdit(m_menuGroup, static_cast<ExplosionEdit::ExplosionType>(m_type), m_gearClass, this);
if (dialog->init(aesItemId, false, m_session))
addDialog(dialog, m_menuGroup, dialog->dialogIdentifier(), LtsWidgets::LayoutArea::eDialogTab);
else
delete dialog;
}
}
void ExplosionList::onRemoveAesItem()
{
Core::RemoveElementRequest req(model()->aesId(currentRow()));
m_requestHelper->startSingleRequest(
[req, this]()
{
switch (m_type)
{
case etSingle:
return m_ftc->explosionSingleRemoveRequest(req, this);
break;
case etArea:
return m_ftc->explosionAreaRemoveRequest(req, this);
break;
case etExplosionCluster:
{
ProjectDataManagement::EffectSource effectSource = model()->aesEffectSourceId(currentRow());
if (effectSource == ProjectDataManagement::EffectSource::ES_ADLER_STANDALONE)
{
return m_ftc->effectClusterRemoveRequest(req, this);
}
return m_ftc->explosionClusterRemoveRequest(req, this);
break;
}
default:
// empty
break;
} // switch
return int64_t(0);
});
}
void ExplosionList::retranslate() { translateBase(m_windowTitle); }
void ExplosionList::onExplosionAreaRemoveReply(const Core::FunctionReplyObject &replyObject) { m_requestHelper->requestReply(replyObject); }
void ExplosionList::onExplosionSingleRemoveReply(const Core::FunctionReplyObject &replyObject) { m_requestHelper->requestReply(replyObject); }
void ExplosionList::onExplosionClusterRemoveReply(const Core::FunctionReplyObject &replyObject) { m_requestHelper->requestReply(replyObject); }
void ExplosionList::onEffectClusterRemoveReply(const Core::FunctionReplyObject &replyObject) { m_requestHelper->requestReply(replyObject); }
//
// ExplosionSingleList
//
ExplosionSingleList::ExplosionSingleList(const QString &menuGroup, ProjectDataManagement::GearClass gc, QWidget *parent)
: ExplosionList(menuGroup, etSingle, gc, parent), m_model(nullptr)
{
}
bool ExplosionSingleList::init(LtsSession::LtsSession *session)
{
if (!ExplosionList::init(session))
return false;
// Single - keine Effect Duration
hideColumn(ExplosionsSingleModel::BcEffectDuration);
return true;
}
void ExplosionSingleList::createModel()
{
m_model = new AesItemSortFilterProxyModelTmpl<ExplosionSingle>(m_session, this);
ExplosionsSingleModel *sourceModel = new ExplosionsSingleModel(m_gearClass, this);
sourceModel->initModel(m_session);
m_model->setSourceModel(sourceModel);
}
//
// ExplosionAreaList
//
ExplosionAreaList::ExplosionAreaList(const QString &menuGroup, ProjectDataManagement::GearClass gc, QWidget *parent)
: ExplosionList(menuGroup, etArea, gc, parent), m_model(nullptr)
{
}
void ExplosionAreaList::createModel()
{
m_model = new AesItemSortFilterProxyModelTmpl<ExplosionArea>(m_session, this);
ExplosionsAreaModel *sourceModel = new ExplosionsAreaModel(m_gearClass, this);
sourceModel->initModel(m_session);
m_model->setSourceModel(sourceModel);
}
//
// ExplosionClusterList
//
ExplosionClusterList::ExplosionClusterList(const QString &menuGroup, const QVector<ProjectDataManagement::GearClass> &gcs, QWidget *parent)
: ExplosionList(menuGroup, etExplosionCluster, ProjectDataManagement::GearClass_def::Artillery, parent), m_model(nullptr), m_gearClasses(gcs)
{
}
bool ExplosionClusterList::init(LtsSession::LtsSession *session)
{
if (!ExplosionList::init(session))
return false;
// ColLaunchVelocity is more or less requested velocity, value is transfered to calculatedFiringSpeed
hideColumn(EffectClusterModel::AdditionalColumns::ColLaunchVelocity);
if (m_session->app() == LtsAppDescriptor::App::OC)
{
hideColumn(EffectClusterModel::AdditionalColumns::ColAnnotationString);
hideColumn(EffectClusterModel::AdditionalColumns::ColCloudBase);
hideColumn(EffectClusterModel::AdditionalColumns::ColLcAttack_Prf);
hideColumn(EffectClusterModel::AdditionalColumns::ColLcTermination);
hideColumn(EffectClusterModel::AdditionalColumns::ColTapTimepoint);
hideColumn(EffectClusterModel::AdditionalColumns::ColDropAngle);
hideColumn(EffectClusterModel::AdditionalColumns::ColLaunchAngleDeg);
hideColumn(EffectClusterModel::AdditionalColumns::ColCalculatedFiringSpeed);
hideColumn(EffectClusterModel::AdditionalColumns::ColCalculatedPeakHeight);
hideColumn(EffectClusterModel::AdditionalColumns::ColCalculatedFlightDuration);
hideColumn(EffectClusterModel::AdditionalColumns::ColOriginalPeakHeight);
hideColumn(EffectClusterModel::AdditionalColumns::ColOriginalFlightDuration);
hideColumn(EffectClusterModel::AdditionalColumns::ColZpElement);
}
return true;
}
void ExplosionClusterList::createModel()
{
m_model = new AesItemSortFilterProxyModelTmpl<EffectCluster>(m_session, this);
EffectClusterModel *sourceModel = new EffectClusterModel(m_gearClasses, this);
sourceModel->initModel(m_session);
m_model->setSourceModel(sourceModel);
}
} // namespace AreaEffectSimulation
@@ -0,0 +1,109 @@
/**
* @RDE_HEADER@
* AreaEffectSimulation - Explosion Overview Dialog
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-09-26
*/
#pragma once
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_itemlist.h>
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_base_model.h>
namespace AreaEffectSimulation
{
class ExplosionList : public AesItemList
, protected AreaEffectSimulation::Interface::Ftc::ExplosionAreaRemoveReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::ExplosionSingleRemoveReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterRemoveReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::EffectClusterRemoveReplyHandler
{
Q_OBJECT
public:
bool init(LtsSession::LtsSession *session) override;
enum ExplosionType
{
etSingle,
etArea,
// etSingleCentral, // outdated
etExplosionCluster
};
protected:
ExplosionList(const QString &menuGroup, ExplosionList::ExplosionType type, ProjectDataManagement::GearClass gc, QWidget *parent);
private slots:
void onAddAesItem() override;
void onEditAesItem() override;
void onRemoveAesItem() override;
void onAddAdlerAes();
private:
void retranslate() override;
void onExplosionAreaRemoveReply(const Core::FunctionReplyObject &replyObject) override;
void onExplosionSingleRemoveReply(const Core::FunctionReplyObject &replyObject) override;
void onExplosionClusterRemoveReply(const Core::FunctionReplyObject &replyObject) override;
void onEffectClusterRemoveReply(const Core::FunctionReplyObject &replyObject) override;
ExplosionType m_type;
protected:
ProjectDataManagement::GearClass m_gearClass;
QString m_windowTitle;
};
class ExplosionSingleList final : public ExplosionList
{
Q_OBJECT
protected:
public:
ExplosionSingleList(const QString &menuGroup, ProjectDataManagement::GearClass gc, QWidget *parent = nullptr);
bool init(LtsSession::LtsSession *session) override;
protected:
void createModel() override;
AesItemSortFilterProxyModel *model() override { return m_model; }
const AesItemSortFilterProxyModel *model() const override { return m_model; }
AesItemSortFilterProxyModelTmpl<ExplosionSingle> *m_model{nullptr};
};
class ExplosionAreaList final : public ExplosionList
{
Q_OBJECT
public:
ExplosionAreaList(const QString &menuGroup, ProjectDataManagement::GearClass gc, QWidget *parent = nullptr);
protected:
void createModel() override;
AesItemSortFilterProxyModel *model() override { return m_model; }
const AesItemSortFilterProxyModel *model() const override { return m_model; }
AesItemSortFilterProxyModelTmpl<ExplosionArea> *m_model{nullptr};
};
//
// ExplosionClusterList
//
class ExplosionClusterList final : public ExplosionList
{
Q_OBJECT
public:
ExplosionClusterList(const QString &menuGroup, const QVector<ProjectDataManagement::GearClass> &gcs, QWidget *parent = nullptr);
bool init(LtsSession::LtsSession *session) override;
protected:
void createModel() override;
AesItemSortFilterProxyModel *model() override { return m_model; }
const AesItemSortFilterProxyModel *model() const override { return m_model; }
AesItemSortFilterProxyModelTmpl<EffectCluster> *m_model{nullptr};
QVector<ProjectDataManagement::GearClass> m_gearClasses;
};
} // namespace AreaEffectSimulation
@@ -0,0 +1,32 @@
/**
* @RDE_HEADER@
* AreaEffectManangement - Explosion Area Overview Dialog Model
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-09-26
*/
#include "aes_explosions_area_model.h"
namespace AreaEffectSimulation
{
bool ExplosionsAreaModel::initModel(LtsSession::LtsSession *session)
{
updateEffectStateComboboxFilterData(true);
if (!AesGuiBaseModel::initModel(session))
return false;
connect(m_aesDtc.get(), &Interface::Dtc::explosionAreaChanged,
this, &ExplosionsAreaModel::onDataChanged);
fillAvailableChargeIds(m_gearClass);
m_aesDtc->explosionAreas([this](const ExplosionArea &item) { insertRow(item); });
return true;
}
} // namespace AreaEffectSimulation
@@ -0,0 +1,38 @@
/**
* @RDE_HEADER@
* ExplosionManangement - Explosion Area Overview Dialog Model
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-09-26
*/
#pragma once
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_base_model.h>
namespace AreaEffectSimulation
{
/************ Abstract Class for Artillery and Mortar Explosion Area ***************/
class ExplosionsAreaModel : public AesGuiBaseModel<ExplosionArea>
{
Q_OBJECT
public:
ExplosionsAreaModel(ProjectDataManagement::GearClass gc, QObject *parent)
: AesGuiBaseModel<ExplosionArea>(parent)
, m_gearClass(gc)
{}
bool initModel(LtsSession::LtsSession *session);
ProjectDataManagement::GearClass gearClass() const { return m_gearClass; }
protected:
ProjectDataManagement::GearClass m_gearClass;
};
} //namespace AreaEffectSimulation
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,228 @@
/**
* @RDE_HEADER@
* AreaEffectSimulation - Explosions Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Tougnia, SLTE, 2023-09-05
*/
#pragma once
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_base_edit.h>
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <Plugins/EffectShowManagement/esm_gui_combobox_plugin_interface.h>
#include <AreaEffectSimulation/aes_ftc.h>
#include <ProjectDataManagement/pdm.hpp>
#include "LtsElevation/lts_elevation_manager.h"
#include <ElevationMap/elevation_map_manager.h>
#include <iosfwd>
namespace Ui
{
class ExplosionsEdit;
}
class QSpinBox;
namespace AdvancedSymbology {
class SymbolResultWatcherLabel;
class ForeignDataInterface;
}
namespace AreaEffectSimulation
{
class ExplosionsEdit final
: public BaseEdit
, protected AreaEffectSimulation::Interface::Ftc::ExplosionAreaModifyReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::ExplosionSingleModifyReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::ExplosionAreaPauseResumeReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterModifyReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterPauseResumeReplyHandler
{
Q_OBJECT
public:
using BaseClass = BaseEdit;
enum class FlighDurationOrPeakHeight
{
FDPH_flightDuration,
FDPH_peakHeight
};
QString toString(FlighDurationOrPeakHeight val);
explicit ExplosionsEdit(const QString &menuGroup, QWidget *parent = nullptr);
~ExplosionsEdit();
bool init(int aesItemId, bool copy, LtsSession::LtsSession *session);
void setExplosionClusterData(const ExplosionCluster &ecData);
QString dialogIdentifier() const override;
void onExplosionAreaModifyReply(const Core::FunctionReplyObject &replyObject) override final { onAesItemModifyReply(replyObject); }
void onExplosionSingleModifyReply(const Core::FunctionReplyObject &replyObject) override final { onAesItemModifyReply(replyObject); }
void onExplosionClusterModifyReply(const Core::FunctionReplyObject &replyObject) override final { onAesItemModifyReply(replyObject); }
void onExplosionAreaPauseResumeReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onExplosionClusterPauseResumeReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onExplosionClusterChanged(const AreaEffectSimulation::ExplosionCluster &ecData, DataModification modType);
void handleLaserPrecisionChargeType(const int chargeTypeId);
QPointF centerOfFiringUnitGeo(int particpantUnitId);
void showCenterOfFiringUnit(int particpantUnitId);
private Q_SLOTS:
void showPreviewObject() override;
bool isDataSufficiant();
bool apply() override final;
void onGeometrySelected(int explosionGeometryInt);
void onFireClicked();
void onGearClassChanged();
void onPositionChanged(const QPointF &newGeoCoord);
void onPartyChanged();
void onChargeTypeChanged();
void onIgniterTypeChanged();
void onParticipantUnitChanged(int idx);
void onParticipantUnitEntered();
void onParticipantUnitLeaved();
void onParticipantPositionChanged();
void getPosition();
void onCoordinate(const QPointF &centerPoint);
void onMapRecData(const QPointF &bottomLeft, double width, double height, double angleDegNorth, const QPolygonF &bufferOutlinePolygon);
void onCircleData(const QPointF &position, double radius);
void onPolylineData(const QPolygonF &polyline);
void setCoord(const QPointF &coord);
void onFirePurposeChanged();
void onDropAngleChanged();
void onWidthChanged(int width);
void onAimingAxisChanged(int aimingAxis);
void onLineP1Changed(const QPointF &point);
void onLineP2Changed(const QPointF &point);
void onPeakHeigthChanged(int data);
void onFlightDurationChanged(int data);
void onEffectDurationChanged(int value);
void switchTo(FlighDurationOrPeakHeight phfd);
void setMinMaxConstraints(ExplosionsEdit::FlighDurationOrPeakHeight phfd, ProjectDataManagement::GearClass_def::type gearClass, int chargeTypeId);
bool setValueAccordingContraints(int newValue, ExplosionsEdit::FlighDurationOrPeakHeight phfd);
bool isGuiVulcano();
void doCalculations(bool executeEnableUiElements = true);
void onPartitionTimeChanged(qint64 newPartitionTimeMsec = 0);
private:
friend class DoCalculationsExitGuard;
static double s_minWidth;
static double s_maxWidth;
static double s_stepWidth;
static double s_minHeight;
static double s_maxHeight;
static double s_stepHeight;
static double s_minRadius;
static double s_maxRadius;
static double s_stepRadius;
static int s_maxChargeUsage;
static double s_minAltitude;
static double s_maxAltitude;
static qint64 s_maxDurationSeconds;
static int s_dropAngleDown;
static int s_dropAngleUp;
void retranslate() override;
void enableUiElements();
void enableUiElements(bool enable) override;
void enableUiFireButton();
void fillParticipantUnit();
void gatherParticipantUnits(const int &partyId, QHash<int/*superiorId*/, QSet<int> > &units) const;
void fillParties();
bool isValidParty(qint32 partyId);
void fillCharges();
void fillGearClasses();
int currentDropAngleDegree();
void setDropAngleTo(double dropAngleDegree);
double currentDropAngleRadiant();
private:
bool isOnlyNameModifiable() const override;
bool isSmoke();
void updateActorComboBox(const Core::GeoPosition &coordGeo);
struct Charges
{
Charges() {}
explicit Charges(const ProjectDataManagement::ChargeType &type) : chargeType(type) {}
ProjectDataManagement::ChargeType chargeType;
QMap<int, int> available; // PartyId
};
QVector<ProjectDataManagement::GearClass> m_gearClassFilter;
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asbIfc;
std::shared_ptr<EffectShowManagement::ForeignGuiComboboxInterface> m_esmActorCbx;
std::shared_ptr<ProjectDataManagement::ForeignGuiInterface> m_pdmCbx;
ExplosionCluster m_explosionClusterData;
QPointF m_coord;
// doCalculations will update following:
struct temporaryData
{
qint64 m_estimatedFlightDurationMsec{-1};
qint64 m_distanceFiringToTarget{-1};
Core::GeoPosition m_idealTapAbsoluteGeoOut;
QString m_remainingTimeStr;
QString m_annotationStringFiring4Dlg;
QStringList m_annotationString4Dlg;
void reset()
{
m_estimatedFlightDurationMsec = -1;
m_distanceFiringToTarget = -1;
m_remainingTimeStr.clear();
m_annotationStringFiring4Dlg.clear();
m_annotationString4Dlg.clear();
}
} m_temporaryData;
void resetTempAndAnnotationStr();
void addAnnotationStr(const QString &newAnno);
void updateAnnotationStr();
double getElevation(const double lon, const double lat) const;
QMap<qint32, Charges> m_chargeTypeMap; // ChargeTypeId
QPointF m_previewCircleCenter;
double m_previewCircleRadius;
QPolygonF m_previewPolygon;
QButtonGroup *m_geometrieButtonGroup;
AreaEffectSimulation::AesExplosionGeometry m_currentGeometry; // safe_enum is initialized by itself
Ui::ExplosionsEdit *m_ui;
bool m_initDone{false};
QTimer *m_enableFireBtnTimer{nullptr};
Core::GeoPosition m_coordGeo;
LtsElevation::LTS_ELEVATION_MANAGER_TYPE m_elevationManager{nullptr};
};
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,763 @@
/**
* @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 &centerCoordGeo = 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 &centerFiringUnitGeo = 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
@@ -0,0 +1,153 @@
/**
* @RDE_HEADER@
* AreaEffectSimulation - Explosions Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Tougnia, SLTE, 2023-09-05
*/
#pragma once
#include <AreaEffectSimulation/aes_ftc.h>
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_base_edit.h>
#include <Plugins/EffectShowManagement/esm_gui_combobox_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_gui_plugin_interface.h>
#include <ProjectDataManagement/pdm.hpp>
#include <iosfwd>
namespace Ui
{
class ExplosionsEditAdler;
}
class QSpinBox;
namespace AdvancedSymbology
{
class SymbolResultWatcherLabel;
class ForeignDataInterface;
} // namespace AdvancedSymbology
namespace AreaEffectSimulation
{
class ExplosionsEditAdler final
: public BaseEdit
, protected AreaEffectSimulation::Interface::Ftc::EffectClusterModifyReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::EffectClusterModifyActorReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::SetAesItemEffectorStateReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::AcknowledgeExternalAesItemReplyHandler
{
Q_OBJECT
public:
using BaseClass = BaseEdit;
enum class FlighDurationOrPeakHeight
{
FDPH_flightDuration,
FDPH_peakHeight
};
QString toString(FlighDurationOrPeakHeight val);
explicit ExplosionsEditAdler(const QString &menuGroup, QWidget *parent = nullptr);
~ExplosionsEditAdler();
bool init(int aesItemId, bool copy, LtsSession::LtsSession *session);
void setEffectClusterData(const EffectCluster &ecData);
void setEffector(int participantId, const AreaEffectSimulation::AesEffectorState &effectorState);
void setEffectClusterDataFromJson(const std::string &properties);
void setOWUWFromTrajectory(const std::vector<Core::RelativePositionRelativeTime> &vecGeometry);
QString dialogIdentifier() const override;
void onEffectClusterModifyReply(const Core::FunctionReplyObject &replyObject) override final { onAesItemModifyReply(replyObject); }
void onEffectClusterModifyActorReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onAcknowledgeExternalAesItemReply(const Core::FunctionReplyObject &replyObject) override final;
void onSetAesItemEffectorStateReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onEffectClusterChanged(const AreaEffectSimulation::EffectCluster &ecData, DataModification modType);
QPointF centerOfFiringUnitGeo(int particpantUnitId);
void showCenterOfFiringUnit(int particpantUnitId);
void showPreviewObject() override;
private Q_SLOTS:
bool isDataSufficiant();
bool apply() override final;
void onPbStateChangeClicked();
void onEffectorChanged(const AreaEffectSimulation::Effector &data, DataModification modType);
private:
friend class doCalculationsAdlerStandAloneExitGuard;
void retranslate() override;
void enableUiElements();
void enableUiElements(bool enable) override;
void setPbStateChangeName();
private:
bool isOnlyNameModifiable() const override;
struct Charges
{
Charges() {}
explicit Charges(const ProjectDataManagement::ChargeType &type) : chargeType(type) {}
ProjectDataManagement::ChargeType chargeType;
QMap<int, int> available; // PartyId
};
QVector<ProjectDataManagement::GearClass> m_gearClassFilter;
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asbIfc;
std::shared_ptr<EffectShowManagement::ForeignGuiComboboxInterface> m_esmActorCbx;
std::shared_ptr<ProjectDataManagement::ForeignGuiInterface> m_pdmCbx;
EffectCluster m_effectClusterData;
QPointF m_coord;
// doCalculationsAdler will update following:
struct temporaryData
{
qint64 m_estimatedFlightDurationMsec{-1};
qint64 m_distanceFiringToTarget{-1};
Core::GeoPosition m_idealTapAbsoluteGeoOut;
QString m_remainingTimeStr;
QString m_annotationStringFiring4Dlg;
QStringList m_annotationString4Dlg;
void reset()
{
m_estimatedFlightDurationMsec = -1;
m_distanceFiringToTarget = -1;
m_remainingTimeStr.clear();
m_annotationStringFiring4Dlg.clear();
m_annotationString4Dlg.clear();
}
} m_temporaryData;
void resetTempAndAnnotationStr();
void addAnnotationStr(const QString &newAnno);
void updateAnnotationStr();
QMap<qint32, Charges> m_chargeTypeMap; // ChargeTypeId
QPointF m_previewCircleCenter;
double m_previewCircleRadius;
QPolygonF m_previewPolygon;
QButtonGroup *m_geometrieButtonGroup;
AreaEffectSimulation::AesExplosionGeometry m_currentGeometry; // safe_enum is initialized by itself
Ui::ExplosionsEditAdler *m_ui;
bool m_initDone{false};
Core::GeoPosition m_coordGeo;
int m_maxColumns{4};
int m_effectorNumber{0};
};
} // namespace AreaEffectSimulation
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,232 @@
/**
* @RDE_HEADER@
* AreaEffectSimulation - Explosions Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Tougnia, SLTE, 2023-09-05
*/
#pragma once
#include "LtsElevation/lts_elevation_manager.h"
#include <AreaEffectSimulation/aes_ftc.h>
#include <ElevationMap/elevation_map_manager.h>
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_base_edit.h>
#include <Plugins/EffectShowManagement/esm_gui_combobox_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_gui_plugin_interface.h>
#include <ProjectDataManagement/pdm.hpp>
#include <iosfwd>
namespace Ui
{
class ExplosionsEditAdlerStandAlone;
}
class QSpinBox;
namespace AdvancedSymbology
{
class SymbolResultWatcherLabel;
class ForeignDataInterface;
} // namespace AdvancedSymbology
namespace AreaEffectSimulation
{
class ExplosionsEditAdlerStandAlone final
: public BaseEdit
, protected AreaEffectSimulation::Interface::Ftc::EffectClusterModifyReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::EffectClusterPauseResumeReplyHandler
, protected AreaEffectSimulation::Interface::Ftc::SetAesItemEffectorStateReplyHandler
{
Q_OBJECT
public:
using BaseClass = BaseEdit;
enum class FlighDurationOrPeakHeight
{
FDPH_flightDuration,
FDPH_peakHeight
};
QString toString(FlighDurationOrPeakHeight val);
explicit ExplosionsEditAdlerStandAlone(const QString &menuGroup, QWidget *parent = nullptr);
~ExplosionsEditAdlerStandAlone();
bool init(int aesItemId, bool copy, LtsSession::LtsSession *session);
void setEffectClusterData(const EffectCluster &ecData);
void setEffector(const ParticipantManagement::Participant &part, const AreaEffectSimulation::AesEffectorState &effectorState);
QString dialogIdentifier() const override;
void onEffectClusterModifyReply(const Core::FunctionReplyObject &replyObject) override final { onAesItemModifyReply(replyObject); }
void onEffectClusterPauseResumeReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
void onSetAesItemEffectorStateReply(const Core::FunctionReplyObject &replyObject) override final;
void onEffectClusterChanged(const AreaEffectSimulation::EffectCluster &ecData, DataModification modType);
QPointF centerOfFiringUnitGeo(int particpantUnitId);
void showCenterOfFiringUnit(int particpantUnitId);
private Q_SLOTS:
void showPreviewObject() override;
bool isDataSufficiant();
bool apply() override final;
void onGeometrySelected(int explosionGeometryInt);
void onStartBtnClicked();
void onGearClassChanged();
void onPositionChanged(const QPointF &newGeoCoord);
void onPartyChanged();
void onChargeTypeChanged();
void onIgniterTypeChanged();
void onLoadTypeChanged();
void onTargetTypeChanged();
void onParticipantUnitChanged(int idx);
void onParticipantUnitEntered();
void onParticipantUnitLeaved();
void onParticipantPositionChanged();
void getPosition();
void onCoordinate(const QPointF &centerPoint);
void onMapRecData(const QPointF &bottomLeft, double width, double height, double angleDegNorth, const QPolygonF &bufferOutlinePolygon);
void onCircleData(const QPointF &position, double radius);
void onPolylineData(const QPolygonF &polyline);
void setCoord(const QPointF &coord);
void onFirePurposeChanged();
void onCbFiringTypeChanged();
void setFireBtnState();
void onFireBtnClicked();
void onWidthChanged(int width);
void onAimingAxisChanged(int aimingAxis);
void onLineP1Changed(const QPointF &point);
void onLineP2Changed(const QPointF &point);
void onPeakHeigthChanged(int data);
void onEffectDurationChanged(int value);
void switchTo(FlighDurationOrPeakHeight phfd);
void setMinMaxConstraints(ExplosionsEditAdlerStandAlone::FlighDurationOrPeakHeight phfd, ProjectDataManagement::GearClass_def::type gearClass, int chargeTypeId);
bool setValueAccordingContraints(int newValue, ExplosionsEditAdlerStandAlone::FlighDurationOrPeakHeight phfd);
bool isGuiVulcano();
void doCalculationsAdlerStandAlone(bool executeEnableUiElements = true);
void onPartitionTimeChanged(qint64 newPartitionTimeMsec = 0);
void onEffectorChanged(const AreaEffectSimulation::Effector &data, DataModification modType);
private:
friend class doCalculationsAdlerStandAloneExitGuard;
static double s_minWidth;
static double s_maxWidth;
static double s_stepWidth;
static double s_minHeight;
static double s_maxHeight;
static double s_stepHeight;
static double s_minRadius;
static double s_maxRadius;
static double s_stepRadius;
static int s_maxChargeUsage;
static double s_minAltitude;
static double s_maxAltitude;
static qint64 s_maxDurationSeconds;
void retranslate() override;
void enableUiElements();
void enableUiElements(bool enable) override;
void enableUiFireButton();
void fillParticipantUnit();
void gatherParticipantUnits(const int &partyId, QHash<int /*superiorId*/, QSet<int>> &units) const;
void fillParties();
bool isValidParty(qint32 partyId);
bool allEffectorReadyToFire() const;
void fillCharges();
void fillFiringTypCbox();
void fillGearClasses();
void mmiToJsonproperties(QJsonObject &data);
void setEffectClusterDataFromJson(const std::string &properties);
private:
bool isOnlyNameModifiable() const override;
bool isSmoke();
void updateActorComboBox(const Core::GeoPosition &coordGeo);
QPair<int, int> getMinMaxDistance(ProjectDataManagement::GearClass_def::type gearClass, int chargeTypeId);
int getMinDistance(ProjectDataManagement::GearClass::inner_enum gearClass, int chargeTypeId);
int getMaxDistance(ProjectDataManagement::GearClass::inner_enum gearClass, int chargeTypeId);
QPair<int, int> getMinMaxFlightDurationSec(ProjectDataManagement::GearClass::inner_enum gearClass, int chargeTypeId);
int getMinFlightDurationSec(ProjectDataManagement::GearClass::inner_enum gearClass, int chargeTypeId);
int getMaxFlightDurationSec(ProjectDataManagement::GearClass::inner_enum gearClass, int chargeTypeId);
QPair<int, int> getMinMaxPeakHeight(ProjectDataManagement::GearClass::inner_enum gearClass, int chargeTypeId);
int getMinPeakHeight(ProjectDataManagement::GearClass::inner_enum gearClass, int chargeTypeId);
int getMaxPeakHeight(ProjectDataManagement::GearClass::inner_enum gearClass, int chargeTypeId);
bool isPointSimilar(AreaEffectSimulation::AesExplosionGeometry geometry);
struct Charges
{
Charges() {}
explicit Charges(const ProjectDataManagement::ChargeType &type)
: chargeType(type)
{
}
ProjectDataManagement::ChargeType chargeType;
QMap<int, int> available; // PartyId
};
QVector<ProjectDataManagement::GearClass> m_gearClassFilter;
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> m_asbIfc;
std::shared_ptr<EffectShowManagement::ForeignGuiComboboxInterface> m_esmActorCbx;
std::shared_ptr<ProjectDataManagement::ForeignGuiInterface> m_pdmCbx;
EffectCluster m_effectClusterData;
QPointF m_coord;
double m_firstFlightTime;
// doCalculationsAdlerStandAlone will update following:
struct temporaryData
{
qint64 m_estimatedFlightDurationMsec{-1};
qint64 m_distanceFiringToTarget{-1};
Core::GeoPosition m_idealTapAbsoluteGeoOut;
QString m_remainingTimeStr;
QString m_annotationStringFiring4Dlg;
QStringList m_annotationString4Dlg;
void reset()
{
m_estimatedFlightDurationMsec = -1;
m_distanceFiringToTarget = -1;
m_remainingTimeStr.clear();
m_annotationStringFiring4Dlg.clear();
m_annotationString4Dlg.clear();
}
} m_temporaryData;
void resetTempAndAnnotationStr();
void addAnnotationStr(const QString &newAnno);
void updateAnnotationStr();
double getElevation(const double lon, const double lat) const;
EffectCluster m_data;
QMap<qint32, Charges> m_chargeTypeMap; // ChargeTypeId
QPointF m_previewCircleCenter;
double m_previewCircleRadius;
QPolygonF m_previewPolygon;
QButtonGroup *m_geometrieButtonGroup;
AreaEffectSimulation::AesExplosionGeometry m_currentGeometry; // safe_enum is initialized by itself
Ui::ExplosionsEditAdlerStandAlone *m_ui;
bool m_initDone{false};
QTimer *m_enableStartBtnTimer{nullptr};
Core::GeoPosition m_coordGeo;
const int m_maxColumns{4};
int m_effectorNumber{0};
LtsElevation::LTS_ELEVATION_MANAGER_TYPE m_elevationManager{nullptr};
};
} // namespace AreaEffectSimulation
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,30 @@
/**
* @RDE_HEADER@
* AreaEffectManangement - Explosion Single Overview Dialog Model
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-09-26
*/
#include "aes_explosions_single_model.h"
namespace AreaEffectSimulation
{
bool ExplosionsSingleModel::initModel(LtsSession::LtsSession *session)
{
if (!AesGuiBaseModel::initModel(session))
return false;
connect(m_aesDtc.get(), &Interface::Dtc::explosionSingleChanged,
this, &ExplosionsSingleModel::onDataChanged);
fillAvailableChargeIds(m_gearClass);
m_aesDtc->explosionSingles([this](const ExplosionSingle &item) { insertRow(item); });
return true;
}
} // namespace AreaEffectSimulation
@@ -0,0 +1,38 @@
/**
* @RDE_HEADER@
* ExplosionManangement - Explosion Single Overview Dialog Model
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-09-26
*/
#pragma once
#include <Plugins/AreaEffectSimulation/Gui/Base/aes_base_model.h>
namespace AreaEffectSimulation
{
/************ Class for Artillery and Mortar Explosion Single ***************/
class ExplosionsSingleModel : public AesGuiBaseModel<ExplosionSingle>
{
Q_OBJECT
public:
ExplosionsSingleModel(ProjectDataManagement::GearClass gc, QObject *parent)
: AesGuiBaseModel<ExplosionSingle>(parent)
, m_gearClass(gc)
{}
bool initModel(LtsSession::LtsSession *session);
ProjectDataManagement::GearClass gearClass() const { return m_gearClass; }
protected:
ProjectDataManagement::GearClass m_gearClass;
};
} //namespace AreaEffectSimulation
@@ -0,0 +1,257 @@
/**
* @RDE_HEADER@
* Namespace for rocket related functions
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Fritsche, ESZS, 2026-06-03
*/
#include "aes_rocket_utility.h"
#include <QComboBox>
#include <QJsonDocument>
#include <QJsonObject>
#include <QStandardItemModel>
#include <AreaEffectSimulation/aes.hpp>
#include <AreaEffectSimulation/Trajectory/trajectory_generator.h>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <LtsUtils/LtsUtilsCore/qpoint3d.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ProjectDataManagement/pdm_enums.hpp>
#include <Proxies/TrainingAreaBase/Plugins/AdlerJson/telegrams.h>
namespace AreaEffectSimulation
{
namespace RocketUtility
{
void enaDisaWirkmittel(QComboBox *wirkmittelCombobox, AesExplosionGeometry::type geometry)
{
if (wirkmittelCombobox == nullptr)
return;
const QStandardItemModel *cboModel = qobject_cast<QStandardItemModel *>(wirkmittelCombobox->model());
if (cboModel == nullptr)
return;
switch (geometry)
{
case AesExplosionGeometry::type::EgAimPoint:
case AesExplosionGeometry::type::EgPoint:
case AesExplosionGeometry::type::EgLine:
for (int indexCounter = 0; indexCounter < wirkmittelCombobox->count(); ++indexCounter)
{
const QVariant currentData = wirkmittelCombobox->itemData(indexCounter);
const ProjectDataManagement::GearClass::type currentGearClass = static_cast<ProjectDataManagement::GearClass::type>(currentData.toInt());
if (currentGearClass == ProjectDataManagement::GearClass::Rocket)
{
QStandardItem *item = cboModel->item(indexCounter);
if (item == nullptr)
continue;
item->setFlags(item->flags() | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
// we do not break the loop here because there may be more rocket wirkmittel in the future
}
}
return;
case AesExplosionGeometry::type::EgRadial:
case AesExplosionGeometry::type::EgArea:
{
const int currentIndex = wirkmittelCombobox->currentIndex();
for (int indexCounter = 0; indexCounter < wirkmittelCombobox->count(); ++indexCounter)
{
const QVariant currentData = wirkmittelCombobox->itemData(indexCounter);
const ProjectDataManagement::GearClass::type currentGearClass = static_cast<ProjectDataManagement::GearClass::type>(currentData.toInt());
if (currentGearClass == ProjectDataManagement::GearClass::Rocket)
{
QStandardItem *item = cboModel->item(indexCounter);
if (item == nullptr)
continue;
item->setFlags(item->flags() & ~Qt::ItemIsEnabled & ~Qt::ItemIsSelectable);
// if rocket ist currently selected, we have to set another index
if (indexCounter == currentIndex && wirkmittelCombobox->count() > 1)
{
const int newIndex = currentIndex == 0 ? 1 : 0;
wirkmittelCombobox->setCurrentIndex(newIndex);
}
// we do not break the loop here because there may be more rocket wirkmittel in the future
}
}
return;
}
default:
return;
}
}
void addRocketPropertiesToRequest(EffectClusterModifyRequest &request, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc)
{
switch (request.explosionGeometry().underlying())
{
case AesExplosionGeometry::type::EgAimPoint:
case AesExplosionGeometry::type::EgPoint:
addRocketPropertiesForPointGeometry(request, ppmDtc);
return;
case AesExplosionGeometry::type::EgLine:
addRocketPropertiesForLinearGeometry(request, ppmDtc);
return;
case AesExplosionGeometry::type::EgRadial:
case AesExplosionGeometry::type::EgArea:
default:
return;
}
}
void addRocketPropertiesForLinearGeometry(EffectClusterModifyRequest &request, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc)
{
using namespace LtsCoordTrans;
AdlerJson::WirkmittelFeuerkommandoRakete wirkmittel;
AdlerJson::Treffpunkt treffpunkt;
wirkmittel.wirkzeit = 6;
const UtmCoordinate areaBottomLeftUtm = UtmCoordinate::fromGeographic(request.area().cornerBottomLeft().lon(), request.area().cornerBottomLeft().lat());
QTransform transform;
transform.translate(areaBottomLeftUtm.x, areaBottomLeftUtm.y);
transform.rotate(-request.area().rotation());
const double yLocal = request.area().height() / 2;
int mhpSliceCounter = 1;
for (EffectorData &currentEffector : request.effectors())
{
wirkmittel.geschoss.anzahl = currentEffector.chargeAmount();
treffpunkt.anzahl = wirkmittel.geschoss.anzahl;
// calculate local x
double xLocal = request.area().width() * (static_cast<double>(mhpSliceCounter++) / (request.effectors().size() + 1));
// transform local point to UTM
const QPointF localPoint(xLocal, yLocal);
const QPointF utmPoint = transform.map(localPoint);
// tranform utm point to geographic WGS84 coordinate
const UtmCoordinate currentUtm(areaBottomLeftUtm.zone, utmPoint.x(), utmPoint.y());
const QPointF mhpGeo = currentUtm.geographic();
// treffpunkt
currentEffector.mhpPosition().lon(mhpGeo.x());
currentEffector.mhpPosition().lat(mhpGeo.y());
treffpunkt.koordinate.koordinate.longitude = currentEffector.mhpPosition().lon() * LtsCoordTrans::rad2deg();
treffpunkt.koordinate.koordinate.latitude = currentEffector.mhpPosition().lat() * LtsCoordTrans::rad2deg();
wirkmittel.treffpunkte.clear();
wirkmittel.treffpunkte.append(treffpunkt);
QJsonObject wirkmittelObj;
AdlerJson::wirkmittelFeuerkommandoRaketeToJson(wirkmittelObj, wirkmittel);
currentEffector.properties(QJsonDocument(wirkmittelObj).toJson().toStdString());
// trajectory
const ParticipantManagement::ParticipantPosition &participantPosition = ppmDtc->participantPosition(currentEffector.participantId());
const LtsUtils::QPoint3D trajectoryStart(participantPosition.pos().lon(),
participantPosition.pos().lat(),
participantPosition.pos().z());
const LtsUtils::QPoint3D trajectoryEnd(currentEffector.mhpPosition().lon(),
currentEffector.mhpPosition().lat(),
currentEffector.mhpPosition().z()); // TODO
TrajectoryGeoPosition trajectoryWithoutTime;
TrajectoryGenerator::getInstance()->generateTrajectoryBiedziak(trajectoryStart, trajectoryEnd, 45.0, trajectoryWithoutTime);
currentEffector.flightTime(60000.0);
const double flightTimeStep = currentEffector.flightTime() / static_cast<double>(trajectoryWithoutTime.size());
double currentFlightTime = 0.0;
const LtsCoordTrans::UtmCoordinate utmStartPos = LtsCoordTrans::UtmCoordinate::fromGeographic(participantPosition.pos().lon(), participantPosition.pos().lat());
for (const Core::GeoPosition &pos : trajectoryWithoutTime)
{
const LtsCoordTrans::UtmCoordinate utmCurrentPos = LtsCoordTrans::UtmCoordinate::fromGeographic(pos.lon(), pos.lat());
currentEffector.trajectoryRelative().emplace_back(utmCurrentPos.x - utmStartPos.x,
utmCurrentPos.y - utmStartPos.y, pos.z(), currentFlightTime);
currentFlightTime += flightTimeStep;
}
}
}
void addRocketPropertiesForPointGeometry(EffectClusterModifyRequest &request, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc)
{
using namespace LtsCoordTrans;
AdlerJson::WirkmittelFeuerkommandoRakete wirkmittel;
AdlerJson::Treffpunkt treffpunkt;
wirkmittel.wirkzeit = 6;
treffpunkt.anzahl = 1;
const UtmCoordinate areaBottomLeftUtm = UtmCoordinate::fromGeographic(request.area().cornerBottomLeft().lon(), request.area().cornerBottomLeft().lat());
const QPointF areaCenterGeo = areaBottomLeftUtm.geographic(request.area().width() / 2, request.area().height() / 2);
for (EffectorData &currentEffector : request.effectors())
{
wirkmittel.geschoss.anzahl = currentEffector.chargeAmount();
treffpunkt.anzahl = wirkmittel.geschoss.anzahl;
// treffpunkt
currentEffector.mhpPosition().lon(areaCenterGeo.x());
currentEffector.mhpPosition().lat(areaCenterGeo.y());
treffpunkt.koordinate.koordinate.longitude = currentEffector.mhpPosition().lon() * LtsCoordTrans::rad2deg();
treffpunkt.koordinate.koordinate.latitude = currentEffector.mhpPosition().lat() * LtsCoordTrans::rad2deg();
wirkmittel.treffpunkte.clear();
wirkmittel.treffpunkte.append(treffpunkt);
QJsonObject wirkmittelObj;
AdlerJson::wirkmittelFeuerkommandoRaketeToJson(wirkmittelObj, wirkmittel);
currentEffector.properties(QJsonDocument(wirkmittelObj).toJson().toStdString());
// trajectory
const ParticipantManagement::ParticipantPosition &participantPosition = ppmDtc->participantPosition(currentEffector.participantId());
const LtsUtils::QPoint3D trajectoryStart(participantPosition.pos().lon(),
participantPosition.pos().lat(),
participantPosition.pos().z());
const LtsUtils::QPoint3D trajectoryEnd(currentEffector.mhpPosition().lon(),
currentEffector.mhpPosition().lat(),
currentEffector.mhpPosition().z());
TrajectoryGeoPosition trajectoryWithoutTime;
TrajectoryGenerator::getInstance()->generateTrajectoryBiedziak(trajectoryStart, trajectoryEnd, 45.0, trajectoryWithoutTime);
currentEffector.flightTime(60000.0);
const double flightTimeStep = currentEffector.flightTime() / static_cast<double>(trajectoryWithoutTime.size());
double currentFlightTime = 0.0;
const LtsCoordTrans::UtmCoordinate utmStartPos = LtsCoordTrans::UtmCoordinate::fromGeographic(participantPosition.pos().lon(), participantPosition.pos().lat());
for (const Core::GeoPosition &pos : trajectoryWithoutTime)
{
const LtsCoordTrans::UtmCoordinate utmCurrentPos = LtsCoordTrans::UtmCoordinate::fromGeographic(pos.lon(), pos.lat());
currentEffector.trajectoryRelative().emplace_back(utmCurrentPos.x - utmStartPos.x,
utmCurrentPos.y - utmStartPos.y, pos.z(), currentFlightTime);
currentFlightTime += flightTimeStep;
}
}
}
} // namespace RocketUtility
} // namespace AreaEffectSimulation
@@ -0,0 +1,38 @@
/**
* @RDE_HEADER@
* Namespace for rocket related functions
* $Id$
* $HeadURL$
* $Author$
* Created by Hannes Fritsche, ESZS, 2026-06-03
*/
#pragma once
#include <AreaEffectSimulation/aes_enums.hpp>
class QComboBox;
namespace ParticipantManagement
{
namespace Interface
{
class Dtc;
}
}
namespace AreaEffectSimulation
{
class EffectClusterModifyRequest;
namespace RocketUtility
{
void enaDisaWirkmittel(QComboBox *wirkmittelCombobox, AesExplosionGeometry::type geometry);
void addRocketPropertiesToRequest(EffectClusterModifyRequest &request, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc);
void addRocketPropertiesForPointGeometry(EffectClusterModifyRequest &request, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc);
void addRocketPropertiesForLinearGeometry(EffectClusterModifyRequest &request, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc);
} // namespace RocketUtility
} // namespace AreaEffectSimulation
File diff suppressed because it is too large. Load diff