Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
Executable
+151
@@ -0,0 +1,151 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
INCLUDE(MacroRTIDDSGen)
|
||||
INCLUDE(MacroCodeGenIdl)
|
||||
|
||||
SET(xml_FILE alm_service.xml)
|
||||
#
|
||||
# --- Library svcAlmCommon --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_common
|
||||
alm_export.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
)
|
||||
|
||||
# Generate alm_enums.idl / alm.idl
|
||||
CODEGEN_IDL_SVC(SRCS_common ${xml_FILE})
|
||||
# Generate alm_db_impl.cpp/.h, alm_db.h
|
||||
CODEGEN_DATABASE(SRCS_common ${xml_FILE})
|
||||
|
||||
# Generate *.cpp/*.hpp from idl
|
||||
RTIDDSGEN(SRCS_common alm_enums.idl)
|
||||
RTIDDSGEN(SRCS_common alm.idl)
|
||||
|
||||
# Generate alm_dt[s,c]_types.h, alm_ft[s,c]_types.h
|
||||
CODEGEN_TOPIC_TYPEDEFS(SRCS_common ${xml_FILE})
|
||||
# Generate alm_[d|f]tc.h
|
||||
CODEGEN_CLIENT_TOPICS_IFC(SRCS_common ${xml_FILE})
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV WS svcAlmCommon SHARED ${SRCS_common})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcAlmCommon
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(svcAlmCommon
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
ddscore
|
||||
NGLLogger
|
||||
svcPdmCommon
|
||||
ngldb
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcAlmCommon)
|
||||
|
||||
#
|
||||
# --- Library svcAlmClient --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_client
|
||||
alm_export.h
|
||||
)
|
||||
# generate alm_[d|f]tc.h, tlm_[d|f]tc_impl.[cpp|h]
|
||||
CODEGEN_CLIENT_TOPICS_IMPL(SRCS_client ${xml_FILE})
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV WS svcAlmClient SHARED ${SRCS_client})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcAlmClient
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(svcAlmClient
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
ddsconnector
|
||||
PUBLIC
|
||||
svcAlmCommon
|
||||
ddsftc
|
||||
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcAlmClient)
|
||||
|
||||
#
|
||||
# --- Library svcAlmServer --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_server
|
||||
alm_export.h
|
||||
dds_handler.cpp
|
||||
dds_handler.h
|
||||
handler_configure_alarms.cpp
|
||||
handler_configure_alarms.h
|
||||
handler_participant.cpp
|
||||
handler_participant.h
|
||||
handler_emergency_call.cpp
|
||||
handler_emergency_call.h
|
||||
initialization.cpp
|
||||
initialization.h
|
||||
object_emergency_call.cpp
|
||||
object_emergency_call.h
|
||||
# settings.cpp
|
||||
# settings.h
|
||||
)
|
||||
# generate alm_[d|f]ts.h, alm_[d|f]ts_impl.[cpp|h]
|
||||
CODEGEN_SERVER_TOPICS(SRCS_server ${xml_FILE})
|
||||
# Generate alm.sql, alm.xml
|
||||
CODEGEN_SQL(SRCS_server ${xml_FILE})
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV svcAlmServer SHARED ${SRCS_server})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcAlmServer
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(svcAlmServer
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
Qt5::Core
|
||||
ddsfts
|
||||
ddsconnector
|
||||
ddsQoS
|
||||
svcPdmCommon
|
||||
svcAlmCommon
|
||||
svcAlmClient
|
||||
svcEemClient
|
||||
svcPpmClient
|
||||
svcMrkClient
|
||||
svcCoreClient
|
||||
svcTabClient
|
||||
svcExmClient
|
||||
svcTabServer
|
||||
nglsettings
|
||||
NGLLogger
|
||||
ddscore
|
||||
ngltools
|
||||
PUBLIC
|
||||
svcAlmCommon
|
||||
ngldb
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcAlmServer)
|
||||
|
||||
#
|
||||
# --- Topic Type Plugin --------------------------------------------------------------
|
||||
#
|
||||
CREATE_TOPIC_TYPE_PLUGIN(${xml_FILE})
|
||||
|
||||
#
|
||||
# --- RecordReplayPlugin --------------------------------------------------------------
|
||||
#
|
||||
CREATE_RECORD_REPLAY_PLUGIN(${xml_FILE} SRCS_server)
|
||||
|
||||
|
||||
# Uncomment if necessary
|
||||
#ADD_SUBDIRECTORY(UnitTests)
|
||||
ADD_SUBDIRECTORY(ModuleTests)
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
IF(TARGET svcAlmClient AND TARGET svcTabServer)
|
||||
|
||||
####################################
|
||||
# Message Test
|
||||
####################################
|
||||
|
||||
SET(SRCS_TEST_ALM
|
||||
alm_tests.cpp
|
||||
)
|
||||
SET(HDRS_TEST_ALM
|
||||
alm_tests.h
|
||||
)
|
||||
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(almTests
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
# Testing FunctionTopic Functionality (FTC)
|
||||
ADD_EXECUTABLE(almTests ${SRCS_TEST_ALM} ${HDRS_TEST_ALM})
|
||||
TARGET_LINK_LIBRARIES(almTests
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
RTI::nddscpp2
|
||||
svcAlmClient
|
||||
svcCoreClient
|
||||
svcEemServer
|
||||
svcPpmServer
|
||||
LtsCommandLineParser
|
||||
ddsconnector
|
||||
nglcoreapplication
|
||||
)
|
||||
IF(NOT BUILD_RPM)
|
||||
NGL_INSTALL(AAR SV TARGETS almTests DESTINATION bin/test)
|
||||
NGL_INSTALL(AAR SV FILES log4cxx_alm.props DESTINATION bin/test)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
+335
@@ -0,0 +1,335 @@
|
||||
/**
|
||||
* Msg Function Topic Module Test
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "alm_tests.h"
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
/* ----------------------------------------------------------------------------------
|
||||
* HOW TO RUN THE TESTS
|
||||
* ----------------------------------------------------------------------------------
|
||||
*
|
||||
* Preconditions: Nothing
|
||||
*
|
||||
* Start services: (SV)
|
||||
* ./svcExerciseEventManagement -e 42
|
||||
* ./almTests -t 1 -e 42 // Configure Alarms with participantId=0, send EEM-Event and receive Alarm
|
||||
* ./almTests -t 2 -e 42 // Configure Alarms with participantId-List, send EEM-Event and receive Alarm
|
||||
* ./almTests -t 3 -e 42 // Configure Alarms with vulnerability > 0, send EEM-Event and receive Alarm
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
namespace AlarmManagement
|
||||
{
|
||||
AlmTests::AlmTests(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_testId(0)
|
||||
, m_bTestsSuccessful(true)
|
||||
, m_logger(getLogger("AlmTests"))
|
||||
, m_participantIndex(0)
|
||||
{}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
AlmTests::~AlmTests()
|
||||
{}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
bool AlmTests::init(int domainId, int testId, int operatorId)
|
||||
{
|
||||
INFO_LOG(m_logger) << "init begin";
|
||||
|
||||
m_testId = testId;
|
||||
m_operatorId = operatorId;
|
||||
m_participantIndex = 0;
|
||||
|
||||
m_ddsConnector.reset(new DDSConnector::DdsConnector(domainId, IDL::PartitionType::Any));
|
||||
if (!m_ddsConnector->init())
|
||||
return false;
|
||||
m_ddsConnector->initPublisherSubscriber();
|
||||
|
||||
m_ftcAlm = AlarmManagement::Interface::Ftc::create(m_ddsConnector);
|
||||
bool bRet = m_ftcAlm->enableAll();
|
||||
|
||||
m_dtcAlm = AlarmManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
bRet &= m_dtcAlm->enableAll();
|
||||
|
||||
m_dtsEem = ExerciseEventManagement::Interface::Dts::create(m_ddsConnector);
|
||||
bRet &= m_dtsEem->enableAll();
|
||||
|
||||
m_dtsPpm = ParticipantManagement::Interface::Dts::create(m_ddsConnector);
|
||||
bRet &= m_dtsPpm->enableAll();
|
||||
|
||||
return bRet;
|
||||
} // init
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
void AlmTests::startTest()
|
||||
{
|
||||
INFO_LOG(m_logger) << "startTest m_testId=" << m_testId;
|
||||
if (m_testId <= 1) // Send FTC ConfigureAlarms and EEM Event
|
||||
{
|
||||
QTimer::singleShot(0, this, &AlmTests::tryConfigureAlarms);
|
||||
QTimer::singleShot(100, this, &AlmTests::trySendEvent);
|
||||
QTimer::singleShot(200, this, &AlmTests::checkAlarm);
|
||||
}
|
||||
if (m_testId == 2)
|
||||
{
|
||||
QTimer::singleShot(0, this, &AlmTests::tryCreateParticipant);
|
||||
QTimer::singleShot(100, this, &AlmTests::tryCreateParticipant);
|
||||
QTimer::singleShot(200, this, &AlmTests::tryConfigureAlarmsList);
|
||||
QTimer::singleShot(300, this, &AlmTests::trySendEvent);
|
||||
QTimer::singleShot(400, this, &AlmTests::checkAlarm);
|
||||
}
|
||||
if (m_testId == 3)
|
||||
{
|
||||
QTimer::singleShot(0, this, &AlmTests::tryCreateParticipant);
|
||||
QTimer::singleShot(100, this, &AlmTests::tryCreateParticipant);
|
||||
QTimer::singleShot(200, this, &AlmTests::tryConfigureAlarmsList);
|
||||
QTimer::singleShot(300, this, &AlmTests::trySendEvent);
|
||||
QTimer::singleShot(400, this, &AlmTests::checkAlarm);
|
||||
}
|
||||
QTimer::singleShot(5000, this, &AlmTests::failExit);
|
||||
} // startTest
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
void AlmTests::tryConfigureAlarms()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send createRequest Operator Message";
|
||||
|
||||
std::vector<AlarmManagement::AlarmAction> alarms;
|
||||
alarms.resize(2);
|
||||
|
||||
alarms[0].setMarker(true);
|
||||
alarms[0].messageWindow(true);
|
||||
alarms[0].vulnerabilityState(-1);
|
||||
alarms[0].eventTypeId(ProjectDataManagement::EventType_def::Hit);
|
||||
|
||||
alarms[1].setMarker(true);
|
||||
alarms[1].messageWindow(true);
|
||||
alarms[1].vulnerabilityState(0);
|
||||
alarms[1].eventTypeId(ProjectDataManagement::EventType_def::EnterNuclear);
|
||||
|
||||
std::vector<int32_t> participantIds;
|
||||
participantIds.push_back(0);
|
||||
bool globalEvent = true;
|
||||
bool remove = false;
|
||||
|
||||
if (!m_ftcAlm->configureAlarmsRequest(ConfigureAlarmsRequest(alarms, m_operatorId, participantIds, globalEvent, remove), this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting create data";
|
||||
failExit();
|
||||
}
|
||||
} // tryConfigureAlarms
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
void AlmTests::tryCreateParticipant()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to create Participant index = " << m_participantIndex;
|
||||
ParticipantManagement::Participant participant;
|
||||
switch (m_participantIndex)
|
||||
{
|
||||
case 0:
|
||||
participant.id(1);
|
||||
participant.superiorId(0);
|
||||
participant.inferiorIds().resize(2);
|
||||
participant.inferiorIds().at(0) = 2;
|
||||
participant.inferiorIds().at(1) = 3;
|
||||
participant.partyId(5);
|
||||
break;
|
||||
case 1:
|
||||
participant.id(2);
|
||||
participant.superiorId(1);
|
||||
participant.inferiorIds().resize(2);
|
||||
participant.inferiorIds().at(0) = 4;
|
||||
participant.inferiorIds().at(1) = 5;
|
||||
participant.partyId(5);
|
||||
break;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "Publishing Participant";
|
||||
if (!m_dtsPpm->publish(participant))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error publish Participant";
|
||||
failExit();
|
||||
}
|
||||
m_participantIndex++;
|
||||
} // tryCreateParticipant
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
void AlmTests::tryConfigureAlarmsList()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send createRequest Operator Message";
|
||||
|
||||
std::vector<AlarmManagement::AlarmAction> alarms;
|
||||
alarms.resize(2);
|
||||
|
||||
alarms[0].setMarker(true);
|
||||
alarms[0].messageWindow(true);
|
||||
alarms[0].eventTypeId(ProjectDataManagement::EventType_def::Hit);
|
||||
alarms[0].vulnerabilityState(-1);
|
||||
|
||||
alarms[1].setMarker(true);
|
||||
alarms[1].messageWindow(true);
|
||||
alarms[1].vulnerabilityState(-1);
|
||||
alarms[1].eventTypeId(ProjectDataManagement::EventType_def::WeaponAssignment);
|
||||
|
||||
std::vector<int32_t> participantIds;
|
||||
participantIds.push_back(1);
|
||||
participantIds.push_back(2);
|
||||
bool globalEvent = true;
|
||||
bool remove = false;
|
||||
|
||||
if (!m_ftcAlm->configureAlarmsRequest(ConfigureAlarmsRequest(alarms, m_operatorId, participantIds, globalEvent, remove), this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting create data";
|
||||
failExit();
|
||||
}
|
||||
} // tryConfigureAlarmsList
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
void AlmTests::trySendEvent()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send ParticipantEvent";
|
||||
|
||||
ExerciseEventManagement::Event pe;
|
||||
|
||||
// publish new Event data here
|
||||
pe.id(100);
|
||||
//pe.aesItemId(5);
|
||||
pe.eventTypeId(ProjectDataManagement::EventType_def::Hit); // same as eventTypeId in ConfigureAlarms
|
||||
pe.participantId(2);
|
||||
pe.equipmentNumber(55);
|
||||
pe.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
//pe.friendlyFire(1);
|
||||
//pe.vulnerability(0);
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("FriendlyFire")] = QJsonValue(true);
|
||||
|
||||
QString properties = QString::fromUtf8(QJsonDocument(obj).toJson());
|
||||
pe.properties(properties.toStdString());
|
||||
DEBUG_LOG(m_logger) << "Publishing EEM Event";
|
||||
if (!m_dtsEem->publish(pe))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error publish EEM Event";
|
||||
failExit();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
void AlmTests::onConfigureAlarmsReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
INFO_LOG(m_logger) << "onConfigureAlarmsReply, error = " << replyObject.error();
|
||||
if (replyObject.error())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error ConfigureAlarms - aborting";
|
||||
failExit();
|
||||
}
|
||||
} // onConfigureAlarmsReply
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
void AlmTests::checkAlarm()
|
||||
{
|
||||
INFO_LOG(m_logger) << "checkAlarm";
|
||||
m_dtcAlm->waitForHistoricalDataNotification();
|
||||
qint32 id = 0;
|
||||
AlarmManagement::Notification notification = m_dtcAlm->notification(id);
|
||||
INFO_LOG(m_logger) << "Recived AlarmManagement::Notification: " << notification
|
||||
<< " testId: " << m_testId;
|
||||
|
||||
switch (m_testId)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
INFO_LOG(m_logger) << "ExitSuccess";
|
||||
ExitSuccess();
|
||||
break;
|
||||
default:
|
||||
// nothing
|
||||
INFO_LOG(m_logger) << "failExit";
|
||||
failExit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
void AlmTests::failExit()
|
||||
{
|
||||
m_bTestsSuccessful = false;
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
} // failExit
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
void AlmTests::ExitSuccess()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "SUCCESS";
|
||||
m_bTestsSuccessful = true;
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
} // ExitSuccess
|
||||
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser()
|
||||
{
|
||||
addOption({ QStringList() << QLatin1String("t") << QLatin1String("testId")
|
||||
, QLatin1String("TestId.")
|
||||
, QLatin1String("Default: 0 (all tests)")
|
||||
, QLatin1String("0")
|
||||
});
|
||||
addOption({ QStringList() << QLatin1String("o") << QLatin1String("operatorId")
|
||||
, QLatin1String("OperatorId.")
|
||||
, QLatin1String("Default: 10")
|
||||
, QLatin1String("10")
|
||||
});
|
||||
|
||||
}
|
||||
int testId() const { return isSet(QLatin1String("t")) ? value(QLatin1String("t")).toInt() : 0; }
|
||||
int operatorId() const { return isSet(QLatin1String("o")) ? value(QLatin1String("o")).toInt() : 10; }
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("ALM", "log4cxx_alm.props");
|
||||
|
||||
CmdLineParser options;
|
||||
if (!options.init())
|
||||
return -1;
|
||||
|
||||
int iRet = -1;
|
||||
{
|
||||
std::unique_ptr<AlarmManagement::AlmTests> almTests(new AlarmManagement::AlmTests);
|
||||
|
||||
if (!almTests->init(options.domainId(), options.testId(), options.operatorId()))
|
||||
return iRet;
|
||||
|
||||
almTests->startTest();
|
||||
|
||||
STARTUP_LOG(app.baseLogger());
|
||||
|
||||
app.exec();
|
||||
|
||||
iRet = almTests->testsSuccessful() ? 0 : 1;
|
||||
fprintf(stderr, "%d\n", iRet);
|
||||
|
||||
SHUTDOWN_LOG(app.baseLogger());
|
||||
}
|
||||
|
||||
return iRet;
|
||||
} // main
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* ModuleTests for Msg
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AlarmManagement/alm_dtc.h>
|
||||
#include <AlarmManagement/alm_ftc.h>
|
||||
#include <AlarmManagement/alm_ftc_types.h>
|
||||
#include <AlarmManagement/logger.h>
|
||||
#include <ExerciseEventManagement/eem_dts.h>
|
||||
#include <ParticipantManagement/ppm_dts.h>
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
class AlmTests : public QObject
|
||||
, protected AlarmManagement::Interface::Ftc::ConfigureAlarmsReplyHandler
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AlmTests(QObject *parent = nullptr);
|
||||
~AlmTests();
|
||||
|
||||
bool init(int domainId, int testId, int operatorId);
|
||||
|
||||
bool testsSuccessful() const
|
||||
{
|
||||
return m_bTestsSuccessful;
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
void startTest();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void tryConfigureAlarms();
|
||||
void tryConfigureAlarmsList();
|
||||
void trySendEvent();
|
||||
void tryCreateParticipant();
|
||||
void failExit();
|
||||
void ExitSuccess();
|
||||
|
||||
protected:
|
||||
void onConfigureAlarmsReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
|
||||
private:
|
||||
void checkAlarm();
|
||||
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
std::shared_ptr<AlarmManagement::Interface::Ftc> m_ftcAlm;
|
||||
std::shared_ptr<AlarmManagement::Interface::Dtc> m_dtcAlm;
|
||||
std::shared_ptr<ExerciseEventManagement::Interface::Dts> m_dtsEem;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dts> m_dtsPpm;
|
||||
|
||||
int m_testId;
|
||||
bool m_bTestsSuccessful;
|
||||
int m_operatorId;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
int m_participantIndex;
|
||||
|
||||
};
|
||||
|
||||
} // namespace AlarmManagement
|
||||
@@ -0,0 +1,86 @@
|
||||
log4j.reset=true
|
||||
log4j.rootLogger=WARN, file
|
||||
|
||||
# Service: AlarmManagement
|
||||
###########################################################
|
||||
|
||||
#log4j.logger.ALM=WARN
|
||||
#log4j.logger.ALM.main=WARN
|
||||
#log4j.logger.ALM.DbAdmin=WARN
|
||||
#log4j.logger.ALM.DdsHandler=WARN
|
||||
#log4j.logger.ALM.HandlerConfigureAlarms=DEBUG
|
||||
#log4j.logger.ALM.HandlerParticipant=DEBUG
|
||||
#log4j.logger.ALM.MainHandler=DEBUG
|
||||
#log4j.logger.ALM.Settings=WARN
|
||||
#log4j.logger.ALM.Publisher=WARN
|
||||
#log4j.logger.ALM.Fts=WARN
|
||||
|
||||
# File
|
||||
###########################################################
|
||||
log4j.appender.file=Lts::RollingFileAppender
|
||||
log4j.appender.file.MaxFileSize=1MB
|
||||
log4j.appender.file.MaxBackupIndex=9
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Console
|
||||
###########################################################
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern= %d %p %c %c{1} - %m (%-.30F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Syslog
|
||||
###########################################################
|
||||
log4j.appender.syslog=org.apache.log4j.SyslogAppender
|
||||
log4j.appender.syslog.Threshold=ERROR
|
||||
log4j.appender.syslog.SysLogHost=localhost
|
||||
log4j.appender.syslog.Facility=LOCAL7
|
||||
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
|
||||
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
|
||||
|
||||
|
||||
###########################################################
|
||||
###########################################################
|
||||
###########################################################
|
||||
# 1) Available Levels in LOG4CXX Version 0.10.0:
|
||||
# TRACE,
|
||||
# DEBUG,
|
||||
# INFO,
|
||||
# WARN,
|
||||
# ERROR
|
||||
# FATAL
|
||||
#
|
||||
# d = date/time
|
||||
# p = priority (Level)
|
||||
# c = category/channel
|
||||
# m = message
|
||||
# F = file
|
||||
# L = line
|
||||
# n = platform dependent line separator character or characters.
|
||||
# ....
|
||||
#
|
||||
# Examples for console:
|
||||
# a)
|
||||
# %d %p %c #%m# (%.50F:%L)%n
|
||||
# date/time
|
||||
# priority
|
||||
# category/channel
|
||||
# #message#
|
||||
# (Maximal 50Character des Filename von rechts:Line)
|
||||
# line separator
|
||||
#
|
||||
# b)
|
||||
# %d (%.15F:%L) %-5p %c |#| %m%n
|
||||
# date/time
|
||||
# (Maximal 15Character des Filename von rechts:Line)
|
||||
# priority, Right pad with spaces if the priority name is less than 5 characters long.
|
||||
# category/channel
|
||||
# message
|
||||
# line separator
|
||||
#
|
||||
# Examples for files:
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Export definitions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hanna E. Rathje, SLSE, 2015-08-04
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef ALM_COMMON_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define ALM_COMMON_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCALMCOMMON_LIB)
|
||||
# define ALM_COMMON_EXPORT Q_DECL_EXPORT
|
||||
# ifndef WIN32
|
||||
# ifdef NDDSUSERDllExport
|
||||
# undef NDDSUSERDllExport
|
||||
# endif
|
||||
# define NDDSUSERDllExport Q_DECL_EXPORT
|
||||
# endif
|
||||
# else
|
||||
# define ALM_COMMON_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ALM_CLIENT_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define ALM_CLIENT_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCALMCLIENT_LIB)
|
||||
# define ALM_CLIENT_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define ALM_CLIENT_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ALM_SERVER_EXPORT
|
||||
# ifdef BUILD_STATIC_LIBRARIES
|
||||
# define ALM_SERVER_EXPORT
|
||||
# else
|
||||
# if defined(MAKE_SVCALMSERVER_LIB)
|
||||
# define ALM_SERVER_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define ALM_SERVER_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
Executable
+153
@@ -0,0 +1,153 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<service namespace="AlarmManagement" abbreviation="ALM" procNames="AlarmManagement" exerciseDependency="Exercise">
|
||||
<rcs>
|
||||
<Id Id="$Id$"/>
|
||||
<HeadURL HeadURL="$HeadURL$"/>
|
||||
<Author Author="$Author$"/>
|
||||
</rcs>
|
||||
<operatorRights offset="45">
|
||||
<guiPlugin name="AlarmManagement" offset="1">
|
||||
<operatorRightGroup name="Alarm Management (Global)" description="Configure Alarms">
|
||||
<operatorRight right="ConfigGlobalDialog" value="1" description="Configure Alarms"/>
|
||||
</operatorRightGroup>
|
||||
</guiPlugin>
|
||||
<guiPlugin name="AlmConfigParticipantAlarms" offset="2">
|
||||
<operatorRightGroup name="Alarm Management (Participants)" description="Configure Participant Alarms">
|
||||
<operatorRight right="ConfigParticipantDialog" value="1" description="Configure Participant Alarms"/>
|
||||
</operatorRightGroup>
|
||||
</guiPlugin>
|
||||
<guiPlugin name="AlmEmergencyCall" offset="3">
|
||||
<operatorRightGroup name="Emergency Call" description="Allow User to Handle Emergency Calls">
|
||||
<operatorRight right="EmergencyCall" value="1" description="Allow User to Handle Emergency Calls"/>
|
||||
</operatorRightGroup>
|
||||
</guiPlugin>
|
||||
</operatorRights>
|
||||
<tables>
|
||||
<table name="alm_config">
|
||||
<column name="id" datatype="integer" isPrimaryKey="1">
|
||||
<sequence start="1" increment="1"/>
|
||||
</column>
|
||||
<column name="operator_id" datatype="integer" isForeignKey="1"/>
|
||||
<column name="event_type_id" datatype="integer" isForeignKey="1"/>
|
||||
<column name="set_marker" datatype="boolean"/>
|
||||
<column name="message_window" datatype="boolean"/>
|
||||
<column name="participant_id" datatype="integer" isOptional="1" isForeignKey="1"/>
|
||||
<column name="global" datatype="boolean"/>
|
||||
<column name="vulnerability_state" datatype="integer" comment="-1 = All Types other Values see PDM-&gt;Service-&gt;Enumerations-&gt;VulnerabilityState"/>
|
||||
<constraint name="IDX_operator_id" type="index">
|
||||
<column name="operator_id"/>
|
||||
</constraint>
|
||||
<foreignKey name="FK_alm_config_opm_operator">
|
||||
<source table="alm_config" column="operator_id"/>
|
||||
<destination service="OperatorManagement" serviceAbbr="opm" schema="opm" table="opm_operator" column="id"/>
|
||||
</foreignKey>
|
||||
<foreignKey name="FK_alm_config_pdm_event_type">
|
||||
<source table="alm_config" column="event_type_id"/>
|
||||
<destination service="ProjectDataManagement" serviceAbbr="pdm" schema="pdm" table="pdm_event_type" column="id"/>
|
||||
</foreignKey>
|
||||
<foreignKey name="FK_alm_config_ppm_participant">
|
||||
<source table="alm_config" column="participant_id"/>
|
||||
<destination service="ParticipantManagement" serviceAbbr="ppm" table="ppm_participant" column="id"/>
|
||||
</foreignKey>
|
||||
</table>
|
||||
<table name="alm_emergency_call">
|
||||
<column name="id" datatype="integer" isPrimaryKey="1">
|
||||
<sequence start="1" increment="1"/>
|
||||
</column>
|
||||
<column name="sample_time" datatype="bigint"/>
|
||||
<column name="incoming_time" datatype="bigint"/>
|
||||
<column name="name" datatype="text"/>
|
||||
<column name="issi" datatype="integer"/>
|
||||
<column name="position" datatype="point_2d"/>
|
||||
<column name="expired" datatype="boolean"/>
|
||||
<column name="operator_id" datatype="integer"/>
|
||||
<column name="deleted" datatype="bigint"/>
|
||||
<column name="comment" datatype="text"/>
|
||||
</table>
|
||||
</tables>
|
||||
<views/>
|
||||
<dbServiceStructs>
|
||||
<serviceStruct name="AlmConfig" table="alm_config"/>
|
||||
<table name="alm_config"/>
|
||||
<serviceStruct name="AlmEmergencyCall" table="alm_emergency_call"/>
|
||||
<table name="alm_emergency_call"/>
|
||||
</dbServiceStructs>
|
||||
<topicTypes>
|
||||
<topicType name="AlmEmergencyCall" isDataObject="1" routeToClient="1" routeToServer="0" routeInReplay="0" recordTopic="1" >
|
||||
<column name="id" idlType="long" isKey="1"/>
|
||||
<column name="sampleTime" idlType="long long"/>
|
||||
<column name="incomingTime" idlType="long long"/>
|
||||
<column name="name" idlType="string"/>
|
||||
<column name="issi" idlType="long"/>
|
||||
<column name="position" idlType="Core::GeoPosition2D"/>
|
||||
<column name="expired" idlType="boolean"/>
|
||||
<column name="operatorId" idlType="long"/>
|
||||
<column name="deleted" idlType="long long"/>
|
||||
<column name="comment" idlType="string"/>
|
||||
</topicType>
|
||||
<topicType name="EmergencyCallAcknowledgeRequest">
|
||||
<column name="id" idlType="long"/>
|
||||
<column name="timestamp" idlType="long long"/>
|
||||
<column name="incomingTime" idlType="long long"/>
|
||||
<column name="name" idlType="string"/>
|
||||
<column name="issi" idlType="long"/>
|
||||
<column name="operatorId" idlType="long"/>
|
||||
<column name="comment" idlType="string"/>
|
||||
<column name="expired" idlType="boolean"/>
|
||||
</topicType>
|
||||
<topicType name="AlarmAction">
|
||||
<column name="setMarker" idlType="boolean"/>
|
||||
<column name="messageWindow" idlType="boolean"/>
|
||||
<column name="eventTypeId" idlType="ProjectDataManagement::EventType"/>
|
||||
<column name="vulnerabilityState" idlType="long" comment="Only trigger, when this state is reached"/>
|
||||
</topicType>
|
||||
<topicType name="AlarmConfig" isDataObject="1" routeToClient="1" routeToServer="0" routeInReplay="0">
|
||||
<column name="operatorId" idlType="long"/>
|
||||
<column name="participantId" idlType="long"/>
|
||||
<column name="eventTypeId" idlType="ProjectDataManagement::EventType"/>
|
||||
<column name="messageWindow" idlType="boolean"/>
|
||||
<column name="setMarker" idlType="boolean"/>
|
||||
<column name="id" idlType="long" isKey="1"/>
|
||||
<column name="global" idlType="boolean"/>
|
||||
<column name="vulnerabilityState" idlType="long"/>
|
||||
</topicType>
|
||||
<topicType name="ConfigureAlarmsRequest">
|
||||
<column name="alarms" idlType="sequence<AlarmAction>"/>
|
||||
<column name="operatorId" idlType="long"/>
|
||||
<column name="participantIds" idlType="sequence<long>" comment="<ul> <li>Any event that comes for a participant in the list is sent as an alarm.</li> </ul> <ul> <li>If the participant is 0, an alarm is sent for each event independently of the participant.</li> </ul>"/>
|
||||
<column name="global" idlType="boolean" comment="global/local Alarm"/>
|
||||
<column name="remove" idlType="boolean" comment="Remove alarm from Service, DDS and DB"/>
|
||||
</topicType>
|
||||
<topicType name="Notification" isDataObject="1" routeToClient="1" routeToServer="0" routeInReplay="0">
|
||||
<column name="id" idlType="long" isKey="1"/>
|
||||
<column name="operatorId" idlType="long"/>
|
||||
<column name="eventId" idlType="long" comment="ExerciseEventManagement::EventType"/>
|
||||
<column name="eventType" idlType="ProjectDataManagement::EventType"/>
|
||||
<column name="time" idlType="long long"/>
|
||||
<column name="equipmentNumber" idlType="long"/>
|
||||
<column name="participantId" idlType="long" isOptional="1"/>
|
||||
<column name="aesId" idlType="long" isOptional="1"/>
|
||||
<column name="position" idlType="Core::GeoPosition"/>
|
||||
<column name="properties" idlType="string" comment="Json-Object: Globale und lokale Borderlines: Global (Type boolean: true = global, false = local) optional Global, FriendlyFire , equipmentNumber, EventTypeId, participantId, aesId"/>
|
||||
</topicType>
|
||||
<topicType name="AcknowledgeSOSInAllExercises" isDataObject="1" >
|
||||
<column name="id" idlType="long" isKey="1"/>
|
||||
<column name="timestamp" idlType="long long"/>
|
||||
<column name="incomingTime" idlType="long long"/>
|
||||
<column name="name" idlType="string"/>
|
||||
<column name="issi" idlType="long"/>
|
||||
<column name="operatorId" idlType="long"/>
|
||||
<column name="comment" idlType="string"/>
|
||||
<column name="expired" idlType="boolean"/>
|
||||
</topicType>
|
||||
</topicTypes>
|
||||
<functionTopics>
|
||||
<functionTopic name="EmergencyCallAcknowledge" requestTopicType="EmergencyCallAcknowledgeRequest" replyTopicType="Core::FunctionReply" requestTopicName="EmergencyCallAcknowledgeRequest" replyTopicName="EmergencyCallAcknowledgeReply" routeInReplay="0"/>
|
||||
<functionTopic name="ConfigureAlarms" requestTopicType="ConfigureAlarmsRequest" replyTopicType="Core::FunctionReply" requestTopicName="ConfigureAlarmsRequest" replyTopicName="ConfigureAlarmsReply" routeInReplay="0"/>
|
||||
</functionTopics>
|
||||
<enumerations>
|
||||
<enumeration name="Dummy">
|
||||
<attribute key="dummy1" value="1"/>
|
||||
</enumeration>
|
||||
</enumerations>
|
||||
</service>
|
||||
Executable
+97
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* DdsHandler for DDS
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by gr, SLSE, 2015-09-02
|
||||
*/
|
||||
|
||||
#include "dds_handler.h"
|
||||
#include <DDS/DTS/generic_dts_impl.h>
|
||||
#include <DDS/DDSConnector/publisher.h>
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
|
||||
DdsHandler::DdsHandler(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector)
|
||||
: m_ddsConnector(ddsConnector)
|
||||
, m_logger(getLogger("DdsHandler"))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "DdsHandler(" << m_ddsConnector->getDomainId() << ") for partition: " << m_ddsConnector->getDefaultPartition();
|
||||
}
|
||||
|
||||
bool DdsHandler::init(const QStringList &qosFileList)
|
||||
{
|
||||
if (!m_ddsConnector->init(qosFileList))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error initializing dds connections - aborting";
|
||||
return false;
|
||||
}
|
||||
|
||||
// default initialize Publisher and Subscriber
|
||||
m_ddsConnector->initPublisherSubscriber();
|
||||
|
||||
// has to be false, because Snapshot Data Topics can be very large and fragmentation is not supported for batched writers!
|
||||
m_ddsConnector->enableBatchedWriter(false);
|
||||
|
||||
m_topicLockMaster = std::make_shared<Core::TopicLockMaster>(m_ddsConnector);
|
||||
|
||||
m_dtcCore = Core::Interface::Dtc::create(m_ddsConnector);
|
||||
m_dtcCore->enablePartitionTime();
|
||||
|
||||
m_dtsAlm = AlarmManagement::Interface::Dts::create(m_ddsConnector);
|
||||
bool bRet = m_dtsAlm->enableAll();
|
||||
INFO_LOG(m_logger) << "Dts initialised";
|
||||
|
||||
m_dtcAlm = AlarmManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
bRet &= m_dtcAlm->enableAcknowledgeSOSInAllExercises();
|
||||
INFO_LOG(m_logger) << "Dts initialised";
|
||||
|
||||
m_ftsAlm = AlarmManagement::Interface::Fts::create(m_ddsConnector);
|
||||
bRet &= m_ftsAlm->enableAll();
|
||||
INFO_LOG(m_logger) << "Fts initialised";
|
||||
|
||||
m_dtcEem = ExerciseEventManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
bRet &= m_dtcEem->enableEvent();
|
||||
INFO_LOG(m_logger) << "Dtc EEM initialised";
|
||||
|
||||
m_ftcMrk = MarkerManagement::Interface::Ftc::create(m_ddsConnector);
|
||||
bRet &= m_ftcMrk->enableMarkerModify();
|
||||
INFO_LOG(m_logger) << "Ftc MRK initialised";
|
||||
|
||||
m_dtcPpm = ParticipantManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
bRet &= m_dtcPpm->enableParticipant();
|
||||
INFO_LOG(m_logger) << "Dtc PPM initialised";
|
||||
|
||||
m_exmDtc = ExerciseManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
bRet &= m_exmDtc->enableExercise();
|
||||
|
||||
m_dtcTab = TrainingAreaBase::Interface::Dtc::create(m_ddsConnector);
|
||||
bRet &= m_dtcTab->enableEmergencyCall();
|
||||
INFO_LOG(m_logger) << "Dtc TAB initialised";
|
||||
|
||||
|
||||
m_dtsEmergencyCallPublisher = std::make_shared<DDSConnector::Publisher>(m_ddsConnector->getDomainParticipant(),
|
||||
DDSConnector::DdsConnector::getPartitionString(IDL::PartitionType::AllExercises));
|
||||
|
||||
m_dtsEmergencyCall = std::make_shared<DTS::AcknowledgeSOSInAllExercisesImpl>(m_ddsConnector->getDomainParticipant(),
|
||||
m_dtsEmergencyCallPublisher->getDdsPublisher(),
|
||||
DDS::Helper::getShortTopicName(DDS::topic_type_name<AlarmManagement::AcknowledgeSOSInAllExercises>::value()));
|
||||
|
||||
INFO_LOG(m_logger) << "Dtc TAB initialised";
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
int DdsHandler::exerciseId() const
|
||||
{
|
||||
return m_ddsConnector->getPartitionId();
|
||||
} // end of init
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
qint64 DdsHandler::currentPartitionTime() const
|
||||
{
|
||||
return m_dtcCore->partitionTime().timeStamp();
|
||||
}
|
||||
|
||||
} // Namespace AlarmManagement
|
||||
Executable
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* DdsHandler for DDS
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by gr, SLSE, 2015-09-02
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <DDS/Core/core_dtc.h>
|
||||
#include <DDS/Core/topic_lock_master.h>
|
||||
#include <AlarmManagement/alm_dts.h>
|
||||
#include <AlarmManagement/alm_dtc.h>
|
||||
#include <AlarmManagement/alm_fts.h>
|
||||
#include <AlarmManagement/alm_dts_types.h>
|
||||
#include <ExerciseEventManagement/eem_dtc.h>
|
||||
#include <MarkerManagement/mrk_ftc.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <TrainingAreaBase/tab_dtc.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
#include "logger.h"
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
class DdsHandler final
|
||||
{
|
||||
public:
|
||||
explicit DdsHandler(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector);
|
||||
~DdsHandler() = default;
|
||||
|
||||
bool init(const QStringList &qosFileList = QStringList());
|
||||
|
||||
std::shared_ptr<DDSConnector::DdsConnector> dds() const { return m_ddsConnector; }
|
||||
|
||||
std::shared_ptr<AlarmManagement::Interface::Dts> dtsAlm() const { return m_dtsAlm;} ///< Pointer to DTS AlarmManagement interface object
|
||||
std::shared_ptr<AlarmManagement::Interface::Dtc> dtcAlm() const { return m_dtcAlm;} ///< Pointer to DTC AlarmManagement interface object
|
||||
std::shared_ptr<AlarmManagement::Interface::Fts> ftsAlm() const { return m_ftsAlm;} ///< Pointer to FTS AlarmManagement interface object
|
||||
std::shared_ptr<ExerciseEventManagement::Interface::Dtc> dtcEem() const { return m_dtcEem;} ///< Pointer to DTC ExerciseEventManagement interface object
|
||||
std::shared_ptr<MarkerManagement::Interface::Ftc> ftcMrk() const { return m_ftcMrk;}
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> dtcPpm() const { return m_dtcPpm;} ///< Pointer to DTC Participant Management interface object
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Dtc> dtcTab() const { return m_dtcTab;} ///< Pointer to DTC TrainingAreaBase Management interface object
|
||||
std::shared_ptr<DTS::AcknowledgeSOSInAllExercises> publishSOS() const {return m_dtsEmergencyCall;}
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> dtcExm() const {return m_exmDtc;}
|
||||
|
||||
std::shared_ptr<Core::TopicLockMaster> topicLockMaster() const { return m_topicLockMaster; }
|
||||
|
||||
int exerciseId() const;
|
||||
qint64 currentPartitionTime() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
std::shared_ptr<Core::Interface::Dtc> m_dtcCore;
|
||||
std::shared_ptr<Core::TopicLockMaster> m_topicLockMaster;
|
||||
|
||||
std::shared_ptr<AlarmManagement::Interface::Dts> m_dtsAlm; ///< Pointer to DTS AlarmManagement interface object
|
||||
std::shared_ptr<AlarmManagement::Interface::Dtc> m_dtcAlm; ///< Pointer to DTC AlarmManagement interface object
|
||||
std::shared_ptr<AlarmManagement::Interface::Fts> m_ftsAlm; ///< Pointer to FTS AlarmManagement interface object
|
||||
std::shared_ptr<ExerciseEventManagement::Interface::Dtc> m_dtcEem;
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
|
||||
std::shared_ptr<MarkerManagement::Interface::Ftc> m_ftcMrk;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtcPpm;
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Dtc> m_dtcTab;
|
||||
std::shared_ptr<DDSConnector::Publisher> m_dtsEmergencyCallPublisher;
|
||||
std::shared_ptr<DTS::AcknowledgeSOSInAllExercises> m_dtsEmergencyCall;
|
||||
|
||||
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
+404
@@ -0,0 +1,404 @@
|
||||
/**
|
||||
* Handler for message data request
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by hjl, SLSE, 2016-10-12
|
||||
*/
|
||||
|
||||
#include "handler_configure_alarms.h"
|
||||
#include "initialization.h"
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QSet>
|
||||
#include <QTimer>
|
||||
#include <ProjectDataManagement/pdm_translation.h>
|
||||
#include <LtsUtilsCore/json_object.h>
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
static AlarmConfig toDds(const Database::AlmConfig &data)
|
||||
{
|
||||
AlarmConfig almConfig;
|
||||
almConfig.id(data.id);
|
||||
almConfig.operatorId(data.operatorId);
|
||||
if (data.participantId.isValid())
|
||||
almConfig.participantId(data.participantId.toInt());
|
||||
else
|
||||
almConfig.participantId(0);
|
||||
almConfig.eventTypeId(data.eventTypeId);
|
||||
almConfig.messageWindow(data.messageWindow);
|
||||
almConfig.global(data.global);
|
||||
almConfig.vulnerabilityState(data.vulnerabilityState);
|
||||
almConfig.setMarker(data.setMarker);
|
||||
return almConfig;
|
||||
}
|
||||
|
||||
HandlerConfigureAlarms::HandlerConfigureAlarms(Initialization *mainHandler)
|
||||
: QObject()
|
||||
, ConfigureAlarmsRequestHandler(mainHandler->dds()->ftsAlm())
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("HandlerConfigureAlarms"))
|
||||
, m_windowIndex(0)
|
||||
{
|
||||
} // end of ctor()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
HandlerConfigureAlarms::~HandlerConfigureAlarms()
|
||||
{
|
||||
} // end of dtor()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool HandlerConfigureAlarms::init()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Start HandlerConfigureAlarms.";
|
||||
|
||||
auto dtcEem = m_mainHandler->dds()->dtcEem();
|
||||
|
||||
connect(dtcEem.get(), &ExerciseEventManagement::Interface::Dtc::eventChanged,
|
||||
this, &HandlerConfigureAlarms::onEventChanged);
|
||||
|
||||
// publish data from db-table 'alm_config'
|
||||
auto cb = [this](const Database::AlmConfig & data)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "restore AlarmConfig from DB data: id=" << data.id
|
||||
<< " operatorId=" << data.operatorId
|
||||
<< " participantId=" << data.participantId.toInt()
|
||||
<< " global=" << data.global
|
||||
<< " eventTypeId=" << data.eventTypeId
|
||||
<< " setMarker=" << data.setMarker
|
||||
<< " messageWindow=" << data.messageWindow
|
||||
<< " vulnerabilityState=" << data.vulnerabilityState;
|
||||
|
||||
m_mainHandler->dds()->dtsAlm()->publish(toDds(data));
|
||||
m_alarms.insert(data.id, data);
|
||||
};
|
||||
if (!m_mainHandler->db()->select(cb))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error reading data from database 'alm_config'!";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} // end init()
|
||||
|
||||
|
||||
void HandlerConfigureAlarms::removeAlarmConfig(int operatorId,
|
||||
int participantId,
|
||||
int eventTypeId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "removeAlarmConfig m_alarms.size=" << m_alarms.size()
|
||||
<< " operatorId=" << operatorId
|
||||
<< " participantId=" << participantId
|
||||
<< " eventTypeId=" << eventTypeId;
|
||||
|
||||
// Find Key
|
||||
QMapIterator<int, Database::AlmConfig> i(m_alarms);
|
||||
while (i.hasNext())
|
||||
{
|
||||
i.next();
|
||||
DEBUG_LOG(m_logger) << "key= " << i.key() << ": "
|
||||
<< " operatorId=" << i.value().operatorId
|
||||
<< " participantId=" << i.value().participantId.toInt()
|
||||
<< " eventTypeId=" << i.value().eventTypeId.underlying();
|
||||
if ((operatorId == i.value().operatorId)
|
||||
&& (participantId == i.value().participantId)
|
||||
&& (eventTypeId == ProjectDataManagement::EventType_def::Unknown || eventTypeId == i.value().eventTypeId.underlying()))
|
||||
{
|
||||
const int key = i.key();
|
||||
DEBUG_LOG(m_logger) << "found alarm to remove: " << key << ", eventTypeId: " << eventTypeId;
|
||||
m_mainHandler->db()->removeAlmConfig(key);
|
||||
m_mainHandler->dds()->dtsAlm()->removeAlarmConfigByKey(key);
|
||||
m_alarms.remove(key); // is ok, QMapIterator work on a copy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandlerConfigureAlarms::removeGlobalAlarmConfig(int operatorId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "removeAlarmConfig m_alarms.size=" << m_alarms.size();
|
||||
|
||||
// Find Key
|
||||
QMapIterator<int, Database::AlmConfig> i(m_alarms);
|
||||
while (i.hasNext())
|
||||
{
|
||||
i.next();
|
||||
DEBUG_LOG(m_logger) << "key= " << i.key()
|
||||
<< " participantId=" << i.value().participantId.toInt();
|
||||
if ((operatorId == i.value().operatorId)
|
||||
&& (i.value().participantId.toInt()) == 0)
|
||||
{
|
||||
const int key = i.key();
|
||||
DEBUG_LOG(m_logger) << "found alarm to remove: " << key;
|
||||
m_mainHandler->db()->removeAlmConfig(key);
|
||||
m_mainHandler->dds()->dtsAlm()->removeAlarmConfigByKey(key);
|
||||
m_alarms.remove(key); // is ok, QMapIterator work on a copy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerConfigureAlarms::onConfigureAlarmsRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ConfigureAlarmsRequest &request)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onConfigureAlarmsRequest " << request;
|
||||
if (request.participantIds().size() == 0)
|
||||
{
|
||||
Core::FunctionReplyObject ret(0, tr_lts("dds", "Error adding ConfigureAlarms to database. There were no participants given."));
|
||||
m_mainHandler->dds()->ftsAlm()->configureAlarmsReply(cookie, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.remove())
|
||||
{
|
||||
// remove only this one Alarm, not all types of the participant for operator
|
||||
// in DB,
|
||||
// from DDS
|
||||
DEBUG_LOG(m_logger) << "request.remove()";
|
||||
if (request.participantIds().size() > 0 &&
|
||||
request.alarms().size() > 0)
|
||||
{
|
||||
int participantId = request.participantIds()[0];
|
||||
int eventTypeId = request.alarms()[0].eventTypeId().underlying();
|
||||
DEBUG_LOG(m_logger) << "removeAlarmConfig(request.operatorId()=" << request.operatorId()
|
||||
<< " participantId=" << participantId
|
||||
<< " eventTypeId=" << eventTypeId;
|
||||
removeAlarmConfig(request.operatorId(), participantId, eventTypeId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove old configuration
|
||||
for (int participantId : request.participantIds())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "remove old configuration participantId=" << participantId;
|
||||
removeAlarmConfig(request.operatorId(), participantId, 0);
|
||||
}
|
||||
if ( request.global())
|
||||
{
|
||||
removeGlobalAlarmConfig(request.operatorId());
|
||||
}
|
||||
|
||||
for (int participantId : request.participantIds())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "participantId: " << participantId;
|
||||
for (const AlarmManagement::AlarmAction &action : request.alarms())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "action: " << action;
|
||||
|
||||
AlarmManagement::AlarmConfig almConfig;
|
||||
almConfig.operatorId(request.operatorId());
|
||||
almConfig.participantId(participantId);
|
||||
almConfig.eventTypeId(action.eventTypeId());
|
||||
almConfig.messageWindow(action.messageWindow());
|
||||
almConfig.vulnerabilityState(action.vulnerabilityState());
|
||||
almConfig.setMarker(action.setMarker());
|
||||
almConfig.global(request.global());
|
||||
|
||||
Database::AlmConfig newConfig;
|
||||
newConfig.operatorId = request.operatorId();
|
||||
if (participantId != 0)
|
||||
newConfig.participantId = participantId;
|
||||
|
||||
newConfig.eventTypeId = action.eventTypeId();
|
||||
newConfig.messageWindow = action.messageWindow();
|
||||
newConfig.vulnerabilityState = action.vulnerabilityState();
|
||||
newConfig.setMarker = action.setMarker();
|
||||
newConfig.global = request.global();
|
||||
if (!m_mainHandler->db()->insert(newConfig))
|
||||
{
|
||||
Core::FunctionReplyObject ret(0, tr_lts("dds", "Error adding ConfigureAlarms to database."));
|
||||
m_mainHandler->dds()->ftsAlm()->configureAlarmsReply(cookie, ret);
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "m_dbAlmConfig.insert id=" << newConfig.id;
|
||||
|
||||
almConfig.id(newConfig.id);
|
||||
m_alarms.insert(newConfig.id, newConfig);
|
||||
m_mainHandler->dds()->dtsAlm()->publish(almConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_mainHandler->dds()->ftsAlm()->configureAlarmsReply(cookie, Core::FunctionReplyObject());
|
||||
|
||||
} // end onConfigureAlarmsRequest()
|
||||
//-----------------------------------------------------------------------------
|
||||
void HandlerConfigureAlarms::onEventChanged(const ExerciseEventManagement::Event &eventData, DataModification modType)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onParticipantEventChanged participantId=" << eventData.participantId();
|
||||
if (modType == DataModification::eRemoved ||
|
||||
modType == DataModification::eModified)
|
||||
return;
|
||||
DEBUG_LOG(m_logger) << "onParticipantEventChanged verarbeiten m_alarms.size =" << m_alarms.size();
|
||||
|
||||
ExerciseEventManagement::Event eventDatalocal = eventData;
|
||||
|
||||
QVector<int> participants;
|
||||
QSet<int> sentEventToOperator;
|
||||
|
||||
// toBool() returns false if attribute does not exist
|
||||
const QJsonObject eventObject = getEventProperties(eventDatalocal);
|
||||
const bool friendlyFireBool = eventObject.value(QStringLiteral("FriendlyFire")).toBool();
|
||||
const int vulnerabilityState = eventObject.value(QStringLiteral("vulnerabilityState")).toInt();
|
||||
|
||||
// Schleife ueber jede Konfiguration,
|
||||
// pruefen, ob eventTypeId == EventTypeId
|
||||
// Schleife ueber jeden Participant in der Konfiguration
|
||||
// Vergleich Participant-ID Event mit Konfiguration Event
|
||||
// Wenn ja, Alarm an operatorId schicken
|
||||
for (const Database::AlmConfig &alarm : qAsConst(m_alarms))
|
||||
{
|
||||
{
|
||||
/*DEBUG_LOG(m_logger) << " alarmConfigItem.id=" << alarm.id
|
||||
<< " alarmConfigItem.participantId=" << alarm.participantId
|
||||
<< " alarmConfigItem.eventTypeId=" << alarm.eventTypeId
|
||||
<< " eventDatalocal.eventTypeId()=" << eventDatalocal.eventTypeId().underlying()
|
||||
<< " alarm.operatorId=" << alarm.operatorId
|
||||
<< " friendyFire =" << friendlyFireBool;*/
|
||||
|
||||
if ((alarm.eventTypeId == eventDatalocal.eventTypeId().underlying()) ||
|
||||
(alarm.eventTypeId == ProjectDataManagement::EventType_def::FriendlyFire && friendlyFireBool))
|
||||
{
|
||||
if (friendlyFireBool && eventDatalocal.eventTypeId() == ProjectDataManagement::EventType_def::FireEvent)
|
||||
eventDatalocal.eventTypeId(ProjectDataManagement::EventType_def::FriendlyFire);
|
||||
|
||||
participants.clear();
|
||||
if (alarm.participantId.isValid())
|
||||
participants = m_mainHandler->hdlParticipant()->getRecursiveInferiorIds(alarm.participantId.toInt());
|
||||
else
|
||||
participants.append(0);
|
||||
|
||||
for (int participantId : qAsConst(participants))
|
||||
{
|
||||
bool allVulnerabilityStates = alarm.vulnerabilityState == -1;
|
||||
bool vulnerabilityCheck = vulnerabilityState == alarm.vulnerabilityState;
|
||||
bool globalAlarm = participantId == 0;
|
||||
DEBUG_LOG(m_logger) << " allVulnerabilityStates=" << allVulnerabilityStates
|
||||
<< " vulnerabilityCheck=" << vulnerabilityCheck
|
||||
<< " participantId=" << participantId
|
||||
<< " eventDatalocal.participantId()=" << eventDatalocal.participantId();
|
||||
if (((allVulnerabilityStates || vulnerabilityCheck) &&
|
||||
(participantId == eventDatalocal.participantId())) || globalAlarm)
|
||||
{
|
||||
if (sentEventToOperator.contains(alarm.operatorId))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Event " << eventDatalocal.eventTypeId() << " already handled for Operator:" << alarm.operatorId;
|
||||
continue;
|
||||
}
|
||||
|
||||
sentEventToOperator += alarm.operatorId;
|
||||
if (alarm.messageWindow)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "send Window to Operator:" << alarm.operatorId;
|
||||
sendWindow(eventDatalocal, alarm);
|
||||
}
|
||||
if (alarm.setMarker)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "set Marker to Operator:" << alarm.operatorId;
|
||||
sendMarker(eventDatalocal, alarm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end onParticipantEventChanged
|
||||
|
||||
|
||||
void HandlerConfigureAlarms::sendWindow(const ExerciseEventManagement::Event &eventData,
|
||||
const Database::AlmConfig &config)
|
||||
{
|
||||
AlarmManagement::Notification wi;
|
||||
QJsonObject eventObject = getEventProperties(eventData);
|
||||
QJsonObject obj;
|
||||
|
||||
wi.id(m_windowIndex);
|
||||
wi.operatorId(config.operatorId);
|
||||
wi.time(eventData.sampleTime());
|
||||
wi.eventId(eventData.id());
|
||||
|
||||
if (eventData.eventTypeId() == ProjectDataManagement::EventType_def::CrossGlobalBorderline
|
||||
|| eventData.eventTypeId() == ProjectDataManagement::EventType_def::CrossLocalBorderline)
|
||||
{
|
||||
if (eventObject.contains(QStringLiteral("Global")))
|
||||
obj[QStringLiteral("Global")] = eventObject.value(QStringLiteral("Global"));
|
||||
}
|
||||
if (eventObject.contains(QStringLiteral("FriendlyFire")))
|
||||
obj[QStringLiteral("FriendlyFire")] = eventObject.value(QStringLiteral("FriendlyFire"));
|
||||
if (eventObject.contains(QStringLiteral("AesId")))
|
||||
wi.aesId(eventObject.value(QStringLiteral("AesId")).toInt());
|
||||
// AesEvent from the radio:
|
||||
int originatorType = eventObject[QStringLiteral("OriginatorType")].toInt();
|
||||
if (originatorType == ProjectDataManagement::StateChangeOriginator_def::AreaEffectSimulation
|
||||
|| originatorType == ProjectDataManagement::StateChangeOriginator_def::FunctionalArea)
|
||||
obj[QStringLiteral("aesId")] = eventObject[QStringLiteral("OriginatorId")].toInt();
|
||||
|
||||
wi.equipmentNumber(eventData.equipmentNumber());
|
||||
wi.eventType(eventData.eventTypeId());
|
||||
wi.participantId(eventData.participantId());
|
||||
wi.position(eventData.position());
|
||||
|
||||
const QByteArray propertiesStr = QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||
wi.properties() = propertiesStr.data();
|
||||
m_mainHandler->dds()->dtsAlm()->publish(wi);
|
||||
// take data from dds-bus after 1 min
|
||||
const auto id = wi.id();
|
||||
QTimer::singleShot(1 * 60 * 1000, this, [id, this]() { m_mainHandler->dds()->dtsAlm()->removeNotificationByKey(id); });
|
||||
incrementWindowIndex(); // m_windowIndex++;
|
||||
|
||||
} // end sendWindow
|
||||
|
||||
|
||||
|
||||
QJsonObject HandlerConfigureAlarms::getEventProperties(const ExerciseEventManagement::Event &eventData)
|
||||
{
|
||||
return LtsUtils::JsonObject::fromJson(eventData.properties());
|
||||
}
|
||||
|
||||
void HandlerConfigureAlarms::sendMarker(const ExerciseEventManagement::Event &eventData,
|
||||
const Database::AlmConfig &config)
|
||||
{
|
||||
int defaultOffset = 10000;
|
||||
|
||||
DEBUG_LOG(m_logger) << "eventProperties =" << eventData.properties();
|
||||
|
||||
QString contentStr;
|
||||
contentStr = QStringLiteral("Equip No.: ");
|
||||
const int participantId = eventData.participantId();
|
||||
const int equipNo = m_mainHandler->hdlParticipant()->participantId2EquipNo(participantId);
|
||||
QJsonObject eventObject = getEventProperties(eventData);
|
||||
|
||||
contentStr += QString::number(equipNo);
|
||||
contentStr += QStringLiteral(" ");
|
||||
contentStr += ProjectDataManagement::toString(eventData.eventTypeId());
|
||||
if (eventObject.contains(QStringLiteral("AesName")))
|
||||
{
|
||||
contentStr += QStringLiteral(" (");
|
||||
contentStr += eventObject.value(QStringLiteral("AesName")).toString();
|
||||
contentStr += QStringLiteral(")");
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "contentStr=" << contentStr;
|
||||
|
||||
const QByteArray contentArr = contentStr.toUtf8();
|
||||
|
||||
MarkerManagement::MarkerDescription ma;
|
||||
ma.content(contentArr.data());
|
||||
ma.markerType(MarkerManagement::MarkerType_def::Situation);
|
||||
|
||||
MarkerManagement::Marker mcr;
|
||||
mcr.operatorId(config.operatorId);
|
||||
mcr.note(ma.content()); // really?
|
||||
mcr.timeStamp(eventData.sampleTime());
|
||||
mcr.timeStampOffset(defaultOffset);
|
||||
mcr.descriptions().push_back(ma);
|
||||
mcr.position(eventData.position());
|
||||
mcr.fileContentId(0); // we cannot save an image here
|
||||
m_mainHandler->dds()->ftcMrk()->markerModifyRequest(mcr, this);
|
||||
|
||||
} // end sendMarker
|
||||
|
||||
void HandlerConfigureAlarms::onMarkerModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
Q_UNUSED(replyObject);
|
||||
INFO_LOG(m_logger) << "************** onMarkerCreateReply";
|
||||
} // end onMarkerCreateReply
|
||||
} // namespace AlarmManagement
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Handler for table-io message data request
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by hjl, SLSE, 2016-10-12
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include "dds_handler.h"
|
||||
#include "logger.h"
|
||||
#include <alm_db.h>
|
||||
|
||||
#include <AlarmManagement/alm_fts.h>
|
||||
#include <AlarmManagement/alm_ftc.h>
|
||||
#include <AlarmManagement/alm_dtc.h>
|
||||
#include <AlarmManagement/alm_dts.h>
|
||||
|
||||
#include <ExerciseEventManagement/eem_dtc.h>
|
||||
#include <MarkerManagement/mrk_ftc.h>
|
||||
#include <handler_participant.h>
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
class Initialization;
|
||||
|
||||
class HandlerConfigureAlarms final
|
||||
: public QObject
|
||||
, protected Interface::Fts::ConfigureAlarmsRequestHandler
|
||||
, protected MarkerManagement::Interface::Ftc::MarkerModifyReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HandlerConfigureAlarms(Initialization *mainHandler);
|
||||
|
||||
~HandlerConfigureAlarms();
|
||||
|
||||
bool init();
|
||||
|
||||
void onMarkerModifyReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
void incrementWindowIndex() { m_windowIndex++; }
|
||||
int getWindowIndex() const { return m_windowIndex; }
|
||||
|
||||
|
||||
private Q_SLOTS:
|
||||
void onEventChanged(const ExerciseEventManagement::Event &eventData, DataModification modType);
|
||||
|
||||
private: // methods
|
||||
void onConfigureAlarmsRequest(const rti::core::SampleIdentity &cookie,
|
||||
const ConfigureAlarmsRequest &request) override;
|
||||
void sendWindow(const ExerciseEventManagement::Event &eventData,
|
||||
const Database::AlmConfig &config);
|
||||
void sendMarker(const ExerciseEventManagement::Event &eventData,
|
||||
const Database::AlmConfig &config);
|
||||
static QJsonObject getEventProperties(const ExerciseEventManagement::Event &eventData);
|
||||
|
||||
void removeAlarmConfig(int operatorId, int participantId, int eventTypeId);
|
||||
void removeGlobalAlarmConfig(int operatorId);
|
||||
|
||||
private: // attributes
|
||||
Initialization *m_mainHandler;
|
||||
|
||||
struct AlarmKey
|
||||
{
|
||||
int operatorId = 0;
|
||||
int participantId = 0;
|
||||
AlarmKey() = default;
|
||||
explicit AlarmKey(const Database::AlmConfig &db)
|
||||
: operatorId(db.operatorId)
|
||||
, participantId(db.participantId.isNull() ? 0 : db.participantId.toInt())
|
||||
{}
|
||||
explicit AlarmKey(int operatorId_, int participantId_)
|
||||
: operatorId(operatorId_)
|
||||
, participantId(participantId_)
|
||||
{}
|
||||
|
||||
bool operator<(const AlarmKey &o) const
|
||||
{
|
||||
if (operatorId != o.operatorId)
|
||||
return operatorId < o.operatorId;
|
||||
return participantId < o.participantId;
|
||||
}
|
||||
};
|
||||
QMap<int, Database::AlmConfig> m_alarms; // Key = almConfig.id
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
int m_windowIndex;
|
||||
};
|
||||
} // namespace AlarmManagement
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* Handler emergency call from tetra radio
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Astrid Müller, SGAS, 2018-02-23
|
||||
*/
|
||||
|
||||
#include "handler_emergency_call.h"
|
||||
#include "initialization.h"
|
||||
#include "handler_configure_alarms.h"
|
||||
#include "object_emergency_call.h"
|
||||
#include "alm_db.h"
|
||||
#include <DDS/DTS/generic_dts.h>
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QDebug>
|
||||
namespace AlarmManagement
|
||||
{
|
||||
HandlerEmergencyCall::HandlerEmergencyCall(const std::shared_ptr<HandlerConfigureAlarms> &configAlarmHandler,
|
||||
Initialization *mainHandler)
|
||||
: QObject()
|
||||
, EmergencyCallAcknowledgeRequestHandler(mainHandler->dds()->ftsAlm())
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_configAlarmHandler(configAlarmHandler)
|
||||
, m_logger(getLogger("HandlerEmergencyCall"))
|
||||
{
|
||||
}
|
||||
|
||||
HandlerEmergencyCall::~HandlerEmergencyCall()
|
||||
{
|
||||
}
|
||||
|
||||
bool HandlerEmergencyCall::init()
|
||||
{
|
||||
INFO_LOG(m_logger) << "Start HandlerEmergencyCall.";
|
||||
|
||||
auto dtcTab = m_mainHandler->dds()->dtcTab();
|
||||
|
||||
connect(dtcTab.get(), &TrainingAreaBase::Interface::Dtc::emergencyCallChanged,
|
||||
this, &HandlerEmergencyCall::onEmergencyCallChanged);
|
||||
connect(m_mainHandler->dds()->dtcAlm().get(), &AlarmManagement::Interface::Dtc::acknowledgeSOSInAllExercisesChanged,
|
||||
this, &HandlerEmergencyCall::onAcknowledgeSOSInExercises);
|
||||
|
||||
|
||||
// create and init Object
|
||||
bool bRet = true;
|
||||
auto cbEmergencyCall = [this, &bRet](const Database::AlmEmergencyCall &data)
|
||||
{
|
||||
WARNING_LOG(m_logger)<<" ALM_EMERGENCY " << "Reading from DB AlmEmergencyCall with id = " << data.id;
|
||||
if (!this->isExerciseValidForEmergencyCall() && !data.expired)
|
||||
return;
|
||||
|
||||
ObjectEmergencyCall *ifs(new ObjectEmergencyCall(m_mainHandler));
|
||||
Core::FunctionReplyObject ret = ifs->createObject(data);
|
||||
if (ret.error())
|
||||
{
|
||||
delete ifs;
|
||||
ERROR_LOG(m_logger) << ret();
|
||||
bRet = false;
|
||||
return;
|
||||
}
|
||||
|
||||
m_emergencyObjMap.insert(ifs->getId(), ifs);
|
||||
};
|
||||
|
||||
if (!m_mainHandler->db()->select(cbEmergencyCall) || !bRet)
|
||||
{
|
||||
ERROR_LOG(m_logger) <<"Error reading data from database 'alm_emergency_call!";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandlerEmergencyCall::createEmergencyCallObject(const AlarmManagement::AlmEmergencyCall &data)
|
||||
{
|
||||
if (!isNewEmergencyCall(data) || std::isnan(data.position().lat()))
|
||||
return false;
|
||||
|
||||
Database::AlmEmergencyCall newData;
|
||||
newData.id = 0;
|
||||
newData.operatorId = 0;
|
||||
newData.sampleTime = data.sampleTime();
|
||||
newData.incomingTime = data.sampleTime();
|
||||
newData.expired = false;
|
||||
newData.issi = data.issi();
|
||||
newData.position.setX(data.position().lon());
|
||||
newData.position.setY(data.position().lat());
|
||||
newData.comment = QStringLiteral("");
|
||||
newData.name = QStringLiteral("");
|
||||
ObjectEmergencyCall *ifs(new ObjectEmergencyCall(m_mainHandler, this));
|
||||
Core::FunctionReplyObject ret = ifs->createObject(newData);
|
||||
if (ret.error())
|
||||
{
|
||||
delete ifs;
|
||||
ERROR_LOG(m_logger)<< ret();
|
||||
return false;
|
||||
}
|
||||
|
||||
WARNING_LOG(m_logger)<< "Entry createEmergencyCallObject in the DB id: "<<ifs->getData().id<<" issi: "<<ifs->getData().issi<<" expired: "<<ifs->getData().expired;
|
||||
m_emergencyObjMap.insert(ifs->getId(), ifs);
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandlerEmergencyCall::onEmergencyCallAcknowledgeRequest(const rti::core::SampleIdentity &cookie, const EmergencyCallAcknowledgeRequest &request)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "[onEmergencyCallAcknowledgeRequest] request: " << request;
|
||||
Core::FunctionReplyObject ret = emergencyCallAcknowledgeRequest(request);
|
||||
if (ret.error())
|
||||
WARNING_LOG(m_logger)<< ret();
|
||||
|
||||
if (request.expired())
|
||||
{
|
||||
AcknowledgeSOSInAllExercises ackInEx;
|
||||
ackInEx.id(request.id());
|
||||
ackInEx.timestamp(request.timestamp());
|
||||
ackInEx.incomingTime(request.incomingTime());
|
||||
ackInEx.name(request.name());
|
||||
ackInEx.issi(request.issi());
|
||||
ackInEx.operatorId(request.operatorId());
|
||||
ackInEx.comment(request.comment());
|
||||
ackInEx.expired(request.expired());
|
||||
WARNING_LOG(m_logger) << "onEmergencyCallAcknowledgeRequest: issi: "<<ackInEx.issi();
|
||||
m_mainHandler->dds()->publishSOS()->write(ackInEx);
|
||||
}
|
||||
m_mainHandler->dds()->ftsAlm()->emergencyCallAcknowledgeReply(cookie,ret);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject HandlerEmergencyCall::emergencyCallAcknowledgeRequest(const EmergencyCallAcknowledgeRequest &request)
|
||||
{
|
||||
ObjectEmergencyCall *ifs = nullptr;
|
||||
for(auto _ifs : qAsConst(m_emergencyObjMap))
|
||||
{
|
||||
auto data = _ifs->getData();
|
||||
if (data.issi == request.issi()
|
||||
&& data.incomingTime == request.incomingTime()
|
||||
&& !data.expired)
|
||||
{
|
||||
ifs = _ifs;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifs == nullptr)
|
||||
{
|
||||
WARNING_LOG(m_logger)<<" Couldn't acknowledge SOS with issi: " <<request.issi()<< ": already acknowledged or issi doesn't exist.";
|
||||
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "already acknowledged or issi(%1) couldn't be found")).arg(request.issi());
|
||||
}
|
||||
|
||||
if (ifs->getData().expired) // if already expired do nothing
|
||||
{
|
||||
WARNING_LOG(m_logger) << "SOS Already expired do nothing";
|
||||
return Core::FunctionReplyObject(ifs->getData().id);
|
||||
}
|
||||
|
||||
WARNING_LOG(m_logger) << "emergencyCallAcknowledgeRequest: issi found!: "<<request.issi()<<" ifs->state: "<<ifs->getData().expired;
|
||||
Database::AlmEmergencyCall newData(ifs->getData());
|
||||
newData.expired = true;
|
||||
newData.issi = request.issi();
|
||||
newData.sampleTime = request.timestamp();
|
||||
newData.deleted = request.timestamp();
|
||||
newData.operatorId = request.operatorId();
|
||||
newData.name = QString::fromStdString(request.name());
|
||||
newData.comment = QString::fromStdString(request.comment());
|
||||
return ifs->updateObject(newData);
|
||||
}
|
||||
|
||||
bool HandlerEmergencyCall::isExerciseValidForEmergencyCall() const
|
||||
{
|
||||
const auto &exmDtc = m_mainHandler->dds()->dtcExm();
|
||||
exmDtc->waitForHistoricalDataExercise();
|
||||
const ExerciseManagement::Exercise exercise = exmDtc->exercise(m_mainHandler->dds()->exerciseId());
|
||||
|
||||
if (exercise.state() != ExerciseManagement::ExerciseState::Started
|
||||
&& exercise.state() != ExerciseManagement::ExerciseState::Paused)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandlerEmergencyCall::isNewEmergencyCall(const AlmEmergencyCall &newdata)
|
||||
{
|
||||
for(const auto &ifs : qAsConst(m_emergencyObjMap))
|
||||
{
|
||||
const auto &data = ifs->getData();
|
||||
if (data.issi == newdata.issi()
|
||||
&& data.incomingTime == newdata.incomingTime()
|
||||
&& !data.expired)
|
||||
{
|
||||
WARNING_LOG(m_logger)<<" SOS EXISTS and not yet quit! issi: "<<data.issi<<" incomingTime: "<<data.incomingTime<<" expired: "<<data.expired;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandlerEmergencyCall::onEmergencyCallChanged(const TrainingAreaBase::EmergencyCall &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved || !isExerciseValidForEmergencyCall())
|
||||
return;
|
||||
|
||||
AlarmManagement::AlmEmergencyCall emc;
|
||||
emc.id(0);
|
||||
emc.operatorId(0); // global
|
||||
emc.sampleTime(data.sampleTime());
|
||||
emc.incomingTime(data.sampleTime());
|
||||
emc.expired(false);
|
||||
emc.issi(data.equipmentNumber());
|
||||
Core::GeoPosition position;
|
||||
position.lat(data.position().lat());
|
||||
position.lon(data.position().lon());
|
||||
emc.position(position);
|
||||
|
||||
createEmergencyCallObject(emc);
|
||||
}
|
||||
|
||||
void HandlerEmergencyCall::onAcknowledgeSOSInExercises(const AcknowledgeSOSInAllExercises &data, DataModification modType)
|
||||
{
|
||||
DEBUG_LOG(m_logger)<< "onAcknowledgeSOSInExercises START ";
|
||||
Q_UNUSED(modType)
|
||||
|
||||
EmergencyCallAcknowledgeRequest request;
|
||||
request.comment(data.comment());
|
||||
request.expired(data.expired());
|
||||
request.id(data.id());
|
||||
request.issi(data.issi());
|
||||
request.incomingTime(data.incomingTime());
|
||||
request.name(data.name());
|
||||
request.timestamp(data.timestamp());
|
||||
request.operatorId(data.operatorId());
|
||||
emergencyCallAcknowledgeRequest(request);
|
||||
|
||||
DEBUG_LOG(m_logger)<< "onAcknowledgeEmergencyInExercises END ";
|
||||
}
|
||||
|
||||
} // namespace AlarmManagement
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Handler emergency call from tetra radio
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Astrid Müller, SGAS, 2018-02-23
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <AlarmManagement/alm_db.h>
|
||||
#include "dds_handler.h"
|
||||
#include "logger.h"
|
||||
#include "alm_fts.h"
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
class Initialization;
|
||||
class HandlerConfigureAlarms;
|
||||
class ObjectEmergencyCall;
|
||||
|
||||
class HandlerEmergencyCall final : public QObject
|
||||
, protected Interface::Fts::EmergencyCallAcknowledgeRequestHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit HandlerEmergencyCall(const std::shared_ptr<HandlerConfigureAlarms> &configAlarmHandler,
|
||||
Initialization *mainHandler);
|
||||
~HandlerEmergencyCall();
|
||||
|
||||
bool init();
|
||||
|
||||
private:
|
||||
bool createEmergencyCallObject(const AlmEmergencyCall &data);
|
||||
void onEmergencyCallAcknowledgeRequest(const rti::core::SampleIdentity &cookie,
|
||||
const EmergencyCallAcknowledgeRequest &request) override final;
|
||||
Core::FunctionReplyObject emergencyCallAcknowledgeRequest(const EmergencyCallAcknowledgeRequest &request);
|
||||
bool isExerciseValidForEmergencyCall() const;
|
||||
bool isNewEmergencyCall(const AlmEmergencyCall &newdata);
|
||||
|
||||
private slots:
|
||||
void onEmergencyCallChanged(const TrainingAreaBase::EmergencyCall &data, DataModification modType);
|
||||
void onAcknowledgeSOSInExercises(const AlarmManagement::AcknowledgeSOSInAllExercises &data, DataModification modType);
|
||||
|
||||
private:
|
||||
Initialization *m_mainHandler;
|
||||
std::shared_ptr<HandlerConfigureAlarms> m_configAlarmHandler;
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
QMap<int, ObjectEmergencyCall *> m_emergencyObjMap; // Key = DangerAreaId
|
||||
};
|
||||
|
||||
} // namespace AlarmManagement
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* Handler for player data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by gr, SLSE, 2017-02-20
|
||||
*/
|
||||
|
||||
#include "handler_participant.h"
|
||||
#include "settings.h"
|
||||
|
||||
using namespace AlarmManagement;
|
||||
|
||||
HandlerParticipant::HandlerParticipant(const std::shared_ptr<DdsHandler> &ddsHandler)
|
||||
: QObject()
|
||||
, m_ddsHandler(ddsHandler)
|
||||
, m_logger(getLogger("HandlerParticipant"))
|
||||
{
|
||||
} // end of ctor()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
HandlerParticipant::~HandlerParticipant()
|
||||
{
|
||||
} // end of dtor()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool HandlerParticipant::init()
|
||||
{
|
||||
auto dtcPpm = m_ddsHandler->dtcPpm();
|
||||
|
||||
connect(dtcPpm.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
|
||||
this, &HandlerParticipant::onParticipantChanged);
|
||||
connect(dtcPpm.get(), &ParticipantManagement::Interface::Dtc::dynamicParticipantDataChanged,
|
||||
this, &HandlerParticipant::onDynamicParticipantChanged);
|
||||
|
||||
// Get 'static' data for all participants
|
||||
{
|
||||
auto cb = [this](const ParticipantManagement::Participant & es)
|
||||
{
|
||||
onParticipantChanged(es, DataModification::eAdded);
|
||||
};
|
||||
if (!dtcPpm->participants(cb))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dtcPpm->enableParticipant())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not initialize ParticipantManagement enableParticipant data topic client";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dtcPpm->enableDynamicParticipantData())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not initialize ParticipantManagement enableDynamicParticipant data topic client";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get 'static' data for all participants (playerdata)
|
||||
QMap<qint32, ParticipantManagement::Participant> participantsMap;
|
||||
participantsMap = dtcPpm->participants();
|
||||
|
||||
// Player in Referenzmap eintragen
|
||||
for (auto i = participantsMap.begin(); i != participantsMap.end(); ++i)
|
||||
{
|
||||
const ParticipantManagement::Participant &participant = i.value();
|
||||
|
||||
if (participant.equipmentNumber().is_set())
|
||||
{
|
||||
m_partId2EquipNoMap.insert(participant.id(), participant.equipmentNumber().get());
|
||||
DEBUG_LOG(m_logger) << "m_partId2EquipNoMap.insert participantId=" << participant.id() << "EquimentNo=" << participant.equipmentNumber().get();
|
||||
}
|
||||
else
|
||||
m_partId2EquipNoMap.insert(participant.id(), 0);
|
||||
}
|
||||
|
||||
// Get 'static' data for all dynamicParticipants (playerdata)
|
||||
QMap<qint32, ParticipantManagement::DynamicParticipantData> dynamicParticipantsMap = dtcPpm->dynamicParticipantDatas();
|
||||
|
||||
// Player in Referenzmap eintragen
|
||||
for (auto i = dynamicParticipantsMap.begin(); i != dynamicParticipantsMap.end(); ++i)
|
||||
{
|
||||
const ParticipantManagement::DynamicParticipantData &dynamicParticipant = i.value();
|
||||
|
||||
if (dynamicParticipant.stateHistory().size() > 0)
|
||||
{
|
||||
std::vector<ParticipantManagement::StateInformation> states = dynamicParticipant.stateHistory();
|
||||
ParticipantManagement::StateInformation state = states[0];
|
||||
int vulnerability = state.vulnerabilityState().underlying();
|
||||
m_partId2VulnerabilityMap.insert(i.value().participantId(), vulnerability);
|
||||
DEBUG_LOG(m_logger) << "m_partId2EquipNoMap.insert participantId=" << i.value().participantId() << "vulnerability=" << vulnerability;
|
||||
}
|
||||
else
|
||||
m_partId2VulnerabilityMap.insert(i.value().participantId(), -1);
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "HandlerParticipant::init() finished. ";
|
||||
return true;
|
||||
} // end of init()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void HandlerParticipant::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onParticipantChanged - remove: " << data.id();
|
||||
m_participantHierarchy.remove(data.id());
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onParticipantChanged:" << data;
|
||||
m_participantHierarchy.insert(data.id(),
|
||||
AlarmManagement::HandlerParticipant::ParticipantHierarchy(data));
|
||||
const int equipNo = data.equipmentNumber().is_set() ? data.equipmentNumber().get() : 0;
|
||||
m_partId2EquipNoMap.insert(data.id(), equipNo);
|
||||
|
||||
}
|
||||
} // end of onParticipantChanged()
|
||||
|
||||
void HandlerParticipant::onDynamicParticipantChanged(const ParticipantManagement::DynamicParticipantData &data, DataModification modType)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onDynamicParticipant participantId=" << data.participantId();
|
||||
if (modType == DataModification::eRemoved)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(m_logger) << "onDynamicParticipant()"
|
||||
<< " participantId: " << data.participantId();
|
||||
if (data.stateHistory().size() > 0)
|
||||
{
|
||||
std::vector<ParticipantManagement::StateInformation> states = data.stateHistory();
|
||||
ParticipantManagement::StateInformation state = states[0];
|
||||
int vulnerability = state.vulnerabilityState().underlying();
|
||||
m_partId2VulnerabilityMap.insert(data.participantId(), vulnerability);
|
||||
DEBUG_LOG(m_logger) << "m_partId2EquipNoMap.insert participantId=" << data.participantId()
|
||||
<< " vulnerability=" << vulnerability;
|
||||
}
|
||||
else
|
||||
m_partId2VulnerabilityMap.insert(data.participantId(), -1);
|
||||
|
||||
}
|
||||
} // end of onParticipantChanged()
|
||||
|
||||
QVector<AlarmManagement::HandlerParticipant::ParticipantHierarchy> HandlerParticipant::getInferiorParts(int participantId) const
|
||||
{
|
||||
QVector<AlarmManagement::HandlerParticipant::ParticipantHierarchy> retVector;
|
||||
auto it = m_participantHierarchy.find(participantId);
|
||||
if (it == m_participantHierarchy.end())
|
||||
return retVector;
|
||||
|
||||
const AlarmManagement::HandlerParticipant::ParticipantHierarchy &participant = it.value();
|
||||
retVector.reserve(participant.inferiorIds.size() + retVector.size());
|
||||
|
||||
retVector.append(participant);
|
||||
for (int inferiorId : participant.inferiorIds)
|
||||
retVector.append(getInferiorParts(inferiorId));
|
||||
|
||||
return retVector;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QVector<int> HandlerParticipant::getRecursiveInferiorIds(const int participantId) const
|
||||
{
|
||||
QVector <int> result;
|
||||
if (participantId == 0)
|
||||
{
|
||||
result.append(participantId);
|
||||
return result;
|
||||
}
|
||||
|
||||
const QVector<AlarmManagement::HandlerParticipant::ParticipantHierarchy> inferiorParts = HandlerParticipant::getInferiorParts(participantId);
|
||||
result.reserve(inferiorParts.size());
|
||||
for (const auto &inferior : inferiorParts)
|
||||
result.append(inferior.participantId);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int HandlerParticipant::participantId2EquipNo(const int participantId) const
|
||||
{
|
||||
int ret = m_partId2EquipNoMap.value(participantId, 0);
|
||||
INFO_LOG(m_logger) << "participantId2EquipNo participantId=" << participantId
|
||||
<< " EquipmentNumber=" << ret;
|
||||
return ret;
|
||||
} // end of participantId2EquipNo()
|
||||
|
||||
int HandlerParticipant::participantId2Vulnerability(const int participantId) const
|
||||
{
|
||||
int ret = m_partId2VulnerabilityMap.value(participantId, 0);
|
||||
INFO_LOG(m_logger) << "m_partId2VulnerabilityMap participantId=" << participantId
|
||||
<< " Vulnerability=" << ret;
|
||||
return ret;
|
||||
} // end of participantId2Vulnerability()
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Handler for player data
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by gr, SLSE, 2017-02-20
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include "dds_handler.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QHash>
|
||||
|
||||
// AES-Handling for participants outside buildings
|
||||
namespace AlarmManagement
|
||||
{
|
||||
|
||||
class HandlerParticipant : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
struct ParticipantHierarchy
|
||||
{
|
||||
int participantId = 0;
|
||||
int superiorId = 0;
|
||||
std::vector<int32_t> inferiorIds;
|
||||
|
||||
ParticipantHierarchy() = default;
|
||||
explicit ParticipantHierarchy(const ParticipantManagement::Participant &p)
|
||||
: participantId(p.id())
|
||||
, superiorId(p.superiorId())
|
||||
, inferiorIds(p.inferiorIds())
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
explicit HandlerParticipant(const std::shared_ptr<DdsHandler> &ddsHandler);
|
||||
|
||||
~HandlerParticipant();
|
||||
|
||||
/**
|
||||
* Initialize the handler to manage information from participant management
|
||||
*/
|
||||
bool init();
|
||||
|
||||
QVector<int> getRecursiveInferiorIds(const int participantId) const;
|
||||
|
||||
/**
|
||||
* Get equipment number for the given participant
|
||||
* @param participantId participant id to get the equipment number for
|
||||
* @return equipment number or 0 in case of failure
|
||||
*/
|
||||
int participantId2EquipNo(const int participantId) const;
|
||||
|
||||
/**
|
||||
* Get vulnerability for the given participant
|
||||
* @param participantId participant id to get the equipment number for
|
||||
* @return vulnerability
|
||||
*/
|
||||
int participantId2Vulnerability(const int participantId) const;
|
||||
|
||||
|
||||
private Q_SLOTS:
|
||||
/**
|
||||
* Handle the signals from 'ParticipantManagement'
|
||||
*/
|
||||
void onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType);
|
||||
void onDynamicParticipantChanged(const ParticipantManagement::DynamicParticipantData &data, DataModification modType);
|
||||
|
||||
private: // methoden
|
||||
QVector<AlarmManagement::HandlerParticipant::ParticipantHierarchy> getInferiorParts(int participantId) const;
|
||||
|
||||
private: // attributes
|
||||
QMap<int, int> m_partId2EquipNoMap; ///< Reference map participant (player) to equipment number (participantId, equipmentNo)
|
||||
QMap<int, int> m_partId2VulnerabilityMap; ///< Reference map participant (player) to Vulnerability
|
||||
QHash<int, ParticipantHierarchy> m_participantHierarchy;
|
||||
std::shared_ptr<DdsHandler> m_ddsHandler; ///< Pointer to VOM DDS handler
|
||||
NGL::INGLLogger &m_logger; ///< Interface to the Logging-Facility
|
||||
|
||||
};
|
||||
} // namespace AlarmManagement
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Initialization for MessageDataManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by hjl, SLSE, 2016-09-21
|
||||
*/
|
||||
|
||||
#include "initialization.h"
|
||||
#include "handler_configure_alarms.h"
|
||||
#include "handler_emergency_call.h"
|
||||
#include "handler_participant.h"
|
||||
|
||||
#include <ngldb/db_service_handler.h>
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
|
||||
using namespace AlarmManagement;
|
||||
|
||||
Initialization::Initialization()
|
||||
: m_logger(getLogger("Initialization"))
|
||||
{
|
||||
INFO_LOG(m_logger) << "Initialization::Initialization";
|
||||
} // end of ctor()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Initialization::~Initialization()
|
||||
{
|
||||
m_handlerConfigureAlarms = nullptr;
|
||||
m_handlerParticipant = nullptr;
|
||||
m_handlerEmergencyCall = nullptr;
|
||||
|
||||
m_dbHandler = nullptr;
|
||||
m_ddsHandler = nullptr;
|
||||
|
||||
INFO_LOG(m_logger) << "Initialization::~Initialization";
|
||||
} // end of dtor()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool Initialization::initialize(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector, const QSqlDatabase &sqlDb)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Start AlarmManagement Initialization. domainId =" << ddsConnector->getDomainId()
|
||||
<< " exerciseId=" << ddsConnector->getPartitionId();
|
||||
|
||||
// initialize DDS
|
||||
m_ddsHandler = std::make_shared<DdsHandler>(ddsConnector);
|
||||
if (!m_ddsHandler->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Initialisation DdsHandler failed.";
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(m_logger) << "m_ddsHandler initialized. ";
|
||||
|
||||
// initialize database
|
||||
m_dbHandler = std::make_shared<DbHandler>();
|
||||
if (!m_dbHandler->init(ddsConnector->getPartitionId(), sqlDb))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Initialisation DbHandler failed.";
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(m_logger) << "DbHandler initialized. ";
|
||||
|
||||
|
||||
// create handlers
|
||||
m_handlerParticipant = std::make_shared<HandlerParticipant>(m_ddsHandler);
|
||||
m_handlerConfigureAlarms = std::make_shared<HandlerConfigureAlarms>(this);
|
||||
m_handlerEmergencyCall = std::make_shared<HandlerEmergencyCall>(m_handlerConfigureAlarms, this);
|
||||
|
||||
DEBUG_LOG(m_logger) << "initialize successfully finished";
|
||||
|
||||
return true;
|
||||
} // end of init()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool Initialization::loadFromDatabase()
|
||||
{
|
||||
// initialize handlers
|
||||
if (!m_handlerParticipant || !m_handlerParticipant->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not initialize Participant handler";
|
||||
return false;
|
||||
}
|
||||
if (!m_handlerConfigureAlarms || !m_handlerConfigureAlarms->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not initialize Alarm handler";
|
||||
return false;
|
||||
}
|
||||
if (!m_handlerEmergencyCall || !m_handlerEmergencyCall->init())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Can not initialize EmergencyCall handler";
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "loadFromDatabase successfully finished";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<DatabaseInterface> Initialization::db() const
|
||||
{
|
||||
return m_dbHandler->db();
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* MainHandler for Messaging
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by hjl, SLSE, 2016-09-21
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <AlarmManagement/alm_db.h>
|
||||
#include <ngldb/db_service_handler.h>
|
||||
#include "dds_handler.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace DDSConnector
|
||||
{
|
||||
class DdsConnector;
|
||||
}
|
||||
namespace NGLDB
|
||||
{
|
||||
template <typename DB> class DbServiceHandler;
|
||||
}
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
using DbHandler = NGLDB::DbServiceHandler<DatabaseInterface>;
|
||||
class DdsHandler;
|
||||
class HandlerConfigureAlarms;
|
||||
class HandlerEmergencyCall;
|
||||
class HandlerParticipant;
|
||||
|
||||
class ALM_SERVER_EXPORT Initialization
|
||||
{
|
||||
public:
|
||||
Initialization();
|
||||
~Initialization();
|
||||
|
||||
bool initialize(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector, const QSqlDatabase &sqlDb);
|
||||
bool loadFromDatabase();
|
||||
|
||||
std::shared_ptr<DdsHandler> dds() const { return m_ddsHandler; }
|
||||
std::shared_ptr<DatabaseInterface> db() const;
|
||||
std::shared_ptr<HandlerParticipant> hdlParticipant() const { return m_handlerParticipant; }
|
||||
|
||||
private: // attributes
|
||||
std::shared_ptr<DdsHandler> m_ddsHandler;
|
||||
std::shared_ptr<DbHandler> m_dbHandler; ///< Pointer to DB handler
|
||||
std::shared_ptr<HandlerConfigureAlarms> m_handlerConfigureAlarms;
|
||||
std::shared_ptr<HandlerParticipant> m_handlerParticipant; ///< Pointer to handler for all participants
|
||||
std::shared_ptr<HandlerEmergencyCall> m_handlerEmergencyCall;
|
||||
|
||||
NGL::INGLLogger &m_logger; ///< Interface to the Logging-Facility
|
||||
|
||||
};
|
||||
} // namespace MessagingDataManagement
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Building Config - logging facility
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
|
||||
LOGGER_T getLogger(const char *name)
|
||||
{
|
||||
static const char ns[] = "ALM.";
|
||||
std::string loggerName;
|
||||
const size_t len = strlen(name);
|
||||
loggerName.reserve(sizeof(ns) + len);
|
||||
loggerName.append(ns, sizeof(ns) - 1);
|
||||
loggerName.append(name, len);
|
||||
|
||||
try
|
||||
{
|
||||
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
|
||||
getNGLLogger(loggerName);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
fprintf(stderr, "Error retrieving logger: %s", ex.what());
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AlarmManagement
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging for AlarmManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
#include "alm_export.h"
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
using LOGGER_T = NGL::INGLLogger &;
|
||||
|
||||
ALM_COMMON_EXPORT LOGGER_T getLogger(const char *name);
|
||||
inline LOGGER_T getLogger(const QString &loggerName)
|
||||
{
|
||||
return getLogger(loggerName.toUtf8().constData());
|
||||
}
|
||||
} // namespace AlarmManagement
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
#include "object_emergency_call.h"
|
||||
#include "logger.h"
|
||||
#include "initialization.h"
|
||||
|
||||
namespace AlarmManagement{
|
||||
|
||||
ObjectEmergencyCall::ObjectEmergencyCall(Initialization *mainHandler, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_mainHandler(mainHandler)
|
||||
, m_logger(getLogger("ObjectEmergencyCall"))
|
||||
{
|
||||
}
|
||||
|
||||
ObjectEmergencyCall::~ObjectEmergencyCall()
|
||||
{
|
||||
if (m_data.id > 0)
|
||||
m_mainHandler->dds()->dtsAlm()->removeAlarmConfigByKey(m_data.id);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectEmergencyCall::createObject(const Database::AlmEmergencyCall &data)
|
||||
{
|
||||
m_data = data;
|
||||
if (m_data.id <= 0)
|
||||
{
|
||||
if (!m_mainHandler->db()->insert(m_data))
|
||||
return Core::FunctionReplyObject(0, tr_lts("dds", "Error inserting Order into database."));
|
||||
WARNING_LOG(m_logger) << "New EmergencyCall created Id: " << m_data.id;
|
||||
}
|
||||
// Publish Data via DTS
|
||||
onPublishData();
|
||||
|
||||
return Core::FunctionReplyObject(m_data.id);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectEmergencyCall::updateObject(const Database::AlmEmergencyCall &data)
|
||||
{
|
||||
if (data.id <= 0)
|
||||
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Object not valid/blocked"));
|
||||
m_data = data;
|
||||
|
||||
if (!m_mainHandler->db()->update(m_data))
|
||||
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "Error updating EmergencyCall into database"));
|
||||
|
||||
DEBUG_LOG(m_logger) << "Data changed for Changed Id: " << m_data.id;
|
||||
|
||||
// Publish Data via DTS
|
||||
onPublishData();
|
||||
|
||||
return Core::FunctionReplyObject(m_data.id);
|
||||
}
|
||||
|
||||
Core::FunctionReplyObject ObjectEmergencyCall::removeObject()
|
||||
{
|
||||
if (!m_mainHandler->db()->removeAlmEmergencyCall(m_data.id))
|
||||
return Core::FunctionReplyObject(m_data.id, tr_lts("dds", "AlmEmergencyCall %1 can not be removed")).arg(m_data.id);
|
||||
|
||||
return Core::FunctionReplyObject(m_data.id);
|
||||
}
|
||||
|
||||
|
||||
void ObjectEmergencyCall::onPublishData()
|
||||
{
|
||||
AlarmManagement::AlmEmergencyCall ddsData;
|
||||
ddsData.id(m_data.id);
|
||||
ddsData.sampleTime(m_data.sampleTime);
|
||||
ddsData.incomingTime(m_data.incomingTime);
|
||||
ddsData.name(m_data.name.toStdString());
|
||||
ddsData.issi(m_data.issi);
|
||||
ddsData.position(Core::GeoPosition2D(m_data.position.x(), m_data.position.y()));
|
||||
ddsData.expired(m_data.expired);
|
||||
ddsData.deleted(m_data.deleted);
|
||||
ddsData.operatorId(m_data.operatorId);
|
||||
ddsData.comment(m_data.comment.toStdString());
|
||||
|
||||
INFO_LOG(m_logger) << "Publish AlmEmergencyCall-data to dds (" << m_data.id << ") ...";
|
||||
|
||||
if (!m_mainHandler->dds()->dtsAlm()->publish(ddsData))
|
||||
ERROR_LOG(m_logger) << "Error publishing AlmEmergencyCall-data to dds";
|
||||
}
|
||||
|
||||
}// namespace AlarmManagement
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <dds_handler.h>
|
||||
#include "logger.h"
|
||||
|
||||
#include <DDS/Core/function_reply_object.h>
|
||||
//Generated
|
||||
#include <AlarmManagement/alm_db.h>
|
||||
|
||||
|
||||
namespace AlarmManagement {
|
||||
|
||||
class Initialization;
|
||||
|
||||
class ObjectEmergencyCall : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ObjectEmergencyCall(Initialization *mainHandler, QObject *parent = nullptr);
|
||||
~ObjectEmergencyCall();
|
||||
|
||||
Core::FunctionReplyObject createObject(const Database::AlmEmergencyCall &data);
|
||||
Core::FunctionReplyObject updateObject(const Database::AlmEmergencyCall &data);
|
||||
Core::FunctionReplyObject removeObject();
|
||||
|
||||
int getId() const { return m_data.id; }
|
||||
const Database::AlmEmergencyCall &getData() const { return m_data; }
|
||||
Core::FunctionReplyObject updateObject() { return updateObject(m_data); }
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onPublishData();
|
||||
|
||||
private:
|
||||
Initialization *m_mainHandler;
|
||||
Database::AlmEmergencyCall m_data;
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Settings for AlarmManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
class NGLSettingsClass : public NGL::Settings
|
||||
{
|
||||
public:
|
||||
NGLSettingsClass()
|
||||
: NGL::Settings(s_iniFile.isEmpty() ? NGL::findProjectConfigFile() : s_iniFile)
|
||||
{}
|
||||
static void setIniFile(const QString &fn)
|
||||
{
|
||||
s_iniFile = fn;
|
||||
}
|
||||
static QString s_iniFile;
|
||||
};
|
||||
QString NGLSettingsClass::s_iniFile;
|
||||
Q_GLOBAL_STATIC(NGLSettingsClass, s)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
NGL::Settings *Settings::settings()
|
||||
{
|
||||
return s();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Settings::setIniFile(const QString &ini)
|
||||
{
|
||||
NGLSettingsClass::setIniFile(ini);
|
||||
}
|
||||
|
||||
} // namespace AlarmManagement
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Settings for AlarmManagement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QString>
|
||||
|
||||
namespace NGL
|
||||
{
|
||||
class Settings;
|
||||
}
|
||||
|
||||
namespace AlarmManagement
|
||||
{
|
||||
namespace Settings
|
||||
{
|
||||
NGL::Settings *settings();
|
||||
void setIniFile(const QString &ini);
|
||||
}
|
||||
|
||||
} // namespace AlarmManagement
|
||||
+467
@@ -0,0 +1,467 @@
|
||||
#es
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
INCLUDE(MacroRTIDDSGen)
|
||||
INCLUDE(MacroCodeGenIdl)
|
||||
|
||||
SET(xml_FILE aes_service.xml)
|
||||
|
||||
#
|
||||
# --- Library svcAesCommon --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_common
|
||||
aes_export.h
|
||||
logger.cpp
|
||||
logger.h
|
||||
Utils/icons.cpp
|
||||
Utils/icons.h
|
||||
Utils/intersections.cpp
|
||||
Utils/intersections.h
|
||||
Utils/tne_algorithmen.h
|
||||
Utils/tne_algorithmen.cpp
|
||||
Utils/polygons.h
|
||||
Utils/polygons.cpp
|
||||
Utils/polygons.h
|
||||
Utils/ddsdbconvert.cpp
|
||||
Utils/ddsdbconvert.h
|
||||
Utils/aes_helper.cpp
|
||||
Utils/aes_helper.h
|
||||
Utils/fire_automaton.cpp
|
||||
Utils/fire_automaton.h
|
||||
Utils/firing_timer.cpp
|
||||
Utils/firing_timer.h
|
||||
settings.cpp
|
||||
settings.h
|
||||
)
|
||||
|
||||
# copy aes_predefined_data.sql to share
|
||||
SET(in_file_sql "aes_predefined_data.sql")
|
||||
SET(out_dir_sql "${CMAKE_BINARY_DIR}/share/Lts/sql/")
|
||||
SET(out_file_sql "${out_dir_sql}/${in_file_sql}")
|
||||
ADD_CUSTOM_COMMAND(OUTPUT ${out_file_sql}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS -E make_directory ${out_dir_sql}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS -E copy_if_different ${in_file_sql} ${out_file_sql}
|
||||
DEPENDS ${in_file_sql}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
LIST(APPEND SRCS_common ${in_file_sql} ${out_file_sql})
|
||||
|
||||
# Generate aes_enums.idl / aes.idl / aes_enums.cpp/aes_enums.h
|
||||
CODEGEN_IDL_SVC(SRCS_common ${xml_FILE})
|
||||
# Generate aes_db_structs.cpp/.h
|
||||
CODEGEN_DATABASE_STRUCTS(SRCS_common ${xml_FILE})
|
||||
# Generate aes_db_impl.cpp/.h,
|
||||
CODEGEN_DATABASE_SQL(SRCS_common ${xml_FILE})
|
||||
# Generate aes_dao.cpp/.h
|
||||
CODEGEN_DAO(SRCS_common ${xml_FILE})
|
||||
|
||||
# Generate *.cpp/*.hpp from aes_enums.idl / aes.idl
|
||||
RTIDDSGEN(SRCS_common aes_enums.idl)
|
||||
RTIDDSGEN(SRCS_common aes.idl)
|
||||
|
||||
# Generate aes_dt[s,c]_types.h, aes_ft[s,c]_types.h
|
||||
CODEGEN_TOPIC_TYPEDEFS(SRCS_common ${xml_FILE})
|
||||
# generate aes_[d|f]tc.h
|
||||
CODEGEN_CLIENT_TOPICS_IFC(SRCS_common ${xml_FILE})
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV WS HLA svcAesCommon SHARED ${SRCS_common} )
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcAesCommon
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(svcAesCommon
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
LtsCoordTrans
|
||||
PUBLIC
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Xml
|
||||
ddscore
|
||||
svcPdmCommon
|
||||
svcPpmCommon
|
||||
NGLLogger
|
||||
nglsettings
|
||||
ngltools
|
||||
situationMapElevationMap
|
||||
Trajectory
|
||||
ngldb
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcAesCommon)
|
||||
|
||||
#
|
||||
# --- Library svcAesClient --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_client
|
||||
aes_dtc_impl_custom.cpp
|
||||
aes_dtc_impl_custom.h
|
||||
aes_export.h
|
||||
)
|
||||
# generate aes_[d|f]tc_impl.[cpp|h]
|
||||
CODEGEN_CLIENT_TOPICS_IMPL(SRCS_client ${xml_FILE})
|
||||
# SV wegen ft unit test
|
||||
NGL_ADD_LIBRARY(AAR SV HLA WS svcAesClient SHARED ${SRCS_client})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcAesClient
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(svcAesClient
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
ddsconnector
|
||||
PUBLIC
|
||||
svcAesCommon
|
||||
nglsettings
|
||||
ngltools
|
||||
ddsftc
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcAesClient)
|
||||
|
||||
#
|
||||
# --- Library svcAesServer --------------------------------------------------------------------------------
|
||||
#
|
||||
SET(SRCS_server
|
||||
aes_export.h
|
||||
log4cxx_aes.props
|
||||
)
|
||||
# generate aes_[d|f]ts.h, aes_[d|f]ts_impl.[cpp|h]
|
||||
CODEGEN_SERVER_TOPICS(SRCS_server ${xml_FILE})
|
||||
|
||||
|
||||
#WS for Record Replay plugin stand alone build
|
||||
|
||||
NGL_ADD_LIBRARY(AAR SV WS svcAesServer SHARED ${SRCS_server})
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(svcAesServer
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(svcAesServer
|
||||
PRIVATE
|
||||
RTI::nddscpp2
|
||||
ddsconnector
|
||||
ddsfts
|
||||
PUBLIC
|
||||
svcAesCommon
|
||||
ngldb
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcAesServer)
|
||||
|
||||
#
|
||||
# --- Topic Type Plugin --------------------------------------------------------------
|
||||
#
|
||||
CREATE_TOPIC_TYPE_PLUGIN(${xml_FILE})
|
||||
|
||||
#
|
||||
# --- RecordReplayPlugin --------------------------------------------------------------
|
||||
#
|
||||
CREATE_RECORD_REPLAY_PLUGIN_SHARED(${xml_FILE})
|
||||
|
||||
#
|
||||
# --- RecordReplayPlugin --------------------------------------------------------------
|
||||
#
|
||||
IF (TARGET aesRecordReplayPlugin)
|
||||
TARGET_SOURCES(aesRecordReplayPlugin
|
||||
PRIVATE
|
||||
RecordReplay/aes_record_replay_plugin_custom.cpp
|
||||
RecordReplay/aes_record_replay_plugin_custom.h
|
||||
)
|
||||
TARGET_LINK_LIBRARIES(aesRecordReplayPlugin
|
||||
Qt5::Concurrent
|
||||
svcAesServer
|
||||
svcAesClient
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
|
||||
|
||||
#
|
||||
# --- Executable svcAreaEffectSimulation (sAES) --------------------------------------------------------------
|
||||
#
|
||||
|
||||
LIST(APPEND SRCS_exe
|
||||
dds_handler.cpp
|
||||
dds_handler.h
|
||||
handler_air_support_impact.cpp
|
||||
handler_air_support_impact.h
|
||||
handler_base.cpp
|
||||
handler_base.h
|
||||
handler_bccontamination.cpp
|
||||
handler_bccontamination.h
|
||||
handler_booby_trap.cpp
|
||||
handler_booby_trap.h
|
||||
handler_borderline.cpp
|
||||
handler_borderline.h
|
||||
handler_charge_administration.cpp
|
||||
handler_charge_administration.h
|
||||
handler_charge_effect.cpp
|
||||
handler_charge_effect.h
|
||||
handler_danger_area.cpp
|
||||
handler_danger_area.h
|
||||
handler_dus_single_mine.cpp
|
||||
handler_dus_single_mine.h
|
||||
handler_effect_cluster.h
|
||||
handler_effect_cluster.cpp
|
||||
handler_explosion_area.cpp
|
||||
handler_explosion_area.h
|
||||
handler_explosion_cluster.cpp
|
||||
handler_explosion_cluster.h
|
||||
handler_explosion_single.cpp
|
||||
handler_explosion_single.h
|
||||
handler_functional_area.cpp
|
||||
handler_functional_area.h
|
||||
handler_gas_pipe.cpp
|
||||
handler_gas_pipe.h
|
||||
handler_mine_area.cpp
|
||||
handler_mine_area.h
|
||||
handler_mine_corridor.cpp
|
||||
handler_mine_corridor.h
|
||||
handler_ncontamination.cpp
|
||||
handler_ncontamination.h
|
||||
handler_off_route_mine.cpp
|
||||
handler_off_route_mine.h
|
||||
handler_recon_area.cpp
|
||||
handler_recon_area.h
|
||||
handler_technical_area.cpp
|
||||
handler_technical_area.h
|
||||
handler_effector.cpp
|
||||
handler_effector.h
|
||||
handler_trajectory.cpp
|
||||
handler_trajectory.h
|
||||
main.cpp
|
||||
main_handler.cpp
|
||||
main_handler.h
|
||||
meteo_data_provider.cpp
|
||||
meteo_data_provider.h
|
||||
mine_corridor_creator.cpp
|
||||
mine_corridor_creator.h
|
||||
object_air_support_impact.cpp
|
||||
object_air_support_impact.h
|
||||
object_base.cpp
|
||||
object_base.h
|
||||
object_bccontamination.cpp
|
||||
object_bccontamination.h
|
||||
object_booby_trap.cpp
|
||||
object_booby_trap.h
|
||||
object_borderline.cpp
|
||||
object_borderline.h
|
||||
object_charge_administration.cpp
|
||||
object_charge_administration.h
|
||||
object_charge_effect.cpp
|
||||
object_charge_effect.h
|
||||
object_danger_area.cpp
|
||||
object_danger_area.h
|
||||
object_dus_single_mine.cpp
|
||||
object_dus_single_mine.h
|
||||
object_effect_cluster.h
|
||||
object_effect_cluster.cpp
|
||||
object_explosion_area.cpp
|
||||
object_explosion_area.h
|
||||
object_explosion_cluster.cpp
|
||||
object_explosion_cluster.h
|
||||
object_explosion_single.cpp
|
||||
object_explosion_single.h
|
||||
object_functional_area.cpp
|
||||
object_functional_area.h
|
||||
object_gas_pipe.cpp
|
||||
object_gas_pipe.h
|
||||
object_mine_area.cpp
|
||||
object_mine_area.h
|
||||
object_mine_area_null.cpp
|
||||
object_mine_area_null.h
|
||||
object_mine_corridor.cpp
|
||||
object_mine_corridor.h
|
||||
object_ncontamination.cpp
|
||||
object_ncontamination.h
|
||||
object_off_route_mine.cpp
|
||||
object_off_route_mine.h
|
||||
object_recon_area.cpp
|
||||
object_recon_area.h
|
||||
object_technical_area.cpp
|
||||
object_technical_area.h
|
||||
object_effector.cpp
|
||||
object_effector.h
|
||||
object_trajectory.cpp
|
||||
object_trajectory.h
|
||||
special_area_provider.cpp
|
||||
special_area_provider.h
|
||||
effector_state_machine.cpp
|
||||
effector_state_machine.h
|
||||
./EffectorFiringStrategy/abstract_firing_strategy.cpp
|
||||
./EffectorFiringStrategy/abstract_firing_strategy.h
|
||||
./EffectorFiringStrategy/default_firing_strategy.cpp
|
||||
./EffectorFiringStrategy/default_firing_strategy.h
|
||||
./EffectorFiringStrategy/dm72_firing_strategy.cpp
|
||||
./EffectorFiringStrategy/dm72_firing_strategy.h
|
||||
./EffectorFiringStrategy/firing_strategy_factory.cpp
|
||||
./EffectorFiringStrategy/firing_strategy_factory.h
|
||||
./EffectorFiringStrategy/gmlrs_firing_strategy.cpp
|
||||
./EffectorFiringStrategy/gmlrs_firing_strategy.h
|
||||
./EffectorFiringStrategy/smart_firing_strategy.h
|
||||
./EffectorFiringStrategy/smart_firing_strategy.cpp
|
||||
./TrajectorySplitter/trajectory_splitter.cpp
|
||||
./TrajectorySplitter/trajectory_splitter.h
|
||||
)
|
||||
|
||||
# Generate aes.sql, aes.xml
|
||||
CODEGEN_SQL(SRCS_exe ${xml_FILE})
|
||||
|
||||
NGL_ADD_SVC_ICON(SRCS_exe)
|
||||
NGL_ADD_EXECUTABLE(AAR SV svcAreaEffectSimulation ${SRCS_exe})
|
||||
NGL_TARGET_LINK_LIBRARIES(svcAreaEffectSimulation
|
||||
svcAesServer
|
||||
svcCesClient
|
||||
svcCoreClient
|
||||
svcMdmClient
|
||||
svcPdmClient
|
||||
svcPpmClient
|
||||
svcTabClient
|
||||
svcIsmClient
|
||||
svcExmClient
|
||||
svcAsmClient
|
||||
Qt5::Core
|
||||
Qt5::Gui # QVector3D
|
||||
RTI::nddscpp2
|
||||
nglsettings
|
||||
ProjectConfig
|
||||
LtsCommandLineParser
|
||||
LtsCoordTrans
|
||||
LtsUtilsCore
|
||||
LtsUtilsDds
|
||||
LtsElevation
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
ddsconnector
|
||||
ngltools
|
||||
saaTelegrams
|
||||
)
|
||||
NGL_INSTALL_TARGET(svcAreaEffectSimulation)
|
||||
NGL_INSTALL(AAR SV FILES log4cxx_aes.props DESTINATION bin)
|
||||
NGL_ADD_TARGET_LINK(svcAreaEffectSimulation sAES)
|
||||
|
||||
#
|
||||
# --- Tests --------------------------------------------------------------
|
||||
#
|
||||
MACRO(ADD_FT_TEST type)
|
||||
IF(TARGET svcAesClient)
|
||||
IF(NOT TARGET aes_test_base)
|
||||
NGL_ADD_LIBRARY2(AAR SV NO_TRANSLATION aes_test_base SHARED
|
||||
ModuleTests/aes_test_base.cpp
|
||||
ModuleTests/aes_test_base.h
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(aes_test_base
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
ddsconnector
|
||||
LtsCommandLineParser
|
||||
nglcoreapplication
|
||||
svcAesClient
|
||||
LtsCoordTrans
|
||||
)
|
||||
ENDIF()
|
||||
SET(_tgt_name aes_test_${type})
|
||||
NGL_ADD_EXECUTABLE(AAR SV NO_TRANSLATION ${_tgt_name}
|
||||
ModuleTests/aes_test_${type}.cpp
|
||||
ModuleTests/aes_test_${type}.h
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(${_tgt_name}
|
||||
aes_test_base
|
||||
)
|
||||
NGL_INSTALL_TARGET(${_tgt_name} DESTINATION bin/test)
|
||||
ENDIF()
|
||||
ENDMACRO()
|
||||
ADD_FT_TEST(air_support_impact)
|
||||
ADD_FT_TEST(bccontamination)
|
||||
ADD_FT_TEST(booby_trap)
|
||||
ADD_FT_TEST(charge_administration)
|
||||
ADD_FT_TEST(danger_area)
|
||||
ADD_FT_TEST(explosion_area)
|
||||
ADD_FT_TEST(explosion_area_bulk)
|
||||
ADD_FT_TEST(explosion_single)
|
||||
ADD_FT_TEST(explosion_cluster)
|
||||
ADD_FT_TEST(gas_pipe)
|
||||
ADD_FT_TEST(mine_area)
|
||||
ADD_FT_TEST(ncontamination)
|
||||
ADD_FT_TEST(off_route_mine)
|
||||
NGL_INSTALL(AAR SV FILES log4cxx_aes.props DESTINATION bin/test)
|
||||
|
||||
#
|
||||
# --- Tests --------------------------------------------------------------
|
||||
#
|
||||
NGL_ADD_EXECUTABLE(AAR SV NO_TRANSLATION aes_utils_test
|
||||
Utils/test_main.cpp
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(aes_utils_test
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
RTI::nddscpp2
|
||||
svcAesCommon
|
||||
ProjectConfig
|
||||
ddsconnector
|
||||
nglapplication
|
||||
LtsCoordTrans
|
||||
)
|
||||
NGL_INSTALL(AAR SV TARGETS aes_utils_test DESTINATION bin/test)
|
||||
|
||||
#
|
||||
# --- Tests --------------------------------------------------------------
|
||||
#
|
||||
NGL_ADD_EXECUTABLE(SV NO_TRANSLATION aes_convert_mine_area
|
||||
ModuleTests/aes_convert_mine_area.cpp
|
||||
)
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(aes_convert_mine_area
|
||||
Qt5::Core
|
||||
# Qt5::Widgets
|
||||
# RTI::nddscpp2
|
||||
svcAesServer
|
||||
ProjectConfig
|
||||
# nglapplication
|
||||
LtsCoordTrans
|
||||
ngldb
|
||||
LtsCommandLineParser
|
||||
nglcoreapplication
|
||||
nglsettings
|
||||
ngltools
|
||||
)
|
||||
NGL_INSTALL(SV TARGETS aes_convert_mine_area DESTINATION bin/test)
|
||||
|
||||
|
||||
#
|
||||
# --- SUBDIRECTORY --------------------------------------------------------------
|
||||
#
|
||||
ADD_SUBDIRECTORY(Trajectory)
|
||||
|
||||
# Used to pack this specific Module Test in rpm. Please not use this for other tests
|
||||
ADD_SUBDIRECTORY(ModuleTest_Limits)
|
||||
|
||||
|
||||
#
|
||||
# --- Tests --------------------------------------------------------------
|
||||
#
|
||||
IF(BUILD_TESTING)
|
||||
ADD_SUBDIRECTORY(UnitTests)
|
||||
ADD_SUBDIRECTORY(UnitTest_FireAutomaton)
|
||||
ADD_SUBDIRECTORY(TrajectorySplitter)
|
||||
ADD_SUBDIRECTORY(ModuleTest_EffectCluster)
|
||||
ADD_SUBDIRECTORY(ModuleTest_ExplosionCluster)
|
||||
ADD_SUBDIRECTORY(ModuleTest_others)
|
||||
|
||||
|
||||
ENDIF()
|
||||
|
||||
|
||||
NGL_INSTALL(AAR SV FILES log4cxx_aes.props DESTINATION bin)
|
||||
|
||||
NGL_INSTALL(AAR SV FILES aes_predefined_data.sql DESTINATION share/Lts/sql)
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
* Base Class for Effector Firing Strategy
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2025-05-11
|
||||
*/
|
||||
|
||||
#include "abstract_firing_strategy.h"
|
||||
|
||||
#include "object_effector.h"
|
||||
#include "main_handler.h"
|
||||
#include "handler_charge_effect.h"
|
||||
|
||||
#include <ParticipantManagement/ppm.hpp>
|
||||
#include "Trajectory/trajectory_transform.h"
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
|
||||
|
||||
AbstractFiringStrategy::AbstractFiringStrategy(ObjectEffector *parent)
|
||||
: QObject(parent)
|
||||
, m_effector(parent)
|
||||
, m_logger(getLogger("FiringStrategy"))
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
AbstractFiringStrategy::~AbstractFiringStrategy()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
void AbstractFiringStrategy::calculateDispersionTrajectory()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "calculateDispersionTrajectory";
|
||||
// 1. Neuen Zielpunkt berechnen
|
||||
|
||||
const auto &intendendTrajectory = m_effector->intendendTrajectory();
|
||||
|
||||
// sanity check:
|
||||
if (intendendTrajectory.size() < 2)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " size of intendendTrajectory not sufficiant, size=" << intendendTrajectory.size();
|
||||
return;
|
||||
}
|
||||
|
||||
LtsUtils::QPoint3D newTarget = intendendTrajectory.last().position;
|
||||
|
||||
const int scatterLength = qRound(m_effector->effectorData().mhpScatterLenght());
|
||||
const int randomValueX = QRandomGenerator::global()->bounded(-scatterLength, scatterLength + 1);
|
||||
const int scatterWidth = qRound(m_effector->effectorData().mhpScatterWidth());
|
||||
const int randomValueY = QRandomGenerator::global()->bounded(-scatterWidth, scatterWidth + 1);
|
||||
newTarget.setX(newTarget.x() + randomValueX);
|
||||
newTarget.setY(newTarget.y() + randomValueY);
|
||||
|
||||
// 2. Neue Trajektorie berechnen
|
||||
m_transformedTrajectory = TrajectoryTransform::transformToNewTarget(intendendTrajectory, newTarget);
|
||||
}
|
||||
|
||||
std::vector<Core::GeoPositionRelativeTime> AbstractFiringStrategy::buildTrajectoryGeometry(const QVector<TrajectoryPoint> &relativeTrajectory)
|
||||
{
|
||||
// sanity check:
|
||||
if (relativeTrajectory.size() < 2)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " size of relativeTrajectory not sufficiant, size=" << relativeTrajectory.size();
|
||||
return {};
|
||||
}
|
||||
|
||||
// setup some vars of effector, which is used as launch position:
|
||||
Core::GeoPosition effectorPositionGeo = participantPosition(m_effector->participantId());
|
||||
const LtsCoordTrans::UtmCoordinate &launchUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(effectorPositionGeo.lon(), effectorPositionGeo.lat());
|
||||
|
||||
|
||||
std::vector<Core::GeoPositionRelativeTime> geometry;
|
||||
geometry.reserve(relativeTrajectory.size());
|
||||
|
||||
// Aehnlich wie Lts/Proxies/TrainingAreaBase/Plugins/AdlerJson/aes_handler.cpp Zeile 365
|
||||
for (const TrajectoryPoint &trajPntRelPos : qAsConst(relativeTrajectory))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Flugbahnpunkt: trajPntRelPos :" << trajPntRelPos; // benefit from operator<<:
|
||||
|
||||
// // geographic offers nice feature to add an offset:
|
||||
// const QPointF &trajectoryAbsGeo = launchUtm.geographic(trajPntRelPos);
|
||||
// but lets stay with trajectoryAbsUtm to enable DEBUG_LOG
|
||||
|
||||
const QPointF &trajPntRelPosUtm = trajPntRelPos.position.toPointF(); // still relativ to launch
|
||||
const LtsCoordTrans::UtmCoordinate trajPntAbsUtm(launchUtm.zone,
|
||||
launchUtm.x + trajPntRelPosUtm.x(),
|
||||
launchUtm.y + trajPntRelPosUtm.y());
|
||||
const QPointF &trajPntAbsGeo = trajPntAbsUtm.geographic();
|
||||
|
||||
// Position des Participants mit der m_participantId
|
||||
const double zValue = effectorPositionGeo.z() + trajPntRelPos.position.z(); // trajPntRelPos.position.z() ist die Hoehe
|
||||
|
||||
DEBUG_LOG(m_logger) << "trajPntAbsUtm :" << trajPntAbsUtm << ", trajPntAbsGeo :" << trajPntAbsGeo;
|
||||
geometry.emplace_back(Core::GeoPositionRelativeTime(trajPntAbsGeo.x(), trajPntAbsGeo.y(), zValue, trajPntRelPos.time));
|
||||
}
|
||||
return geometry;
|
||||
}
|
||||
|
||||
TrajectoryTimeAware AbstractFiringStrategy::buildTrajectoryTimeAware(const std::vector<Core::GeoPositionRelativeTime> &trajectoryGeometry, qint64 trajectoryStartTime, int index)
|
||||
{
|
||||
// sanity check:
|
||||
if (trajectoryGeometry.size() < 2)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " size of trajectoryGeometry not sufficiant, size=" << trajectoryGeometry.size();
|
||||
return {};
|
||||
}
|
||||
|
||||
TrajectoryTimeAware trajectory;
|
||||
trajectory.trajectoryStartTime(trajectoryStartTime);
|
||||
|
||||
trajectory.index(index); // see SituationMap : charge_effect_to_map ::updateSingleTrajectory()
|
||||
// [E01562-259] use originatorId, originatorTypeId (instead of aesItemId, aesTypeId)
|
||||
trajectory.originatorId(m_effector->aesItemId());
|
||||
trajectory.originatorTypeId(ProjectDataManagement::StateChangeOriginator::ChargeEffect);
|
||||
trajectory.geometry(trajectoryGeometry);
|
||||
return trajectory;
|
||||
}
|
||||
|
||||
int AbstractFiringStrategy::sendChargeEffect(const TrajectoryTimeAware &trajectoryTimeAware, const QJsonObject &properties)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "sendChargeEffect";
|
||||
|
||||
const auto &trajGeometry = trajectoryTimeAware.geometry();
|
||||
|
||||
// sanity check:
|
||||
if (trajGeometry.size() < 2)
|
||||
{
|
||||
ERROR_LOG(m_logger) << LOGFUNCTION
|
||||
<< " size of trajectoryTimeAware.geometry not sufficiant, size=" << trajGeometry.size();
|
||||
return -1;
|
||||
}
|
||||
|
||||
const qint64 trajectoryStartTime = trajectoryTimeAware.trajectoryStartTime();
|
||||
|
||||
ChargeEffectModifyRequest chargeEffect;
|
||||
chargeEffect.id(0);
|
||||
chargeEffect.effectDuration(3000);
|
||||
chargeEffect.name("Schuss");
|
||||
chargeEffect.chargeTypeId(m_effector->effectorData().chargeStruct().chargeTypeId());
|
||||
chargeEffect.effectStart(trajectoryStartTime + trajectoryTimeAware.geometry().back().relativeTime()); // Einschlag Zeit
|
||||
chargeEffect.igniterTypeId(m_effector->effectorData().chargeStruct().igniterTypeId());
|
||||
chargeEffect.gearTypeId(gearTypeId(m_effector->effectorData().chargeStruct().chargeTypeId(), m_effector->participantId()));
|
||||
chargeEffect.originatorId(m_effector->aesItemId());
|
||||
chargeEffect.originatorTypeId(ProjectDataManagement::StateChangeOriginator::AreaEffectSimulation);
|
||||
chargeEffect.properties(QJsonDocument(properties).toJson().toStdString());
|
||||
|
||||
const Core::GeoPosition &impactPosition = trajGeometry.back();
|
||||
chargeEffect.position(impactPosition); // Impact Position
|
||||
|
||||
chargeEffect.trajectoryTimeAware(trajectoryTimeAware);
|
||||
|
||||
const auto &reply = m_effector->mainHandler()->chargeEffectHandler()->createChargeEffect(chargeEffect);
|
||||
DEBUG_LOG(m_logger) << "reply.id=" << reply.id() << ", str:" << reply.str() << ", uniqueId:" << reply.uniqueId();
|
||||
return reply.id();
|
||||
}
|
||||
|
||||
Core::GeoPosition AbstractFiringStrategy::participantPosition(int participantId)
|
||||
{
|
||||
m_effector->mainHandler()->dds()->ppmDtc()->enableParticipantPosition(true);
|
||||
const ParticipantManagement::ParticipantPosition &pos = m_effector->mainHandler()->dds()->ppmDtc()->participantPosition(participantId);
|
||||
return pos.pos();
|
||||
}
|
||||
|
||||
int32_t AbstractFiringStrategy::gearTypeId(int chargeTypeId, int participantId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getGearTypeId"
|
||||
<< ", chargeTypeId:" << chargeTypeId << ", participantId:" << participantId;
|
||||
|
||||
m_effector->mainHandler()->dds()->ppmDtc()->enableDynamicParticipantData(true);
|
||||
m_effector->mainHandler()->dds()->ppmDtc()->waitForHistoricalDataDynamicParticipantData(1000);
|
||||
const ParticipantManagement::DynamicParticipantData &dynamicParticipantData = m_effector->mainHandler()->dds()->ppmDtc()->dynamicParticipantData(participantId);
|
||||
DEBUG_LOG(m_logger) << "gearSize " << dynamicParticipantData.gear().size();
|
||||
|
||||
const auto& participantData_gear = dynamicParticipantData.gear();
|
||||
for (const auto &gear : qAsConst(participantData_gear))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "gear.chargeTypeId(): " << gear.chargeTypeId() << ", chargeTypeId:" << chargeTypeId;
|
||||
if (gear.chargeTypeId() == chargeTypeId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "getGearTypeId return: " << gear.gearTypeId();
|
||||
if (gear.gearTypeId() != 0)
|
||||
return gear.gearTypeId();
|
||||
else
|
||||
return 701; // MALTE XKCD
|
||||
}
|
||||
}
|
||||
return 701; // MALTE XKCD
|
||||
}
|
||||
|
||||
qint64 AbstractFiringStrategy::getStartTime() const
|
||||
{
|
||||
const auto trajectoryAndEffectStartTime = m_effector->mainHandler()->dds()->currentPartitionTimeMSec() + 1000;
|
||||
return trajectoryAndEffectStartTime;
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Base Class for Effector Firing Strategy
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2026-05-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Diese Implementierung des Strategie- und Factory-Patterns ist ein Schritt, die Logik der Erzeugung der Trajektorien und der ChargeEffects von dem Effektor zu trennen.
|
||||
* Aus zeitlichen Gründen ist die SW-technische Abhängigkeit Strategie und Effektor bidirektional.
|
||||
*
|
||||
* Bei zukünftigen Implementierungen sollte diese Abhängigkeit nur in einer Richtung bestehen.
|
||||
* Oder anders gesagt: Die Strategie sollte möglichst UNABHÄNGIG (von ihren Vater) sein.
|
||||
*
|
||||
* Vorteile waeren:
|
||||
* - Strategie kann unabhängig erstellt, gestestet und vielfältiger/flexibler ein gesetzt werden.
|
||||
* - Es ist besser erkennbar, WAS die Strategie genau macht, da Ein- und Ausgangsdaten klar definiert sind.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AreaEffectSimulation/logger.h>
|
||||
#include <QObject>
|
||||
#include <Core/core.hpp>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class GeoPosition;
|
||||
}
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class ObjectEffector;
|
||||
class TrajectoryPoint;
|
||||
class TrajectoryTimeAware;
|
||||
|
||||
class AbstractFiringStrategy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AbstractFiringStrategy(ObjectEffector *parent);
|
||||
virtual ~AbstractFiringStrategy();
|
||||
|
||||
virtual void doFiring() = 0;
|
||||
|
||||
Q_SIGNALS:
|
||||
// Has to be emitted in doFiring() implementation!
|
||||
void signalFired(int participantId, int aesItemId, const QVector<int> &chargeEffectIds);
|
||||
|
||||
protected:
|
||||
// methods:
|
||||
void calculateDispersionTrajectory();
|
||||
std::vector<Core::GeoPositionRelativeTime> buildTrajectoryGeometry(const QVector<TrajectoryPoint> &trajectory);
|
||||
TrajectoryTimeAware buildTrajectoryTimeAware(const std::vector<Core::GeoPositionRelativeTime> &trajectoryGeometry, qint64 curTime, int index = 0);
|
||||
|
||||
int sendChargeEffect(const TrajectoryTimeAware &trajectoryTimeAware, const QJsonObject &properties = QJsonObject());
|
||||
|
||||
Core::GeoPosition participantPosition(int participantId);
|
||||
int32_t gearTypeId(int chargeTypeId, int participantId);
|
||||
qint64 getStartTime() const;
|
||||
|
||||
|
||||
// attributes:
|
||||
ObjectEffector *m_effector {nullptr};
|
||||
QVector<TrajectoryPoint> m_transformedTrajectory;
|
||||
LOGGER_T &m_logger;
|
||||
}; // class ObjectEffector
|
||||
} // namespace AreaEffectSimulation
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Default Effector Firing Strategy (RRohr)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2026-05-11
|
||||
*/
|
||||
|
||||
#include "default_firing_strategy.h"
|
||||
#include "object_effector.h"
|
||||
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
DefaultFiringStrategy::DefaultFiringStrategy(ObjectEffector *effector)
|
||||
: BaseClass(effector)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
DEBUG_LOG(m_logger) << "using DefaultFiringStrategy";
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
DefaultFiringStrategy::~DefaultFiringStrategy()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
void DefaultFiringStrategy::doFiring()
|
||||
{
|
||||
calculateDispersionTrajectory();
|
||||
|
||||
const qint64 trajectoryStartTime = getStartTime();
|
||||
|
||||
const auto &geometry = buildTrajectoryGeometry(m_transformedTrajectory);
|
||||
const auto &trajTimeAware = buildTrajectoryTimeAware(geometry, trajectoryStartTime);
|
||||
|
||||
const int chargeEffectId = sendChargeEffect(trajTimeAware);
|
||||
|
||||
emit signalFired(m_effector->participantId(), m_effector->aesItemId(), {chargeEffectId});
|
||||
DEBUG_LOG(m_logger) << "created ChargeEffectId: " << chargeEffectId;
|
||||
}
|
||||
|
||||
} //namespace AreaEffectSimulation
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Default Effector Firing Strategy (RRohr)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2026-05-11
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "abstract_firing_strategy.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class DefaultFiringStrategy final : public AbstractFiringStrategy
|
||||
{
|
||||
using BaseClass = AbstractFiringStrategy;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DefaultFiringStrategy(ObjectEffector *effector);
|
||||
virtual ~DefaultFiringStrategy();
|
||||
|
||||
void doFiring() override;
|
||||
|
||||
}; // class DefaultFiringStrategy
|
||||
} // namespace AreaEffectSimulation
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* Effector Firing Strategy for DM72
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2026-05-21
|
||||
*/
|
||||
|
||||
#include "dm72_firing_strategy.h"
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "object_effector.h"
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <TrainingAreaBase/Plugins/AdlerJson/telegrams.h>
|
||||
#include <Trajectory/trajectory_transform.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QTransform>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
Dm72FiringStrategy::Dm72FiringStrategy(ObjectEffector *effector)
|
||||
: AbstractFiringStrategy(effector)
|
||||
{
|
||||
init();
|
||||
|
||||
DEBUG_LOG(m_logger) << "using Dm72FiringStrategy";
|
||||
}
|
||||
|
||||
void Dm72FiringStrategy::doFiring()
|
||||
{
|
||||
m_transformedTrajectory = TrajectoryTransform::transformToNewTarget(m_effector->intendendTrajectory(), m_impactPoints.at(m_impactPointIndex++));
|
||||
|
||||
if (m_impactPointIndex >= m_impactPoints.size())
|
||||
m_impactPointIndex = 0;
|
||||
|
||||
const qint64 trajectoryStartTime = getStartTime();
|
||||
|
||||
const auto &geometry = buildTrajectoryGeometry(m_transformedTrajectory);
|
||||
const auto &trajTimeAware = buildTrajectoryTimeAware(geometry, trajectoryStartTime);
|
||||
|
||||
QJsonObject props{{QStringLiteral("effectDurationMsec"), m_effectDurationMsec}};
|
||||
const int chargeEffectId = sendChargeEffect(trajTimeAware, props);
|
||||
|
||||
emit signalFired(m_effector->participantId(), m_effector->aesItemId(), {chargeEffectId});
|
||||
}
|
||||
|
||||
void Dm72FiringStrategy::init()
|
||||
{
|
||||
using namespace AdlerJson;
|
||||
using namespace LtsCoordTrans;
|
||||
|
||||
m_impactPointIndex = 0;
|
||||
m_impactPoints.clear();
|
||||
|
||||
bool bOk;
|
||||
WirkmittelFeuerkommandoRakete wirkmittel;
|
||||
const QJsonObject properties = QJsonDocument::fromJson(QByteArray::fromStdString(m_effector->effectorData().properties())).object();
|
||||
const Core::GeoPosition geoStartPos = participantPosition(m_effector->participantId());
|
||||
const UtmCoordinate utmStartPos = UtmCoordinate::fromGeographic(geoStartPos.lon(), geoStartPos.lat());
|
||||
|
||||
wirkmittelFeuerkommandoRaketeFromJson(properties, wirkmittel, bOk);
|
||||
|
||||
using UtmWithHeight = std::pair<UtmCoordinate, int>;
|
||||
|
||||
m_effectDurationMsec = getFeuerkommandoRaketeEffectDurationMsec(properties);
|
||||
QVector<UtmWithHeight> tempUtmTreffpunkte;
|
||||
tempUtmTreffpunkte.reserve(wirkmittel.geschoss.anzahl);
|
||||
|
||||
for (const Treffpunkt &treffpunkt : qAsConst(wirkmittel.treffpunkte))
|
||||
{
|
||||
const UtmCoordinate utmTreffpunkt = UtmCoordinate::fromGeographic(treffpunkt.koordinate.koordinate.longitude * deg2rad(),
|
||||
treffpunkt.koordinate.koordinate.latitude * deg2rad(),
|
||||
utmStartPos.zone);
|
||||
|
||||
for (int anzahlCounter = 1; anzahlCounter <= treffpunkt.anzahl; ++anzahlCounter)
|
||||
tempUtmTreffpunkte.append({utmTreffpunkt, treffpunkt.koordinate.hoehe});
|
||||
}
|
||||
|
||||
const QVector<QPointF> mineLayingCentroidDeviations = mineLayingCentroids();
|
||||
int deviationIndex = 0;
|
||||
|
||||
for (const UtmWithHeight &tempUtmTreffpunkt : tempUtmTreffpunkte)
|
||||
{
|
||||
const QPointF &deviation = mineLayingCentroidDeviations.at(deviationIndex++);
|
||||
const LtsUtils::QPoint3D impactPoint(tempUtmTreffpunkt.first.x - utmStartPos.x + deviation.x(),
|
||||
tempUtmTreffpunkt.first.y - utmStartPos.y + deviation.y(),
|
||||
tempUtmTreffpunkt.second);
|
||||
|
||||
m_impactPoints.append(impactPoint);
|
||||
|
||||
if (deviationIndex >= mineLayingCentroidDeviations.size())
|
||||
deviationIndex = 0;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got " << m_impactPoints.size() << " impact points";
|
||||
}
|
||||
|
||||
QVector<QPointF> Dm72FiringStrategy::mineLayingCentroids() const
|
||||
{
|
||||
using namespace LtsCoordTrans;
|
||||
|
||||
const int chargeTypeId = m_effector->effectorData().chargeStruct().chargeTypeId();
|
||||
const ProjectDataManagement::ChargeType &chargeType = m_effector->mainHandler()->dds()->pdmDtc()->chargeType(chargeTypeId);
|
||||
const QJsonObject chargeTypeProperties = QJsonDocument::fromJson(QByteArray::fromStdString(chargeType.properties())).object();
|
||||
const QJsonObject mineLaying = chargeTypeProperties.value(QStringLiteral("mineLaying")).toObject();
|
||||
const QJsonArray mineLayingPattern = mineLaying.value(QStringLiteral("pattern")).toArray();
|
||||
/* QMap is used here because it sort its entries by key.
|
||||
* Since each pattern has an id and we want the pattern sorted by id, adding them to a QMap
|
||||
* automatically sorts the pattern.
|
||||
*/
|
||||
QMap<int, QPointF> centroidsMap;
|
||||
const UtmCoordinate mhpUtm = UtmCoordinate::fromGeographic(m_effector->effectorData().mhpPosition().lon(),
|
||||
m_effector->effectorData().mhpPosition().lat());
|
||||
const double rotationAngle = angleToMhpUtm(mhpUtm.toPoint());
|
||||
QTransform rotation;
|
||||
|
||||
rotation.rotate(rotationAngle);
|
||||
|
||||
for (const QJsonValue &patternValue: mineLayingPattern)
|
||||
{
|
||||
const QJsonObject patternObject = patternValue.toObject();
|
||||
const int patternId = patternObject.value(QStringLiteral("id")).toInt();
|
||||
const QJsonArray patternPositionArray = patternObject.value(QStringLiteral("positions")).toArray();
|
||||
int sumNorthing = 0;
|
||||
int sumEasting = 0;
|
||||
|
||||
for (const QJsonValue &positionValue : patternPositionArray)
|
||||
{
|
||||
const QJsonObject positionObject = positionValue.toObject();
|
||||
|
||||
const int northing = positionObject.value(QStringLiteral("northing")).toInt();
|
||||
const int easting = positionObject.value(QStringLiteral("easting")).toInt();
|
||||
|
||||
sumNorthing += northing;
|
||||
sumEasting += easting;
|
||||
}
|
||||
|
||||
QPointF centroid(static_cast<double>(sumEasting) / patternPositionArray.size(), static_cast<double>(sumNorthing) / patternPositionArray.size());
|
||||
|
||||
centroid = rotation.map(centroid);
|
||||
|
||||
centroidsMap.insert(patternId, centroid);
|
||||
}
|
||||
|
||||
if (centroidsMap.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Could not read mine laying patterns from DM72 ammunition properties for creation of DM72 trajectories.";
|
||||
|
||||
return { QPointF(0.0, 0.0) }; // We have to return at least one QPointF(0.0, 0.0) to ensure later DM72 functionality
|
||||
}
|
||||
|
||||
int vectorIndex = 0;
|
||||
QVector<QPointF> mineLayingCentroids;
|
||||
|
||||
mineLayingCentroids.reserve(centroidsMap.size());
|
||||
|
||||
for (auto it = centroidsMap.constBegin(); it != centroidsMap.constEnd(); ++it)
|
||||
mineLayingCentroids.insert(vectorIndex++, it.value()); // insert with index ensures sorting
|
||||
|
||||
return mineLayingCentroids;
|
||||
}
|
||||
|
||||
double Dm72FiringStrategy::angleToMhpUtm(const QPointF &mhpUtm) const
|
||||
{
|
||||
const ParticipantManagement::ParticipantPosition &ownPosition = m_effector->mainHandler()->dds()->ppmDtc()->participantPosition(m_effector->participantId());
|
||||
const LtsCoordTrans::UtmCoordinate ownPositionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(ownPosition.pos().lon(), ownPosition.pos().lat());
|
||||
const double angle = QLineF(mhpUtm, ownPositionUtm.toPoint()).angle();
|
||||
double northAngle = 90 - angle;
|
||||
|
||||
northAngle = std::fmod(northAngle, 360.0);
|
||||
|
||||
if (northAngle < 0.0)
|
||||
northAngle += 360.0;
|
||||
|
||||
DEBUG_LOG(m_logger) << "angleToMhpUtm:"
|
||||
<< "mhpUtm=" << mhpUtm
|
||||
<< ", ownPositionUtm=" << ownPositionUtm.toPoint()
|
||||
<< ", angle=" << angle
|
||||
<< ", northAngle=" << northAngle;
|
||||
|
||||
return northAngle;
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Effector Firing Strategy for DM72
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2026-05-21
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "abstract_firing_strategy.h"
|
||||
|
||||
namespace LtsUtils
|
||||
{
|
||||
class QPoint3D;
|
||||
}
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class Dm72FiringStrategy : public AbstractFiringStrategy
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Dm72FiringStrategy(ObjectEffector *effector);
|
||||
|
||||
void doFiring() override final;
|
||||
|
||||
private: // methods
|
||||
void init();
|
||||
QVector<QPointF> mineLayingCentroids() const;
|
||||
double angleToMhpUtm(const QPointF &mhpUtm) const;
|
||||
|
||||
private: // attributes
|
||||
QVector<LtsUtils::QPoint3D> m_impactPoints;
|
||||
int m_impactPointIndex {0};
|
||||
int m_effectDurationMsec = 3 * 60 * 60 * 1000; // default 3h
|
||||
|
||||
}; // class Dm72FiringStrategy
|
||||
} // namespace AreaEffectSimulation
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Namespace and function for creating a Firing Strategy
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2026-05-11
|
||||
*/
|
||||
|
||||
#include "firing_strategy_factory.h"
|
||||
|
||||
#include "default_firing_strategy.h"
|
||||
#include "dm72_firing_strategy.h"
|
||||
#include "gmlrs_firing_strategy.h"
|
||||
#include "smart_firing_strategy.h"
|
||||
|
||||
#include "main_handler.h"
|
||||
#include "object_effector.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
namespace FiringStrategyFactory
|
||||
{
|
||||
|
||||
AbstractFiringStrategy *createFiringStrategy(ObjectEffector *parent)
|
||||
{
|
||||
LOGGER_T &logger = getLogger("FiringStrategyFactory");
|
||||
|
||||
TRACE_LOG(logger) << LOGFUNCTION << " START";
|
||||
|
||||
if (!parent)
|
||||
return nullptr;
|
||||
|
||||
const ChargeStruct &cs = parent->effectorData().chargeStruct();
|
||||
|
||||
DEBUG_LOG(logger) << LOGFUNCTION << " ChargeStruct = " << cs;
|
||||
|
||||
// GMLRS
|
||||
if (parent->mainHandler()->dds()->pdmDtc()->isGmlrs(cs.chargeTypeId()))
|
||||
{
|
||||
TRACE_LOG(logger) << LOGFUNCTION << " END";
|
||||
return new GmlrsFiringStrategy(parent);
|
||||
}
|
||||
|
||||
// SMArt
|
||||
const bool bIsSmart = parent->mainHandler()->dds()->pdmDtc()->isSmart(cs.chargeTypeId(), cs.igniterTypeId(), cs.igniterFunctionId());
|
||||
if (bIsSmart)
|
||||
{
|
||||
TRACE_LOG(logger) << LOGFUNCTION << " END";
|
||||
return new SmartFiringStrategy(parent);
|
||||
}
|
||||
|
||||
// DM72
|
||||
if (parent->mainHandler()->dds()->pdmDtc()->isDm72(cs.chargeTypeId()))
|
||||
{
|
||||
TRACE_LOG(logger) << LOGFUNCTION << " END";
|
||||
return new Dm72FiringStrategy(parent);
|
||||
}
|
||||
|
||||
TRACE_LOG(logger) << LOGFUNCTION << " END";
|
||||
return new DefaultFiringStrategy(parent);
|
||||
}
|
||||
|
||||
} //namespace FiringFactory
|
||||
} //namespace AreaEffectSimulation
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Namespace and function for creating a Firing Strategy
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2026-05-11
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class AbstractFiringStrategy;
|
||||
class ObjectEffector;
|
||||
|
||||
namespace FiringStrategyFactory
|
||||
{
|
||||
|
||||
AbstractFiringStrategy *createFiringStrategy(ObjectEffector *parent);
|
||||
|
||||
} //namespace FiringFactory
|
||||
} //namespace AreaEffectSimulation
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Effector Firing Strategy for GMLRS
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2026-05-12
|
||||
*/
|
||||
|
||||
#include "gmlrs_firing_strategy.h"
|
||||
#include "object_effector.h"
|
||||
|
||||
#include <TrainingAreaBase/Plugins/AdlerJson/telegrams.h>
|
||||
#include <Trajectory/trajectory_transform.h>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
GmlrsFiringStrategy::GmlrsFiringStrategy(ObjectEffector *effector)
|
||||
: BaseClass(effector)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
init();
|
||||
DEBUG_LOG(m_logger) << "using GmlrsFiringStrategy";
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
GmlrsFiringStrategy::~GmlrsFiringStrategy()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
void GmlrsFiringStrategy::doFiring()
|
||||
{
|
||||
m_transformedTrajectory = TrajectoryTransform::transformToNewTarget(m_effector->intendendTrajectory(), m_impactPoints.at(m_impactPointIndex++));
|
||||
|
||||
if (m_impactPointIndex >= m_impactPoints.size())
|
||||
m_impactPointIndex = 0;
|
||||
|
||||
const qint64 trajectoryStartTime = getStartTime();
|
||||
|
||||
const auto &geometry = buildTrajectoryGeometry(m_transformedTrajectory);
|
||||
const auto &trajTimeAware = buildTrajectoryTimeAware(geometry, trajectoryStartTime);
|
||||
|
||||
const int chargeEffectId = sendChargeEffect(trajTimeAware);
|
||||
|
||||
emit signalFired(m_effector->participantId(), m_effector->aesItemId(), {chargeEffectId});
|
||||
}
|
||||
|
||||
void GmlrsFiringStrategy::init()
|
||||
{
|
||||
using namespace AdlerJson;
|
||||
|
||||
m_impactPointIndex = 0;
|
||||
m_impactPoints.clear();
|
||||
|
||||
const QJsonObject &properties = QJsonDocument::fromJson(QByteArray::fromStdString(m_effector->effectorData().properties())).object();
|
||||
const Core::GeoPosition &geoStartPos = participantPosition(m_effector->participantId());
|
||||
const LtsCoordTrans::UtmCoordinate &utmStartPos = LtsCoordTrans::UtmCoordinate::fromGeographic(geoStartPos.lon(), geoStartPos.lat());
|
||||
|
||||
bool bOk = false;
|
||||
WirkmittelFeuerkommandoRakete wirkmittel;
|
||||
wirkmittelFeuerkommandoRaketeFromJson(properties, wirkmittel, bOk);
|
||||
|
||||
for (const Treffpunkt &treffpunkt : qAsConst(wirkmittel.treffpunkte))
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate utmTreffpunkt =
|
||||
LtsCoordTrans::UtmCoordinate::fromGeographic(treffpunkt.koordinate.koordinate.longitude * LtsCoordTrans::deg2rad(),
|
||||
treffpunkt.koordinate.koordinate.latitude * LtsCoordTrans::deg2rad());
|
||||
const LtsUtils::QPoint3D relImpactPoint(utmTreffpunkt.x - utmStartPos.x,
|
||||
utmTreffpunkt.y - utmStartPos.y,
|
||||
treffpunkt.koordinate.hoehe);
|
||||
|
||||
for (int anzahlCounter = 1; anzahlCounter <= treffpunkt.anzahl; ++anzahlCounter)
|
||||
m_impactPoints.append(relImpactPoint);
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Got " << m_impactPoints.size() << " impact points";
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Effector Firing Strategy for GMLRS
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Hannes Fritsche, ESZS, 2026-05-12
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "abstract_firing_strategy.h"
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class RelativePosition;
|
||||
}
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class GmlrsFiringStrategy final : public AbstractFiringStrategy
|
||||
{
|
||||
using BaseClass = AbstractFiringStrategy;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GmlrsFiringStrategy(ObjectEffector *effector);
|
||||
virtual ~GmlrsFiringStrategy();
|
||||
|
||||
void doFiring() override;
|
||||
|
||||
private: // methods
|
||||
void init();
|
||||
|
||||
private: // attributes
|
||||
QVector<LtsUtils::QPoint3D> m_impactPoints;
|
||||
int m_impactPointIndex {0};
|
||||
}; // class GmlrsFiringStrategy
|
||||
} // namespace AreaEffectSimulation
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Effector Firing Strategy for SMart
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, ESVG, 2026-05-20
|
||||
*/
|
||||
|
||||
#include "smart_firing_strategy.h"
|
||||
#include "object_effector.h"
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <TrainingAreaBase/Plugins/AdlerJson/telegrams.h>
|
||||
#include <TrajectorySplitter/trajectory_splitter.h>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
SmartFiringStrategy::SmartFiringStrategy(ObjectEffector *effector)
|
||||
: BaseClass(effector)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
DEBUG_LOG(m_logger) << "using SmartFiringStrategy";
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
SmartFiringStrategy::~SmartFiringStrategy()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
void SmartFiringStrategy::doFiring()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
|
||||
// by default, following is done
|
||||
// - calculateDispersionTrajectory
|
||||
// - calc new target
|
||||
// - calc matching trajectory
|
||||
// (intendendTrajectory -> m_transformedTrajectory)
|
||||
// - sendChargeEffect
|
||||
// - emit signalFired
|
||||
|
||||
// for SMArt, calculateDispersionTrajectory is not necessary
|
||||
// But we have to split the tow-in-one trajectory:
|
||||
|
||||
const qint64 trajectoryStartTime = getStartTime();
|
||||
|
||||
//
|
||||
// first check, if trajectory is a tow-in-one trajectory:
|
||||
//
|
||||
|
||||
// convert from intendendTrajectory (relativ) to TRAJECTORY_TYPE (absolute)
|
||||
// The TrajectorySplitter needs TRAJECTORY_TYPE
|
||||
// using TRAJECTORY_TYPE = std::vector<Core::GeoPositionRelativeTime>;
|
||||
const auto &intendendTrajectory = m_effector->intendendTrajectory();
|
||||
const auto &trajGeometry = buildTrajectoryGeometry(intendendTrajectory);
|
||||
|
||||
// split and avoid copying:
|
||||
const TrajectorySplitter<std::vector<Core::GeoPositionRelativeTime>> splitter(trajGeometry);
|
||||
const auto &trajGeo1 = splitter.getTrajectory1();
|
||||
const auto &trajGeo2 = splitter.getTrajectory2();
|
||||
|
||||
DEBUG_LOG(m_logger) << "splitter: " << " intendendTrajectory.size = " << intendendTrajectory.size();
|
||||
DEBUG_LOG(m_logger) << "splitter: " << " trajGeometry.size = " << trajGeometry.size();
|
||||
DEBUG_LOG(m_logger) << "splitter: " << " rawTrajectorySize = " << splitter.rawTrajectorySize();
|
||||
DEBUG_LOG(m_logger) << "splitter: " << " trajGeo1 = " << trajGeo1.size();
|
||||
DEBUG_LOG(m_logger) << "splitter: " << " trajGeo2 = " << trajGeo2.size();
|
||||
|
||||
//
|
||||
// and second, process both Trajectories/Impacts
|
||||
//
|
||||
|
||||
// ToDo: Check, how oftem signalFired should be fired?
|
||||
QVector<int> chargeEffectIds;
|
||||
if (trajGeo1.size() > 2)
|
||||
{
|
||||
const auto &trajTimeAware = buildTrajectoryTimeAware(trajGeo1, trajectoryStartTime, 0);
|
||||
const int chargeEffectId = sendChargeEffect(trajTimeAware);
|
||||
chargeEffectIds << chargeEffectId;
|
||||
DEBUG_LOG(m_logger) << "Trajectory1 - created ChargeEffectId: " << chargeEffectId;
|
||||
}
|
||||
if (trajGeo2.size() > 2)
|
||||
{
|
||||
const auto &trajTimeAware = buildTrajectoryTimeAware(trajGeo2, trajectoryStartTime, 1);
|
||||
const int chargeEffectId = sendChargeEffect(trajTimeAware);
|
||||
chargeEffectIds << chargeEffectId;
|
||||
DEBUG_LOG(m_logger) << "Trajectory2 - created ChargeEffectId: " << chargeEffectId;
|
||||
}
|
||||
if (chargeEffectIds.size())
|
||||
emit signalFired(m_effector->participantId(), m_effector->aesItemId(), chargeEffectIds);
|
||||
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Effector Firing Strategy for SMart
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, ESVG, 2026-05-20
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "abstract_firing_strategy.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class RelativePosition;
|
||||
}
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class SmartFiringStrategy final : public AbstractFiringStrategy
|
||||
{
|
||||
using BaseClass = AbstractFiringStrategy;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SmartFiringStrategy(ObjectEffector *effector);
|
||||
virtual ~SmartFiringStrategy();
|
||||
|
||||
void doFiring() override;
|
||||
|
||||
private: // methods
|
||||
|
||||
private: // attributes
|
||||
|
||||
}; // class SmartFiringStrategy
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,38 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(UnitTestSources
|
||||
effect_cluster_module_test.cpp
|
||||
effect_cluster_module_test.h
|
||||
)
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
ADD_EXECUTABLE(aesModuleTestEffectCluster ${LinkedSources} ${UnitTestSources} )
|
||||
|
||||
TARGET_LINK_LIBRARIES(aesModuleTestEffectCluster
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
LtsCommandLineParser
|
||||
LtsCoordinate
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
ddsconnector
|
||||
svcAesCommon
|
||||
svcAesClient
|
||||
svcBldClient
|
||||
svcExmClient
|
||||
svcIsmClient
|
||||
svcPdmClient
|
||||
svcPpmClient
|
||||
svcTabServer
|
||||
)
|
||||
|
||||
# ADD_TEST(NAME aesModuleTestExplosionCluster COMMAND $<TARGET_FILE:aesUnitTestTneAlgorithmen>)
|
||||
ENDIF()
|
||||
|
||||
#NGL_INSTALL(TESTING SV FILES EffectClusterModifyRequest_ESG.spl DESTINATION bin)
|
||||
NGL_INSTALL(SV FILES EffectClusterModifyRequest_ESG.spl DESTINATION bin)
|
||||
Executable
+631
@@ -0,0 +1,631 @@
|
||||
<!DOCTYPE Samples>
|
||||
<Samples>
|
||||
<Sample>
|
||||
<TopicName>LTS_EffectClusterModifyRequest</TopicName>
|
||||
<TypeName>AreaEffectSimulation::EffectClusterModifyRequest</TypeName>
|
||||
<Pause>1000</Pause>
|
||||
<DdsData topic="LTS_EffectClusterModifyRequest" type="AreaEffectSimulation::EffectClusterModifyRequest" count="17">
|
||||
<id>8</id>
|
||||
<name>eb511ab7d8414b88af248fd32ef03285</name>
|
||||
<element>eb511ab7d8414b88af248fd32ef03285</element>
|
||||
<effectStart/>
|
||||
<effectDuration>0</effectDuration>
|
||||
<effectSourceId>1</effectSourceId>
|
||||
<area type="AreaEffectSimulation::Area" count="4">
|
||||
<cornerBottomLeft type="Core::GeoPosition2D" count="2">
|
||||
<lon>0.201951</lon>
|
||||
<lat>0.915259</lat>
|
||||
</cornerBottomLeft>
|
||||
<width>50</width>
|
||||
<height>50</height>
|
||||
<rotation>0</rotation>
|
||||
</area>
|
||||
<explosionGeometry>4</explosionGeometry>
|
||||
<tla>0</tla>
|
||||
<effectors count="1">
|
||||
<effectors.1>
|
||||
<angleOfFall>0</angleOfFall>
|
||||
<participantId>240</participantId>
|
||||
<flightTime>39526.3</flightTime>
|
||||
<peakHeight>2002</peakHeight>
|
||||
<interval>0</interval>
|
||||
<chargeStruct type="AreaEffectSimulation::ChargeStruct" count="3">
|
||||
<chargeTypeId>367</chargeTypeId>
|
||||
<igniterTypeId>1</igniterTypeId>
|
||||
<igniterFunctionId>2</igniterFunctionId>
|
||||
</chargeStruct>
|
||||
<chargeAmount>2</chargeAmount>
|
||||
<mhpScatterLenght>3.08314e-316</mhpScatterLenght>
|
||||
<mhpScatterWidth>8.76302e-315</mhpScatterWidth>
|
||||
<mhpScatterLengthDetonationHeight>9.69057e-316</mhpScatterLengthDetonationHeight>
|
||||
<mhpScatterWidthDetonationHeight>8.76639e-315</mhpScatterWidthDetonationHeight>
|
||||
<mhpRotation>-45.4373</mhpRotation>
|
||||
<mhpPosition type="Core::GeoPosition" count="3">
|
||||
<lon>0.201958</lon>
|
||||
<lat>0.915263</lat>
|
||||
<z>88</z>
|
||||
</mhpPosition>
|
||||
<trajectory count="95">
|
||||
<trajectory.1>
|
||||
<lon>0</lon>
|
||||
<lat>0</lat>
|
||||
<z>85</z>
|
||||
<relativeTime>0</relativeTime>
|
||||
</trajectory.1>
|
||||
<trajectory.2>
|
||||
<lon>41.6079</lon>
|
||||
<lat>-39.6154</lat>
|
||||
<z>168.375</z>
|
||||
<relativeTime>0</relativeTime>
|
||||
</trajectory.2>
|
||||
<trajectory.3>
|
||||
<lon>82.7348</lon>
|
||||
<lat>-78.773</lat>
|
||||
<z>249.195</z>
|
||||
<relativeTime>0</relativeTime>
|
||||
</trajectory.3>
|
||||
<trajectory.4>
|
||||
<lon>123.367</lon>
|
||||
<lat>-117.46</lat>
|
||||
<z>327.472</z>
|
||||
<relativeTime>1000</relativeTime>
|
||||
</trajectory.4>
|
||||
<trajectory.5>
|
||||
<lon>169.188</lon>
|
||||
<lat>-161.086</lat>
|
||||
<z>413.849</z>
|
||||
<relativeTime>1000</relativeTime>
|
||||
</trajectory.5>
|
||||
<trajectory.6>
|
||||
<lon>214.339</lon>
|
||||
<lat>-204.075</lat>
|
||||
<z>496.976</z>
|
||||
<relativeTime>2000</relativeTime>
|
||||
</trajectory.6>
|
||||
<trajectory.7>
|
||||
<lon>258.83</lon>
|
||||
<lat>-246.435</lat>
|
||||
<z>576.935</z>
|
||||
<relativeTime>2000</relativeTime>
|
||||
</trajectory.7>
|
||||
<trajectory.8>
|
||||
<lon>302.659</lon>
|
||||
<lat>-288.166</lat>
|
||||
<z>653.787</z>
|
||||
<relativeTime>3000</relativeTime>
|
||||
</trajectory.8>
|
||||
<trajectory.9>
|
||||
<lon>345.82</lon>
|
||||
<lat>-329.26</lat>
|
||||
<z>727.59</z>
|
||||
<relativeTime>3000</relativeTime>
|
||||
</trajectory.9>
|
||||
<trajectory.10>
|
||||
<lon>388.317</lon>
|
||||
<lat>-369.722</lat>
|
||||
<z>798.415</z>
|
||||
<relativeTime>3000</relativeTime>
|
||||
</trajectory.10>
|
||||
<trajectory.11>
|
||||
<lon>430.153</lon>
|
||||
<lat>-409.555</lat>
|
||||
<z>866.336</z>
|
||||
<relativeTime>4000</relativeTime>
|
||||
</trajectory.11>
|
||||
<trajectory.12>
|
||||
<lon>471.335</lon>
|
||||
<lat>-448.764</lat>
|
||||
<z>931.431</z>
|
||||
<relativeTime>4000</relativeTime>
|
||||
</trajectory.12>
|
||||
<trajectory.13>
|
||||
<lon>511.87</lon>
|
||||
<lat>-487.359</lat>
|
||||
<z>993.78</z>
|
||||
<relativeTime>5000</relativeTime>
|
||||
</trajectory.13>
|
||||
<trajectory.14>
|
||||
<lon>551.768</lon>
|
||||
<lat>-525.346</lat>
|
||||
<z>1053.46</z>
|
||||
<relativeTime>5000</relativeTime>
|
||||
</trajectory.14>
|
||||
<trajectory.15>
|
||||
<lon>591.038</lon>
|
||||
<lat>-562.736</lat>
|
||||
<z>1110.56</z>
|
||||
<relativeTime>5000</relativeTime>
|
||||
</trajectory.15>
|
||||
<trajectory.16>
|
||||
<lon>629.691</lon>
|
||||
<lat>-599.538</lat>
|
||||
<z>1165.15</z>
|
||||
<relativeTime>6000</relativeTime>
|
||||
</trajectory.16>
|
||||
<trajectory.17>
|
||||
<lon>672.451</lon>
|
||||
<lat>-640.25</lat>
|
||||
<z>1223.66</z>
|
||||
<relativeTime>6000</relativeTime>
|
||||
</trajectory.17>
|
||||
<trajectory.18>
|
||||
<lon>714.459</lon>
|
||||
<lat>-680.247</lat>
|
||||
<z>1279.22</z>
|
||||
<relativeTime>7000</relativeTime>
|
||||
</trajectory.18>
|
||||
<trajectory.19>
|
||||
<lon>755.733</lon>
|
||||
<lat>-719.544</lat>
|
||||
<z>1331.91</z>
|
||||
<relativeTime>7000</relativeTime>
|
||||
</trajectory.19>
|
||||
<trajectory.20>
|
||||
<lon>796.291</lon>
|
||||
<lat>-758.16</lat>
|
||||
<z>1381.86</z>
|
||||
<relativeTime>8000</relativeTime>
|
||||
</trajectory.20>
|
||||
<trajectory.21>
|
||||
<lon>836.152</lon>
|
||||
<lat>-796.112</lat>
|
||||
<z>1429.17</z>
|
||||
<relativeTime>8000</relativeTime>
|
||||
</trajectory.21>
|
||||
<trajectory.22>
|
||||
<lon>875.334</lon>
|
||||
<lat>-833.417</lat>
|
||||
<z>1473.94</z>
|
||||
<relativeTime>8000</relativeTime>
|
||||
</trajectory.22>
|
||||
<trajectory.23>
|
||||
<lon>913.857</lon>
|
||||
<lat>-870.096</lat>
|
||||
<z>1516.26</z>
|
||||
<relativeTime>9000</relativeTime>
|
||||
</trajectory.23>
|
||||
<trajectory.24>
|
||||
<lon>951.743</lon>
|
||||
<lat>-906.167</lat>
|
||||
<z>1556.24</z>
|
||||
<relativeTime>9000</relativeTime>
|
||||
</trajectory.24>
|
||||
<trajectory.25>
|
||||
<lon>989.01</lon>
|
||||
<lat>-941.65</lat>
|
||||
<z>1593.96</z>
|
||||
<relativeTime>10000</relativeTime>
|
||||
</trajectory.25>
|
||||
<trajectory.26>
|
||||
<lon>1029.72</lon>
|
||||
<lat>-980.41</lat>
|
||||
<z>1633.33</z>
|
||||
<relativeTime>10000</relativeTime>
|
||||
</trajectory.26>
|
||||
<trajectory.27>
|
||||
<lon>1069.72</lon>
|
||||
<lat>-1018.49</lat>
|
||||
<z>1670.15</z>
|
||||
<relativeTime>11000</relativeTime>
|
||||
</trajectory.27>
|
||||
<trajectory.28>
|
||||
<lon>1109.04</lon>
|
||||
<lat>-1055.93</lat>
|
||||
<z>1704.52</z>
|
||||
<relativeTime>11000</relativeTime>
|
||||
</trajectory.28>
|
||||
<trajectory.29>
|
||||
<lon>1147.71</lon>
|
||||
<lat>-1092.75</lat>
|
||||
<z>1736.55</z>
|
||||
<relativeTime>11000</relativeTime>
|
||||
</trajectory.29>
|
||||
<trajectory.30>
|
||||
<lon>1185.76</lon>
|
||||
<lat>-1128.98</lat>
|
||||
<z>1766.34</z>
|
||||
<relativeTime>12000</relativeTime>
|
||||
</trajectory.30>
|
||||
<trajectory.31>
|
||||
<lon>1223.22</lon>
|
||||
<lat>-1164.65</lat>
|
||||
<z>1793.99</z>
|
||||
<relativeTime>12000</relativeTime>
|
||||
</trajectory.31>
|
||||
<trajectory.32>
|
||||
<lon>1260.12</lon>
|
||||
<lat>-1199.78</lat>
|
||||
<z>1819.58</z>
|
||||
<relativeTime>13000</relativeTime>
|
||||
</trajectory.32>
|
||||
<trajectory.33>
|
||||
<lon>1296.49</lon>
|
||||
<lat>-1234.41</lat>
|
||||
<z>1843.2</z>
|
||||
<relativeTime>13000</relativeTime>
|
||||
</trajectory.33>
|
||||
<trajectory.34>
|
||||
<lon>1335.91</lon>
|
||||
<lat>-1271.94</lat>
|
||||
<z>1867</z>
|
||||
<relativeTime>14000</relativeTime>
|
||||
</trajectory.34>
|
||||
<trajectory.35>
|
||||
<lon>1374.77</lon>
|
||||
<lat>-1308.94</lat>
|
||||
<z>1888.6</z>
|
||||
<relativeTime>14000</relativeTime>
|
||||
</trajectory.35>
|
||||
<trajectory.36>
|
||||
<lon>1413.1</lon>
|
||||
<lat>-1345.43</lat>
|
||||
<z>1908.1</z>
|
||||
<relativeTime>14000</relativeTime>
|
||||
</trajectory.36>
|
||||
<trajectory.37>
|
||||
<lon>1450.94</lon>
|
||||
<lat>-1381.46</lat>
|
||||
<z>1925.57</z>
|
||||
<relativeTime>15000</relativeTime>
|
||||
</trajectory.37>
|
||||
<trajectory.38>
|
||||
<lon>1488.32</lon>
|
||||
<lat>-1417.05</lat>
|
||||
<z>1941.1</z>
|
||||
<relativeTime>15000</relativeTime>
|
||||
</trajectory.38>
|
||||
<trajectory.39>
|
||||
<lon>1525.3</lon>
|
||||
<lat>-1452.26</lat>
|
||||
<z>1954.75</z>
|
||||
<relativeTime>16000</relativeTime>
|
||||
</trajectory.39>
|
||||
<trajectory.40>
|
||||
<lon>1561.9</lon>
|
||||
<lat>-1487.11</lat>
|
||||
<z>1966.58</z>
|
||||
<relativeTime>16000</relativeTime>
|
||||
</trajectory.40>
|
||||
<trajectory.41>
|
||||
<lon>1598.17</lon>
|
||||
<lat>-1521.64</lat>
|
||||
<z>1976.64</z>
|
||||
<relativeTime>16000</relativeTime>
|
||||
</trajectory.41>
|
||||
<trajectory.42>
|
||||
<lon>1634.14</lon>
|
||||
<lat>-1555.89</lat>
|
||||
<z>1984.97</z>
|
||||
<relativeTime>17000</relativeTime>
|
||||
</trajectory.42>
|
||||
<trajectory.43>
|
||||
<lon>1669.86</lon>
|
||||
<lat>-1589.89</lat>
|
||||
<z>1991.63</z>
|
||||
<relativeTime>17000</relativeTime>
|
||||
</trajectory.43>
|
||||
<trajectory.44>
|
||||
<lon>1705.35</lon>
|
||||
<lat>-1623.69</lat>
|
||||
<z>1996.63</z>
|
||||
<relativeTime>18000</relativeTime>
|
||||
</trajectory.44>
|
||||
<trajectory.45>
|
||||
<lon>1740.66</lon>
|
||||
<lat>-1657.31</lat>
|
||||
<z>2000</z>
|
||||
<relativeTime>18000</relativeTime>
|
||||
</trajectory.45>
|
||||
<trajectory.46>
|
||||
<lon>1775.83</lon>
|
||||
<lat>-1690.79</lat>
|
||||
<z>2001.77</z>
|
||||
<relativeTime>19000</relativeTime>
|
||||
</trajectory.46>
|
||||
<trajectory.47>
|
||||
<lon>1810.9</lon>
|
||||
<lat>-1724.18</lat>
|
||||
<z>2001.94</z>
|
||||
<relativeTime>19000</relativeTime>
|
||||
</trajectory.47>
|
||||
<trajectory.48>
|
||||
<lon>1845.89</lon>
|
||||
<lat>-1757.5</lat>
|
||||
<z>2000.51</z>
|
||||
<relativeTime>19000</relativeTime>
|
||||
</trajectory.48>
|
||||
<trajectory.49>
|
||||
<lon>1880.86</lon>
|
||||
<lat>-1790.79</lat>
|
||||
<z>1997.5</z>
|
||||
<relativeTime>20000</relativeTime>
|
||||
</trajectory.49>
|
||||
<trajectory.50>
|
||||
<lon>1915.83</lon>
|
||||
<lat>-1824.09</lat>
|
||||
<z>1992.87</z>
|
||||
<relativeTime>20000</relativeTime>
|
||||
</trajectory.50>
|
||||
<trajectory.51>
|
||||
<lon>1950.85</lon>
|
||||
<lat>-1857.44</lat>
|
||||
<z>1986.63</z>
|
||||
<relativeTime>21000</relativeTime>
|
||||
</trajectory.51>
|
||||
<trajectory.52>
|
||||
<lon>1985.96</lon>
|
||||
<lat>-1890.86</lat>
|
||||
<z>1978.74</z>
|
||||
<relativeTime>21000</relativeTime>
|
||||
</trajectory.52>
|
||||
<trajectory.53>
|
||||
<lon>2021.19</lon>
|
||||
<lat>-1924.41</lat>
|
||||
<z>1969.18</z>
|
||||
<relativeTime>21000</relativeTime>
|
||||
</trajectory.53>
|
||||
<trajectory.54>
|
||||
<lon>2056.58</lon>
|
||||
<lat>-1958.1</lat>
|
||||
<z>1957.91</z>
|
||||
<relativeTime>22000</relativeTime>
|
||||
</trajectory.54>
|
||||
<trajectory.55>
|
||||
<lon>2092.18</lon>
|
||||
<lat>-1991.99</lat>
|
||||
<z>1944.87</z>
|
||||
<relativeTime>22000</relativeTime>
|
||||
</trajectory.55>
|
||||
<trajectory.56>
|
||||
<lon>2128.01</lon>
|
||||
<lat>-2026.11</lat>
|
||||
<z>1930.02</z>
|
||||
<relativeTime>23000</relativeTime>
|
||||
</trajectory.56>
|
||||
<trajectory.57>
|
||||
<lon>2164.13</lon>
|
||||
<lat>-2060.5</lat>
|
||||
<z>1913.29</z>
|
||||
<relativeTime>23000</relativeTime>
|
||||
</trajectory.57>
|
||||
<trajectory.58>
|
||||
<lon>2200.56</lon>
|
||||
<lat>-2095.19</lat>
|
||||
<z>1894.62</z>
|
||||
<relativeTime>23000</relativeTime>
|
||||
</trajectory.58>
|
||||
<trajectory.59>
|
||||
<lon>2237.36</lon>
|
||||
<lat>-2130.22</lat>
|
||||
<z>1873.91</z>
|
||||
<relativeTime>24000</relativeTime>
|
||||
</trajectory.59>
|
||||
<trajectory.60>
|
||||
<lon>2271.16</lon>
|
||||
<lat>-2162.41</lat>
|
||||
<z>1853.24</z>
|
||||
<relativeTime>24000</relativeTime>
|
||||
</trajectory.60>
|
||||
<trajectory.61>
|
||||
<lon>2305.33</lon>
|
||||
<lat>-2194.94</lat>
|
||||
<z>1830.75</z>
|
||||
<relativeTime>25000</relativeTime>
|
||||
</trajectory.61>
|
||||
<trajectory.62>
|
||||
<lon>2339.89</lon>
|
||||
<lat>-2227.84</lat>
|
||||
<z>1806.34</z>
|
||||
<relativeTime>25000</relativeTime>
|
||||
</trajectory.62>
|
||||
<trajectory.63>
|
||||
<lon>2374.89</lon>
|
||||
<lat>-2261.16</lat>
|
||||
<z>1779.93</z>
|
||||
<relativeTime>26000</relativeTime>
|
||||
</trajectory.63>
|
||||
<trajectory.64>
|
||||
<lon>2410.34</lon>
|
||||
<lat>-2294.92</lat>
|
||||
<z>1751.41</z>
|
||||
<relativeTime>26000</relativeTime>
|
||||
</trajectory.64>
|
||||
<trajectory.65>
|
||||
<lon>2446.3</lon>
|
||||
<lat>-2329.15</lat>
|
||||
<z>1720.68</z>
|
||||
<relativeTime>26000</relativeTime>
|
||||
</trajectory.65>
|
||||
<trajectory.66>
|
||||
<lon>2482.79</lon>
|
||||
<lat>-2363.9</lat>
|
||||
<z>1687.61</z>
|
||||
<relativeTime>27000</relativeTime>
|
||||
</trajectory.66>
|
||||
<trajectory.67>
|
||||
<lon>2516.11</lon>
|
||||
<lat>-2395.63</lat>
|
||||
<z>1655.75</z>
|
||||
<relativeTime>27000</relativeTime>
|
||||
</trajectory.67>
|
||||
<trajectory.68>
|
||||
<lon>2549.93</lon>
|
||||
<lat>-2427.82</lat>
|
||||
<z>1621.78</z>
|
||||
<relativeTime>28000</relativeTime>
|
||||
</trajectory.68>
|
||||
<trajectory.69>
|
||||
<lon>2584.26</lon>
|
||||
<lat>-2460.51</lat>
|
||||
<z>1585.61</z>
|
||||
<relativeTime>28000</relativeTime>
|
||||
</trajectory.69>
|
||||
<trajectory.70>
|
||||
<lon>2619.13</lon>
|
||||
<lat>-2493.71</lat>
|
||||
<z>1547.11</z>
|
||||
<relativeTime>28000</relativeTime>
|
||||
</trajectory.70>
|
||||
<trajectory.71>
|
||||
<lon>2654.58</lon>
|
||||
<lat>-2527.47</lat>
|
||||
<z>1506.15</z>
|
||||
<relativeTime>29000</relativeTime>
|
||||
</trajectory.71>
|
||||
<trajectory.72>
|
||||
<lon>2690.64</lon>
|
||||
<lat>-2561.79</lat>
|
||||
<z>1462.59</z>
|
||||
<relativeTime>29000</relativeTime>
|
||||
</trajectory.72>
|
||||
<trajectory.73>
|
||||
<lon>2723.22</lon>
|
||||
<lat>-2592.82</lat>
|
||||
<z>1421.57</z>
|
||||
<relativeTime>30000</relativeTime>
|
||||
</trajectory.73>
|
||||
<trajectory.74>
|
||||
<lon>2756.33</lon>
|
||||
<lat>-2624.34</lat>
|
||||
<z>1378.26</z>
|
||||
<relativeTime>30000</relativeTime>
|
||||
</trajectory.74>
|
||||
<trajectory.75>
|
||||
<lon>2789.99</lon>
|
||||
<lat>-2656.38</lat>
|
||||
<z>1332.55</z>
|
||||
<relativeTime>31000</relativeTime>
|
||||
</trajectory.75>
|
||||
<trajectory.76>
|
||||
<lon>2824.22</lon>
|
||||
<lat>-2688.98</lat>
|
||||
<z>1284.3</z>
|
||||
<relativeTime>31000</relativeTime>
|
||||
</trajectory.76>
|
||||
<trajectory.77>
|
||||
<lon>2859.05</lon>
|
||||
<lat>-2722.14</lat>
|
||||
<z>1233.38</z>
|
||||
<relativeTime>31000</relativeTime>
|
||||
</trajectory.77>
|
||||
<trajectory.78>
|
||||
<lon>2894.51</lon>
|
||||
<lat>-2755.9</lat>
|
||||
<z>1179.62</z>
|
||||
<relativeTime>32000</relativeTime>
|
||||
</trajectory.78>
|
||||
<trajectory.79>
|
||||
<lon>2930.63</lon>
|
||||
<lat>-2790.29</lat>
|
||||
<z>1122.88</z>
|
||||
<relativeTime>32000</relativeTime>
|
||||
</trajectory.79>
|
||||
<trajectory.80>
|
||||
<lon>2962.79</lon>
|
||||
<lat>-2820.91</lat>
|
||||
<z>1070.65</z>
|
||||
<relativeTime>33000</relativeTime>
|
||||
</trajectory.80>
|
||||
<trajectory.81>
|
||||
<lon>2995.5</lon>
|
||||
<lat>-2852.05</lat>
|
||||
<z>1015.86</z>
|
||||
<relativeTime>33000</relativeTime>
|
||||
</trajectory.81>
|
||||
<trajectory.82>
|
||||
<lon>3028.77</lon>
|
||||
<lat>-2883.73</lat>
|
||||
<z>958.393</z>
|
||||
<relativeTime>34000</relativeTime>
|
||||
</trajectory.82>
|
||||
<trajectory.83>
|
||||
<lon>3062.63</lon>
|
||||
<lat>-2915.97</lat>
|
||||
<z>898.099</z>
|
||||
<relativeTime>34000</relativeTime>
|
||||
</trajectory.83>
|
||||
<trajectory.84>
|
||||
<lon>3097.11</lon>
|
||||
<lat>-2948.8</lat>
|
||||
<z>834.825</z>
|
||||
<relativeTime>34000</relativeTime>
|
||||
</trajectory.84>
|
||||
<trajectory.85>
|
||||
<lon>3132.22</lon>
|
||||
<lat>-2982.23</lat>
|
||||
<z>768.404</z>
|
||||
<relativeTime>35000</relativeTime>
|
||||
</trajectory.85>
|
||||
<trajectory.86>
|
||||
<lon>3167.99</lon>
|
||||
<lat>-3016.29</lat>
|
||||
<z>698.657</z>
|
||||
<relativeTime>35000</relativeTime>
|
||||
</trajectory.86>
|
||||
<trajectory.87>
|
||||
<lon>3199.21</lon>
|
||||
<lat>-3046.01</lat>
|
||||
<z>636.077</z>
|
||||
<relativeTime>36000</relativeTime>
|
||||
</trajectory.87>
|
||||
<trajectory.88>
|
||||
<lon>3230.96</lon>
|
||||
<lat>-3076.24</lat>
|
||||
<z>570.777</z>
|
||||
<relativeTime>36000</relativeTime>
|
||||
</trajectory.88>
|
||||
<trajectory.89>
|
||||
<lon>3263.25</lon>
|
||||
<lat>-3106.99</lat>
|
||||
<z>502.616</z>
|
||||
<relativeTime>37000</relativeTime>
|
||||
</trajectory.89>
|
||||
<trajectory.90>
|
||||
<lon>3296.12</lon>
|
||||
<lat>-3138.28</lat>
|
||||
<z>431.443</z>
|
||||
<relativeTime>37000</relativeTime>
|
||||
</trajectory.90>
|
||||
<trajectory.91>
|
||||
<lon>3329.58</lon>
|
||||
<lat>-3170.14</lat>
|
||||
<z>357.096</z>
|
||||
<relativeTime>37000</relativeTime>
|
||||
</trajectory.91>
|
||||
<trajectory.92>
|
||||
<lon>3363.65</lon>
|
||||
<lat>-3202.58</lat>
|
||||
<z>279.399</z>
|
||||
<relativeTime>38000</relativeTime>
|
||||
</trajectory.92>
|
||||
<trajectory.93>
|
||||
<lon>3398.36</lon>
|
||||
<lat>-3235.63</lat>
|
||||
<z>198.163</z>
|
||||
<relativeTime>38000</relativeTime>
|
||||
</trajectory.93>
|
||||
<trajectory.94>
|
||||
<lon>3433.74</lon>
|
||||
<lat>-3269.31</lat>
|
||||
<z>113.182</z>
|
||||
<relativeTime>39000</relativeTime>
|
||||
</trajectory.94>
|
||||
<trajectory.95>
|
||||
<lon>3444.05</lon>
|
||||
<lat>-3279.13</lat>
|
||||
<z>88</z>
|
||||
<relativeTime>39000</relativeTime>
|
||||
</trajectory.95>
|
||||
</trajectory>
|
||||
</effectors.1>
|
||||
</effectors>
|
||||
<firePurposeId>2</firePurposeId>
|
||||
<partyId>4</partyId>
|
||||
<participantId>239</participantId>
|
||||
<esmParticipantIds count="0"/>
|
||||
<externalId>7</externalId>
|
||||
<effectMarkingInTa>1</effectMarkingInTa>
|
||||
<properties>{"effectSource":1,"elemente":1,"feuerkampfReferenz":"eb511ab7d8414b88af248fd32ef03285","firingType":1,"ladung":"DM16","ladungsNummer":3,"partyId":4,"subTyp":0,"typ":0,"useReceived":true}</properties>
|
||||
</DdsData>
|
||||
</Sample>
|
||||
</Samples>
|
||||
Executable
+942
@@ -0,0 +1,942 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ModuleTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "effect_cluster_module_test.h"
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
|
||||
// AES
|
||||
#include <AreaEffectSimulation/Utils/polygons.h>
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
|
||||
// PPM
|
||||
#include "ParticipantManagement/ppm_ftc_types.h"
|
||||
#include "TrainingAreaBase/tab.hpp"
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QTimer>
|
||||
#include <QVector>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace AreaEffectSimulation;
|
||||
using namespace LtsCoordTrans;
|
||||
|
||||
static QString s_REQUEST_SPL_FILE = QStringLiteral("EffectClusterModifyRequest_ESG.spl");
|
||||
|
||||
//
|
||||
// some helper functions
|
||||
//
|
||||
|
||||
template <typename T> dds::core::optional<T> toOptional(T inVal) { return inVal != T() ? dds::core::optional<T>(inVal) : dds::core::optional<T>(); }
|
||||
|
||||
template <typename T> dds::core::optional<T> optional() { return dds::core::optional<T>(); }
|
||||
|
||||
// mathematical positive north -> mathematical negativ, east = 0°, 0,01 degree in 1/100° -> factor 100
|
||||
static inline int compassToMathAngleForSfm(double compassDegree)
|
||||
{
|
||||
int ret = qRound((90.0 - compassDegree) * 100.0);
|
||||
while (ret < 0)
|
||||
ret += 36000;
|
||||
while (ret > 36000)
|
||||
ret -= 36000;
|
||||
return ret;
|
||||
}
|
||||
|
||||
double distanceMeter(const LtsCoordTrans::UtmCoordinate &utmCoord1, const LtsCoordTrans::UtmCoordinate &utmCoord2)
|
||||
{
|
||||
|
||||
double dist = LtsCoordTrans::distance(utmCoord1, utmCoord2);
|
||||
return dist;
|
||||
}
|
||||
|
||||
double distanceMeter(const Core::GeoPosition &geoPos, const LtsCoordTrans::UtmCoordinate &utmCoord)
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate &utmPos = LtsCoordTrans::UtmCoordinate::fromGeographic(geoPos.lon(), geoPos.lat());
|
||||
return distanceMeter(utmPos, utmCoord);
|
||||
}
|
||||
|
||||
double distanceMeter(const Core::GeoPosition2D &geoPos2D, const LtsCoordTrans::UtmCoordinate &utmCoord)
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate &utmPos = LtsCoordTrans::UtmCoordinate::fromGeographic(geoPos2D.lon(), geoPos2D.lat());
|
||||
return distanceMeter(utmPos, utmCoord);
|
||||
}
|
||||
|
||||
ModuleTestEffectCluster::ModuleTestEffectCluster(int domainId, int exerciseId)
|
||||
: m_domainId(domainId)
|
||||
, m_exerciseId(exerciseId)
|
||||
, m_logger(getLogger("ModuleTestEffectCluster"))
|
||||
{
|
||||
m_timer = new QTimer(this);
|
||||
m_timer->setSingleShot(true);
|
||||
connect(m_timer,
|
||||
&QTimer::timeout,
|
||||
this,
|
||||
[this]()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Wirkfeldplanung";
|
||||
doEffectClusterModifyRequest();
|
||||
});
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::onEffectClusterModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_replyError = replyObject.error();
|
||||
DEBUG_LOG(m_logger) << " got reply - onEffectClusterModifyReply: " << m_replyError << ", aesItemId=" << replyObject.id();
|
||||
m_aesItemId = replyObject.id();
|
||||
if (!replyObject.str().empty())
|
||||
ERROR_LOG(m_logger) << " got reply - onEffectClusterModifyReply: " << replyObject.translated();
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::onAcknowledgeExternalAesItemReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_replyError = replyObject.error();
|
||||
DEBUG_LOG(m_logger) << " got reply - onAcknowledgeExternalAesItemReply: " << m_replyError;
|
||||
sendTabExFire();
|
||||
// AES::EffectState von ES_Received -> ES_Created
|
||||
if (!replyObject.str().empty())
|
||||
ERROR_LOG(m_logger) << " got reply - onAcknowledgeExternalAesItemReply: " << replyObject.translated();
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::onModifyPartyDataReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_replyError = replyObject.error();
|
||||
DEBUG_LOG(m_logger) << " got reply - onModifyPartyDataReply: " << m_replyError << " " << replyObject.additionalInfo();
|
||||
if (!replyObject.str().empty())
|
||||
ERROR_LOG(m_logger) << " got reply - onModifyPartyDataReply: " << replyObject.translated();
|
||||
if (!m_participantChangeRequestDone)
|
||||
{
|
||||
participantChangeRequest();
|
||||
m_participantChangeRequestDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::onModifyParticipantDataReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_replyError = replyObject.error();
|
||||
DEBUG_LOG(m_logger) << " \n\ngot reply - onModifyParticipantDataReply error: " << m_replyError << ", additionalInfo: " << replyObject.additionalInfo();
|
||||
if (!replyObject.str().empty())
|
||||
ERROR_LOG(m_logger) << " got reply - onModifyParticipantDataReply: " << replyObject.translated();
|
||||
DEBUG_LOG(m_logger) << "onModifyParticipantDataReply => Set Participant Pos";
|
||||
QJsonArray jsonArray = QJsonDocument::fromJson(QByteArray::fromStdString(replyObject.additionalInfo())).object().value(QLatin1String("participants")).toArray();
|
||||
DEBUG_LOG(m_logger) << "available_in_exercise jsonDocument.size()=" << jsonArray.size();
|
||||
// ParticipantId aus dem Result bestimmen, keine Unit
|
||||
// Dieser einfache Test arbeitet mit einem Participant
|
||||
for (auto it = jsonArray.constBegin(); it != jsonArray.constEnd(); ++it)
|
||||
{
|
||||
int participantId = it->toInt();
|
||||
DEBUG_LOG(m_logger) << "participantId=" << participantId;
|
||||
ParticipantManagement::Participant participant = m_ppmDtc->participant(participantId);
|
||||
if (m_ppmDtc->type(participant.typeId()).typeClass().underlying() != ParticipantManagement::TypeClass::Unit)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "m_participant1.id=" << participantId;
|
||||
m_participant1.id(participantId); // wichtig zum loeschen
|
||||
DEBUG_LOG(m_logger) << "m_participantId keine Unit=" << participantId;
|
||||
setParticipantPos(participantId);
|
||||
setEquipmentGearCharge(participantId);
|
||||
|
||||
// Wirkfeldplanung
|
||||
if (!m_timer->isActive())
|
||||
m_timer->start(500);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "m_participant0.id=" << participantId;
|
||||
m_participant0.id(participantId); // wichtig zum loeschen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::onAesItemViewChanged(const AesItemView &aesItemView, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
AreaEffectSimulation::AesType_def::type aesType = aesItemView.aesTypeId().underlying();
|
||||
if (aesType != AreaEffectSimulation::AesType_def::AtEffectCluster)
|
||||
return;
|
||||
|
||||
if (aesItemView.aesItemId() != m_aesItemId)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << " got onAesItemViewChanged: "
|
||||
<< ", aesItemId=" << aesItemView.aesItemId() << ", aesType=" << aesType << ", effectStateId=" << aesItemView.effectStateId();
|
||||
|
||||
QCOMPARE(aesItemView.effectStateId(), m_effectStates[m_effectStateCounter]);
|
||||
m_effectStateCounter++;
|
||||
|
||||
if (aesItemView.effectStateId() == AreaEffectSimulation::AesEffectState::EsReceived)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "sendAcknowledgeExternalAesItemRequest aesItemId=" << aesItemView.aesItemId();
|
||||
sendAcknowledgeExternalAesItemRequest(aesItemView.aesItemId());
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::sendTabExFire()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "sendTabExFire";
|
||||
TrainingAreaBase::EX_Fire exFire;
|
||||
exFire.effectorId(m_effectorId); // Kenner z.B B1
|
||||
exFire.identifier(m_identifier.toStdString()); // Verein z.B 451100
|
||||
exFire.reference(m_reference.toStdString()); // UUID Feuerkampf
|
||||
exFire.equipmentNumber(m_participant1.id() * -1);
|
||||
exFire.sampleTime(QDateTime::currentMSecsSinceEpoch() + 500);
|
||||
|
||||
m_tabDts->publish(exFire);
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::onEffectsChanged(const Effects &effects, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
AreaEffectSimulation::AesType_def::type aesType = effects.aesTypeId().underlying();
|
||||
DEBUG_LOG(m_logger) << " got onEffectsChanged - m_data: " << m_data.id() << ", aesType=" << aesType;
|
||||
++m_counterDds.cntEffectClusterEffects;
|
||||
|
||||
m_effects = effects;
|
||||
DEBUG_LOG(m_logger) << " got onEffectsChanged - m_effects: " << m_effects;
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::onChargeEffectChanged(const ChargeEffect &chargeEffect, DataModification modType)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onChargeEffectChanged state=" << chargeEffect.state();
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
if (chargeEffect.state() == AreaEffectSimulation::AesEffectState::EsActivated)
|
||||
{
|
||||
// Compare Position
|
||||
// mhpPosition.lon(0.201958);
|
||||
// mhpPosition.lat(0.915263);
|
||||
// mhpPosition.z(88.0);
|
||||
double lon = qRound64(chargeEffect.position().lon() * 100000) / 100000.0; // Nur die ersten 5 Nachkommastellen beruecksichtigen
|
||||
double lat = qRound64(chargeEffect.position().lat() * 100000) / 100000.0;
|
||||
QCOMPARE(lon, 0.20196);
|
||||
QCOMPARE(lat, 0.91526);
|
||||
QCOMPARE(chargeEffect.position().z(), 88.0);
|
||||
}
|
||||
else if (chargeEffect.state() == AreaEffectSimulation::AesEffectState::EsExpired)
|
||||
participantDeleteRequest();
|
||||
DEBUG_LOG(m_logger) << " got onEffectsChanged - m_effects: " << m_effects;
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::onTrajectoryTimeAwareChanged(const TrajectoryTimeAware &data, DataModification modType)
|
||||
{
|
||||
Q_UNUSED(modType);
|
||||
if (data.id() == -1)
|
||||
return;
|
||||
|
||||
++m_counterDds.cntTrajectory;
|
||||
|
||||
DEBUG_LOG(m_logger) << " got TrajectoryTimeAwareChanged - data: " << data.id() << ", cntTrajectory=" << m_counterDds.cntTrajectory;
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::dumpCnt()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " Counter: "
|
||||
<< " cntEffectCluster = " << m_counterDds.cntEffectCluster << ", cntAtEffectCluster = " << m_counterDds.cntAtEffectCluster
|
||||
<< ", cntGunToTargetLine = " << m_counterDds.cntAtEffectClusterGunToTargetLine << ", cntClusterEffects = " << m_counterDds.cntEffectClusterEffects
|
||||
<< ", cntTrajectory = " << m_counterDds.cntTrajectory;
|
||||
}
|
||||
|
||||
bool ModuleTestEffectCluster::waitForData(const std::function<bool()> &func, int retryCount)
|
||||
{
|
||||
// Maybe give QTRY_VERIFY2 or QTRY_VERIFY2_WITH_TIMEOUT a chance
|
||||
// Or better QTRY_IMPL ??
|
||||
// QTRY_IMPL(m_replyError == false, 1);
|
||||
|
||||
// wait for data
|
||||
retryCount *= 10;
|
||||
|
||||
for (int i = 0; i < retryCount; ++i)
|
||||
{
|
||||
TRACE_LOG(m_logger) << " waitForData - i: " << i;
|
||||
if (func())
|
||||
return true;
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
return func();
|
||||
}
|
||||
|
||||
EffectCluster ModuleTestEffectCluster::getEcForTneVerification(const QString &eaName, double rotation)
|
||||
{
|
||||
AreaEffectSimulation::EffectCluster eaData;
|
||||
eaData.id(0);
|
||||
|
||||
eaData.effectStart((time(nullptr) + 30) * 1000); // msec
|
||||
|
||||
QString name(eaName);
|
||||
name += QString::number(eaData.effectStart().get());
|
||||
eaData.name(name.toStdString());
|
||||
|
||||
eaData.effectDuration(10000); // 10 seconds
|
||||
// eaData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
// eaData.chargeStruct().igniterTypeId(s_IgniterTypeProximity);
|
||||
|
||||
eaData.partyId(2);
|
||||
eaData.participantId(7);
|
||||
|
||||
// SubStruct FlightCurve
|
||||
FlightCurve fc;
|
||||
fc.requestedRelativePeakHeight(100);
|
||||
|
||||
// siehe auch: GUEZE-2311 Verifikation des Algorithmus bzgl. MTPs zw. TNE und EXCON.
|
||||
const double height = 100; // Y
|
||||
const double width = 40; // X
|
||||
const double rot = rotation;
|
||||
|
||||
// In Kontext GUEZE-2311 werden die MTPs unabhängig von eigentliche WirkfeldGeometrie an die TNE übermittelt.
|
||||
// Um in der Zentrale den gewünschten MTP zu erhalten, muss das Wirkfeld entsprechend angelegt werden:
|
||||
LtsCoordTrans::UtmCoordinate cp = LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 97000 78000"));
|
||||
|
||||
QPointF bottomLeft(Polygons::centerPoint2BottomLeft(cp.geographic(), width, height, rot));
|
||||
|
||||
DEBUG_LOG(m_logger) << " bottomLeft" << bottomLeft;
|
||||
|
||||
eaData.area().cornerBottomLeft(Core::GeoPosition(bottomLeft.x(), bottomLeft.y(), 0.0));
|
||||
eaData.area().height(height);
|
||||
eaData.area().width(width);
|
||||
eaData.area().rotation(rot);
|
||||
|
||||
eaData.explosionGeometry(AreaEffectSimulation::AesExplosionGeometry_def::EgArea);
|
||||
eaData.tla(0); // aka zop
|
||||
|
||||
eaData.externalId(0);
|
||||
|
||||
return eaData;
|
||||
}
|
||||
|
||||
std::vector<Core::RelativePositionRelativeTime> ModuleTestEffectCluster::parseTrajectory(const QString &filePath)
|
||||
{
|
||||
|
||||
// EffectClusterModifyRequest
|
||||
// AreaEffectSimulation::EffectorData
|
||||
// std::vector< Core::GeoPositionRelativeTime >& trajectory
|
||||
// GeoPositionRelativeTime ( lon, lat, z, relativeTime)
|
||||
|
||||
QFile file(filePath);
|
||||
std::vector<Core::RelativePositionRelativeTime> points;
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return points;
|
||||
|
||||
QXmlStreamReader xml(&file);
|
||||
|
||||
while (!xml.atEnd() && !xml.hasError())
|
||||
{
|
||||
xml.readNext();
|
||||
|
||||
// Wir suchen nach Start-Elementen, die mit "trajectory." beginnen
|
||||
if (xml.isStartElement() && xml.name().toString().startsWith(QStringLiteral("trajectory.")))
|
||||
{
|
||||
Core::RelativePositionRelativeTime p;
|
||||
|
||||
// Wir lesen die Unterelemente (lon, lat, z, relativeTime)
|
||||
while (!(xml.isEndElement() && xml.name().toString().startsWith(QStringLiteral("trajectory."))))
|
||||
{
|
||||
xml.readNext();
|
||||
if (xml.isStartElement())
|
||||
{
|
||||
QString name = xml.name().toString();
|
||||
QString val = xml.readElementText();
|
||||
|
||||
if (name == QStringLiteral("lon"))
|
||||
p.offsetX(val.toDouble());
|
||||
else if (name == QStringLiteral("lat"))
|
||||
p.offsetY(val.toDouble());
|
||||
else if (name == QStringLiteral("z"))
|
||||
p.offsetZ(val.toDouble());
|
||||
else if (name == QStringLiteral("relativeTime"))
|
||||
p.relativeTime(val.toDouble());
|
||||
}
|
||||
}
|
||||
points.push_back(p);
|
||||
DEBUG_LOG(m_logger) << "Punkt gelesen: offsetY" << p.offsetX() << ", offsetY" << p.offsetY() << ", offsetZ" << p.offsetZ() << ", time=" << p.relativeTime();
|
||||
}
|
||||
}
|
||||
|
||||
if (xml.hasError())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "XML Fehler:" << xml.errorString();
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "file.close()";
|
||||
file.close();
|
||||
DEBUG_LOG(m_logger) << "return points";
|
||||
return points;
|
||||
}
|
||||
|
||||
int ModuleTestEffectCluster::sendAcknowledgeExternalAesItemRequest(int aesItemId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "sendAcknowledgeExternalAesItemRequest aesItemId=" << aesItemId;
|
||||
int ret = m_aesFtc->acknowledgeExternalAesItemRequest(AcknowledgeExternalAesItemRequest(aesItemId), this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ModuleTestEffectCluster::doEffectClusterModifyRequest()
|
||||
{
|
||||
EffectCluster eaData;
|
||||
QString dateTimeString = QDateTime::currentDateTime().toString(QStringLiteral("dd.MM.yyyy hh:mm"));
|
||||
m_reference = dateTimeString;
|
||||
|
||||
if (eaData.effectStart().is_set())
|
||||
INFO_LOG(m_logger) << " effectClusterModifyRequest with effectStart: " << QDateTime::fromMSecsSinceEpoch(eaData.effectStart().get()).toString();
|
||||
else
|
||||
INFO_LOG(m_logger) << " effectClusterModifyRequest with effectStart: not set ";
|
||||
|
||||
FlightCurve fc;
|
||||
// if (eaData.flightCurve().is_set())
|
||||
// fc = eaData.flightCurve().get();
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("effectSource")] = 1;
|
||||
obj[QStringLiteral("elemente")] = 1;
|
||||
obj[QStringLiteral("feuerkampfReferenz")] = dateTimeString;
|
||||
obj[QStringLiteral("firingType")] = 1;
|
||||
obj[QStringLiteral("ladung")] = QStringLiteral("DM16");
|
||||
obj[QStringLiteral("ladungsNummer")] = 3;
|
||||
obj[QStringLiteral("partyId")] = 4;
|
||||
obj[QStringLiteral("subTyp")] = 0;
|
||||
obj[QStringLiteral("typ")] = 0;
|
||||
obj[QStringLiteral("useReceived")] = true;
|
||||
obj[QStringLiteral("effectSource")] = ProjectDataManagement::EffectSource::ES_ADLER;
|
||||
|
||||
QString propertiesStr = QString::fromStdString(QJsonDocument(obj).toJson(QJsonDocument::Compact).toStdString());
|
||||
|
||||
eaData.properties(propertiesStr.toStdString());
|
||||
AreaEffectSimulation::ChargeStruct chargeStruct;
|
||||
chargeStruct.chargeTypeId(367);
|
||||
chargeStruct.igniterTypeId(1);
|
||||
chargeStruct.igniterFunctionId(2);
|
||||
|
||||
Core::GeoPosition mhpPosition;
|
||||
mhpPosition.lon(0.201958);
|
||||
mhpPosition.lat(0.915263);
|
||||
mhpPosition.z(88.0);
|
||||
|
||||
Core::GeoPosition2D cornerBottomLeft;
|
||||
cornerBottomLeft.lon(0.201951);
|
||||
cornerBottomLeft.lat(0.915259);
|
||||
|
||||
AreaEffectSimulation::Area area;
|
||||
area.cornerBottomLeft(cornerBottomLeft);
|
||||
area.width(50);
|
||||
area.height(50);
|
||||
area.rotation(0);
|
||||
eaData.area(area);
|
||||
|
||||
eaData.explosionGeometry(AreaEffectSimulation::AesExplosionGeometry::EgPoint);
|
||||
|
||||
std::vector<Core::RelativePositionRelativeTime> trajectory = parseTrajectory(s_REQUEST_SPL_FILE);
|
||||
|
||||
AreaEffectSimulation::EffectorData effector;
|
||||
effector.angleOfFall(0);
|
||||
effector.participantId(m_participant1.id()); // Participant
|
||||
DEBUG_LOG(m_logger) << "effector.participantId(m_participant1.id()=" << m_participant1.id();
|
||||
|
||||
effector.flightTime(39526.3);
|
||||
effector.peakHeight(2002.0);
|
||||
effector.interval(0);
|
||||
effector.chargeStruct(chargeStruct);
|
||||
effector.chargeAmount(1);
|
||||
effector.mhpScatterLenght(3.08314e-316);
|
||||
effector.mhpScatterWidth(8.76302e-315);
|
||||
effector.mhpScatterLengthDetonationHeight(9.69057e-316);
|
||||
effector.mhpScatterWidthDetonationHeight(8.76638e-315);
|
||||
effector.mhpRotation(-45.4373);
|
||||
effector.mhpPosition(mhpPosition);
|
||||
effector.trajectoryRelative(trajectory);
|
||||
|
||||
DEBUG_LOG(m_logger) << "effector";
|
||||
|
||||
std::vector<AreaEffectSimulation::EffectorData> effectors;
|
||||
effectors.push_back(effector);
|
||||
|
||||
DEBUG_LOG(m_logger) << "Nach effector";
|
||||
|
||||
eaData.id(0);
|
||||
eaData.effectSourceId(ProjectDataManagement::EffectSource::ES_ADLER);
|
||||
eaData.firePurposeId(2);
|
||||
eaData.partyId(4);
|
||||
eaData.participantId(m_participant0.id()); // Unit
|
||||
DEBUG_LOG(m_logger) << "eaData.participantId(m_participant0.id()=" << m_participant0.id();
|
||||
eaData.externalId(7);
|
||||
eaData.effectMarkingInTa(1);
|
||||
|
||||
eaData.name(dateTimeString.toStdString());
|
||||
eaData.element(dateTimeString.toStdString());
|
||||
|
||||
DEBUG_LOG(m_logger) << "Vor send effectClusterModifyRequest";
|
||||
|
||||
int ret = m_aesFtc->effectClusterModifyRequest(EffectClusterModifyRequest(eaData.id(),
|
||||
eaData.name(),
|
||||
eaData.element(),
|
||||
eaData.effectStart(),
|
||||
eaData.effectDuration(),
|
||||
eaData.effectSourceId(),
|
||||
eaData.area(),
|
||||
eaData.explosionGeometry(), // AimPoint, Radial, Area, Line, Point
|
||||
eaData.tla(), // ZielOrtungsGenauigkeit
|
||||
effectors,
|
||||
eaData.firePurposeId(), // FirePurpose: blenden, niederhalten, vernichten
|
||||
eaData.partyId(),
|
||||
eaData.participantId(),
|
||||
{}, // esmParticipantIds
|
||||
eaData.externalId(),
|
||||
eaData.effectMarkingInTa(),
|
||||
eaData.properties()),
|
||||
this);
|
||||
DEBUG_LOG(m_logger) << "send effectClusterModifyRequest ret=" << ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::waitForEffectStates(int lineNumber, int durPrep, int durAct, int durExp)
|
||||
{
|
||||
// expected condition:
|
||||
if (!waitForData([this]() { return m_replyError == false; }, 1))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error on request"
|
||||
<< ", lineNumber = " << lineNumber;
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " waiting for EsPrepared...";
|
||||
if (!waitForData([this]() { return m_data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsPrepared; }, durPrep))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for EsPrepared of explosion cluster with id " << m_data.id() << ", lineNumber = " << lineNumber;
|
||||
QVERIFY2(false, "ERROR, exit");
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " waiting for EsActivated...";
|
||||
if (!waitForData([this]() { return m_data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated; }, durAct))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for EsActivated of explosion cluster with id " << m_data.id() << ", lineNumber = " << lineNumber;
|
||||
QVERIFY2(false, "ERROR, exit");
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " waiting for EsExpired...";
|
||||
if (!waitForData([this]() { return m_data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired; }, durExp))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for EsExpired of explosion cluster with id " << m_data.id() << ", lineNumber = " << lineNumber;
|
||||
QVERIFY2(false, "ERROR, exit");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::disconnectFromParty()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "PPM::ModifyPartyDataRequest";
|
||||
|
||||
ParticipantManagement::Party party;
|
||||
|
||||
party.name("GREEN");
|
||||
party.role(ParticipantManagement::Role::Neutral);
|
||||
party.color(-16711936);
|
||||
party.fadingColor(-6553701);
|
||||
|
||||
ModifyPartyDataRequest req;
|
||||
req.id(m_partyId);
|
||||
req.name(party.name());
|
||||
req.color(party.color());
|
||||
req.fadingColor(party.fadingColor());
|
||||
req.role(party.role());
|
||||
req.isUsedBy(true);
|
||||
req.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
const HlaForceIdentifierEnum hlaId = HlaForceIdentifierEnum::Neutral_1;
|
||||
req.hlaForceIdentifier(hlaId);
|
||||
QString properties = QStringLiteral("{\"Adler\": {\"wsId\": 3, \"SaaName\": \"UI Test\", \"assetId\": -1, \"saaName\": \"SAA1@GUEZ.DE\", \"szenarName\": \"UI Test\", "
|
||||
"\"isSaaConnected\": 1, \"saaConnectedState\": 2}}");
|
||||
req.properties(properties.toStdString());
|
||||
|
||||
if (!m_ppmFtc->modifyPartyDataRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating party data";
|
||||
// failExit();
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::connectToParty()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "PPM::ModifyPartyDataRequest";
|
||||
|
||||
ParticipantManagement::Party party;
|
||||
|
||||
party.name("GREEN");
|
||||
party.role(ParticipantManagement::Role::Neutral);
|
||||
party.color(-16711936);
|
||||
party.fadingColor(-6553701);
|
||||
|
||||
ModifyPartyDataRequest req;
|
||||
req.id(m_partyId);
|
||||
req.name(party.name());
|
||||
req.color(party.color());
|
||||
req.fadingColor(party.fadingColor());
|
||||
req.role(party.role());
|
||||
req.isUsedBy(true);
|
||||
req.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
const HlaForceIdentifierEnum hlaId = HlaForceIdentifierEnum::Neutral_1;
|
||||
req.hlaForceIdentifier(hlaId);
|
||||
QString properties = QStringLiteral("{\"Adler\": {\"wsId\": 3, \"SaaName\": \"UI Test\", \"assetId\": -1, \"saaName\": \"SAA1@GUEZ.DE\", \"szenarName\": \"UI Test\", "
|
||||
"\"isSaaConnected\": 2, \"isVerbund\": true, \"saaConnectedState\": 4}}");
|
||||
|
||||
req.properties(properties.toStdString());
|
||||
|
||||
if (!m_ppmFtc->modifyPartyDataRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating party data";
|
||||
// failExit();
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::participantChangeRequest()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "PPM::participantChangerequest";
|
||||
|
||||
m_participant0.id(0);
|
||||
m_participant0.partyId(4);
|
||||
m_participant0.hierarchyNumber(1);
|
||||
m_participant0.typeId(182);
|
||||
m_participant0.externalId(0);
|
||||
m_participant0.symbol(QStringLiteral("AP6D|CMPL|10011000001308000000").toStdString());
|
||||
m_participant0.name(QStringLiteral("451200").toStdString());
|
||||
m_participant0.identification(QStringLiteral("").toStdString());
|
||||
m_participant0.designator(QStringLiteral("451200").toStdString()), m_participant0.tacticalIdentifier(QStringLiteral("451200").toStdString());
|
||||
m_participant0.info(QStringLiteral("").toStdString());
|
||||
m_participant0.assignState(ParticipantManagement::ParticipantAssignState::NotAssigned);
|
||||
m_participant0.isSimulated(false);
|
||||
m_participant0.isDeleted(false);
|
||||
m_participant0.properties(QStringLiteral("").toStdString());
|
||||
m_participant0.modId(1138783559);
|
||||
m_participant0.superiorModId(0);
|
||||
|
||||
m_participant1.id(0);
|
||||
m_participant1.partyId(4);
|
||||
m_participant1.hierarchyNumber(1);
|
||||
m_participant1.typeId(188);
|
||||
m_participant1.externalId(0);
|
||||
m_participant1.symbol(QStringLiteral("AP6D|CMPL|10011500001114020000").toStdString());
|
||||
m_participant1.name(QStringLiteral("C3").toStdString());
|
||||
m_participant1.identification(QStringLiteral("").toStdString());
|
||||
m_participant1.designator(QStringLiteral("C3").toStdString()), m_participant1.tacticalIdentifier(QStringLiteral("451200").toStdString());
|
||||
m_participant1.info(QStringLiteral("").toStdString());
|
||||
m_participant1.assignState(ParticipantManagement::ParticipantAssignState::NotAssigned);
|
||||
m_participant1.isSimulated(false);
|
||||
m_participant1.isDeleted(false);
|
||||
m_participant1.properties(QStringLiteral("").toStdString());
|
||||
m_participant1.modId(1390608527);
|
||||
m_participant1.superiorModId(1138783559);
|
||||
|
||||
ModifyParticipantDataRequest req;
|
||||
std::vector<ParticipantManagement::ParticipantData> data;
|
||||
data.push_back(m_participant0);
|
||||
data.push_back(m_participant1);
|
||||
req.requestId(548288706);
|
||||
req.data(data);
|
||||
if (!m_ppmFtc->modifyParticipantDataRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating party data";
|
||||
// failExit();
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::participantDeleteRequest()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "PPM::participantDeleteRequest";
|
||||
|
||||
m_participant0.isDeleted(true);
|
||||
|
||||
m_participant1.isDeleted(true);
|
||||
|
||||
ModifyParticipantDataRequest req;
|
||||
std::vector<ParticipantManagement::ParticipantData> data;
|
||||
data.push_back(m_participant0);
|
||||
data.push_back(m_participant1);
|
||||
req.requestId(548288707);
|
||||
req.data(data);
|
||||
if (!m_ppmFtc->modifyParticipantDataRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating party data";
|
||||
// failExit();
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::setParticipantPos(int participantId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "setupParticipants";
|
||||
TrainingAreaBase::TabPosition position;
|
||||
Core::GeoPosition geoPos;
|
||||
TrainingAreaBase::EquipmentPosition pos;
|
||||
|
||||
geoPos.lon(0.20110363);
|
||||
geoPos.lat(0.91579597);
|
||||
geoPos.z(0.0);
|
||||
|
||||
DEBUG_LOG(m_logger) << " initTestCase_data1 ...";
|
||||
pos.equipmentNumber(participantId * -1); // ParticipantId
|
||||
pos.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
position.reportingSource(Core::PositionReportingSource::SetByOperator);
|
||||
position.position(geoPos);
|
||||
pos.position(position);
|
||||
m_tabDts->publish(pos);
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::setEquipmentGearCharge(int participantId)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "setupEquipmentGearCharge";
|
||||
TrainingAreaBase::EquipmentGearChargeState egs;
|
||||
TrainingAreaBase::GearCharge charge;
|
||||
std::vector<TrainingAreaBase::GearCharge> charges;
|
||||
|
||||
egs.equipmentNumber(participantId * -1); // ParticipantId
|
||||
egs.sampleTime(QDateTime::currentMSecsSinceEpoch());
|
||||
charges.resize(7);
|
||||
charge.gearId(138);
|
||||
charge.gearTypeId(801);
|
||||
charge.chargeTypeId(367);
|
||||
charge.remain(50);
|
||||
charges.push_back(charge); // 0
|
||||
|
||||
charge.chargeTypeId(366);
|
||||
charges.push_back(charge); // 1
|
||||
|
||||
charge.chargeTypeId(361);
|
||||
charges.push_back(charge); // 2
|
||||
|
||||
charge.chargeTypeId(362);
|
||||
charges.push_back(charge); // 3
|
||||
|
||||
charge.chargeTypeId(363);
|
||||
charges.push_back(charge); // 4
|
||||
|
||||
charge.chargeTypeId(364);
|
||||
charges.push_back(charge); // 5
|
||||
|
||||
charge.chargeTypeId(365);
|
||||
charges.push_back(charge); // 6
|
||||
|
||||
egs.charge(charges);
|
||||
m_tabDts->publish(egs);
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::onPartyChanged(const ParticipantManagement::Party &data, DataModification modType)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onPartyChanged:" << data;
|
||||
// Remove Participant:
|
||||
if (modType == DataModification::eRemoved)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.id() != m_partyId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "onPartyChanged id= " << data.id();
|
||||
if (m_ppmDtc->saaConnectedState(data.id()) == ParticipantManagement::ConnectState::Connected)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onPartyChanged saaConnectedState == connected";
|
||||
}
|
||||
else if (m_ppmDtc->saaConnectedState(data.id()) == ParticipantManagement::ConnectState::Disconnected)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onPartyChanged saaConnectedState == disconnected => connectToParty";
|
||||
connectToParty();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// context of textCases
|
||||
//
|
||||
void ModuleTestEffectCluster::initTestCase()
|
||||
{
|
||||
//
|
||||
// DdsConnector
|
||||
//
|
||||
|
||||
DEBUG_LOG(m_logger) << "DDSConnector: m_domainId " << m_domainId << ", m_exerciseId " << m_exerciseId;
|
||||
|
||||
QFile file(s_REQUEST_SPL_FILE);
|
||||
const bool bFileExists = file.exists();
|
||||
QVERIFY2(bFileExists, "ERROR, SPL file does not exists in current path");
|
||||
|
||||
// cmd
|
||||
m_ddsConnector.reset(new DDSConnector::DdsConnector(m_domainId, IDL::PartitionType::Exercise, m_exerciseId));
|
||||
bool bInit = m_ddsConnector->init();
|
||||
QVERIFY2(bInit, "ERROR, ddsConnector.init failed!!");
|
||||
if (!bInit)
|
||||
{
|
||||
ERROR_LOG(m_logger) << " ERROR, ddsConnector.init failed!!";
|
||||
return;
|
||||
}
|
||||
INFO_LOG(m_logger) << " ddsConnector.init successfull";
|
||||
|
||||
// cmd
|
||||
m_ddsConnector->initPublisherSubscriber();
|
||||
INFO_LOG(m_logger) << " ddsConnector.initPublisherSubscriber done";
|
||||
|
||||
//
|
||||
// Aes
|
||||
//
|
||||
// cmd
|
||||
m_aesFtc = AreaEffectSimulation::Interface::Ftc::create(m_ddsConnector);
|
||||
QVERIFY2(m_aesFtc, "ERROR, create m_aesFtc failed!!");
|
||||
bool bRet = m_aesFtc->enableAll();
|
||||
QVERIFY2(bRet, "ERROR, enableAll failed!!");
|
||||
|
||||
// cmd
|
||||
m_aesDtc = AreaEffectSimulation::Interface::Dtc::create(m_ddsConnector);
|
||||
QVERIFY2(m_aesDtc, "ERROR, create m_aesDtc failed!!");
|
||||
bRet = bRet && m_aesDtc->enableAll();
|
||||
QVERIFY2(bRet, "ERROR, enableAll failed!!");
|
||||
|
||||
m_aesFtc->enableAll();
|
||||
|
||||
m_aesDtc->enableAesItemView();
|
||||
m_aesDtc->enableChargeEffect();
|
||||
DEBUG_LOG(m_logger) << " waitForHistoricalDataAesItemView... ";
|
||||
m_aesDtc->waitForHistoricalDataAesItemView(2000);
|
||||
DEBUG_LOG(m_logger) << " waitForHistoricalDataAesItemView... Done";
|
||||
|
||||
QMap<qint32, AreaEffectSimulation::AesItemView> aesItemViewsCont = m_aesDtc->aesItemViews();
|
||||
DEBUG_LOG(m_logger) << " aesItemViewsCont.size() " << aesItemViewsCont.size();
|
||||
|
||||
//
|
||||
// PDM
|
||||
//
|
||||
m_pdmDtc = ProjectDataManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
QVERIFY2(m_pdmDtc, "ERROR, create m_pdmDtc failed!!");
|
||||
|
||||
//
|
||||
// ISM
|
||||
//
|
||||
m_ismDtc = InfrastructureManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
QVERIFY2(m_ismDtc, "ERROR, create m_ismDtc failed!!");
|
||||
bRet = bRet && m_ismDtc->enableAll();
|
||||
QVERIFY2(bRet, "ERROR, enableAll failed!!");
|
||||
|
||||
//
|
||||
// EXM ExerciseManagement
|
||||
//
|
||||
m_exmDtc = ExerciseManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
QVERIFY2(m_exmDtc, "ERROR, create m_exmDtc failed!!");
|
||||
bRet = bRet && m_exmDtc->enableAll();
|
||||
QVERIFY2(bRet, "ERROR, enableAll m_exmDtc failed!!");
|
||||
|
||||
m_exmDtc->waitForHistoricalDataExercise(2000);
|
||||
DEBUG_LOG(m_logger) << " waitForHistoricalDataExercise... Done";
|
||||
|
||||
const ExerciseManagement::Exercise &exercise = m_exmDtc->exercise(m_exerciseId);
|
||||
QVERIFY2(exercise.id() == m_exerciseId, "ERROR, exercise failed!!");
|
||||
m_traingAreaId = exercise.trainingAreaId();
|
||||
|
||||
DEBUG_LOG(m_logger) << " ExerciseManagement"
|
||||
<< ", m_traingAreaId = " << m_traingAreaId;
|
||||
//
|
||||
// PPM ParticipantManagement
|
||||
//
|
||||
//
|
||||
m_ppmDtc = ParticipantManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
QVERIFY2(m_ppmDtc, "ERROR, create m_ppmDtc failed!!");
|
||||
bRet = bRet && m_ppmDtc->enableAll();
|
||||
QVERIFY2(bRet, "ERROR, enableAll m_ppmDtc failed!!");
|
||||
|
||||
m_ppmFtc = ParticipantManagement::Interface::Ftc::create(m_ddsConnector);
|
||||
QVERIFY2(m_ppmFtc, "ERROR, create m_ppmFtc failed!!");
|
||||
bRet = bRet && m_ppmFtc->enableAll();
|
||||
m_ppmFtc->enableSetSimulatedPosition();
|
||||
m_ppmFtc->enableModifyParticipantData();
|
||||
QVERIFY2(bRet, "ERROR, m_ppmFtc enableAll failed!!");
|
||||
|
||||
m_tabDts = TrainingAreaBase::Interface::Dts::create(m_ddsConnector);
|
||||
QVERIFY2(m_tabDts, "ERROR, create m_tabDts failed!!");
|
||||
bRet = bRet && m_tabDts->enableAll();
|
||||
QVERIFY2(bRet, "ERROR, m_tabDts enableAll failed!!");
|
||||
|
||||
DEBUG_LOG(m_logger) << "disconnectFromParty";
|
||||
disconnectFromParty();
|
||||
// connectToParty();
|
||||
|
||||
// connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
|
||||
// this, &ModuleTestEffectCluster::onParticipantChanged);
|
||||
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::partyChanged, this, &ModuleTestEffectCluster::onPartyChanged);
|
||||
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged, this, &ModuleTestEffectCluster::onAesItemViewChanged, Qt::UniqueConnection);
|
||||
connect(m_aesDtc.get(),
|
||||
&AreaEffectSimulation::Interface::Dtc::trajectoryTimeAwareChanged,
|
||||
this,
|
||||
&ModuleTestEffectCluster::onTrajectoryTimeAwareChanged,
|
||||
Qt::UniqueConnection);
|
||||
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::effectsChanged, this, &ModuleTestEffectCluster::onEffectsChanged, Qt::UniqueConnection);
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::chargeEffectChanged, this, &ModuleTestEffectCluster::onChargeEffectChanged, Qt::UniqueConnection);
|
||||
|
||||
// spend some for the eventLoop to "consume" existing topics/samples:
|
||||
for (int i = 0; i < 10; ++i)
|
||||
QTest::qWait(1000);
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::init()
|
||||
{
|
||||
// init will be called before each test function is executed.
|
||||
|
||||
m_counterDds.reset();
|
||||
}
|
||||
|
||||
void ModuleTestEffectCluster::cleanupTestCase()
|
||||
{
|
||||
// finish last (dds) calls:
|
||||
waitForData([]() { return false; }, 10);
|
||||
|
||||
INFO_LOG(m_logger) << " ddsConnector destroy...";
|
||||
m_ddsConnector.reset();
|
||||
INFO_LOG(m_logger) << " ddsConnector destroy...DONE";
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("ModuleTest_ExplosionCluster", "log4cxx_aes.props");
|
||||
|
||||
// aesModuleTestExplosionCluster -v2 test_long -e42 -d139
|
||||
// ^^^ ^^^^ // no space!!!
|
||||
// aesModuleTestExplosionCluster -v2 test_long -e42
|
||||
// aesModuleTestExplosionCluster -v2 test_long -e42
|
||||
// aesModuleTestExplosionCluster test_long -e42
|
||||
// aesModuleTestExplosionCluster -e42
|
||||
|
||||
CmdLineParser options;
|
||||
options.setUnitModuleTestMode(true);
|
||||
|
||||
std::cout << " consider 'aesModuleTestEffectCluster -e42' " << std::endl;
|
||||
|
||||
if (!options.init(true)) // showHelp , exitOnBadOption
|
||||
return -1;
|
||||
|
||||
if (options.exerciseId() <= 0)
|
||||
{
|
||||
fprintf(stderr, "ExerciseId not set!\n");
|
||||
return -2;
|
||||
}
|
||||
std::cout << " DomainId = " << options.domainId() << " - ExerciseId = " << options.exerciseId() << std::endl;
|
||||
|
||||
if (options.isSet(QStringLiteral("exerciseid")))
|
||||
--argc;
|
||||
if (options.isSet(QStringLiteral("domainid")))
|
||||
--argc;
|
||||
|
||||
const QStringList &slPositionalArgs = options.positionalArguments();
|
||||
for (const QString &item : qAsConst(slPositionalArgs))
|
||||
std::cout << " item = " << item << std::endl;
|
||||
|
||||
ModuleTestEffectCluster tc(options.domainId(), options.exerciseId());
|
||||
return QTest::qExec(&tc, argc, argv);
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ModuleTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
// Aufruf: ./aesModuleTestEffectCluster -e42
|
||||
|
||||
// Mehr Debug-Ausgaben:
|
||||
// Aufruf: ./aesModuleTestEffectCluster -v2 -e42
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
#include <LtsCoordinate/lts_coordinate.h>
|
||||
|
||||
#include <AreaEffectSimulation/aes_ftc.h>
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <AreaEffectSimulation/logger.h>
|
||||
|
||||
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
|
||||
|
||||
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_ftc.h>
|
||||
|
||||
#include <TrainingAreaBase/tab_dts.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <QtTest/QTest>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace AreaEffectSimulation; // JUST FOR LOGGER_T
|
||||
using namespace ParticipantManagement;
|
||||
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser(ProvideCommandLineParameterOptions(DomainId|ExerciseId|NoVersion))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ModuleTestEffectCluster : public QObject
|
||||
, protected AreaEffectSimulation::Interface::Ftc::EffectClusterModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::AcknowledgeExternalAesItemReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::ModifyPartyDataReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::ModifyParticipantDataReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModuleTestEffectCluster(int domainId, int exerciseId);
|
||||
|
||||
protected:
|
||||
void onEffectClusterModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onAcknowledgeExternalAesItemReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onModifyPartyDataReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onModifyParticipantDataReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &aesItemView, DataModification modType);
|
||||
void onEffectsChanged(const AreaEffectSimulation::Effects &effects, DataModification modType);
|
||||
void onChargeEffectChanged(const ChargeEffect &chargeEffect, DataModification modType);
|
||||
void onTrajectoryTimeAwareChanged(const AreaEffectSimulation::TrajectoryTimeAware &data, DataModification modType);
|
||||
|
||||
// pre-condition
|
||||
void disconnectFromParty();
|
||||
void connectToParty();
|
||||
void participantChangeRequest();
|
||||
void participantDeleteRequest();
|
||||
void setParticipantPos(int participantId);
|
||||
void setEquipmentGearCharge(int participantId);
|
||||
|
||||
|
||||
|
||||
// helper
|
||||
bool waitForData(const std::function<bool()> &func, int retryCount = 10);
|
||||
|
||||
EffectCluster getEcForTneVerification(const QString &eaName = QStringLiteral("ModuleTest_TneVerification__"), double rotation = 0);
|
||||
|
||||
|
||||
int doEffectClusterModifyRequest();
|
||||
int doExplosionClusterSingleEffectOnlyModifyRequest(const ExplosionClusterSingleEffectOnlyRequest &request);
|
||||
std::vector< Core::RelativePositionRelativeTime > parseTrajectory(const QString &filePath);
|
||||
|
||||
int sendAcknowledgeExternalAesItemRequest(int aesItemId);
|
||||
void sendTabExFire();
|
||||
void waitForEffectStates(int lineNumber, int durPrep = 5, int durAct = 60, int durExp = 30);
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
//
|
||||
// TestCases
|
||||
//
|
||||
|
||||
// void initTestCase_data(); // will be called to create a global test data table.
|
||||
void initTestCase(); // will be called before the first test function is executed.
|
||||
|
||||
void init(); // will be called before each test function is executed.
|
||||
void cleanupTestCase();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private:
|
||||
void onPartyChanged(const ParticipantManagement::Party &data, DataModification modType);
|
||||
void dumpCnt();
|
||||
|
||||
private:
|
||||
int m_domainId{-1};
|
||||
int m_exerciseId{-1};
|
||||
int m_traingAreaId{-1};
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
int32_t m_partyId{4};
|
||||
ParticipantManagement::ParticipantData m_participant0; // Unit
|
||||
ParticipantManagement::ParticipantData m_participant1; // Participant
|
||||
const ProjectDataManagement::L27_EffectorId m_effectorId{ProjectDataManagement::L27_EffectorId::C3};
|
||||
QString m_reference;
|
||||
const QString m_identifier{QStringLiteral("451200")};
|
||||
int m_aesItemId{-1};
|
||||
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Ftc> m_aesFtc;
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
|
||||
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
|
||||
|
||||
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
|
||||
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
|
||||
|
||||
std::shared_ptr<TrainingAreaBase::Interface::Dts> m_tabDts;
|
||||
|
||||
EffectCluster m_data;
|
||||
Effects m_effects;
|
||||
long m_objectRequestedTimePointMsec{-1};
|
||||
bool m_replyError{false};
|
||||
QTimer *m_timer;
|
||||
bool m_participantChangeRequestDone{false};
|
||||
|
||||
const QVector<AreaEffectSimulation::AesEffectState> m_effectStates = {AesEffectState::EsReceived,
|
||||
AesEffectState::EsCreated,
|
||||
AesEffectState::EsActivated,
|
||||
AesEffectState::EsExpired};
|
||||
int m_effectStateCounter = 0;
|
||||
|
||||
|
||||
struct counterDds
|
||||
{
|
||||
// ExplosionCluster
|
||||
int cntEffectCluster{0};
|
||||
|
||||
// AesItemView
|
||||
int cntAtEffectCluster{0};
|
||||
int cntAtEffectClusterGunToTargetLine{0};
|
||||
|
||||
// Effects
|
||||
int cntEffectClusterEffects{0};
|
||||
|
||||
// Trajectory
|
||||
int cntTrajectory{0};
|
||||
|
||||
|
||||
void reset()
|
||||
{
|
||||
cntEffectCluster = 0;
|
||||
cntAtEffectCluster = 0;
|
||||
cntAtEffectClusterGunToTargetLine = 0;
|
||||
cntEffectClusterEffects = 0;
|
||||
cntTrajectory = 0;
|
||||
}
|
||||
}
|
||||
m_counterDds;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(UnitTestSources
|
||||
explosion_cluster_module_test.cpp
|
||||
explosion_cluster_module_test.h
|
||||
)
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
ADD_EXECUTABLE(aesModuleTestExplosionCluster ${LinkedSources} ${UnitTestSources} )
|
||||
|
||||
TARGET_LINK_LIBRARIES(aesModuleTestExplosionCluster
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
LtsCommandLineParser
|
||||
LtsCoordinate
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
ddsconnector
|
||||
svcAesCommon
|
||||
svcAesClient
|
||||
svcBldClient
|
||||
svcExmClient
|
||||
svcIsmClient
|
||||
svcPdmClient
|
||||
svcPpmClient
|
||||
)
|
||||
|
||||
# ADD_TEST(NAME aesModuleTestExplosionCluster COMMAND $<TARGET_FILE:aesUnitTestTneAlgorithmen>)
|
||||
ENDIF()
|
||||
Executable
+2757
File diff suppressed because it is too large.
Load diff
Executable
+244
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ModuleTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
#include <LtsCoordinate/lts_coordinate.h>
|
||||
|
||||
#include <AreaEffectSimulation/aes_ftc.h>
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <AreaEffectSimulation/logger.h>
|
||||
|
||||
#include <Plugins/Buildings/bld_data_plugin_interface.h>
|
||||
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
|
||||
|
||||
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_ftc.h>
|
||||
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace AreaEffectSimulation; // JUST FOR LOGGER_T
|
||||
|
||||
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser(ProvideCommandLineParameterOptions(DomainId|ExerciseId|NoVersion))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ModuleTestExplosionCluster : public QObject
|
||||
, protected ParticipantManagement::Interface::Ftc::SetSimulatedPositionReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::SetSimulatedParticipantFormationReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterOcModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterSingleEffectOnlyModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterPauseResumeReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::TargetPositionsModifyReplyHandler
|
||||
, protected Buildings::Interface::Ftc::SetBuildingStatesReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModuleTestExplosionCluster(int domainId, int exerciseId);
|
||||
|
||||
protected:
|
||||
void onSetSimulatedPositionReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onSetSimulatedParticipantFormationReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onExplosionClusterModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onExplosionClusterSingleEffectOnlyModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onExplosionClusterOcModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onExplosionClusterPauseResumeReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onTargetPositionsModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onSetBuildingStatesReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
|
||||
void onExplosionClusterChanged(const AreaEffectSimulation::ExplosionCluster &data, DataModification modType);
|
||||
void onBuildingStateChanged(const Buildings::BuildingState &bldgState, DataModification modType);
|
||||
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &aesItemView, DataModification modType);
|
||||
void onEffectsChanged(const AreaEffectSimulation::Effects &effects, DataModification modType);
|
||||
void onTrajectoryTimeAwareChanged(const AreaEffectSimulation::TrajectoryTimeAware &data, DataModification modType);
|
||||
|
||||
// pre-condition
|
||||
void setupParticipants();
|
||||
bool checkParticipant_5();
|
||||
bool checkParticipant_6();
|
||||
bool checkParticipant_89();
|
||||
bool checkParticipant_99();
|
||||
|
||||
void resetBldgs();
|
||||
int getBldgId(const QString &bldgName) const;
|
||||
|
||||
|
||||
// helper
|
||||
bool waitForData(const std::function<bool()> &func, int retryCount = 10);
|
||||
|
||||
ExplosionCluster getEcForTneVerification(const QString &eaName = QStringLiteral("ModuleTest_TneVerification__"), double rotation = 0);
|
||||
|
||||
ExplosionCluster getEcFor1104(const QString &eaName = QStringLiteral("ModuleTest_ec__"));
|
||||
ExplosionCluster getEcFor1106(const QString &eaName = QStringLiteral("ModuleTest_ec__"));
|
||||
ExplosionCluster getEcForUBAHN(const QString &eaName = QStringLiteral("ModuleTest_ec__"));
|
||||
|
||||
ExplosionCluster getEcFor3101(const QString &eaName = QStringLiteral("ModuleTest_ec__"));
|
||||
|
||||
|
||||
int doExplosionClusterModifyRequest(const ExplosionCluster &eaData);
|
||||
int doExplosionClusterSingleEffectOnlyModifyRequest(const ExplosionClusterSingleEffectOnlyRequest &request);
|
||||
int doExplosionClusterOcModifyRequest(const ExplosionClusterOcModifyRequest &request);
|
||||
|
||||
int doExplosionClusterTargetPositionsModify(const TargetPositionsModifyRequest &request);
|
||||
void waitForEffectStates(int lineNumber, int durPrep = 5, int durAct = 60, int durExp = 30);
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
//
|
||||
// TestCases
|
||||
//
|
||||
|
||||
// void initTestCase_data(); // will be called to create a global test data table.
|
||||
void initTestCase(); // will be called before the first test function is executed.
|
||||
|
||||
void init(); // will be called before each test function is executed.
|
||||
// void cleanup(); // will be called after each test function is executed.
|
||||
|
||||
void dumpCnt();
|
||||
void dumpBldgStates();
|
||||
bool setFilterForBldgState(const QString &bldgName);
|
||||
bool checkSingleEffects(uint idx, const LtsCoordTrans::LtsCoordinate &coord, const AreaEffectSimulation::AesZPlacement zPlace
|
||||
, const QString &context, double maxDist3D = 1);
|
||||
bool checkBldgStates(const QVector<int> &damagePercent, const QString &context);
|
||||
bool isKanaeleAssigned();
|
||||
|
||||
void test_justSetupParticipants();
|
||||
|
||||
void test_TneVerificationBremen_00();
|
||||
void test_TneVerificationBremen_01();
|
||||
void test_TneVerificationBremen_02();
|
||||
|
||||
// !!! assume ONE elevationMap: Altmark_dt1.tif !!!
|
||||
// !!! assume ONE elevationMap: Altmark_dt1.tif !!!
|
||||
// !!! assume ONE elevationMap: Altmark_dt1.tif !!!
|
||||
|
||||
void test_bldg_1104_Proximity();
|
||||
void test_bldg_1104_Impact();
|
||||
void test_bldg_1104_Delay();
|
||||
|
||||
void test_bldg_1106_Proximity();
|
||||
void test_bldg_1106_Impact();
|
||||
void test_bldg_1106_Delay();
|
||||
|
||||
|
||||
void test_bldg_UBAHN_Proximity();
|
||||
void test_bldg_UBAHN_Impact();
|
||||
void test_bldg_UBAHN_Delay();
|
||||
|
||||
void test_bldg_3101_Proximity();
|
||||
void test_bldg_3101_Impact();
|
||||
void test_bldg_3101_Delay();
|
||||
|
||||
|
||||
|
||||
void test_remove_effect_start();
|
||||
|
||||
void test_create_bulk(); // has to be call explicitly called by user
|
||||
|
||||
void test_point_geometry_bldg_1104();
|
||||
void test_point_geometry_bldg_1104_SMArt_Proximity(); // NT, Jan 2025: since SMArt seems to be 'not implememented yet', test case fails
|
||||
|
||||
|
||||
// ExplosionCluster 'OC' / 'ABT'
|
||||
void test_bldg_1104_OC();
|
||||
|
||||
// ExplosionCluster 'Light' (without trajectory)
|
||||
void test_point_geometry_bldg_1104_light();
|
||||
void test_point_geometry_bldg_1104_single_effect_only(); // Von HLA
|
||||
void test_bldg_1104_effects_only(); // Von ABT
|
||||
|
||||
// VULCANO
|
||||
void test_vulcano_bldg_1104();
|
||||
void test_vulcano_bldg_1104_withTargetModify();
|
||||
void test_vulcano_bldg_1104_withTargetModify2();
|
||||
|
||||
|
||||
// will be called after the last test function was executed:
|
||||
void cleanupTestCase(); // will be called after the last test function was executed.
|
||||
|
||||
public:
|
||||
static bool m_enable_create_bulk;
|
||||
|
||||
private:
|
||||
int m_domainId{-1};
|
||||
int m_exerciseId{-1};
|
||||
int m_traingAreaId{-1};
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Ftc> m_aesFtc;
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
|
||||
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
|
||||
|
||||
std::shared_ptr<Buildings::Interface::Ftc> m_bldFtc;
|
||||
std::shared_ptr<Buildings::Interface::Dtc> m_bldDtc;
|
||||
// std::shared_ptr<InfrastructureManagement::Interface::Ftc> m_ismFtc;
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
|
||||
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
|
||||
|
||||
ExplosionCluster m_data;
|
||||
Effects m_effects;
|
||||
long m_objectRequestedTimePointMsec{-1};
|
||||
AesItemView m_aesItemViewSingleExplosions;
|
||||
bool m_replyError{false};
|
||||
|
||||
QMap<int, QString> m_bldgIdToName;
|
||||
int m_bldgIdToFilter{-1};
|
||||
std::vector<Buildings::BuildingState> m_buildingStateVec;
|
||||
|
||||
struct counterDds
|
||||
{
|
||||
// ExplosionCluster
|
||||
int cntExplosionCluster{0};
|
||||
|
||||
// AesItemView
|
||||
int cntAtExplosionCluster{0};
|
||||
int cntAtExplosionClusterGunToTargetLine{0};
|
||||
|
||||
// Effects
|
||||
int cntExplosionClusterEffects{0};
|
||||
|
||||
// Trajectory
|
||||
int cntTrajectory{0};
|
||||
|
||||
|
||||
void reset()
|
||||
{
|
||||
cntExplosionCluster = 0;
|
||||
cntAtExplosionCluster = 0;
|
||||
cntAtExplosionClusterGunToTargetLine = 0;
|
||||
cntExplosionClusterEffects = 0;
|
||||
cntTrajectory = 0;
|
||||
}
|
||||
}
|
||||
m_counterDds;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(UnitTestSources
|
||||
limits_module_test.cpp
|
||||
limits_module_test.h
|
||||
)
|
||||
|
||||
NGL_ADD_EXECUTABLE(SV aesModuleTestLimits ${LinkedSources} ${UnitTestSources} )
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(aesModuleTestLimits
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
LtsCommandLineParser
|
||||
LtsCoordTrans
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
ddsconnector
|
||||
svcAesCommon
|
||||
svcAesClient
|
||||
svcIsmClient
|
||||
svcExmClient
|
||||
svcPpmClient
|
||||
svcPdmClient
|
||||
)
|
||||
|
||||
NGL_INSTALL(SV TARGETS aesModuleTestLimits DESTINATION bin/test)
|
||||
|
||||
# ADD_TEST(NAME aesModuleTestBorders COMMAND $<TARGET_FILE:aesUnitTestTneAlgorithmen>)
|
||||
+1376
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,263 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ModuleTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
|
||||
#include <AreaEffectSimulation/aes_ftc.h>
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <AreaEffectSimulation/logger.h>
|
||||
|
||||
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
|
||||
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ProjectDataManagement/pdm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_ftc.h>
|
||||
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace AreaEffectSimulation; // JUST FOR LOGGER_T
|
||||
|
||||
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser(ProvideCommandLineParameterOptions(DomainId | ExerciseId | NoVersion))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ModuleTestLimits : public QObject
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionAreaModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionSingleModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::MineAreaModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::MineAreaRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::NContaminationModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::NContaminationRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::OffRouteMineModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::OffRouteMineRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::BoobyTrapModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::BoobyTrapRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::BCContaminationModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::BCContaminationRemoveReplyHandler
|
||||
, protected ParticipantManagement::Interface::Ftc::SetSimulatedPositionReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ChargeAdministrationModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::TechnicalAreaModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::FunctionalAreaModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::FunctionalAreaRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::TechnicalAreaRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionSingleRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionAreaRemoveReplyHandler
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModuleTestLimits(int domainId, int exerciseId);
|
||||
|
||||
protected:
|
||||
void onExplosionClusterModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
|
||||
|
||||
// helper
|
||||
bool waitForData(const std::function<bool()> &func, int retryCount = 10);
|
||||
|
||||
ExplosionClusterModifyRequest getEc(const Core::GeoPosition2D& cornerBottomLeft);
|
||||
ExplosionClusterModifyRequest getAs(); //AirSupport
|
||||
ExplosionAreaModifyRequest getEa();
|
||||
ExplosionSingleModifyRequest getEs();
|
||||
MineAreaModifyRequest getMa();
|
||||
NContaminationModifyRequest getNBC();
|
||||
OffRouteMineModifyRequest getORM();
|
||||
BoobyTrapModifyRequest getBT();
|
||||
BCContaminationModifyRequest getBCC();
|
||||
FunctionalAreaModifyRequest getFA();
|
||||
TechnicalAreaModifyRequest getTA();
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
//
|
||||
// TestCases
|
||||
//
|
||||
|
||||
// void initTestCase_data(); // will be called to create a global test data table.
|
||||
void initTestCase(); // will be called before the first test function is executed.
|
||||
|
||||
void init(); // will be called before each test function is executed.
|
||||
// void cleanup(); // will be called before each test function is executed.
|
||||
void cleanup();
|
||||
|
||||
//ExplosionArea and Single is currently not used in GÜZ
|
||||
|
||||
// void testExplosionAreaCentral();
|
||||
// void testExplosionAreaDecentral();
|
||||
// void testExplosionSingleCentral();
|
||||
// void testExplosionSingleDecentral();
|
||||
|
||||
void testExplosionClusterCentral();
|
||||
void testExplosionClusterDecentral();
|
||||
void testAirSupports(); //Always central
|
||||
void testMineAreaCentral();
|
||||
void testMineAreaDecentral();
|
||||
void testNBCCentral();
|
||||
void testNBCDecentral();
|
||||
void testOffRouteMines(); //Always central
|
||||
void testBoobyTraps(); //Always central
|
||||
void testBCCCentral();
|
||||
void testBCCDecentral();
|
||||
void testFADecentral();
|
||||
void testFACentral();
|
||||
// void testTADecentral(); //Only in AHTC
|
||||
// void testTACentral();
|
||||
|
||||
|
||||
void cleanupTestCase(); // will be called after the last test function was executed.
|
||||
|
||||
private:
|
||||
void setupParticipant();
|
||||
void setupCharges();
|
||||
void deleteAesAreas();
|
||||
|
||||
public:
|
||||
static bool m_noDelete;
|
||||
|
||||
private:
|
||||
int m_domainId{-1};
|
||||
int m_exerciseId{-1};
|
||||
int m_traingAreaId{-1};
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
int s_counter{0};
|
||||
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Ftc> m_aesFtc;
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
|
||||
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
|
||||
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
|
||||
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
|
||||
|
||||
ExplosionCluster m_data;
|
||||
long m_objectRequestedTimePointMsec{-1};
|
||||
AesItemView m_aesItemViewSingleExplosions;
|
||||
bool m_replyError{false};
|
||||
|
||||
QMap<int, QString> m_bldgIdToName;
|
||||
int m_maxExplosionsCentral = 200;
|
||||
int m_maxExplosionsDecentral = 50;
|
||||
int m_maxMineAreasCentral = 100;
|
||||
int m_maxMineAreasDecentral = 50;
|
||||
int m_maxNBCCentral = 100;
|
||||
int m_maxNBCDecentral = 10;
|
||||
int m_maxOffRouteMines = 100;
|
||||
int m_maxBoobyTraps = 150;
|
||||
int m_maxSafePzAbwSafe = 10;
|
||||
int m_maxFunctionalAreaCentral = 50;
|
||||
int m_maxFunctionalAreaDec = 10;
|
||||
int m_maxTechnicalAreaCentral = 100;
|
||||
int m_maxTechnicalAreaDecentral = 10;
|
||||
int m_maxAirSupports = 100;
|
||||
|
||||
|
||||
InfrastructureManagement::SpecialArea m_specialArea;
|
||||
Core::GeoPosition2D m_centralPoint;
|
||||
Core::GeoPosition2D m_decentralPoint;
|
||||
std::vector<Core::GeoPosition2D> m_segmentsCentral;
|
||||
std::vector<Core::GeoPosition2D> m_segmentsDecentral;
|
||||
Core::GeoPosition2D m_partPos;
|
||||
|
||||
const Core::GeoPosition2D m_centralBremen = Core::GeoPosition2D(0.154634, 0.926053);
|
||||
const Core::GeoPosition2D m_centralAltmark = Core::GeoPosition2D(0.201526, 0.914231);
|
||||
const Core::GeoPosition2D m_decentralBremen = Core::GeoPosition2D(0.156305, 0.92683);
|
||||
const Core::GeoPosition2D m_decentralAltmark = Core::GeoPosition2D(0.202014, 0.915328);
|
||||
const std::vector<Core::GeoPosition2D> m_segmentsCentralBremen = {{0.154634, 0.926053}, {0.154635, 0.926055} };
|
||||
const std::vector<Core::GeoPosition2D> m_segmentsDecentralBremen = {{0.15609399, 0.92610527}, {0.15580772, 0.92628852}};
|
||||
const std::vector<Core::GeoPosition2D> m_segmentsCentralAltmark = {{0.201412, 0.914215}, {0.201757, 0.914225} };
|
||||
const std::vector<Core::GeoPosition2D> m_segmentsDecentralAltmark = {{0.201799, 0.914842}, {0.201965, 0.914806} };
|
||||
const Core::GeoPosition2D m_partPosAltmark = Core::GeoPosition2D(0.202168, 0.914311);
|
||||
const Core::GeoPosition2D m_partPosBremen = Core::GeoPosition2D(0.156482, 0.925844);
|
||||
|
||||
struct counterDds
|
||||
{
|
||||
// ExplosionCluster
|
||||
int cntExplosionCluster{0};
|
||||
|
||||
// AesItemView
|
||||
int cntAtExplosionCluster{0};
|
||||
int cntAtExplosionClusterGunToTargetLine{0};
|
||||
|
||||
// Effects
|
||||
int cntExplosionClusterEffects{0};
|
||||
|
||||
// Trajectory
|
||||
int cntTrajectory{0};
|
||||
|
||||
|
||||
void reset()
|
||||
{
|
||||
cntExplosionCluster = 0;
|
||||
cntAtExplosionCluster = 0;
|
||||
cntAtExplosionClusterGunToTargetLine = 0;
|
||||
cntExplosionClusterEffects = 0;
|
||||
cntTrajectory = 0;
|
||||
}
|
||||
}
|
||||
m_counterDds;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
public:
|
||||
void onMineAreaModifyReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onExplosionAreaModifyReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onExplosionClusterRemoveReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onNContaminationModifyReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onOffRouteMineModifyReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onBoobyTrapModifyReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onNContaminationRemoveReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onOffRouteMineRemoveReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onBoobyTrapRemoveReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onMineAreaRemoveReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onBCContaminationModifyReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onBCContaminationRemoveReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
|
||||
// SetSimulatedPositionReplyHandler interface
|
||||
void onSetSimulatedPositionReply(const Core::FunctionReplyObject &reply) override
|
||||
{
|
||||
m_replyError = reply.error();
|
||||
DEBUG_LOG(m_logger) << " got reply - onSetSimulatedPositionReply : " << m_replyError;
|
||||
if (!reply.str().empty())
|
||||
ERROR_LOG(m_logger) << " got reply - onExplosionClusterModifyReply: " << reply.translated();
|
||||
}
|
||||
|
||||
// ChargeAdministrationModifyReplyHandler interface
|
||||
void onChargeAdministrationModifyReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
|
||||
void onTechnicalAreaModifyReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onFunctionalAreaModifyReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onTechnicalAreaRemoveReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onFunctionalAreaRemoveReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onExplosionSingleModifyReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onExplosionAreaRemoveReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
void onExplosionSingleRemoveReply(const Core::FunctionReplyObject &reply) override { Q_UNUSED(reply);}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(UnitTestSources
|
||||
aes_others_module_test.h
|
||||
aes_others_module_test.cpp
|
||||
)
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
ADD_EXECUTABLE(aesModuleTestOthers ${LinkedSources} ${UnitTestSources} )
|
||||
|
||||
TARGET_LINK_LIBRARIES(aesModuleTestOthers
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
LtsCommandLineParser
|
||||
LtsCoordinate
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
ddsconnector
|
||||
svcAesCommon
|
||||
svcAesClient
|
||||
svcExmClient
|
||||
svcPdmClient
|
||||
svcPpmClient
|
||||
)
|
||||
|
||||
# ADD_TEST(NAME aesModuleTestExplosionCluster COMMAND $<TARGET_FILE:aesUnitTestTneAlgorithmen>)
|
||||
ENDIF()
|
||||
+828
@@ -0,0 +1,828 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ModuleTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_others_module_test.h"
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
|
||||
|
||||
// AES
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <AreaEffectSimulation/Utils/polygons.h>
|
||||
|
||||
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace AreaEffectSimulation;
|
||||
using namespace LtsCoordTrans;
|
||||
|
||||
|
||||
// must be in pdm.pdm_charge_type
|
||||
static const int s_ChargeTypeId1 = 371;
|
||||
static const int s_ChargeTypeId2 = 372;
|
||||
|
||||
|
||||
static const int s_TraingAreaId_Altmark = 2;
|
||||
static const int s_TraingAreaId_Bremen = 6;
|
||||
|
||||
//
|
||||
// some helper functions
|
||||
//
|
||||
|
||||
template<typename T>
|
||||
dds::core::optional<T> toOptional(T inVal)
|
||||
{
|
||||
return inVal != T() ? dds::core::optional<T>(inVal) : dds::core::optional<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
dds::core::optional<T> optional()
|
||||
{
|
||||
return dds::core::optional<T>();
|
||||
}
|
||||
|
||||
double distanceMeter(const LtsCoordTrans::UtmCoordinate &utmCoord1, const LtsCoordTrans::UtmCoordinate &utmCoord2)
|
||||
{
|
||||
|
||||
double dist = LtsCoordTrans::distance(utmCoord1, utmCoord2);
|
||||
qCritical() << " dist" << dist;
|
||||
return dist;
|
||||
}
|
||||
|
||||
double distanceMeter(const Core::GeoPosition &geoPos, const LtsCoordTrans::UtmCoordinate &utmCoord)
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate &utmPos = LtsCoordTrans::UtmCoordinate::fromGeographic(geoPos.lon(), geoPos.lat());
|
||||
return distanceMeter(utmPos, utmCoord);
|
||||
}
|
||||
|
||||
double distanceMeter(const Core::GeoPosition2D &geoPos2D, const LtsCoordTrans::UtmCoordinate &utmCoord)
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate &utmPos = LtsCoordTrans::UtmCoordinate::fromGeographic(geoPos2D.lon(), geoPos2D.lat());
|
||||
return distanceMeter(utmPos, utmCoord);
|
||||
}
|
||||
|
||||
ModuleTestAesOthers::ModuleTestAesOthers(int domainId, int exerciseId)
|
||||
: m_domainId(domainId)
|
||||
, m_exerciseId(exerciseId)
|
||||
, m_logger(getLogger("ModuleTestAesOthers"))
|
||||
{
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::onSetSimulatedPositionReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_replyError = replyObject.error();
|
||||
DEBUG_LOG(m_logger) << " got reply - onSetSimulatedPositionReply : " << m_replyError;
|
||||
if (!replyObject.str().empty())
|
||||
ERROR_LOG(m_logger) << " got reply - onExplosionClusterModifyReply: " << replyObject.translated();
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::onBoobyTrapModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_replyError = replyObject.error();
|
||||
DEBUG_LOG(m_logger) << " got reply - onBoobyTrapModifyReply : " << m_replyError;
|
||||
if (!replyObject.str().empty())
|
||||
ERROR_LOG(m_logger) << " got reply - onBoobyTrapModifyReply: " << replyObject.translated();
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::onBoobyTrapRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " got reply - onBoobyTrapRemoveReply : " << m_replyError;
|
||||
if (!replyObject.str().empty())
|
||||
ERROR_LOG(m_logger) << " got reply - onBoobyTrapRemoveReply: " << replyObject.translated();
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::onOffRouteMineModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_replyError = replyObject.error();
|
||||
DEBUG_LOG(m_logger) << " got reply - onOffRouteMineModifyReply : " << m_replyError;
|
||||
if (!replyObject.str().empty())
|
||||
ERROR_LOG(m_logger) << " got reply - onOffRouteMineModifyReply: " << replyObject.translated();
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::onOffRouteMineRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " got reply - onOffRouteMineRemoveReply : " << m_replyError;
|
||||
if (!replyObject.str().empty())
|
||||
ERROR_LOG(m_logger) << " got reply - onOffRouteMineRemoveReply: " << replyObject.translated();
|
||||
}
|
||||
|
||||
|
||||
void ModuleTestAesOthers::boobyTrapChanged(const BoobyTrap &data, DataModification modType)
|
||||
{
|
||||
Q_UNUSED(modType);
|
||||
if (data.id() == -1)
|
||||
return;
|
||||
|
||||
++m_counterDds.cntBoobyTrap;
|
||||
|
||||
m_dataBoobyTrap = data;
|
||||
qint64 startTimeMsec = -1;
|
||||
if (m_dataBoobyTrap.effectStart().is_set())
|
||||
startTimeMsec = m_dataBoobyTrap.effectStart().get();
|
||||
|
||||
DEBUG_LOG(m_logger) << " got changed - m_dataBoobyTrap: " << m_dataBoobyTrap.id() << ", state=" << m_dataBoobyTrap.effectStateId()
|
||||
<< ", startTimeMsec=" << startTimeMsec
|
||||
<< ", cntBoobyTrap=" << m_counterDds.cntBoobyTrap;
|
||||
TRACE_LOG(m_logger) << " got changed - m_dataBoobyTrap: " << m_dataBoobyTrap;
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::offRouteMineChanged(const OffRouteMine &data, DataModification modType)
|
||||
{
|
||||
Q_UNUSED(modType);
|
||||
if (data.id() == -1)
|
||||
return;
|
||||
|
||||
++m_counterDds.cntOffRouteMine;
|
||||
|
||||
m_dataOffRouteMine = data;
|
||||
qint64 startTimeMsec = -1;
|
||||
if (m_dataOffRouteMine.effectStart().is_set())
|
||||
startTimeMsec = m_dataOffRouteMine.effectStart().get();
|
||||
|
||||
DEBUG_LOG(m_logger) << " got changed - m_dataOffRouteMine: " << m_dataOffRouteMine.id() << ", state=" << m_dataOffRouteMine.effectStateId()
|
||||
<< ", startTimeMsec=" << startTimeMsec
|
||||
<< ", cntOffRouteMine=" << m_counterDds.cntOffRouteMine;
|
||||
TRACE_LOG(m_logger) << " got changed - m_dataOffRouteMine: " << m_dataOffRouteMine;
|
||||
}
|
||||
|
||||
|
||||
void ModuleTestAesOthers::onAesItemViewChanged(const AesItemView &aesItemView, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
AreaEffectSimulation::AesType_def::type aesType = aesItemView.aesTypeId().underlying();
|
||||
DEBUG_LOG(m_logger) << " got onAesItemViewChanged, aesType=" << aesType;
|
||||
|
||||
switch (aesType)
|
||||
{
|
||||
case AreaEffectSimulation::AesType_def::AtBoobyTrap:
|
||||
case AreaEffectSimulation::AesType_def::AtBoobyTrapSecondary:
|
||||
case AreaEffectSimulation::AesType_def::AtOffRouteMine:
|
||||
case AreaEffectSimulation::AesType_def::AtOffRouteMineSecondary:
|
||||
++m_counterDds.cntItemView;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::dumpCnt()
|
||||
{
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " Counter: "
|
||||
<< " cntBoobyTrap = " << m_counterDds.cntBoobyTrap
|
||||
<< " cntOffRouteMine = " << m_counterDds.cntOffRouteMine
|
||||
<< ", cntItemView = " << m_counterDds.cntItemView;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ModuleTestAesOthers::waitForData(const std::function<bool ()> &func, int retryCount)
|
||||
{
|
||||
// Maybe give QTRY_VERIFY2 or QTRY_VERIFY2_WITH_TIMEOUT a chance
|
||||
// Or better QTRY_IMPL ??
|
||||
// QTRY_IMPL(m_replyError == false, 1);
|
||||
|
||||
|
||||
// wait for data
|
||||
retryCount *= 10;
|
||||
|
||||
for (int i = 0; i < retryCount; ++i)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " waitForData - i: " << i;
|
||||
if (func())
|
||||
return true;
|
||||
QTest::qWait(100);
|
||||
}
|
||||
return func();
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::waitForEffectStatesBT(int lineNumber, int durPrep, int durAct, int durExp)
|
||||
{
|
||||
// expected condition:
|
||||
if (!waitForData([this]() { return m_replyError == false; }, 1))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error on request" << ", lineNumber = " << lineNumber;
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " waiting for EsPrepared...";
|
||||
if (!waitForData([this]() { return m_dataBoobyTrap.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsPrepared;}, durPrep))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for EsPrepared of m_dataBoobyTrap with id " << m_dataBoobyTrap.id()
|
||||
<< ", lineNumber = " << lineNumber;
|
||||
QVERIFY2(false, "ERROR, exit");
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " waiting for EsActivated...";
|
||||
if (!waitForData([this]() { return m_dataBoobyTrap.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated;}, durAct))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for EsActivated of m_dataBoobyTrapr with id " << m_dataBoobyTrap.id()
|
||||
<< ", lineNumber = " << lineNumber;
|
||||
QVERIFY2(false, "ERROR, exit");
|
||||
return;
|
||||
}
|
||||
|
||||
if (durExp > 0)
|
||||
{
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " waiting for EsExpired...";
|
||||
if (!waitForData([this]() { return m_dataBoobyTrap.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired;}, durExp))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for EsExpired of m_dataBoobyTrap with id " << m_dataBoobyTrap.id()
|
||||
<< ", lineNumber = " << lineNumber;
|
||||
QVERIFY2(false, "ERROR, exit");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::waitForEffectStatesORM(int lineNumber, int durPrep, int durAct, int durExp)
|
||||
{
|
||||
// expected condition:
|
||||
if (!waitForData([this]() { return m_replyError == false; }, 1))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error on request" << ", lineNumber = " << lineNumber;
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " waiting for EsPrepared...";
|
||||
if (!waitForData([this]() { return m_dataOffRouteMine.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsPrepared;}, durPrep))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for EsPrepared of m_dataOffRouteMine with id " << m_dataOffRouteMine.id()
|
||||
<< ", lineNumber = " << lineNumber;
|
||||
QVERIFY2(false, "ERROR, exit");
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " waiting for EsActivated...";
|
||||
if (!waitForData([this]() { return m_dataOffRouteMine.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated;}, durAct))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for EsActivated of m_dataOffRouteMine with id " << m_dataOffRouteMine.id()
|
||||
<< ", lineNumber = " << lineNumber;
|
||||
QVERIFY2(false, "ERROR, exit");
|
||||
return;
|
||||
}
|
||||
|
||||
if (durExp > 0)
|
||||
{
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " waiting for EsExpired...";
|
||||
if (!waitForData([this]() { return m_dataOffRouteMine.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired;}, durExp))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for EsExpired of m_dataOffRouteMine with id " << m_dataOffRouteMine.id()
|
||||
<< ", lineNumber = " << lineNumber;
|
||||
QVERIFY2(false, "ERROR, exit");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::setupParticipants()
|
||||
{
|
||||
INFO_LOG(m_logger) << " setupParticipant ...";
|
||||
|
||||
QVERIFY2(m_ppmFtc, "ERROR, no m_ppmFtc");
|
||||
|
||||
{
|
||||
ParticipantManagement::SetSimulatedPosition req;
|
||||
|
||||
{
|
||||
req.participantId(18); // according testDB
|
||||
req.onlyOutdatedParticipants(false);
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate &utmPos =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32UPD7690018100")); // 32U PD 76900 18100
|
||||
QPointF pos = utmPos.geographic();
|
||||
req.position(Core::GeoPosition(pos.x(), pos.y(), 0.0));
|
||||
|
||||
INFO_LOG(m_logger) << " setSimulatedPositionRequest ...";
|
||||
m_replyError = true;
|
||||
m_ppmFtc->setSimulatedPositionRequest(req, this);
|
||||
|
||||
// expected condition:
|
||||
if (!waitForData([this]() { return m_replyError == false; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error on request";
|
||||
}
|
||||
}
|
||||
}
|
||||
INFO_LOG(m_logger) << " setSimulatedPositionRequest ...DONE";
|
||||
}
|
||||
|
||||
bool ModuleTestAesOthers::checkParticipant_18()
|
||||
{
|
||||
// soll: QStringLiteral("32UPD7690018000")); // 32U PD 76900 18000
|
||||
const int partId = 18;
|
||||
const ParticipantManagement::ParticipantPosition &pos = m_ppmDtc->participantPosition(partId);
|
||||
QString mgrsStr = LtsCoordTrans::mgrsFromGeographic(pos.pos().lon(), pos.pos().lat());
|
||||
INFO_LOG(m_logger) << " for partId = '" << partId << "', we got position: " << mgrsStr;
|
||||
|
||||
return mgrsStr == QStringLiteral("32U PD 76900 18100");
|
||||
}
|
||||
|
||||
bool ModuleTestAesOthers::tryRemoveOldBoobyTraps()
|
||||
{
|
||||
m_aesDtc->waitForHistoricalDataBoobyTrap(5000);
|
||||
|
||||
const auto &btMap = m_aesDtc->boobyTraps();
|
||||
|
||||
for (const auto &bt : btMap)
|
||||
{
|
||||
qCritical() << " bt.name" << bt.name().c_str();
|
||||
int ret = m_aesFtc->boobyTrapRemoveRequest(Core::RemoveElementRequest(bt.id()));
|
||||
qCritical() << " bt.name -> " << ret;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int ModuleTestAesOthers::doBoobyTrapModifyRequest(const BoobyTrap &btData)
|
||||
{
|
||||
BoobyTrapModifyRequest req(btData.id(),
|
||||
btData.name(),
|
||||
btData.effectDuration(),
|
||||
btData.chargeStruct().chargeTypeId(),
|
||||
btData.impactPosition(),
|
||||
btData.impactRadius(),
|
||||
btData.triggerRadius(),
|
||||
btData.rotationAngle(),
|
||||
btData.centralAngle(),
|
||||
btData.effectStart(),
|
||||
btData.partyId()
|
||||
);
|
||||
|
||||
int ret = m_aesFtc->boobyTrapModifyRequest(req, this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ModuleTestAesOthers::doOffRouteMineModifyRequest(const OffRouteMine &offRouteMine)
|
||||
{
|
||||
OffRouteMineModifyRequest req(offRouteMine.id(),
|
||||
offRouteMine.name(),
|
||||
offRouteMine.effectDuration(),
|
||||
offRouteMine.chargeStruct().chargeTypeId(),
|
||||
offRouteMine.area(),
|
||||
offRouteMine.impactRadius(),
|
||||
offRouteMine.effectStart(),
|
||||
offRouteMine.partyId()
|
||||
);
|
||||
|
||||
int ret = m_aesFtc->offRouteMineModifyRequest(req, this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ModuleTestAesOthers::doMoveParticipant(int participantId, const QString &newPositionMGRS)
|
||||
{
|
||||
ParticipantManagement::SetSimulatedPosition req;
|
||||
{
|
||||
req.participantId(participantId); // according testDB
|
||||
req.onlyOutdatedParticipants(false);
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate &utmPos =
|
||||
LtsCoordTrans::UtmCoordinate::fromMgrs(newPositionMGRS); // 32U PD 76900 18100
|
||||
QPointF pos = utmPos.geographic();
|
||||
req.position(Core::GeoPosition(pos.x(), pos.y(), 0.0));
|
||||
|
||||
INFO_LOG(m_logger) << " setSimulatedPositionRequest ...";
|
||||
m_replyError = true;
|
||||
m_ppmFtc->setSimulatedPositionRequest(req, this);
|
||||
|
||||
// expected condition:
|
||||
if (!waitForData([this]() { return m_replyError == false; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error on request";
|
||||
}
|
||||
}
|
||||
INFO_LOG(m_logger) << " doMoveParticipant ...DONE";
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// context of textCases
|
||||
//
|
||||
void ModuleTestAesOthers::initTestCase()
|
||||
{
|
||||
//
|
||||
// DdsConnector
|
||||
//
|
||||
|
||||
NOTICE_LOG(m_logger) << "DDSConnector: m_domainId " << m_domainId << ", m_exerciseId " << m_exerciseId;
|
||||
|
||||
// cmd
|
||||
m_ddsConnector.reset(new DDSConnector::DdsConnector(m_domainId, IDL::PartitionType::Exercise, m_exerciseId));
|
||||
bool bInit = m_ddsConnector->init();
|
||||
QVERIFY2(bInit, "ERROR, ddsConnector.init failed!!");
|
||||
if (!bInit)
|
||||
{
|
||||
ERROR_LOG(m_logger) << " ERROR, ddsConnector.init failed!!";
|
||||
return;
|
||||
}
|
||||
INFO_LOG(m_logger) << " ddsConnector.init successfull";
|
||||
|
||||
// cmd
|
||||
m_ddsConnector->initPublisherSubscriber();
|
||||
INFO_LOG(m_logger) << " ddsConnector.initPublisherSubscriber done";
|
||||
|
||||
//
|
||||
// Aes
|
||||
//
|
||||
// cmd
|
||||
m_aesFtc = AreaEffectSimulation::Interface::Ftc::create(m_ddsConnector);
|
||||
QVERIFY2(m_aesFtc, "ERROR, create m_aesFtc failed!!");
|
||||
bool bRet = m_aesFtc->enableAll();
|
||||
QVERIFY2(bRet, "ERROR, enableAll failed!!");
|
||||
|
||||
// cmd
|
||||
m_aesDtc = AreaEffectSimulation::Interface::Dtc::create(m_ddsConnector);
|
||||
QVERIFY2(m_aesDtc, "ERROR, create m_aesDtc failed!!");
|
||||
bRet = bRet && m_aesDtc->enableAll();
|
||||
QVERIFY2(bRet, "ERROR, enableAll failed!!");
|
||||
|
||||
|
||||
std::cout << " waitForHistoricalDataAesItemView... " << std::endl;
|
||||
m_aesDtc->waitForHistoricalDataBoobyTrap(2000);
|
||||
std::cout << " waitForHistoricalDataAesItemView... Done" << std::endl;
|
||||
|
||||
std::cout << " waitForHistoricalDataAesItemView... " << std::endl;
|
||||
m_aesDtc->waitForHistoricalDataAesItemView(2000);
|
||||
std::cout << " waitForHistoricalDataAesItemView... Done" << std::endl;
|
||||
|
||||
QMap<qint32, AreaEffectSimulation::AesItemView> aesItemViewsCont = m_aesDtc->aesItemViews();
|
||||
std::cout << " aesItemViewsCont.size() " << aesItemViewsCont.size() << std::endl;
|
||||
|
||||
//
|
||||
// PDM
|
||||
//
|
||||
// m_pdmDtc = ProjectDataManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
// QVERIFY2(m_pdmDtc, "ERROR, create m_pdmDtc failed!!");
|
||||
// bRet = bRet && m_pdmDtc->enableBuildingChargeEffect();
|
||||
// QVERIFY2(bRet, "ERROR, enableBuildingChargeEffect failed!!");
|
||||
// m_pdmDtc->waitForHistoricalDataBuildingChargeEffect(2000);
|
||||
// std::cout << " waitForHistoricalDataBuildingChargeEffect... Done" << std::endl;
|
||||
|
||||
//
|
||||
// EXM ExerciseManagement
|
||||
//
|
||||
m_exmDtc = ExerciseManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
QVERIFY2(m_exmDtc, "ERROR, create m_exmDtc failed!!");
|
||||
bRet = bRet && m_exmDtc->enableAll();
|
||||
QVERIFY2(bRet, "ERROR, enableAll failed!!");
|
||||
|
||||
m_exmDtc->waitForHistoricalDataExercise(2000);
|
||||
std::cout << " waitForHistoricalDataExercise... Done" << std::endl;
|
||||
|
||||
const ExerciseManagement::Exercise &exercise = m_exmDtc->exercise(m_exerciseId);
|
||||
QVERIFY2(exercise.id() == m_exerciseId, "ERROR, exercise failed!!");
|
||||
m_traingAreaId = exercise.trainingAreaId();
|
||||
|
||||
std::cout << " ExerciseManagement"
|
||||
<< ", m_traingAreaId = " << m_traingAreaId << std::endl;
|
||||
//
|
||||
// PPM ParticipantManagement
|
||||
//
|
||||
//
|
||||
m_ppmDtc = ParticipantManagement::Interface::Dtc::create(m_ddsConnector);
|
||||
QVERIFY2(m_ppmDtc, "ERROR, create m_ppmDtc failed!!");
|
||||
bRet = bRet && m_ppmDtc->enableAll();
|
||||
QVERIFY2(bRet, "ERROR, enableAll failed!!");
|
||||
|
||||
m_ppmFtc = ParticipantManagement::Interface::Ftc::create(m_ddsConnector);
|
||||
QVERIFY2(m_ppmFtc, "ERROR, create m_ppmFtc failed!!");
|
||||
bRet = bRet && m_ppmFtc->enableAll();
|
||||
m_ppmFtc->enableSetSimulatedPosition();
|
||||
QVERIFY2(bRet, "ERROR, enableAll failed!!");
|
||||
|
||||
// Geschuetz
|
||||
setupParticipants();
|
||||
|
||||
// connect at the end to skip unwanted
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::boobyTrapChanged,
|
||||
this, &ModuleTestAesOthers::boobyTrapChanged, Qt::UniqueConnection);
|
||||
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::offRouteMineChanged,
|
||||
this, &ModuleTestAesOthers::offRouteMineChanged, Qt::UniqueConnection);
|
||||
|
||||
connect(m_aesDtc.get(), &AreaEffectSimulation::Interface::Dtc::aesItemViewChanged,
|
||||
this, &ModuleTestAesOthers::onAesItemViewChanged, Qt::UniqueConnection);
|
||||
|
||||
// spend some for the eventLoop to "consume" existing topics/samples:
|
||||
for (int i = 0; i < 10; ++i)
|
||||
QTest::qWait(100);
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::init()
|
||||
{
|
||||
// init will be called before each test function is executed.
|
||||
m_counterDds.reset();
|
||||
|
||||
setupParticipants();
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::test_justSetupParticipants()
|
||||
{
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
setupParticipants();
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
//
|
||||
// 1104
|
||||
//
|
||||
void ModuleTestAesOthers::test_boobyTrap_01()
|
||||
{
|
||||
if (m_traingAreaId != s_TraingAreaId_Altmark)
|
||||
{
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " skip testcase due to m_traingAreaId = " << m_traingAreaId;
|
||||
return;
|
||||
}
|
||||
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " START, m_traingAreaId = " << m_traingAreaId;
|
||||
QVERIFY2(checkParticipant_18(), "ERROR, checkParticipant_5 failed!!");
|
||||
|
||||
AreaEffectSimulation::BoobyTrap bt;
|
||||
bt.id(0);
|
||||
bt.name(QString(QStringLiteral("ModuleTest_BoobyTrap01")).toStdString());
|
||||
bt.chargeStruct().chargeTypeId(252);
|
||||
bt.effectDuration(60000);
|
||||
bt.partyId(2);
|
||||
bt.impactRadius(10);
|
||||
bt.triggerRadius(5);
|
||||
|
||||
// Type1 == SchAbwMi ohne rotationAngle, centralAngle
|
||||
// Type2 == SchAbwRiMi mit rotationAngle, centralAngle
|
||||
|
||||
|
||||
LtsCoordinate lts = LtsCoordinate::fromUtmCoordinate(UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77000 18100")), 0.0);
|
||||
bt.impactPosition(lts.geoPosition2D());
|
||||
|
||||
bt.effectStart((time(nullptr) + 10) * 1000); // msec
|
||||
|
||||
m_replyError = true;
|
||||
m_dataBoobyTrap = AreaEffectSimulation::BoobyTrap();
|
||||
|
||||
int ret = doBoobyTrapModifyRequest(bt);
|
||||
QVERIFY2(ret != 0, "ERROR, doBoobyTrapModifyRequest failed!!");
|
||||
|
||||
waitForEffectStatesBT(__LINE__, 5, 15, 0); // do _not_ wait for expired!
|
||||
QVERIFY2(m_dataBoobyTrap.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated, "ERROR, effectStateId failed!!");
|
||||
dumpCnt();
|
||||
QVERIFY2(m_counterDds.cntBoobyTrap == 2, "ERROR, cnt failed!!"); // EsPrepared, EsActivated,
|
||||
QVERIFY2(m_counterDds.cntItemView == 4, "ERROR, cnt failed!!"); //
|
||||
|
||||
// Move Participant to trigger area, maybe also 3D scene marker:
|
||||
|
||||
doMoveParticipant(18, QStringLiteral("32U PD 77002 18112"));
|
||||
|
||||
// wait...
|
||||
waitForData([]() { return false; }, 2);
|
||||
|
||||
doMoveParticipant(18, QStringLiteral("32U PD 77002 18103"));
|
||||
|
||||
// wait until expired:
|
||||
waitForData([this]() { return m_dataBoobyTrap.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired; }, 60);
|
||||
|
||||
QVERIFY2(m_dataBoobyTrap.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired, "ERROR, effectStateId failed!!");
|
||||
|
||||
// wait to let it disappear:
|
||||
waitForData([]() { return false; }, 15);
|
||||
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
|
||||
void ModuleTestAesOthers::test_boobyTrap_02_IMPL(const QString &name,
|
||||
const LtsCoordinate &impactCoord,
|
||||
double rotationAngle,
|
||||
const LtsCoordinate &particpantCoord)
|
||||
{
|
||||
if (m_traingAreaId != s_TraingAreaId_Altmark)
|
||||
{
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " skip testcase due to m_traingAreaId = " << m_traingAreaId;
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " START, m_traingAreaId = " << m_traingAreaId
|
||||
<< ", name =" << name << "'"
|
||||
<< ", impactCoord= " << impactCoord.mgrs()
|
||||
<< ", rotationAngle = " << rotationAngle
|
||||
<< ", particpantCoord = " << particpantCoord.mgrs();
|
||||
|
||||
QVERIFY2(checkParticipant_18(), "ERROR, checkParticipant_5 failed!!");
|
||||
|
||||
AreaEffectSimulation::BoobyTrap bt;
|
||||
bt.id(0);
|
||||
bt.name(name.toStdString());
|
||||
bt.chargeStruct().chargeTypeId(252);
|
||||
bt.effectDuration(600000);
|
||||
bt.partyId(2);
|
||||
bt.impactRadius(10);
|
||||
bt.triggerRadius(5);
|
||||
|
||||
bt.impactPosition(impactCoord.geoPosition());
|
||||
|
||||
// Type1 == SchAbwMi ohne rotationAngle, centralAngle
|
||||
// Type2 == SchAbwRiMi mit rotationAngle, centralAngle
|
||||
bt.rotationAngle(toOptional(rotationAngle)); // Q1: 30
|
||||
bt.centralAngle(toOptional(90.0));
|
||||
|
||||
bt.effectStart((time(nullptr) + 10) * 1000); // msec
|
||||
|
||||
m_replyError = true;
|
||||
m_dataBoobyTrap = AreaEffectSimulation::BoobyTrap();
|
||||
|
||||
int ret = doBoobyTrapModifyRequest(bt);
|
||||
QVERIFY2(ret != 0, "ERROR, doBoobyTrapModifyRequest failed!!");
|
||||
|
||||
waitForEffectStatesBT(__LINE__, 5, 15, 0); // do _not_ wait for expired!
|
||||
QVERIFY2(m_dataBoobyTrap.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated, "ERROR, m_dataBoobyTrap effectStateId failed!!");
|
||||
dumpCnt();
|
||||
QVERIFY2(m_counterDds.cntBoobyTrap == 2, "ERROR, cnt failed!!"); // EsPrepared, EsActivated,
|
||||
QVERIFY2(m_counterDds.cntItemView == 4, "ERROR, cnt failed!!"); //
|
||||
|
||||
// Move Participant to trigger area, maybe also 3D scene marker:
|
||||
|
||||
// 1. in the near of area:
|
||||
doMoveParticipant(18, QStringLiteral("32U PD 77002 18112"));
|
||||
|
||||
// wait...
|
||||
waitForData([]() { return false; }, 2);
|
||||
|
||||
// 2. move IN the area:
|
||||
doMoveParticipant(18, particpantCoord.mgrs());
|
||||
|
||||
// wait until expired:
|
||||
waitForData([this]() { return m_dataBoobyTrap.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired; }, 60);
|
||||
|
||||
QVERIFY2(m_dataBoobyTrap.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired, "ERROR, effectStateId failed!!");
|
||||
|
||||
// wait to let it disappear:
|
||||
waitForData([]() { return false; }, 15);
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " END"
|
||||
<< ", name =" << name << "'"
|
||||
<< ", impactCoord= " << impactCoord.mgrs()
|
||||
<< ", rotationAngle = " << rotationAngle
|
||||
<< ", particpantCoord = " << particpantCoord.mgrs();
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::test_boobyTrap_02_Q1()
|
||||
{
|
||||
test_boobyTrap_02_IMPL(QStringLiteral("ModuleTest_BoobyTrap02_Q1"),
|
||||
LtsCoordinate::fromUtmCoordinate(UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77000 18100")), 0.0),
|
||||
30+(0*90),
|
||||
LtsCoordinate::fromUtmCoordinate(UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77002 18102")), 0.0));
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::test_boobyTrap_02_Q2()
|
||||
{
|
||||
test_boobyTrap_02_IMPL(QStringLiteral("ModuleTest_BoobyTrap02_Q2"),
|
||||
LtsCoordinate::fromUtmCoordinate(UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77000 18100")), 0.0),
|
||||
30+(1*90),
|
||||
LtsCoordinate::fromUtmCoordinate(UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77002 18098")), 0.0));
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::test_boobyTrap_02_Q3()
|
||||
{
|
||||
test_boobyTrap_02_IMPL(QStringLiteral("test_boobyTrap_02_Q3"),
|
||||
LtsCoordinate::fromUtmCoordinate(UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77000 18100")), 0.0),
|
||||
30+(2*90),
|
||||
LtsCoordinate::fromUtmCoordinate(UtmCoordinate::fromMgrs(QStringLiteral("32U PD 76998 18098")), 0.0));
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::test_boobyTrap_02_Q4()
|
||||
{
|
||||
test_boobyTrap_02_IMPL(QStringLiteral("test_boobyTrap_02_Q4"),
|
||||
LtsCoordinate::fromUtmCoordinate(UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77000 18100")), 0.0),
|
||||
30+(3*90),
|
||||
LtsCoordinate::fromUtmCoordinate(UtmCoordinate::fromMgrs(QStringLiteral("32U PD 76998 18102")), 0.0));
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::test_offRouteMine_02()
|
||||
{
|
||||
if (m_traingAreaId != s_TraingAreaId_Altmark)
|
||||
{
|
||||
NOTICE_LOG(m_logger) << LOGFUNCTION << " skip testcase due to m_traingAreaId = " << m_traingAreaId;
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " START, m_traingAreaId = " << m_traingAreaId;
|
||||
|
||||
QVERIFY2(checkParticipant_18(), "ERROR, checkParticipant_5 failed!!");
|
||||
|
||||
// offRouteMine1 = 253; // OHNE impactRadius
|
||||
// offRouteMine2 = 254; // MIT impactRadius
|
||||
|
||||
AreaEffectSimulation::OffRouteMine orm;
|
||||
orm.id(0);
|
||||
orm.name(QString(QStringLiteral("test_offRouteMine_02")).toStdString());
|
||||
orm.chargeStruct().chargeTypeId(254);
|
||||
orm.effectDuration(600000);
|
||||
orm.partyId(2);
|
||||
orm.impactRadius(10); // 254 -> MIT impactRadius -> mit 3DSphere/Kugel
|
||||
|
||||
const LtsCoordinate &coord =
|
||||
LtsCoordinate::fromUtmCoordinate(UtmCoordinate::fromMgrs(QStringLiteral("32U PD 77000 18100")), 0.0);
|
||||
orm.area().cornerBottomLeft(coord.geoPosition());
|
||||
orm.area().height(50);
|
||||
orm.area().width(1);
|
||||
orm.area().rotation(85);
|
||||
|
||||
orm.effectStart((time(nullptr) + 10) * 1000); // msec
|
||||
|
||||
m_replyError = true;
|
||||
m_dataOffRouteMine = AreaEffectSimulation::OffRouteMine();
|
||||
|
||||
int ret = doOffRouteMineModifyRequest(orm);
|
||||
QVERIFY2(ret != 0, "ERROR, doOffRouteMineModifyRequest failed!!");
|
||||
|
||||
waitForEffectStatesORM(__LINE__, 5, 15, 0); // do _not_ wait for expired!
|
||||
QVERIFY2(m_dataOffRouteMine.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated, "ERROR, effectStateId failed!!");
|
||||
dumpCnt();
|
||||
QVERIFY2(m_counterDds.cntOffRouteMine == 2, "ERROR, cnt failed!!"); // EsPrepared, EsActivated,
|
||||
QVERIFY2(m_counterDds.cntItemView == 4, "ERROR, cnt failed!!"); //
|
||||
|
||||
// Move Participant to trigger area, maybe also 3D scene marker:
|
||||
|
||||
// 1. in the near of area:
|
||||
doMoveParticipant(18, QStringLiteral("32U PD 77002 18112"));
|
||||
|
||||
// wait...
|
||||
waitForData([]() { return false; }, 2);
|
||||
|
||||
// 2. move OVER the area:
|
||||
doMoveParticipant(18, QStringLiteral("32U PD 77020 18095"));
|
||||
|
||||
// wait until expired:
|
||||
waitForData([this]() { return m_dataOffRouteMine.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired; }, 60);
|
||||
|
||||
QVERIFY2(m_dataOffRouteMine.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired, "ERROR, m_dataOffRouteMine effectStateId failed!!");
|
||||
|
||||
// wait to let it disappear:
|
||||
waitForData([]() { return false; }, 15);
|
||||
INFO_LOG(m_logger) << LOGFUNCTION << " END" << ", name =" << orm.name() << "'";
|
||||
}
|
||||
|
||||
void ModuleTestAesOthers::cleanupTestCase()
|
||||
{
|
||||
// finish last (dds) calls:
|
||||
waitForData([]() { return false; }, 10);
|
||||
|
||||
INFO_LOG(m_logger) << " ddsConnector destroy...";
|
||||
m_ddsConnector.reset();
|
||||
INFO_LOG(m_logger) << " ddsConnector destroy...DONE";
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("ModuleTest_ExplosionCluster", "log4cxx_aes.props");
|
||||
|
||||
// aesModuleTestAesOthers -v2 test_long -e42 -d139
|
||||
// ^^^ ^^^^ // no space!!!
|
||||
// aesModuleTestAesOthers -v2 test_long -e42
|
||||
// aesModuleTestAesOthers -v2 test_long -e42
|
||||
// aesModuleTestAesOthers test_long -e42
|
||||
// aesModuleTestAesOthers -e42
|
||||
|
||||
CmdLineParser options;
|
||||
options.setUnitModuleTestMode(true);
|
||||
|
||||
if (!options.init(true)) // showHelp , exitOnBadOption
|
||||
return -1;
|
||||
|
||||
if (options.exerciseId() <= 0)
|
||||
{
|
||||
fprintf(stderr, "ExerciseId not set!\n");
|
||||
return -2;
|
||||
}
|
||||
std::cout << " DomainId = " << options.domainId() << " - ExerciseId = " << options.exerciseId() << std::endl;
|
||||
|
||||
if (options.isSet(QStringLiteral("exerciseid")))
|
||||
--argc;
|
||||
if (options.isSet(QStringLiteral("domainid")))
|
||||
--argc;
|
||||
|
||||
const QStringList &slPositionalArgs = options.positionalArguments();
|
||||
for (const QString &item : qAsConst(slPositionalArgs))
|
||||
std::cout << " item = " << item << std::endl;
|
||||
|
||||
// // enable_create_bulk only if it´s explicitly called by user:
|
||||
// ModuleTestAesOthers::m_enable_create_bulk = slPositionalArgs.contains(QStringLiteral("test_create_bulk"));
|
||||
// std::cout << " enable_create_bulk = " << ModuleTestAesOthers::m_enable_create_bulk << std::endl;
|
||||
|
||||
|
||||
ModuleTestAesOthers tc(options.domainId(), options.exerciseId());
|
||||
return QTest::qExec(&tc, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ModuleTest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
#include <LtsCoordinate/lts_coordinate.h>
|
||||
|
||||
#include <AreaEffectSimulation/aes_ftc.h>
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <AreaEffectSimulation/logger.h>
|
||||
|
||||
|
||||
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_ftc.h>
|
||||
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace AreaEffectSimulation; // JUST FOR LOGGER_T
|
||||
|
||||
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser(ProvideCommandLineParameterOptions(DomainId | ExerciseId | NoVersion))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ModuleTestAesOthers : public QObject
|
||||
, protected ParticipantManagement::Interface::Ftc::SetSimulatedPositionReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::BoobyTrapModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::BoobyTrapRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::OffRouteMineModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::OffRouteMineRemoveReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModuleTestAesOthers(int domainId, int exerciseId);
|
||||
|
||||
protected:
|
||||
void onSetSimulatedPositionReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
void onBoobyTrapModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onBoobyTrapRemoveReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
void onOffRouteMineModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onOffRouteMineRemoveReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
void boobyTrapChanged(const AreaEffectSimulation::BoobyTrap &data, DataModification modType);
|
||||
void offRouteMineChanged(const AreaEffectSimulation::OffRouteMine &data, DataModification modType);
|
||||
void onAesItemViewChanged(const AreaEffectSimulation::AesItemView &aesItemView, DataModification modType);
|
||||
|
||||
|
||||
// pre-condition
|
||||
void setupParticipants();
|
||||
bool checkParticipant_18();
|
||||
bool tryRemoveOldBoobyTraps();
|
||||
|
||||
|
||||
// helper
|
||||
bool waitForData(const std::function<bool()> &func, int retryCount = 10);
|
||||
void waitForEffectStatesBT(int lineNumber, int durPrep = 5, int durAct = 60, int durExp = 30);
|
||||
void waitForEffectStatesORM(int lineNumber, int durPrep = 5, int durAct = 60, int durExp = 30);
|
||||
|
||||
int doMoveParticipant(int participantId, const QString &newPositionMGRS);
|
||||
|
||||
int doBoobyTrapModifyRequest(const BoobyTrap &btData);
|
||||
int doOffRouteMineModifyRequest(const OffRouteMine &offRouteMine);
|
||||
|
||||
void test_boobyTrap_02_IMPL(const QString &name,
|
||||
const LtsCoordTrans::LtsCoordinate &impactCoord,
|
||||
double rotationAngle,
|
||||
const LtsCoordTrans::LtsCoordinate &particpantCoord);
|
||||
|
||||
|
||||
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
//
|
||||
// TestCases
|
||||
//
|
||||
|
||||
// void initTestCase_data(); // will be called to create a global test data table.
|
||||
void initTestCase(); // will be called before the first test function is executed.
|
||||
|
||||
void init(); // will be called before each test function is executed.
|
||||
// void cleanup(); // will be called after each test function is executed.
|
||||
|
||||
void dumpCnt();
|
||||
|
||||
void test_justSetupParticipants();
|
||||
|
||||
|
||||
// !!! assume ONE elevationMap: Altmark_dt1.tif !!!
|
||||
// !!! assume ONE elevationMap: Altmark_dt1.tif !!!
|
||||
// !!! assume ONE elevationMap: Altmark_dt1.tif !!!
|
||||
|
||||
// boobyTrap: VLad1, VLad2
|
||||
void test_boobyTrap_01();
|
||||
|
||||
void test_boobyTrap_02_Q1();
|
||||
void test_boobyTrap_02_Q2();
|
||||
void test_boobyTrap_02_Q3();
|
||||
void test_boobyTrap_02_Q4();
|
||||
|
||||
// offRoute: SchAbwMi, SchAbwRiMi
|
||||
// // void test_offRouteMine_01(); // not implemeneted yet
|
||||
void test_offRouteMine_02();
|
||||
|
||||
|
||||
// will be called after the last test function was executed:
|
||||
void cleanupTestCase(); // will be called after the last test function was executed.
|
||||
|
||||
public:
|
||||
static bool m_enable_create_bulk;
|
||||
|
||||
private:
|
||||
int m_domainId{-1};
|
||||
int m_exerciseId{-1};
|
||||
int m_traingAreaId{-1};
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Ftc> m_aesFtc;
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
|
||||
|
||||
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
|
||||
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
|
||||
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
|
||||
|
||||
BoobyTrap m_dataBoobyTrap;
|
||||
OffRouteMine m_dataOffRouteMine;
|
||||
|
||||
bool m_replyError{false};
|
||||
|
||||
struct counterDds
|
||||
{
|
||||
// AesItem
|
||||
int cntBoobyTrap{0};
|
||||
int cntOffRouteMine{0};
|
||||
|
||||
// AesItemView
|
||||
int cntItemView{0};
|
||||
|
||||
void reset()
|
||||
{
|
||||
cntBoobyTrap = 0;
|
||||
cntOffRouteMine = 0;
|
||||
cntItemView = 0;
|
||||
}
|
||||
}
|
||||
m_counterDds;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_convert_mine_area.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QLineF>
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
|
||||
#include <ngldb/dbtransaction.h>
|
||||
#include <ngldb/nsqlquery.h>
|
||||
#include <ngldb/dbconnection.h>
|
||||
#include <ngldb/sql_query_janitor.h>
|
||||
#include <QtSql/QSqlError>
|
||||
#include <QVariant>
|
||||
|
||||
|
||||
#include <AreaEffectSimulation/aes_db_structs.h>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <nglsettings/nglsettings_connections.h>
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <ngltools/ngltools_filesystem.h>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
ConvertMineArea::ConvertMineArea(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_query(nullptr)
|
||||
, m_exerciseId(-1)
|
||||
, m_bEmitMessageOnError(false)
|
||||
, m_bCanHandleSchemas(true)
|
||||
, m_ownDatabaseConnection(true)
|
||||
, m_logger(getLogger(QStringLiteral("ConvertMineArea")))
|
||||
{}
|
||||
|
||||
bool ConvertMineArea::init(int exerciseId)
|
||||
{
|
||||
m_exerciseId = exerciseId;
|
||||
|
||||
NGL::Settings *s = new NGL::Settings(NGL::findProjectConfigFile());
|
||||
const QString dbUser(QStringLiteral("ets_exm"));
|
||||
const QString dbPasswd(QStringLiteral("ets11de"));
|
||||
const QString hostname(s->databaseHostname());
|
||||
const QString driver(s->databaseDriver());
|
||||
const QString dbname(s->databaseName());
|
||||
|
||||
bool ok = initDB(dbUser, dbPasswd, driver, hostname, dbname);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error opening db, exiting..";
|
||||
return false;
|
||||
}
|
||||
|
||||
ERROR_LOG(m_logger) << "Database open";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertMineArea::initDB(const QString &dbUser,
|
||||
const QString &dbPasswd,
|
||||
const QString &dbDriver,
|
||||
const QString &dbHost,
|
||||
const QString &dbName)
|
||||
{
|
||||
m_ownDatabaseConnection = true;
|
||||
|
||||
m_dbConnection = DBConnection::open(m_logger, dbUser, dbPasswd, dbDriver, dbHost, dbName, schemaName());
|
||||
|
||||
return initDBInternal();
|
||||
}
|
||||
|
||||
bool ConvertMineArea::initDBInternal()
|
||||
{
|
||||
QSqlDriver *driver = m_dbConnection.driver();
|
||||
if (!driver)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "No SQL driver loaded - no database available!";
|
||||
return false;
|
||||
}
|
||||
const QString driverName = m_dbConnection.driverName();
|
||||
DEBUG_LOG(m_logger) << "Connected to database " << m_dbConnection.databaseName() << "@" << m_dbConnection.hostName()
|
||||
<< ", schema: " << schemaName() << ", used driver: " << driverName;
|
||||
if (!m_dbConnection.isOpen())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Database connection is no open - can not initialize database interface";
|
||||
return false;
|
||||
}
|
||||
if (driverName == QLatin1String("QSQLITE"))
|
||||
m_bCanHandleSchemas = false;
|
||||
|
||||
m_query = new NSqlQuery(m_dbConnection, m_logger);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString ConvertMineArea::schemaName() const
|
||||
{
|
||||
if (!m_bCanHandleSchemas)
|
||||
return QString();
|
||||
if (m_exerciseId <= 0)
|
||||
return QStringLiteral("aes");
|
||||
return DBCommon::getExerciseSchemaName(m_exerciseId);
|
||||
}
|
||||
|
||||
QString ConvertMineArea::dbUser() const
|
||||
{
|
||||
if (m_exerciseId > 0)
|
||||
return QStringLiteral("ets_ex_00");
|
||||
else
|
||||
return QStringLiteral("ets_") + schemaName();
|
||||
}
|
||||
|
||||
//
|
||||
// MineArea
|
||||
//
|
||||
QString ConvertMineArea::getTableName(const QString &tableName) const
|
||||
{
|
||||
if (!m_bCanHandleSchemas)
|
||||
return tableName;
|
||||
if (m_exerciseId > 0)
|
||||
return DBCommon::getExerciseTableName(tableName, m_exerciseId);
|
||||
return QStringLiteral("aes.") + tableName;
|
||||
}
|
||||
|
||||
bool ConvertMineArea::tryConvertMineArea()
|
||||
{
|
||||
const QString tableName1(getTableName(QStringLiteral("aes_mine_area")));
|
||||
const QString stmt1(QStringLiteral("SELECT id, density FROM ") + tableName1);
|
||||
m_query->prepare(stmt1);
|
||||
|
||||
if (!m_query->exec(m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
QMap<int,double> densityMap;
|
||||
while (m_query->next())
|
||||
{
|
||||
int i = 0;
|
||||
int aesId = m_query->value(i++).toInt();
|
||||
double density = m_query->value(i++).toInt();
|
||||
densityMap.insert(aesId, density);
|
||||
}
|
||||
|
||||
const QString tableName(getTableName(QStringLiteral("aes_mine_area_segment")));
|
||||
const QString stmt(QStringLiteral("SELECT id, mine_area_id, element_number, start_position_x, start_position_y, rotation_angle, mine_count"
|
||||
" FROM ") + tableName);
|
||||
m_query->prepare(stmt);
|
||||
|
||||
if (!m_query->exec(m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
Database::AesMineAreaSegment data;
|
||||
QVector<Database::AesMineAreaSegment> vecMineArea;
|
||||
while (m_query->next())
|
||||
{
|
||||
int i = 0;
|
||||
data.id = m_query->value(i++).toInt();
|
||||
data.mineAreaId = m_query->value(i++).toInt();
|
||||
data.elementNumber = m_query->value(i++).toInt();
|
||||
data.startPosition.rx() = m_query->value(i++).toDouble();
|
||||
data.startPosition.ry() = m_query->value(i++).toDouble();
|
||||
|
||||
double rotationAngle = m_query->value(i++).toDouble();
|
||||
int mineCount = m_query->value(i++).toInt();
|
||||
|
||||
LtsCoordTrans::UtmCoordinate startPositionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(data.startPosition);
|
||||
|
||||
QLineF line;
|
||||
line.setP1({startPositionUtm.x, startPositionUtm.y});
|
||||
line.setLength(mineCount / densityMap.value(data.mineAreaId));
|
||||
line.setAngle(rotationAngle);
|
||||
QPointF p2 = line.p2();
|
||||
|
||||
LtsCoordTrans::UtmCoordinate endPositionUtm = startPositionUtm;
|
||||
endPositionUtm.x = p2.x();
|
||||
endPositionUtm.y = p2.y();
|
||||
|
||||
data.endPosition = endPositionUtm.geographic();
|
||||
|
||||
DEBUG_LOG(m_logger) << "aesId: " << data.mineAreaId << ", id: " << data.id;
|
||||
DEBUG_LOG(m_logger) << "EndpositionUtm: x: " << endPositionUtm.x << ", y: " << endPositionUtm.y;
|
||||
DEBUG_LOG(m_logger) << "Geographic: x: " << data.endPosition.x() << " y: " << data.endPosition.y();
|
||||
|
||||
vecMineArea.append(data);
|
||||
}
|
||||
|
||||
const QString stmt3(QStringLiteral("UPDATE ") + tableName +
|
||||
QStringLiteral(" SET"
|
||||
" end_position_x = :end_position_x, end_position_y = :end_position_y"
|
||||
" WHERE id = :id"));
|
||||
|
||||
if (!m_query->prepare(stmt3))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
ERROR_LOG(m_logger) << "lastError: " << m_lastError.text();
|
||||
return false;
|
||||
}
|
||||
for ( const Database::AesMineAreaSegment &mineAreaSegment : vecMineArea)
|
||||
{
|
||||
m_query->bindValue(QStringLiteral(":end_position_x"), mineAreaSegment.endPosition.x());
|
||||
m_query->bindValue(QStringLiteral(":end_position_y"), mineAreaSegment.endPosition.y());
|
||||
m_query->bindValue(QStringLiteral(":id"), mineAreaSegment.id);
|
||||
|
||||
if (!m_query->exec(m_bEmitMessageOnError))
|
||||
{
|
||||
m_lastError = m_query->lastError();
|
||||
ERROR_LOG(m_logger) << "lastError: " << m_lastError.text();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser()
|
||||
{
|
||||
}
|
||||
|
||||
int exerciseId() const { return isSet(QLatin1String("e")) ? value(QLatin1String("e")).toInt() : -1; }
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
NGLCoreApplication app(argc, argv);
|
||||
|
||||
app.createLogger("ConvertMineArea", 0 );
|
||||
|
||||
CmdLineParser options;
|
||||
if (!options.init())
|
||||
return -1;
|
||||
|
||||
AreaEffectSimulation::ConvertMineArea convMa(nullptr);
|
||||
|
||||
if (!convMa.init(options.exerciseId()))
|
||||
{
|
||||
ERROR_LOG(app.baseLogger()) << "Initialisation failed.";
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (convMa.tryConvertMineArea())
|
||||
ERROR_LOG(app.baseLogger()) << "Conversion for Exercise " << options.exerciseId() << " successful!";
|
||||
else
|
||||
ERROR_LOG(app.baseLogger()) << "Conversion failed.";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
#include <QSqlDriver>
|
||||
#include <QSqlDatabase>
|
||||
#include <QtSql/QSqlError>
|
||||
|
||||
#include <AreaEffectSimulation/aes_enums.hpp>
|
||||
#include <AreaEffectSimulation/aes_db.h>
|
||||
#include <AreaEffectSimulation/logger.h>
|
||||
|
||||
#include <ngldb/nsqlquery.h>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
class ConvertMineArea : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ConvertMineArea(QObject *parent);
|
||||
|
||||
bool init(int exerciseId);
|
||||
bool tryConvertMineArea();
|
||||
QString getTableName(const QString &tableName) const;
|
||||
|
||||
|
||||
bool initDB(const QString &dbUser,
|
||||
const QString &dbPasswd,
|
||||
const QString &dbDriver,
|
||||
const QString &dbHost,
|
||||
const QString &dbName);
|
||||
bool initDBInternal();
|
||||
|
||||
QString schemaName() const;
|
||||
QString dbUser() const;
|
||||
const QSqlDatabase &database() const { return m_dbConnection; }
|
||||
void setEmitMessageOnError(bool bEmit) ;
|
||||
QSqlError getLastError() const;
|
||||
|
||||
private:
|
||||
QSqlDatabase m_dbConnection;
|
||||
NSqlQuery *m_query;
|
||||
QSqlError m_lastError;
|
||||
int m_exerciseId;
|
||||
bool m_bEmitMessageOnError;
|
||||
bool m_bCanHandleSchemas;
|
||||
bool m_ownDatabaseConnection;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_air_support_impact.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// must be in pdm.pdm_charge_type
|
||||
// single fire charge types = area fire
|
||||
static const int s_ChargeTypeId1 = 471;
|
||||
static const int s_ChargeTypeId2 = 472;
|
||||
|
||||
TestAirSupportImpact::TestAirSupportImpact(QObject *parent)
|
||||
: TestBase("Test.ExplosionSingle", parent)
|
||||
{}
|
||||
|
||||
bool TestAirSupportImpact::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_dtc->waitForHistoricalDataExplosionSingle();
|
||||
m_asData.id(-1);
|
||||
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::airSupportImpactChanged,
|
||||
this, &TestAirSupportImpact::airSupportImpactChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestAirSupportImpact::checkBaseData(const AreaEffectSimulation::AirSupportImpact &a,
|
||||
const AreaEffectSimulation::AirSupportImpact &b) const
|
||||
{
|
||||
if (!checkAesItem(a, b))
|
||||
return false;
|
||||
|
||||
if (a.impactPosition() != b.impactPosition())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "impactPosition does not match: " << a.impactPosition() << " - " << b.impactPosition();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// ExplosionSingle
|
||||
//
|
||||
void TestAirSupportImpact::tryCreate()
|
||||
{
|
||||
m_asData = AreaEffectSimulation::AirSupportImpact();
|
||||
AreaEffectSimulation::AirSupportImpact asData;
|
||||
asData.id(0);
|
||||
asData.name("chris");
|
||||
asData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
asData.chargeStruct().chargeTypeId(345863487);
|
||||
asData.impactPosition(Core::GeoPosition2D(0.15525, 0.926080));
|
||||
asData.partyId(7);
|
||||
asData.participantId(1234);
|
||||
asData.externalId(1);
|
||||
asData.flightTime(123);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send explosionSingleCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->airSupportImpactModifyRequest(
|
||||
AirSupportImpactModifyRequest(
|
||||
0,
|
||||
asData.name(),
|
||||
asData.effectStart(),
|
||||
asData.chargeStruct().chargeTypeId(),
|
||||
asData.impactPosition(),
|
||||
asData.partyId(),
|
||||
asData.participantId(),
|
||||
asData.flightTime(),
|
||||
asData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during explosionSingleCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// since the chargeTypeId is not valid, we should get an error
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating single explosion object (try with error)";
|
||||
}
|
||||
|
||||
// now with correct charge type
|
||||
m_bExpectedFailure = false;
|
||||
m_expectedAesId = -1;
|
||||
|
||||
asData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->airSupportImpactModifyRequest(
|
||||
AirSupportImpactModifyRequest(
|
||||
0,
|
||||
asData.name(),
|
||||
asData.effectStart(),
|
||||
asData.chargeStruct().chargeTypeId(),
|
||||
asData.impactPosition(),
|
||||
asData.partyId(),
|
||||
asData.participantId(),
|
||||
asData.flightTime(),
|
||||
asData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during explosionSingleCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_asData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating single explosion object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_asData, asData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestAirSupportImpact::tryModify);
|
||||
INFO_LOG(m_logger) << "tryCreateExplosionSingle successful";
|
||||
}
|
||||
|
||||
void TestAirSupportImpact::tryModify()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send modify request";
|
||||
m_asData.name("chris2");
|
||||
m_asData.effectStart(m_asData.effectStart().get() + 2000);
|
||||
m_asData.chargeStruct().chargeTypeId(s_ChargeTypeId2);
|
||||
m_asData.impactPosition(Core::GeoPosition2D(0.15525, 0.92607));
|
||||
m_asData.partyId(8);
|
||||
m_asData.participantId(1235);
|
||||
m_asData.flightTime(321);
|
||||
const AreaEffectSimulation::AirSupportImpact asData(m_asData);
|
||||
m_asData = AreaEffectSimulation::AirSupportImpact();
|
||||
m_asData.id(asData.id());
|
||||
|
||||
m_bIsCreatedRequest = false;
|
||||
if (!m_ftc->airSupportImpactModifyRequest(
|
||||
AirSupportImpactModifyRequest(
|
||||
asData.id(),
|
||||
asData.name(),
|
||||
asData.effectStart(),
|
||||
asData.chargeStruct().chargeTypeId(),
|
||||
asData.impactPosition(),
|
||||
asData.partyId(),
|
||||
asData.participantId(),
|
||||
asData.flightTime(),
|
||||
asData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_asData.chargeStruct().chargeTypeId() == s_ChargeTypeId2;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating single explosion object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_asData, asData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Modify data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestAirSupportImpact::waitExpire);
|
||||
INFO_LOG(m_logger) << "tryModifyExplosionSingle successful";
|
||||
}
|
||||
|
||||
void TestAirSupportImpact::waitExpire()
|
||||
{
|
||||
INFO_LOG(m_logger) << "waiting until explosion single expires";
|
||||
|
||||
if (!waitForData([this]() { return m_asData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for expiry of explosion single with id " << m_asData.id();
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "waitExpireExplosionSingle successful";
|
||||
}
|
||||
|
||||
void TestAirSupportImpact::airSupportImpactChanged(const AreaEffectSimulation::AirSupportImpact &data, DataModification modType)
|
||||
{
|
||||
if (m_asData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_asData);
|
||||
}
|
||||
|
||||
void TestAirSupportImpact::onAirSupportImpactModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestAirSupportImpact::onAirSupportImpactRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
onAesRemoveReply(replyObject);
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestAirSupportImpact; });
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestAirSupportImpact final : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::AirSupportImpactModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::AirSupportImpactRemoveReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestAirSupportImpact(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { tryCreate(); }
|
||||
private Q_SLOTS:
|
||||
void tryCreate();
|
||||
void tryModify();
|
||||
void waitExpire();
|
||||
protected Q_SLOTS:
|
||||
void airSupportImpactChanged(const AreaEffectSimulation::AirSupportImpact &data, DataModification modType);
|
||||
protected:
|
||||
void onAirSupportImpactModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onAirSupportImpactRemoveReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
bool checkBaseData(const AreaEffectSimulation::AirSupportImpact &a,
|
||||
const AreaEffectSimulation::AirSupportImpact &b) const;
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::AirSupportImpact m_asData;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_base.h"
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <LtsCommandLineParser/LtsCommandLineParser.h>
|
||||
#include <QTimer>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
TestBase::TestBase(const char *loggerName, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_expectedAesId(-1)
|
||||
, m_bIsCreatedRequest(false)
|
||||
, m_bExpectedFailure(false)
|
||||
, m_replyError(false)
|
||||
, m_bTestsSuccessful(true)
|
||||
, m_testId(0)
|
||||
, m_aesTypeName(QString::fromLatin1(loggerName).splitRef(QLatin1Char('.')).last().toString())
|
||||
, m_logger(getLogger(loggerName))
|
||||
{}
|
||||
|
||||
|
||||
bool TestBase::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
INFO_LOG(m_logger) << "init begin";
|
||||
m_testId = testId;
|
||||
|
||||
// initialize DDS
|
||||
m_ddsConnector.reset(new DDSConnector::DdsConnector(domainId, IDL::PartitionType::Exercise, exerciseId));
|
||||
if (!m_ddsConnector->init())
|
||||
return false;
|
||||
m_ddsConnector->initPublisherSubscriber();
|
||||
|
||||
INFO_LOG(m_logger) << "init create ftc";
|
||||
m_ftc = AreaEffectSimulation::Interface::Ftc::create(m_ddsConnector);
|
||||
INFO_LOG(m_logger) << "init init ftc";
|
||||
bool bRet = m_ftc->enableAll();
|
||||
|
||||
m_dtc = AreaEffectSimulation::Interface::Dtc::create(m_ddsConnector);
|
||||
bRet = bRet && m_dtc->enableAll();
|
||||
|
||||
INFO_LOG(m_logger) << "init end - bRet = " << bRet;
|
||||
return bRet;
|
||||
}
|
||||
|
||||
bool TestBase::waitForData(const std::function<bool()> &func)
|
||||
{
|
||||
// wait for data
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
if (func())
|
||||
return true;
|
||||
QTest::qWait(100);
|
||||
}
|
||||
return func();
|
||||
}
|
||||
|
||||
bool TestBase::checkAesItem(const AreaEffectSimulation::AesItem &a,
|
||||
const AreaEffectSimulation::AesItem &b) const
|
||||
{
|
||||
if (a.name() != b.name())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "name does not match: " << a.name() << " - " << b.name();
|
||||
return false;
|
||||
}
|
||||
if (a.effectStart() != b.effectStart())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "effectStart does not match: " << a.effectStart() << " - " << b.effectStart();
|
||||
return false;
|
||||
}
|
||||
if (a.chargeStruct().chargeTypeId() != b.chargeStruct().chargeTypeId())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "chargeTypeId does not match: " << a.chargeStruct().chargeTypeId() << " - " << b.chargeStruct().chargeTypeId();
|
||||
return false;
|
||||
}
|
||||
if (a.partyId() != b.partyId())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "partyId does not match: " << a.partyId() << " - " << b.partyId();
|
||||
return false;
|
||||
}
|
||||
if (a.participantId() != b.participantId())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "participantId does not match: " << a.participantId() << " - " << b.participantId();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestBase::failExit()
|
||||
{
|
||||
ERROR_LOG(m_logger) << "fail exit!";
|
||||
m_bTestsSuccessful = false;
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
void TestBase::onAesCreateReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Got create " << m_aesTypeName << " reply with id " << replyObject.id()
|
||||
<< ", error = " << replyObject.error()
|
||||
<< " and errorString = '" << replyObject.translated() << "'";
|
||||
m_replyError = replyObject.error();
|
||||
if (m_replyError && !m_bExpectedFailure)
|
||||
ERROR_LOG(m_logger) << "Got create " << m_aesTypeName << " reply error: " << replyObject();
|
||||
else
|
||||
m_expectedAesId = replyObject.id(); // only works as expected because reply is sent before publishing data occours
|
||||
}
|
||||
|
||||
void TestBase::onAesModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_expectedAesId != replyObject.id())
|
||||
return;
|
||||
INFO_LOG(m_logger) << "Got modify " << m_aesTypeName << " reply with id " << replyObject.id()
|
||||
<< ", error = " << replyObject.error()
|
||||
<< " and errorString = '" << replyObject.translated() << "'";
|
||||
m_replyError = replyObject.error();
|
||||
if (m_replyError && !m_bExpectedFailure)
|
||||
ERROR_LOG(m_logger) << "Got modify " << m_aesTypeName << " reply error: " << replyObject();
|
||||
else
|
||||
m_expectedAesId = replyObject.id();
|
||||
}
|
||||
|
||||
void TestBase::onAesRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Got remove " << m_aesTypeName << " reply with id " << replyObject.id()
|
||||
<< " and errorString " << replyObject.translated();
|
||||
m_replyError = replyObject.error();
|
||||
if (m_replyError && !m_bExpectedFailure)
|
||||
ERROR_LOG(m_logger) << "Got remove " << m_aesTypeName << " reply error: " << replyObject();
|
||||
else
|
||||
m_expectedAesId = replyObject.id();
|
||||
}
|
||||
|
||||
void TestBase::onAesTriggerReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Got trigger " << m_aesTypeName << " reply with id " << replyObject.id()
|
||||
<< " and errorString " << replyObject.translated();
|
||||
m_replyError = replyObject.error();
|
||||
if (m_replyError && !m_bExpectedFailure)
|
||||
ERROR_LOG(m_logger) << "Got remove " << m_aesTypeName << " reply error: " << replyObject();
|
||||
else
|
||||
m_expectedAesId = replyObject.id();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser
|
||||
{
|
||||
public:
|
||||
CmdLineParser()
|
||||
: LtsCommandLineParser()
|
||||
{
|
||||
addOption( { QStringList() << QLatin1String("t") << QLatin1String("testId")
|
||||
, QLatin1String("TestId.")
|
||||
, QLatin1String("Default: 0")
|
||||
, QLatin1String("0")
|
||||
} );
|
||||
}
|
||||
|
||||
int testId() const { return isSet(QLatin1String("t")) ? value(QLatin1String("t")).toInt() : 0; }
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int mainBase(int argc, char **argv,
|
||||
const std::function<TestBase*()> &createFunc)
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("AES", "log4cxx_aes.props");
|
||||
|
||||
CmdLineParser options;
|
||||
if (!options.init())
|
||||
return -1;
|
||||
|
||||
if (options.exerciseId() <= 0)
|
||||
{
|
||||
fprintf(stderr, "ExerciseId not set!\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
int iRet = -1;
|
||||
{
|
||||
std::unique_ptr <TestBase> test(createFunc());
|
||||
if (!test->init(options.domainId(), options.exerciseId(), options.testId()))
|
||||
return iRet;
|
||||
|
||||
QTimer::singleShot(0, test.get(), &TestBase::startTest);
|
||||
|
||||
STARTUP_LOG(app.baseLogger());
|
||||
|
||||
app.exec();
|
||||
|
||||
iRet = test->testsSuccessful() ? 0 : 1;
|
||||
fprintf(stderr, "%d\n", iRet);
|
||||
|
||||
SHUTDOWN_LOG(app.baseLogger());
|
||||
}
|
||||
|
||||
return iRet;
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AreaEffectSimulation/aes_ftc.h>
|
||||
#include <AreaEffectSimulation/aes_dtc.h>
|
||||
#include <AreaEffectSimulation/logger.h>
|
||||
#include <QObject>
|
||||
#include <DDS/DDSConnector/dds_connector.h>
|
||||
#include <memory>
|
||||
|
||||
#include <AreaEffectSimulation/aes_test_base_export.h>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class AES_TEST_BASE_EXPORT TestBase : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
explicit TestBase(const char *loggerName, QObject *parent);
|
||||
public:
|
||||
|
||||
bool testsSuccessful() const { return m_bTestsSuccessful; }
|
||||
|
||||
virtual bool init(int domainId, int exerciseId, int testId);
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void startTest() = 0;
|
||||
protected:
|
||||
static bool waitForData(const std::function<bool()> &func);
|
||||
bool checkAesItem(const AreaEffectSimulation::AesItem &a,
|
||||
const AreaEffectSimulation::AesItem &b) const;
|
||||
|
||||
void failExit();
|
||||
|
||||
void onAesCreateReply(const Core::FunctionReplyObject &replyObject);
|
||||
void onAesModifyReply(const Core::FunctionReplyObject &replyObject);
|
||||
void onAesRemoveReply(const Core::FunctionReplyObject &replyObject);
|
||||
void onAesTriggerReply(const Core::FunctionReplyObject &replyObject);
|
||||
|
||||
template <typename T>
|
||||
void onAesChanged(const T &dataIn, DataModification modType, T &dataOut)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Got " << m_aesTypeName << " with mod type " << (int)modType
|
||||
<< ", id: " << dataIn.id() << ", chargeType: " << dataIn.chargeStruct().chargeTypeId()
|
||||
<< ", effectState: " << dataIn.effectStateId();
|
||||
if (m_expectedAesId == dataIn.id())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Expected aes id - updating data for " << m_aesTypeName;
|
||||
dataOut = dataIn;
|
||||
}
|
||||
if (modType == DataModification::eRemoved && dataOut.id() == dataIn.id())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Removed " << m_aesTypeName << " with id " << dataIn.id();
|
||||
m_expectedAesId = dataIn.id();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<DDSConnector::DdsConnector> m_ddsConnector;
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Ftc> m_ftc;
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_dtc;
|
||||
|
||||
int m_expectedAesId; //!< contains the id of the created aes
|
||||
bool m_bIsCreatedRequest;
|
||||
bool m_bExpectedFailure;
|
||||
bool m_replyError;
|
||||
bool m_bTestsSuccessful;
|
||||
int m_testId;
|
||||
QString m_aesTypeName;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
int AES_TEST_BASE_EXPORT mainBase(int argc, char **argv,
|
||||
const std::function<TestBase*()> &createFunc);
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
+331
@@ -0,0 +1,331 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_bccontamination.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// must be in pdm.pdm_charge_type
|
||||
static const int s_ChargeTypeId1 = 341;
|
||||
static const int s_ChargeTypeId2 = 342;
|
||||
|
||||
TestBCContamination::TestBCContamination(QObject *parent)
|
||||
: TestBase("Test.BCContamination", parent)
|
||||
{}
|
||||
|
||||
bool TestBCContamination::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_dtc->waitForHistoricalDataBCContamination();
|
||||
m_bcData.id(-1);
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::bCContaminationChanged,
|
||||
this, &TestBCContamination::bCContaminationChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestBCContamination::checkBaseData(const AreaEffectSimulation::BCContamination &a,
|
||||
const AreaEffectSimulation::BCContamination &b) const
|
||||
{
|
||||
if (!checkAesItem(a, b))
|
||||
return false;
|
||||
|
||||
if (a.impactPosition() != b.impactPosition())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "impactPosition does not match: " << a.impactPosition() << " - " << b.impactPosition();
|
||||
return false;
|
||||
}
|
||||
if (a.impactRadius() != b.impactRadius())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "impactRadius does not match: " << a.impactRadius() << " - " << b.impactRadius();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// BCContamination
|
||||
//
|
||||
void TestBCContamination::tryCreateBCContamination()
|
||||
{
|
||||
m_bcData = AreaEffectSimulation::BCContamination();
|
||||
AreaEffectSimulation::BCContamination bcData;
|
||||
|
||||
bcData.id(0);
|
||||
bcData.name("chris");
|
||||
bcData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
bcData.effectDuration(10234); // msec
|
||||
bcData.chargeStruct().chargeTypeId(345863487);
|
||||
bcData.impactPosition(Core::GeoPosition2D(0.16, 0.92));
|
||||
bcData.impactRadius(100); // 100m
|
||||
bcData.partyId(2);
|
||||
bcData.participantId(1234);
|
||||
bcData.upperOffset(6.0);
|
||||
bcData.lowerOffset(-1000.0);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send BCContaminationCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
m_bIsCreatedRequest = true;
|
||||
m_expectedAesId = -1;
|
||||
|
||||
if(!m_ftc->bCContaminationModifyRequest(
|
||||
BCContaminationModifyRequest(
|
||||
0,
|
||||
bcData.name(),
|
||||
bcData.effectStart(),
|
||||
bcData.effectDuration(),
|
||||
bcData.chargeStruct().chargeTypeId(),
|
||||
bcData.impactPosition(),
|
||||
bcData.impactRadius(),
|
||||
AesWeatherSource::AwsStatic,
|
||||
bcData.partyId(),
|
||||
bcData.participantId(),
|
||||
dds::core::optional<double>(), // propagationDirection
|
||||
dds::core::optional<double>(), // windSpeed
|
||||
dds::core::optional<Core::GeoPosition2D>(), // weatherPosition
|
||||
dds::core::optional<rti::core::int64>(), // weatherTimestamp
|
||||
dds::core::optional<long long>(), // externalId
|
||||
bcData.upperOffset(),
|
||||
bcData.lowerOffset(),
|
||||
dds::core::optional<bool>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during BCContaminationCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// since the chargeTypeId is not valid, we should get an error
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating bc contamination object (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// now with correct charge type
|
||||
m_bExpectedFailure = false;
|
||||
m_bIsCreatedRequest = true;
|
||||
m_expectedAesId = -1;
|
||||
|
||||
bcData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
if (!m_ftc->bCContaminationModifyRequest(
|
||||
BCContaminationModifyRequest(
|
||||
0,
|
||||
bcData.name(),
|
||||
bcData.effectStart(),
|
||||
bcData.effectDuration(),
|
||||
bcData.chargeStruct().chargeTypeId(),
|
||||
bcData.impactPosition(),
|
||||
bcData.impactRadius(),
|
||||
AesWeatherSource::AwsStatic,
|
||||
bcData.partyId(),
|
||||
bcData.participantId(),
|
||||
dds::core::optional<double>(),
|
||||
dds::core::optional<double>(),
|
||||
dds::core::optional<Core::GeoPosition2D>(),
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<long long>(),
|
||||
bcData.upperOffset(),
|
||||
bcData.lowerOffset(),
|
||||
dds::core::optional<bool>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during BCContaminationCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_bcData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating bc contamination object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_bcData, bcData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestBCContamination::tryModifyBCContamination);
|
||||
INFO_LOG(m_logger) << "tryCreateBCContamination successful";
|
||||
}
|
||||
|
||||
void TestBCContamination::tryModifyBCContamination()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send modify request";
|
||||
m_bcData.name("chris2");
|
||||
m_bcData.effectStart(m_bcData.effectStart().get() + 2000);
|
||||
m_bcData.effectDuration(3200); // msec
|
||||
m_bcData.chargeStruct().chargeTypeId(s_ChargeTypeId2);
|
||||
m_bcData.impactPosition(Core::GeoPosition2D(0.17, 0.93));
|
||||
m_bcData.partyId(3);
|
||||
m_bcData.participantId(1235);
|
||||
m_bcData.upperOffset(6.0);
|
||||
m_bcData.lowerOffset(false);
|
||||
const AreaEffectSimulation::BCContamination bcData(m_bcData);
|
||||
m_bcData = AreaEffectSimulation::BCContamination();
|
||||
m_bcData.id(bcData.id());
|
||||
|
||||
m_bIsCreatedRequest = false;
|
||||
if (!m_ftc->bCContaminationModifyRequest(
|
||||
BCContaminationModifyRequest(
|
||||
bcData.id(),
|
||||
bcData.name(),
|
||||
bcData.effectStart(),
|
||||
bcData.effectDuration(),
|
||||
bcData.chargeStruct().chargeTypeId(),
|
||||
bcData.impactPosition(),
|
||||
bcData.impactRadius(),
|
||||
AesWeatherSource::AwsStatic,
|
||||
bcData.partyId(),
|
||||
bcData.participantId(),
|
||||
dds::core::optional<double>(),
|
||||
dds::core::optional<double>(),
|
||||
dds::core::optional<Core::GeoPosition2D>(),
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
bcData.upperOffset(),
|
||||
bcData.lowerOffset(),
|
||||
dds::core::optional<bool>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_bcData.chargeStruct().chargeTypeId() == s_ChargeTypeId2;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating bc contamination object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_bcData, bcData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Modify data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestBCContamination::waitExpireBCContamination);
|
||||
INFO_LOG(m_logger) << "tryModifyBCContamination successful";
|
||||
}
|
||||
|
||||
void TestBCContamination::waitExpireBCContamination()
|
||||
{
|
||||
INFO_LOG(m_logger) << "waiting until bc contamination expires";
|
||||
|
||||
if (!waitForData([this]() { return m_bcData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for expiry of bc contamination with id " << m_bcData.id();
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, this, &TestBCContamination::tryRemoveBCContamination);
|
||||
INFO_LOG(m_logger) << "waitExpireBCContamination successful";
|
||||
}
|
||||
|
||||
void TestBCContamination::tryRemoveBCContamination()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryRemoveBCContamination start";
|
||||
|
||||
AreaEffectSimulation::BCContamination bcData(m_bcData);
|
||||
bcData.name("RemoveTest");
|
||||
bcData.effectStart(0); // not set
|
||||
m_bcData = AreaEffectSimulation::BCContamination();
|
||||
m_expectedAesId = -1;
|
||||
m_bIsCreatedRequest = true;
|
||||
bcData.upperOffset(6.0);
|
||||
bcData.lowerOffset(false);
|
||||
|
||||
if (!m_ftc->bCContaminationModifyRequest(
|
||||
BCContaminationModifyRequest(
|
||||
0,
|
||||
bcData.name(),
|
||||
bcData.effectStart(),
|
||||
bcData.effectDuration(),
|
||||
bcData.chargeStruct().chargeTypeId(),
|
||||
bcData.impactPosition(),
|
||||
bcData.impactRadius(),
|
||||
AesWeatherSource::AwsStatic,
|
||||
bcData.partyId(),
|
||||
bcData.participantId(),
|
||||
dds::core::optional<double>(),
|
||||
dds::core::optional<double>(),
|
||||
dds::core::optional<Core::GeoPosition2D>(),
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
bcData.upperOffset(),
|
||||
bcData.lowerOffset(),
|
||||
dds::core::optional<bool>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during bCContaminationModifyRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_bcData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating bc contamination object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
m_expectedAesId = -1;
|
||||
if (!m_ftc->bCContaminationRemoveRequest(Core::RemoveElementRequest(m_bcData.id()), this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during BCContaminationRemoveRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_bcData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error removing bc contamination object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "tryRemoveBCContamination successful";
|
||||
}
|
||||
|
||||
void TestBCContamination::bCContaminationChanged(const AreaEffectSimulation::BCContamination &data, DataModification modType)
|
||||
{
|
||||
if (m_bcData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_bcData);
|
||||
}
|
||||
|
||||
void TestBCContamination::onBCContaminationModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestBCContamination::onBCContaminationRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
onAesRemoveReply(replyObject);
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestBCContamination; });
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestBCContamination final : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::BCContaminationModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::BCContaminationRemoveReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestBCContamination(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { tryCreateBCContamination(); }
|
||||
private Q_SLOTS:
|
||||
void tryCreateBCContamination();
|
||||
void tryModifyBCContamination();
|
||||
void waitExpireBCContamination();
|
||||
void tryRemoveBCContamination();
|
||||
protected Q_SLOTS:
|
||||
void bCContaminationChanged(const AreaEffectSimulation::BCContamination &data, DataModification modType);
|
||||
protected:
|
||||
void onBCContaminationModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onBCContaminationRemoveReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
bool checkBaseData(const AreaEffectSimulation::BCContamination &a,
|
||||
const AreaEffectSimulation::BCContamination &b) const;
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::BCContamination m_bcData;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,323 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_booby_trap.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// must be in pdm.pdm_charge_type
|
||||
static const int s_ChargeTypeId1 = 251;
|
||||
static const int s_ChargeTypeId2 = 252;
|
||||
|
||||
TestBoobyTrap::TestBoobyTrap(QObject *parent)
|
||||
: TestBase("Test.BoobyTrap", parent)
|
||||
{}
|
||||
|
||||
bool TestBoobyTrap::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_dtc->waitForHistoricalDataBoobyTrap();
|
||||
m_btData.id(-1);
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::boobyTrapChanged,
|
||||
this, &TestBoobyTrap::boobyTrapChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestBoobyTrap::checkBaseData(const AreaEffectSimulation::BoobyTrap &a,
|
||||
const AreaEffectSimulation::BoobyTrap &b) const
|
||||
{
|
||||
if (!checkAesItem(a, b))
|
||||
return false;
|
||||
|
||||
if (a.impactPosition() != b.impactPosition())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "impactPosition does not match: " << a.impactPosition() << " - " << b.impactPosition();
|
||||
return false;
|
||||
}
|
||||
if (a.impactRadius() != b.impactRadius())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "impactRadius does not match: " << a.impactRadius() << " - " << b.impactRadius();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// BoobyTrap
|
||||
//
|
||||
void TestBoobyTrap::tryCreateBoobyTrap()
|
||||
{
|
||||
m_btData = AreaEffectSimulation::BoobyTrap();
|
||||
AreaEffectSimulation::BoobyTrap btData;
|
||||
|
||||
btData.id(0);
|
||||
btData.name("BoobyTrap1");
|
||||
btData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
btData.effectDuration(10234); // msec
|
||||
btData.chargeStruct().chargeTypeId(3456789);
|
||||
btData.impactPosition(Core::GeoPosition2D(0.1547, 0.926));
|
||||
btData.impactRadius(800); // 100m
|
||||
btData.triggerRadius(200);
|
||||
btData.rotationAngle(45);
|
||||
btData.centralAngle(90);
|
||||
btData.partyId(2);
|
||||
//btData.participantId(1234);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send BoobyTrapCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
m_bIsCreatedRequest = true;
|
||||
m_expectedAesId = -1;
|
||||
|
||||
if (!m_ftc->boobyTrapModifyRequest(
|
||||
BoobyTrapModifyRequest(
|
||||
0,
|
||||
btData.name(),
|
||||
btData.effectDuration(),
|
||||
btData.chargeStruct().chargeTypeId(),
|
||||
btData.impactPosition(),
|
||||
btData.impactRadius(),
|
||||
btData.triggerRadius(),
|
||||
btData.rotationAngle().get(),
|
||||
btData.centralAngle().get(),
|
||||
btData.effectStart().get(),
|
||||
btData.partyId().get()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during BoobyTrapCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// since the chargeTypeId is not valid, we should get an error
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating booby trap object (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// now with correct charge type
|
||||
m_bExpectedFailure = false;
|
||||
m_bIsCreatedRequest = true;
|
||||
m_expectedAesId = -1;
|
||||
|
||||
btData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
if (!m_ftc->boobyTrapModifyRequest(
|
||||
BoobyTrapModifyRequest(
|
||||
0,
|
||||
btData.name(),
|
||||
btData.effectDuration(),
|
||||
btData.chargeStruct().chargeTypeId(),
|
||||
btData.impactPosition(),
|
||||
btData.impactRadius(),
|
||||
btData.triggerRadius(),
|
||||
btData.rotationAngle().get(),
|
||||
btData.centralAngle().get(),
|
||||
btData.effectStart().get(),
|
||||
btData.partyId().get()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during BoobyTrapCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_btData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating booby trap object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_btData, btData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestBoobyTrap::tryModifyBoobyTrap);
|
||||
INFO_LOG(m_logger) << "tryCreateBoobyTrap successful";
|
||||
}
|
||||
|
||||
void TestBoobyTrap::tryModifyBoobyTrap()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send modify request";
|
||||
m_btData.name("Booby Trap 2");
|
||||
m_btData.effectStart(m_btData.effectStart().get() + 2000);
|
||||
m_btData.effectDuration(3200); // msec
|
||||
m_btData.chargeStruct().chargeTypeId(s_ChargeTypeId2);
|
||||
m_btData.impactPosition(Core::GeoPosition2D(0.1547, 0.926));
|
||||
m_btData.partyId(3);
|
||||
//m_btData.participantId(1235);
|
||||
const AreaEffectSimulation::BoobyTrap btData(m_btData);
|
||||
m_btData = AreaEffectSimulation::BoobyTrap();
|
||||
m_btData.id(btData.id());
|
||||
|
||||
m_bIsCreatedRequest = false;
|
||||
if (!m_ftc->boobyTrapModifyRequest(
|
||||
BoobyTrapModifyRequest(
|
||||
btData.id(),
|
||||
btData.name(),
|
||||
btData.effectDuration(),
|
||||
btData.chargeStruct().chargeTypeId(),
|
||||
btData.impactPosition(),
|
||||
btData.impactRadius(),
|
||||
btData.triggerRadius(),
|
||||
btData.rotationAngle().get(),
|
||||
btData.centralAngle().get(),
|
||||
btData.effectStart().get(),
|
||||
btData.partyId().get()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_btData.chargeStruct().chargeTypeId() == s_ChargeTypeId2;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating booby trap object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_btData, btData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Modify data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestBoobyTrap::tryTriggerBoobyTrap);
|
||||
INFO_LOG(m_logger) << "tryModifyBoobyTrap successful";
|
||||
}
|
||||
|
||||
void TestBoobyTrap::tryTriggerBoobyTrap()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trigger booby trap -> expires";
|
||||
|
||||
BoobyTrapTriggerRequest req;
|
||||
req.id(m_btData.id());
|
||||
req.triggered(true);
|
||||
if (!m_ftc->boobyTrapTriggerRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting trigger data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, this, &TestBoobyTrap::waitExpireBoobyTrap);
|
||||
INFO_LOG(m_logger) << "waitExpireBoobyTrap successful";
|
||||
}
|
||||
|
||||
void TestBoobyTrap::waitExpireBoobyTrap()
|
||||
{
|
||||
INFO_LOG(m_logger) << "waiting until booby trap expires";
|
||||
|
||||
if (!waitForData([this]() { return m_btData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for expiry of booby trap with id " << m_btData.id();
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
//QTimer::singleShot(0, this, &TestBoobyTrap::tryRemoveBoobyTrap);
|
||||
INFO_LOG(m_logger) << "waitExpireBoobyTrap successful";
|
||||
}
|
||||
|
||||
void TestBoobyTrap::tryRemoveBoobyTrap()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryRemoveBoobyTrap start";
|
||||
|
||||
AreaEffectSimulation::BoobyTrap btData(m_btData);
|
||||
btData.name("RemoveTest");
|
||||
btData.effectStart(0); // not set
|
||||
m_btData = AreaEffectSimulation::BoobyTrap();
|
||||
m_expectedAesId = -1;
|
||||
m_bIsCreatedRequest = true;
|
||||
|
||||
if (!m_ftc->boobyTrapModifyRequest(
|
||||
BoobyTrapModifyRequest(
|
||||
0,
|
||||
btData.name(),
|
||||
btData.effectDuration(),
|
||||
btData.chargeStruct().chargeTypeId(),
|
||||
btData.impactPosition(),
|
||||
btData.impactRadius(),
|
||||
btData.triggerRadius(),
|
||||
btData.rotationAngle().get(),
|
||||
btData.centralAngle().get(),
|
||||
btData.effectStart().get(),
|
||||
btData.partyId().get()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during BoobyTrapModifyRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_btData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating booby trap object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
m_expectedAesId = -1;
|
||||
if (!m_ftc->boobyTrapRemoveRequest(Core::RemoveElementRequest(m_btData.id()), this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during BoobyTrapRemoveRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_btData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error removing booby trap object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "tryRemoveBoobyTrap successful";
|
||||
}
|
||||
|
||||
void TestBoobyTrap::boobyTrapChanged(const AreaEffectSimulation::BoobyTrap &data, DataModification modType)
|
||||
{
|
||||
if (m_btData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_btData);
|
||||
}
|
||||
|
||||
void TestBoobyTrap::onBoobyTrapModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestBoobyTrap::onBoobyTrapRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
onAesRemoveReply(replyObject);
|
||||
}
|
||||
|
||||
void TestBoobyTrap::onBoobyTrapTriggerReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
onAesTriggerReply(replyObject);
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestBoobyTrap; });
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestBoobyTrap final : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::BoobyTrapModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::BoobyTrapRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::BoobyTrapTriggerReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestBoobyTrap(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { tryCreateBoobyTrap(); }
|
||||
private Q_SLOTS:
|
||||
void tryCreateBoobyTrap();
|
||||
void tryModifyBoobyTrap();
|
||||
void tryTriggerBoobyTrap();
|
||||
void waitExpireBoobyTrap();
|
||||
void tryRemoveBoobyTrap();
|
||||
protected Q_SLOTS:
|
||||
void boobyTrapChanged(const AreaEffectSimulation::BoobyTrap &data, DataModification modType);
|
||||
protected:
|
||||
void onBoobyTrapModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onBoobyTrapRemoveReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onBoobyTrapTriggerReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
private:
|
||||
bool checkBaseData(const AreaEffectSimulation::BoobyTrap &a,
|
||||
const AreaEffectSimulation::BoobyTrap &b) const;
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::BoobyTrap m_btData;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_charge_administration.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
static const int s_ChargeAmount = 600;
|
||||
|
||||
TestChargeAdministration::TestChargeAdministration(QObject *parent)
|
||||
: TestBase("Test.ChargeAdministration", parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool TestChargeAdministration::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_testId = testId;
|
||||
m_caData.id(-1);
|
||||
DEBUG_LOG(m_logger) << "Test Id = " << m_testId;
|
||||
|
||||
m_dtc->waitForHistoricalDataChargeAdministration();
|
||||
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::chargeAdministrationChanged, this, &TestChargeAdministration::chargeAdministrationChanged);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestChargeAdministration::checkBaseData(const AreaEffectSimulation::ChargeAdministration &a, const AreaEffectSimulation::ChargeAdministration &b) const
|
||||
{
|
||||
|
||||
if (a.amount() != b.amount())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Amount does not match: " << a.amount() << " - " << b.amount();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.planned() != b.planned())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Planned does not match: " << a.planned() << " - " << b.planned();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.chargeTypeId() != b.chargeTypeId())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "ChargeTypeId does not match: " << a.chargeTypeId() << " - " << b.chargeTypeId();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.partyId() != b.partyId())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "PartyId does not match: " << a.partyId() << " - " << b.partyId();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.used() != b.used())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Used does not match: " << a.used() << " - " << b.used();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//
|
||||
// ChargeAdministration
|
||||
//
|
||||
void TestChargeAdministration::tryCreateChargeAdministration()
|
||||
{
|
||||
m_caData = AreaEffectSimulation::ChargeAdministration();
|
||||
m_expectedAesId = -1;
|
||||
AreaEffectSimulation::ChargeAdministration esData;
|
||||
|
||||
esData.chargeTypeId(471);
|
||||
esData.partyId(2);
|
||||
esData.amount(450);
|
||||
esData.effectSourceId(ProjectDataManagement::EffectSource::ES_Internal);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send ChargeAdministrationCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bIsCreatedRequest = true;
|
||||
|
||||
// amountChangedByOperator=true
|
||||
if (!m_ftc->chargeAdministrationModifyRequest(ChargeAdministrationModifyRequest(0,
|
||||
esData.chargeTypeId(),
|
||||
esData.partyId(),
|
||||
esData.effectSourceId(),
|
||||
esData.amount(),
|
||||
true),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during ChargeAdministrationCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_caData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating charge admin object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_caData, esData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestChargeAdministration::tryModifyChargeAdministration);
|
||||
INFO_LOG(m_logger) << "tryCreateChargeAdministration successful";
|
||||
}
|
||||
|
||||
void TestChargeAdministration::tryModifyChargeAdministration()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send modify request";
|
||||
m_caData.chargeTypeId(471);
|
||||
m_caData.partyId(2);
|
||||
m_caData.amount(600);
|
||||
|
||||
const AreaEffectSimulation::ChargeAdministration esData(m_caData);
|
||||
m_caData = AreaEffectSimulation::ChargeAdministration();
|
||||
m_caData.id(esData.id());
|
||||
m_bIsCreatedRequest = false;
|
||||
|
||||
// amountChangedByOperator=true
|
||||
if (!m_ftc->chargeAdministrationModifyRequest(ChargeAdministrationModifyRequest(esData.id(),
|
||||
esData.chargeTypeId(),
|
||||
esData.partyId(),
|
||||
esData.effectSourceId(),
|
||||
esData.amount(),
|
||||
true),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_caData.amount() == s_ChargeAmount; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating charge admin object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "tryModifyChargeAdministration successful";
|
||||
}
|
||||
|
||||
//
|
||||
// ChargeAdministration
|
||||
//
|
||||
void TestChargeAdministration::chargeAdministrationChanged(const AreaEffectSimulation::ChargeAdministration &data, DataModification modType)
|
||||
{
|
||||
if (m_caData.id() < 0)
|
||||
return;
|
||||
INFO_LOG(m_logger) << "Got ChargeAdministrationData with mod type " << (int)modType << ", id: " << data.id() << ", name: " << data.chargeTypeId()
|
||||
<< ", amount: " << data.amount();
|
||||
if ((modType == DataModification::eAdded && m_caData.id() == 0) || (modType == DataModification::eModified && m_caData.id() == data.id()))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "** Updating m_caData";
|
||||
m_caData = data;
|
||||
}
|
||||
}
|
||||
|
||||
void TestChargeAdministration::onChargeAdministrationModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestChargeAdministration::tryCreateCA()
|
||||
{
|
||||
tryCreateChargeAdministration(371, 3, 1383);
|
||||
tryCreateChargeAdministration(371, 2, 1382);
|
||||
tryCreateChargeAdministration(372, 3, 1393);
|
||||
tryCreateChargeAdministration(372, 2, 1392);
|
||||
tryCreateChargeAdministration(381, 3, 9999);
|
||||
tryCreateChargeAdministration(382, 3, 9999);
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
void TestChargeAdministration::tryCreateChargeAdministration(int chargeTypeId, int partyId, int amount)
|
||||
{
|
||||
m_caData = AreaEffectSimulation::ChargeAdministration();
|
||||
AreaEffectSimulation::ChargeAdministration esData;
|
||||
|
||||
esData.chargeTypeId(chargeTypeId);
|
||||
esData.partyId(partyId);
|
||||
esData.amount(amount);
|
||||
esData.amountChangedByOperator(true);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send ChargeAdministrationCreateRequest(int,int,int)";
|
||||
m_replyError = false;
|
||||
m_bIsCreatedRequest = true;
|
||||
// amountChangedByOperator=true
|
||||
if (!m_ftc->chargeAdministrationModifyRequest(ChargeAdministrationModifyRequest(0,
|
||||
esData.chargeTypeId(),
|
||||
esData.partyId(),
|
||||
esData.effectSourceId(),
|
||||
esData.amount(),
|
||||
true),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during ChargeAdministrationCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_caData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating charge admin object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_caData, esData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
INFO_LOG(m_logger) << "tryCreateChargeAdministration successful";
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestChargeAdministration; });
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestChargeAdministration final : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ChargeAdministrationModifyReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestChargeAdministration(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
bool checkBaseData(const AreaEffectSimulation::ChargeAdministration &a,
|
||||
const AreaEffectSimulation::ChargeAdministration &b) const;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { if (m_testId == 0) tryCreateChargeAdministration(); else tryCreateCA();}
|
||||
private Q_SLOTS:
|
||||
void tryCreateChargeAdministration();
|
||||
void tryCreateCA();
|
||||
void tryCreateChargeAdministration(int, int, int);
|
||||
void tryModifyChargeAdministration();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void chargeAdministrationChanged(const AreaEffectSimulation::ChargeAdministration &data, DataModification modType);
|
||||
protected:
|
||||
void onChargeAdministrationModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::ChargeAdministration m_caData;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,245 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_danger_area.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
const std::string TestDangerArea::s_name = "chris2";
|
||||
|
||||
TestDangerArea::TestDangerArea(QObject *parent)
|
||||
: TestBase("Test.DangerArea", parent)
|
||||
{}
|
||||
|
||||
bool TestDangerArea::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_dtc->waitForHistoricalDataDangerArea();
|
||||
|
||||
m_daData.id(-1);
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::dangerAreaChanged,
|
||||
this, &TestDangerArea::dangerAreaChanged);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestDangerArea::checkBaseData(const AreaEffectSimulation::DangerArea &a,
|
||||
const AreaEffectSimulation::DangerArea &b) const
|
||||
{
|
||||
|
||||
if (a.name() != b.name())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Name does not macht: " << a.name() << " - " << b.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.effectStart() != b.effectStart())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "StartTime does not match: " << a.effectStart() << " - " << b.effectStart();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i<a.segments().size() && i<b.segments().size(); ++i)
|
||||
{
|
||||
if (a.segments()[i] != b.segments()[i])
|
||||
{
|
||||
WARNING_LOG(m_logger) << "impactPosition does not match: " << a.segments()[i] << " - " << b.segments()[i];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//
|
||||
// DangerArea
|
||||
//
|
||||
void TestDangerArea::tryCreateDangerArea()
|
||||
{
|
||||
m_daData = AreaEffectSimulation::DangerArea();
|
||||
AreaEffectSimulation::DangerArea esData;
|
||||
esData.id(0);
|
||||
esData.name("chris");
|
||||
esData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
esData.sampleTime(time(nullptr) *1000);
|
||||
|
||||
std::vector<Core::GeoPosition2D> segments;
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17001, 0.93001));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17002, 0.93002));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17003, 0.93003));
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send dangerAreaCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->dangerAreaModifyRequest(
|
||||
DangerAreaModifyRequest(
|
||||
0,
|
||||
esData.name(),
|
||||
0, // Effect Duration
|
||||
311, // Charge Type Id -> 311 = Danger Area Dummy
|
||||
esData.effectStart(),
|
||||
segments,
|
||||
dds::core::optional<int32_t>(), // Party Id
|
||||
dds::core::optional<int32_t>(), // Player Id
|
||||
dds::core::optional<int32_t>() // associatedAesId
|
||||
),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during dangerAreaCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_daData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating danger area object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_daData, esData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestDangerArea::tryModifyDangerArea);
|
||||
INFO_LOG(m_logger) << "tryCreateDangerArea successful";
|
||||
}
|
||||
|
||||
void TestDangerArea::tryModifyDangerArea()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send modify request";
|
||||
m_daData.name(s_name);
|
||||
m_daData.effectStart(time(nullptr)+ 6 * 1000);
|
||||
|
||||
const AreaEffectSimulation::DangerArea esData(m_daData);
|
||||
m_daData = AreaEffectSimulation::DangerArea();
|
||||
m_daData.id(esData.id());
|
||||
|
||||
// resize to 2 elements
|
||||
std::vector<Core::GeoPosition2D> segments;
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17004, 0.93004));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17004, 0.93005));
|
||||
|
||||
m_bIsCreatedRequest = false;
|
||||
if (!m_ftc->dangerAreaModifyRequest(
|
||||
DangerAreaModifyRequest(
|
||||
esData.id(),
|
||||
esData.name(),
|
||||
0, // Effect Duration
|
||||
311, // Charge Type Id -> 311 = Danger Area Dummy
|
||||
esData.effectStart(),
|
||||
segments,
|
||||
dds::core::optional<int32_t>(), // Party Id
|
||||
dds::core::optional<int32_t>(), // Player Id
|
||||
dds::core::optional<int32_t>() // associatedAesId
|
||||
),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_daData.segments().size() == 2;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating danger area object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// increase to 4 elements
|
||||
segments.resize(4);
|
||||
segments[0] = Core::GeoPosition2D(0.17004, 0.93004);
|
||||
segments[1] = Core::GeoPosition2D(0.17004, 0.93005);
|
||||
segments[2] = Core::GeoPosition2D(0.17005, 0.93006);
|
||||
segments[3] = Core::GeoPosition2D(0.17006, 0.93007);
|
||||
|
||||
if (!m_ftc->dangerAreaModifyRequest(
|
||||
DangerAreaModifyRequest(
|
||||
esData.id(),
|
||||
esData.name(),
|
||||
0, // Effect Duration
|
||||
311, // Charge Type Id -> 311 = Danger Area Dummy
|
||||
esData.effectStart(),
|
||||
segments,
|
||||
dds::core::optional<int32_t>(), // Party Id
|
||||
dds::core::optional<int32_t>(), // Player Id
|
||||
dds::core::optional<int32_t>() // associatedAesId
|
||||
),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_daData.segments().size() == 4;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating danger area object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, this, &TestDangerArea::tryRemoveDangerArea);
|
||||
INFO_LOG(m_logger) << "tryModifyDangerArea successful";
|
||||
}
|
||||
|
||||
void TestDangerArea::tryRemoveDangerArea()
|
||||
{
|
||||
m_expectedAesId = -1;
|
||||
if (!m_ftc->dangerAreaRemoveRequest(
|
||||
Core::RemoveElementRequest( m_daData.id()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_daData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error removing bc contamination object " << m_daData.id() << " != " << m_expectedAesId;
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "tryRemoveDangerArea successful";
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// DangerArea
|
||||
//
|
||||
void TestDangerArea::dangerAreaChanged(const AreaEffectSimulation::DangerArea &data, DataModification modType)
|
||||
{
|
||||
if (m_daData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_daData);
|
||||
}
|
||||
|
||||
void TestDangerArea::onDangerAreaModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestDangerArea::onDangerAreaRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
onAesRemoveReply(replyObject);
|
||||
}
|
||||
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestDangerArea; });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestDangerArea final : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::DangerAreaModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::DangerAreaRemoveReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestDangerArea(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
bool checkBaseData(const AreaEffectSimulation::DangerArea &a,
|
||||
const AreaEffectSimulation::DangerArea &b) const;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { tryCreateDangerArea(); }
|
||||
private Q_SLOTS:
|
||||
void tryCreateDangerArea();
|
||||
void tryModifyDangerArea();
|
||||
void tryRemoveDangerArea();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void dangerAreaChanged(const AreaEffectSimulation::DangerArea &data, DataModification modType);
|
||||
protected:
|
||||
void onDangerAreaModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onDangerAreaRemoveReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::DangerArea m_daData;
|
||||
static const std::string s_name;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,428 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_explosion_area.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTimer>
|
||||
#include <QTest>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// must be in pdm.pdm_charge_type
|
||||
static const int s_ChargeTypeId1 = 371;
|
||||
static const int s_ChargeTypeId2 = 372;
|
||||
|
||||
TestExplosionArea::TestExplosionArea(QObject *parent)
|
||||
: TestBase("Test.ExplosionArea", parent)
|
||||
{}
|
||||
|
||||
bool TestExplosionArea::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_dtc->waitForHistoricalDataExplosionArea();
|
||||
m_eaData.id(-1);
|
||||
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionAreaChanged,
|
||||
this, &TestExplosionArea::explosionAreaChanged);
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::triggeredImpactsChanged,
|
||||
this, &TestExplosionArea::triggeredImpactsChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestExplosionArea::checkBaseData(const AreaEffectSimulation::ExplosionArea &a,
|
||||
const AreaEffectSimulation::ExplosionArea &b) const
|
||||
{
|
||||
if (!checkAesItem(a, b))
|
||||
return false;
|
||||
|
||||
if (a.area() != b.area())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "area does not match: " << a.area() << " - " << b.area();
|
||||
return false;
|
||||
}
|
||||
if (a.cannonCount() != b.cannonCount())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "cannonCount does not match: " << a.cannonCount() << " - " << b.cannonCount();
|
||||
return false;
|
||||
}
|
||||
if (a.cannonRounds() != b.cannonRounds())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "cannonCount does not match: " << a.cannonCount() << " - " << b.cannonCount();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestExplosionArea::tryCreateExplosionArea()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryCreateExplosionArea start";
|
||||
m_eaData = AreaEffectSimulation::ExplosionArea();
|
||||
AreaEffectSimulation::ExplosionArea eaData;
|
||||
eaData.id(0);
|
||||
eaData.name("af1");
|
||||
eaData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
eaData.effectDuration(10000); // 10 seconds
|
||||
eaData.chargeStruct().chargeTypeId(345863487);
|
||||
eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.16, 0.92), 50, 60, 70));
|
||||
eaData.partyId(2);
|
||||
eaData.participantId(1234);
|
||||
eaData.cannonCount(1);
|
||||
eaData.cannonRounds(2);
|
||||
eaData.externalId(2);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send explosionAreaCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->explosionAreaModifyRequest(
|
||||
ExplosionAreaModifyRequest(
|
||||
0,
|
||||
eaData.name(),
|
||||
eaData.effectStart(),
|
||||
eaData.effectDuration(),
|
||||
eaData.effectSourceId(),
|
||||
eaData.chargeStruct().chargeTypeId(),
|
||||
eaData.area(),
|
||||
eaData.partyId(),
|
||||
eaData.participantId(),
|
||||
eaData.cannonCount(),
|
||||
eaData.cannonRounds(),
|
||||
eaData.fireRequestTime(),
|
||||
eaData.altitude(),
|
||||
eaData.purpose(),
|
||||
eaData.effectMarkingInTa(),
|
||||
eaData.externalId()
|
||||
),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during explosionAreaCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// since the chargeTypeId is not valid, we should get an error
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating area explosion object (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// now with correct charge type
|
||||
m_bExpectedFailure = false;
|
||||
m_expectedAesId = -1;
|
||||
|
||||
eaData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->explosionAreaModifyRequest(
|
||||
ExplosionAreaModifyRequest(
|
||||
0,
|
||||
eaData.name(),
|
||||
eaData.effectStart(),
|
||||
eaData.effectDuration(),
|
||||
eaData.effectSourceId(),
|
||||
eaData.chargeStruct().chargeTypeId(),
|
||||
eaData.area(),
|
||||
eaData.partyId(),
|
||||
eaData.participantId(),
|
||||
eaData.cannonCount(),
|
||||
eaData.cannonRounds(),
|
||||
eaData.fireRequestTime(),
|
||||
eaData.altitude(),
|
||||
eaData.purpose(),
|
||||
eaData.effectMarkingInTa(),
|
||||
eaData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during explosionAreaCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_eaData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating area explosion object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_eaData, eaData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestExplosionArea::tryModifyExplosionArea);
|
||||
INFO_LOG(m_logger) << "tryCreateExplosionArea successful";
|
||||
}
|
||||
|
||||
|
||||
void TestExplosionArea::tryModifyExplosionArea()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryModifyExplosionArea start";
|
||||
m_eaData.name("af2");
|
||||
m_eaData.effectStart(m_eaData.effectStart().get() + 3000);
|
||||
m_eaData.effectDuration(9000); // 9 sec
|
||||
m_eaData.chargeStruct().chargeTypeId(s_ChargeTypeId2);
|
||||
m_eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.165, 0.921), 50, 60, 70));
|
||||
m_eaData.partyId(3);
|
||||
m_eaData.participantId(1235);
|
||||
m_eaData.cannonCount(2);
|
||||
m_eaData.cannonRounds(2);
|
||||
m_eaData.effectMarkingInTa(true);
|
||||
|
||||
const AreaEffectSimulation::ExplosionArea eaData(m_eaData);
|
||||
m_eaData = AreaEffectSimulation::ExplosionArea();
|
||||
m_eaData.id(eaData.id());
|
||||
m_bIsCreatedRequest = false;
|
||||
|
||||
if (!m_ftc->explosionAreaModifyRequest(
|
||||
ExplosionAreaModifyRequest(
|
||||
eaData.id(),
|
||||
eaData.name(),
|
||||
eaData.effectStart(),
|
||||
eaData.effectDuration(),
|
||||
eaData.effectSourceId(),
|
||||
eaData.chargeStruct().chargeTypeId(),
|
||||
eaData.area(),
|
||||
eaData.partyId(),
|
||||
eaData.participantId(),
|
||||
eaData.cannonCount(),
|
||||
eaData.cannonRounds(),
|
||||
eaData.fireRequestTime(),
|
||||
eaData.altitude(),
|
||||
eaData.purpose(),
|
||||
eaData.effectMarkingInTa(),
|
||||
eaData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_eaData.chargeStruct().chargeTypeId() == s_ChargeTypeId2; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating area explosion object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_eaData, eaData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Modify data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestExplosionArea::tryWaitForActivationExplosionArea);
|
||||
INFO_LOG(m_logger) << "tryModifyExplosionArea successful";
|
||||
}
|
||||
|
||||
|
||||
void TestExplosionArea::tryWaitForActivationExplosionArea()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryWaitForActivationExplosionArea start";
|
||||
|
||||
if (!waitForData([this]() { return m_eaData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Effect State = " << m_eaData.effectStateId();
|
||||
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestExplosionArea::tryPauseResumeExplosionArea);
|
||||
INFO_LOG(m_logger) << "tryWaitForActivationExplosionArea end";
|
||||
}
|
||||
|
||||
void TestExplosionArea::tryPauseResumeExplosionArea()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryPauseResumeExplosionArea start";
|
||||
// try to resume but is already active -> expected error
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
if (!m_ftc->explosionAreaPauseResumeRequest(
|
||||
ExplosionAreaPauseResumeRequest(
|
||||
m_eaData.id(),
|
||||
true,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionAreaPauseResumeRequest(true)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error waiting for reply error while switching to pause of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// and now pause
|
||||
m_bExpectedFailure = false;
|
||||
if (!m_ftc->explosionAreaPauseResumeRequest(
|
||||
ExplosionAreaPauseResumeRequest(
|
||||
m_eaData.id(),
|
||||
false,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionAreaPauseResumeRequest(false)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_eaData.effectStateId() == AreaEffectSimulation::AesEffectState::EsPaused; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for pause of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// pause again -> expected error
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
if (!m_ftc->explosionAreaPauseResumeRequest(
|
||||
ExplosionAreaPauseResumeRequest(
|
||||
m_eaData.id(),
|
||||
false,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionAreaPauseResumeRequest(false)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating single explosion object (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// and resume execution
|
||||
m_bExpectedFailure = false;
|
||||
if (!m_ftc->explosionAreaPauseResumeRequest(
|
||||
ExplosionAreaPauseResumeRequest(
|
||||
m_eaData.id(),
|
||||
true,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionAreaPauseResumeRequest(true)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_eaData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
INFO_LOG(m_logger) << "tryPauseResumeExplosionArea end";
|
||||
QTimer::singleShot(0, this, &TestExplosionArea::checkTriggeredExplosions);
|
||||
}
|
||||
|
||||
void TestExplosionArea::checkTriggeredExplosions()
|
||||
{
|
||||
INFO_LOG(m_logger) << "checkTriggeredExplosions start";
|
||||
|
||||
// first we should wait for Activation
|
||||
if (!waitForData([this]() { return m_eaData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// attn: msb is bit 7
|
||||
checkTriggeredExplosionsHelper(0x70); // 0b01110000
|
||||
checkTriggeredExplosionsHelper(0x30); // 0b00110000
|
||||
checkTriggeredExplosionsHelper(0x10); // 0b00010000
|
||||
checkTriggeredExplosionsHelper(0x00); // 0b00000000
|
||||
|
||||
// last step: wait for expiry
|
||||
if (!waitForData([this]() { return m_eaData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for expiring of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "checkTriggeredExplosions end";
|
||||
}
|
||||
|
||||
void TestExplosionArea::checkTriggeredExplosionsHelper(int bitfield)
|
||||
{
|
||||
// since we've 9 seconds duration and the first hit is at 0, every 2.5sec should be a new TriggeredExplosions telegram
|
||||
QElapsedTimer et;
|
||||
et.start();
|
||||
if (!waitForData([this, bitfield]() { return m_tiData.bitfield()[0] == bitfield; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for triggered explosison telegram with bitfield 0x" << QByteArray::number(bitfield, 16);
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// 500ms delay through dds allowed :)
|
||||
if (et.elapsed() > 3000)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Something went wrong - waited more than 3 seconds for next impact trigger";
|
||||
failExit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TestExplosionArea::explosionAreaChanged(const AreaEffectSimulation::ExplosionArea &data, DataModification modType)
|
||||
{
|
||||
if (m_eaData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_eaData);
|
||||
}
|
||||
|
||||
void TestExplosionArea::triggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType)
|
||||
{
|
||||
if (m_eaData.id() != data.aesItemId() || modType == DataModification::eRemoved)
|
||||
return;
|
||||
INFO_LOG(m_logger) << "Got TriggeredImpacts data - bitfield[0] = 0x" << QByteArray::number(static_cast<int>(data.bitfield()[0]), 16);
|
||||
m_tiData = data;
|
||||
}
|
||||
|
||||
void TestExplosionArea::onExplosionAreaModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestExplosionArea::onExplosionAreaPauseResumeReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Got pause/resume reply explosion area with id " << replyObject.id()
|
||||
<< ", error = " << replyObject.error()
|
||||
<< " and errorString = '" << replyObject.translated() << "'";
|
||||
m_replyError = replyObject.error();
|
||||
if (m_replyError && !m_bExpectedFailure)
|
||||
ERROR_LOG(m_logger) << "Got pause/resume reply explosion area error: " << replyObject();
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestExplosionArea; });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestExplosionArea final : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionAreaModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionAreaPauseResumeReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestExplosionArea(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { tryCreateExplosionArea(); }
|
||||
private Q_SLOTS:
|
||||
void tryCreateExplosionArea();
|
||||
void tryModifyExplosionArea();
|
||||
void tryWaitForActivationExplosionArea();
|
||||
void tryPauseResumeExplosionArea();
|
||||
void checkTriggeredExplosions();
|
||||
void checkTriggeredExplosionsHelper(int bitfield);
|
||||
protected Q_SLOTS:
|
||||
void explosionAreaChanged(const AreaEffectSimulation::ExplosionArea &data, DataModification modType);
|
||||
void triggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType);
|
||||
protected:
|
||||
void onExplosionAreaModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onExplosionAreaPauseResumeReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
bool checkBaseData(const AreaEffectSimulation::ExplosionArea &a,
|
||||
const AreaEffectSimulation::ExplosionArea &b) const;
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::ExplosionArea m_eaData;
|
||||
AreaEffectSimulation::TriggeredImpacts m_tiData;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
+411
@@ -0,0 +1,411 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_explosion_area_bulk.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTimer>
|
||||
#include <QTest>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// must be in pdm.pdm_charge_type
|
||||
static const int s_ChargeTypeId1 = 371;
|
||||
static const int s_ChargeTypeId2 = 372;
|
||||
|
||||
TestExplosionAreaBulk::TestExplosionAreaBulk(QObject *parent)
|
||||
: TestBase("Test.ExplosionAreaBulk", parent)
|
||||
{}
|
||||
|
||||
bool TestExplosionAreaBulk::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_dtc->waitForHistoricalDataExplosionArea();
|
||||
m_eaData.id(-1);
|
||||
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionAreaChanged,
|
||||
this, &TestExplosionAreaBulk::explosionAreaChanged);
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::triggeredImpactsChanged,
|
||||
this, &TestExplosionAreaBulk::triggeredImpactsChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestExplosionAreaBulk::checkBaseData(const AreaEffectSimulation::ExplosionArea &a,
|
||||
const AreaEffectSimulation::ExplosionArea &b) const
|
||||
{
|
||||
if (!checkAesItem(a, b))
|
||||
return false;
|
||||
|
||||
if (a.area() != b.area())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "area does not match: " << a.area() << " - " << b.area();
|
||||
return false;
|
||||
}
|
||||
if (a.cannonCount() != b.cannonCount())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "cannonCount does not match: " << a.cannonCount() << " - " << b.cannonCount();
|
||||
return false;
|
||||
}
|
||||
if (a.cannonRounds() != b.cannonRounds())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "cannonCount does not match: " << a.cannonCount() << " - " << b.cannonCount();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestExplosionAreaBulk::tryCreateExplosionArea()
|
||||
{
|
||||
const int count = 100;
|
||||
|
||||
const int effectDurationMesc = 60 * 1000; // 10 seconds
|
||||
const double lonOffset = 0.0001;
|
||||
|
||||
for (int i=0; i<count;++i)
|
||||
{
|
||||
QString objName = QString(QStringLiteral("af_bulk_%1")).arg(i);
|
||||
|
||||
INFO_LOG(m_logger) << "tryCreateExplosionArea start, objName=" << objName;
|
||||
|
||||
m_eaData = AreaEffectSimulation::ExplosionArea();
|
||||
AreaEffectSimulation::ExplosionArea eaData;
|
||||
eaData.id(0);
|
||||
eaData.name(objName.toStdString().c_str());
|
||||
eaData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
eaData.effectDuration(effectDurationMesc); // 10 seconds
|
||||
eaData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
|
||||
// Bremen : 0.155 ; 0.926
|
||||
eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.15 + (lonOffset*i), 0.926), 500, 600, 70));
|
||||
|
||||
|
||||
eaData.partyId((i%3) + 2);
|
||||
eaData.participantId(1234);
|
||||
eaData.cannonCount(10);
|
||||
eaData.cannonRounds(10);
|
||||
eaData.externalId(2);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send explosionAreaCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->explosionAreaModifyRequest(
|
||||
ExplosionAreaModifyRequest(
|
||||
0,
|
||||
eaData.name(),
|
||||
eaData.effectStart(),
|
||||
eaData.effectDuration(),
|
||||
eaData.effectSourceId(),
|
||||
eaData.chargeStruct().chargeTypeId(),
|
||||
eaData.area(),
|
||||
eaData.partyId(),
|
||||
eaData.participantId(),
|
||||
eaData.cannonCount(),
|
||||
eaData.cannonRounds(),
|
||||
eaData.fireRequestTime(),
|
||||
eaData.altitude(),
|
||||
eaData.purpose(),
|
||||
eaData.effectMarkingInTa(),
|
||||
eaData.externalId()
|
||||
),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during explosionAreaCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// if (!waitForData([this]() { return m_eaData.id() == m_expectedAesId; }))
|
||||
// {
|
||||
// ERROR_LOG(m_logger) << "Error creating area explosion object";
|
||||
// failExit();
|
||||
// return;
|
||||
// }
|
||||
// if (!checkBaseData(m_eaData, eaData))
|
||||
// {
|
||||
// ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
// failExit();
|
||||
// return;
|
||||
// }
|
||||
|
||||
INFO_LOG(m_logger) << "tryCreateExplosionArea successful objName=" << objName;
|
||||
|
||||
} //for
|
||||
|
||||
QTimer::singleShot(0, this, &TestExplosionAreaBulk::tryWaitForActivationExplosionArea);
|
||||
|
||||
}
|
||||
|
||||
void TestExplosionAreaBulk::tryModifyExplosionArea()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryModifyExplosionArea start";
|
||||
m_eaData.name("af2");
|
||||
m_eaData.effectStart(m_eaData.effectStart().get() + 3000);
|
||||
m_eaData.effectDuration(9000); // 9 sec
|
||||
m_eaData.chargeStruct().chargeTypeId(s_ChargeTypeId2);
|
||||
m_eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.165, 0.921), 50, 60, 70));
|
||||
m_eaData.partyId(3);
|
||||
m_eaData.participantId(1235);
|
||||
m_eaData.cannonCount(2);
|
||||
m_eaData.cannonRounds(2);
|
||||
m_eaData.effectMarkingInTa(true);
|
||||
|
||||
const AreaEffectSimulation::ExplosionArea eaData(m_eaData);
|
||||
m_eaData = AreaEffectSimulation::ExplosionArea();
|
||||
m_eaData.id(eaData.id());
|
||||
m_bIsCreatedRequest = false;
|
||||
|
||||
if (!m_ftc->explosionAreaModifyRequest(
|
||||
ExplosionAreaModifyRequest(
|
||||
eaData.id(),
|
||||
eaData.name(),
|
||||
eaData.effectStart(),
|
||||
eaData.effectDuration(),
|
||||
eaData.effectSourceId(),
|
||||
eaData.chargeStruct().chargeTypeId(),
|
||||
eaData.area(),
|
||||
eaData.partyId(),
|
||||
eaData.participantId(),
|
||||
eaData.cannonCount(),
|
||||
eaData.cannonRounds(),
|
||||
eaData.fireRequestTime(),
|
||||
eaData.altitude(),
|
||||
eaData.purpose(),
|
||||
eaData.effectMarkingInTa(),
|
||||
eaData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_eaData.chargeStruct().chargeTypeId() == s_ChargeTypeId2; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating area explosion object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_eaData, eaData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Modify data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestExplosionAreaBulk::tryWaitForActivationExplosionArea);
|
||||
INFO_LOG(m_logger) << "tryModifyExplosionArea successful";
|
||||
}
|
||||
|
||||
|
||||
void TestExplosionAreaBulk::tryWaitForActivationExplosionArea()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryWaitForActivationExplosionArea start";
|
||||
|
||||
if (!waitForData([this]() { return m_eaData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Effect State = " << m_eaData.effectStateId();
|
||||
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestExplosionAreaBulk::tryPauseResumeExplosionArea);
|
||||
INFO_LOG(m_logger) << "tryWaitForActivationExplosionArea end";
|
||||
}
|
||||
|
||||
void TestExplosionAreaBulk::tryPauseResumeExplosionArea()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryPauseResumeExplosionArea start";
|
||||
// try to resume but is already active -> expected error
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
if (!m_ftc->explosionAreaPauseResumeRequest(
|
||||
ExplosionAreaPauseResumeRequest(
|
||||
m_eaData.id(),
|
||||
true,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionAreaPauseResumeRequest(true)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error waiting for reply error while switching to pause of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// and now pause
|
||||
m_bExpectedFailure = false;
|
||||
if (!m_ftc->explosionAreaPauseResumeRequest(
|
||||
ExplosionAreaPauseResumeRequest(
|
||||
m_eaData.id(),
|
||||
false,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionAreaPauseResumeRequest(false)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_eaData.effectStateId() == AreaEffectSimulation::AesEffectState::EsPaused; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for pause of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// pause again -> expected error
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
if (!m_ftc->explosionAreaPauseResumeRequest(
|
||||
ExplosionAreaPauseResumeRequest(
|
||||
m_eaData.id(),
|
||||
false,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionAreaPauseResumeRequest(false)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating single explosion object (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// and resume execution
|
||||
m_bExpectedFailure = false;
|
||||
if (!m_ftc->explosionAreaPauseResumeRequest(
|
||||
ExplosionAreaPauseResumeRequest(
|
||||
m_eaData.id(),
|
||||
true,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionAreaPauseResumeRequest(true)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_eaData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
INFO_LOG(m_logger) << "tryPauseResumeExplosionArea end";
|
||||
QTimer::singleShot(0, this, &TestExplosionAreaBulk::checkTriggeredExplosions);
|
||||
}
|
||||
|
||||
void TestExplosionAreaBulk::checkTriggeredExplosions()
|
||||
{
|
||||
INFO_LOG(m_logger) << "checkTriggeredExplosions start";
|
||||
|
||||
// first we should wait for Activation
|
||||
if (!waitForData([this]() { return m_eaData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// attn: msb is bit 7
|
||||
checkTriggeredExplosionsHelper(0x70); // 0b01110000
|
||||
checkTriggeredExplosionsHelper(0x30); // 0b00110000
|
||||
checkTriggeredExplosionsHelper(0x10); // 0b00010000
|
||||
checkTriggeredExplosionsHelper(0x00); // 0b00000000
|
||||
|
||||
// last step: wait for expiry
|
||||
if (!waitForData([this]() { return m_eaData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for expiring of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "checkTriggeredExplosions end";
|
||||
}
|
||||
|
||||
void TestExplosionAreaBulk::checkTriggeredExplosionsHelper(int bitfield)
|
||||
{
|
||||
// since we've 9 seconds duration and the first hit is at 0, every 2.5sec should be a new TriggeredExplosions telegram
|
||||
QElapsedTimer et;
|
||||
et.start();
|
||||
if (!waitForData([this, bitfield]() { return m_tiData.bitfield()[0] == bitfield; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for triggered explosison telegram with bitfield 0x" << QByteArray::number(bitfield, 16);
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// 500ms delay through dds allowed :)
|
||||
if (et.elapsed() > 3000)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Something went wrong - waited more than 3 seconds for next impact trigger";
|
||||
failExit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TestExplosionAreaBulk::explosionAreaChanged(const AreaEffectSimulation::ExplosionArea &data, DataModification modType)
|
||||
{
|
||||
if (m_eaData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_eaData);
|
||||
}
|
||||
|
||||
void TestExplosionAreaBulk::triggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType)
|
||||
{
|
||||
if (m_eaData.id() != data.aesItemId() || modType == DataModification::eRemoved)
|
||||
return;
|
||||
|
||||
if (data.bitfield().size() > 0)
|
||||
INFO_LOG(m_logger) << "Got TriggeredImpacts data - bitfield[0] = 0x" << QByteArray::number(static_cast<int>(data.bitfield()[0]), 16);
|
||||
m_tiData = data;
|
||||
}
|
||||
|
||||
void TestExplosionAreaBulk::onExplosionAreaModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestExplosionAreaBulk::onExplosionAreaPauseResumeReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Got pause/resume reply explosion area with id " << replyObject.id()
|
||||
<< ", error = " << replyObject.error()
|
||||
<< " and errorString = '" << replyObject.translated() << "'";
|
||||
m_replyError = replyObject.error();
|
||||
if (m_replyError && !m_bExpectedFailure)
|
||||
ERROR_LOG(m_logger) << "Got pause/resume reply explosion area error: " << replyObject();
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestExplosionAreaBulk; });
|
||||
}
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestExplosionAreaBulk final : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionAreaModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionAreaPauseResumeReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestExplosionAreaBulk(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { tryCreateExplosionArea(); }
|
||||
private Q_SLOTS:
|
||||
void tryCreateExplosionArea();
|
||||
void tryModifyExplosionArea();
|
||||
void tryWaitForActivationExplosionArea();
|
||||
void tryPauseResumeExplosionArea();
|
||||
void checkTriggeredExplosions();
|
||||
void checkTriggeredExplosionsHelper(int bitfield);
|
||||
protected Q_SLOTS:
|
||||
void explosionAreaChanged(const AreaEffectSimulation::ExplosionArea &data, DataModification modType);
|
||||
void triggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType);
|
||||
protected:
|
||||
void onExplosionAreaModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onExplosionAreaPauseResumeReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
bool checkBaseData(const AreaEffectSimulation::ExplosionArea &a,
|
||||
const AreaEffectSimulation::ExplosionArea &b) const;
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::ExplosionArea m_eaData;
|
||||
AreaEffectSimulation::TriggeredImpacts m_tiData;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
+479
@@ -0,0 +1,479 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_explosion_cluster.h"
|
||||
#include <ProjectDataManagement/pdm.hpp>
|
||||
#include <QCoreApplication>
|
||||
#include <QTimer>
|
||||
#include <QTest>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// must be in pdm.pdm_charge_type
|
||||
static const int s_ChargeTypeId1 = 371;
|
||||
static const int s_ChargeTypeId2 = 372;
|
||||
static const int s_IgniterTypeProximity = 101;
|
||||
static const int s_IgniterTypeImpact = 102;
|
||||
|
||||
|
||||
TestExplosionCluster::TestExplosionCluster(QObject *parent)
|
||||
: TestBase("Test.ExplosionCluster", parent)
|
||||
{}
|
||||
|
||||
|
||||
bool TestExplosionCluster::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_dtc->waitForHistoricalDataExplosionCluster();
|
||||
m_ecData.id(-1);
|
||||
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionClusterChanged,
|
||||
this, &TestExplosionCluster::explosionClusterChanged);
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::triggeredImpactsChanged,
|
||||
this, &TestExplosionCluster::triggeredImpactsChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestExplosionCluster::checkBaseData(const AreaEffectSimulation::ExplosionCluster &a,
|
||||
const AreaEffectSimulation::ExplosionCluster &b) const
|
||||
{
|
||||
if (!checkAesItem(a, b))
|
||||
return false;
|
||||
|
||||
if (a.area() != b.area())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "area does not match: " << a.area() << " - " << b.area();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void TestExplosionCluster::tryCreateExplosionCluster()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryCreateExplosionCluster start";
|
||||
m_ecData = AreaEffectSimulation::ExplosionCluster();
|
||||
AreaEffectSimulation::ExplosionCluster eaData;
|
||||
eaData.id(0);
|
||||
|
||||
eaData.effectStart((time(nullptr) + 30) * 1000); // msec
|
||||
|
||||
QString name(QStringLiteral("ec__"));
|
||||
name += QString::number(eaData.effectStart().get());
|
||||
eaData.name(name.toStdString());
|
||||
|
||||
eaData.effectDuration(10000); // 10 seconds
|
||||
eaData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
eaData.chargeStruct().igniterTypeId(s_IgniterTypeImpact);
|
||||
|
||||
// 32 U MD 93860 79903 -> 0.155484041, 0.92622146
|
||||
// eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202560, 0.91611), 200, 50, 20)); // width, height, rotation
|
||||
// eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202561, 0.916111), 200, 50, 20)); // width, height, rotation
|
||||
// eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202562, 0.916112), 200, 50, 20)); // width, height, rotation
|
||||
// eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202564, 0.916112), 200, 50, 20)); // width, height, rotation
|
||||
// eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202562, 0.916115), 200, 50, 20)); // width, height, rotation
|
||||
|
||||
eaData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.202562, 0.916114), 30, 20, 20)); // width, height, rotation
|
||||
eaData.mhPoints({{0.2025611, 0.9161111}, {0.2025611, 0.9161111}, {0.2025611, 0.9161111}}); // 3
|
||||
|
||||
|
||||
eaData.partyId(3);
|
||||
eaData.participantId(5);
|
||||
|
||||
eaData.externalId(0);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send explosionClusterCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
m_bIsCreatedRequest = true;
|
||||
|
||||
int igniterTypeId = s_IgniterTypeImpact;
|
||||
if ((m_testId >= 0) && (m_testId <= 2) )
|
||||
igniterTypeId = m_testId;
|
||||
|
||||
INFO_LOG(m_logger) << "m_testId " << m_testId << ", igniterType = " << igniterTypeId;
|
||||
|
||||
const std::string& properties = "{}";
|
||||
|
||||
if (!m_ftc->explosionClusterModifyRequest(
|
||||
ExplosionClusterModifyRequest(
|
||||
0,
|
||||
eaData.name(),
|
||||
eaData.element(),
|
||||
eaData.effectStart(),
|
||||
eaData.effectDuration(),
|
||||
eaData.effectSourceId(),
|
||||
eaData.area(),
|
||||
AreaEffectSimulation::AesExplosionGeometry_def::EgArea,
|
||||
0, // zog
|
||||
eaData.mhPoints().size(), // mhpCount;
|
||||
dds::core::optional<double>(), // mhpRotation for ExplosionClusterOcModify only
|
||||
3, // impactCount
|
||||
{ 12345, // eaData.chargeTypeId(),
|
||||
igniterTypeId, // eaData.igniterTypeId(),
|
||||
0 // eaData.igniterFunctionId()
|
||||
},
|
||||
3, // firePurpose 3=Blenden mit Wirkung
|
||||
// 25, // firing_elevation_angle
|
||||
123, // peakHeight,
|
||||
10 * 1000, // flightDuration [msec],
|
||||
eaData.partyId(),
|
||||
eaData.participantId(),
|
||||
{}, // esmParticipantIds
|
||||
eaData.externalId(),
|
||||
-1, // eaData.launchVelocity(),
|
||||
-1, // eaData.launchAngleDeg(),
|
||||
-1, // eaData.dropAngle(),
|
||||
-1, // eaData.tapTime(), // msec since epoch
|
||||
-1, // eaData.lcAttack(), // fka lcPrf
|
||||
-1, // eaData.lcTermination(),
|
||||
-1, // eaData.cloudBase(), // Wolkenuntergrenze
|
||||
eaData.effectMarkingInTa(),
|
||||
properties),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during explosionClusterCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// since the chargeTypeId is not valid, we should get an error
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating area explosion object (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
failExit();
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// now with correct charge type
|
||||
m_bExpectedFailure = false;
|
||||
m_expectedAesId = -1;
|
||||
|
||||
eaData.chargeTypeId(s_ChargeTypeId1);
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->explosionClusterModifyRequest(
|
||||
ExplosionClusterModifyRequest(
|
||||
0,
|
||||
eaData.name(),
|
||||
eaData.effectStart(),
|
||||
eaData.effectDuration(),
|
||||
eaData.chargeTypeId(),
|
||||
eaData.area(),
|
||||
eaData.partyId(),
|
||||
eaData.participantId(),
|
||||
1, // eaData.cannonCount(),
|
||||
1, // eaData.cannonRounds(),
|
||||
123,// eaData.fireRequestTime(),
|
||||
// eaData.altitude(),
|
||||
// eaData.purpose(),
|
||||
// eaData.effectMarkingInTa(),
|
||||
eaData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during explosionClusterCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_ecData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating area explosion object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_ecData, eaData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// QTimer::singleShot(0, this, &TestExplosionCluster::tryModifyExplosionCluster);
|
||||
INFO_LOG(m_logger) << "tryCreateExplosionCluster successful";
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
void TestExplosionCluster::tryModifyExplosionCluster()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryModifyExplosionCluster start";
|
||||
m_ecData.name("af2");
|
||||
m_ecData.effectStart(m_ecData.effectStart().get() + 3000);
|
||||
m_ecData.effectDuration(9000); // 9 sec
|
||||
m_ecData.chargeTypeId(s_ChargeTypeId2);
|
||||
|
||||
// 32 U MD 93860 79903 -> 0.155484041, 0.92622146
|
||||
m_ecData.area(AreaEffectSimulation::Area(Core::GeoPosition2D(0.155484041, 0.92622146), 50, 60, 70));
|
||||
waitForData
|
||||
m_ecData.partyId(3);
|
||||
m_ecData.participantId(5);
|
||||
// m_ecData.cannonCount(2);
|
||||
// m_ecData.cannonRounds(2);
|
||||
m_ecData.effectMarkingInTa(true);
|
||||
|
||||
const AreaEffectSimulation::ExplosionCluster eaData(m_ecData);
|
||||
m_ecData = AreaEffectSimulation::ExplosionCluster();
|
||||
m_ecData.id(eaData.id());
|
||||
m_bIsCreatedRequest = false;
|
||||
|
||||
if (!m_ftc->explosionClusterModifyRequest(
|
||||
ExplosionClusterModifyRequest(
|
||||
eaData.id(),
|
||||
eaData.name(),
|
||||
eaData.effectStart(),
|
||||
eaData.effectDuration(),
|
||||
eaData.chargeTypeId(),
|
||||
eaData.area(),
|
||||
eaData.partyId(),
|
||||
eaData.participantId(),
|
||||
1,// eaData.cannonCount(),
|
||||
1, // eaData.cannonRounds(),
|
||||
123,// eaData.fireRequestTime(),
|
||||
123,// eaData.fireRequestTime(),
|
||||
eaData.subAreaCount(),
|
||||
// eaData.altitude(),
|
||||
// eaData.purpose(),
|
||||
// eaData.effectMarkingInTa(),
|
||||
eaData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_ecData.chargeTypeId() == s_ChargeTypeId2; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating area explosion object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_ecData, eaData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Modify data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestExplosionCluster::tryWaitForActivationExplosionCluster);
|
||||
INFO_LOG(m_logger) << "tryModifyExplosionCluster successful";
|
||||
}
|
||||
*/
|
||||
|
||||
void TestExplosionCluster::tryWaitForActivationExplosionCluster()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryWaitForActivationExplosionCluster start";
|
||||
|
||||
if (!waitForData([this]() { return m_ecData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Effect State = " << m_ecData.effectStateId();
|
||||
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestExplosionCluster::tryPauseResumeExplosionCluster);
|
||||
INFO_LOG(m_logger) << "tryWaitForActivationExplosionCluster end";
|
||||
}
|
||||
|
||||
void TestExplosionCluster::tryPauseResumeExplosionCluster()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryPauseResumeExplosionCluster start";
|
||||
// try to resume but is already active -> expected error
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
if (!m_ftc->explosionClusterPauseResumeRequest(
|
||||
ExplosionClusterPauseResumeRequest(
|
||||
m_ecData.id(),
|
||||
true,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionClusterPauseResumeRequest(true)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error waiting for reply error while switching to pause of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// and now pause
|
||||
m_bExpectedFailure = false;
|
||||
if (!m_ftc->explosionClusterPauseResumeRequest(
|
||||
ExplosionClusterPauseResumeRequest(
|
||||
m_ecData.id(),
|
||||
false,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionClusterPauseResumeRequest(false)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_ecData.effectStateId() == AreaEffectSimulation::AesEffectState::EsPaused; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for pause of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// pause again -> expected error
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
if (!m_ftc->explosionClusterPauseResumeRequest(
|
||||
ExplosionClusterPauseResumeRequest(
|
||||
m_ecData.id(),
|
||||
false,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionClusterPauseResumeRequest(false)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating single explosion object (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// and resume execution
|
||||
m_bExpectedFailure = false;
|
||||
if (!m_ftc->explosionClusterPauseResumeRequest(
|
||||
ExplosionClusterPauseResumeRequest(
|
||||
m_ecData.id(),
|
||||
true,
|
||||
dds::core::optional<rti::core::int64>(),
|
||||
dds::core::optional<int32_t>(),
|
||||
dds::core::optional<int32_t>()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error calling explosionClusterPauseResumeRequest(true)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_ecData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
INFO_LOG(m_logger) << "tryPauseResumeExplosionCluster end";
|
||||
QTimer::singleShot(0, this, &TestExplosionCluster::checkTriggeredExplosions);
|
||||
}
|
||||
|
||||
void TestExplosionCluster::checkTriggeredExplosions()
|
||||
{
|
||||
INFO_LOG(m_logger) << "checkTriggeredExplosions start";
|
||||
|
||||
// first we should wait for Activation
|
||||
if (!waitForData([this]() { return m_ecData.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for activation of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// attn: msb is bit 7
|
||||
checkTriggeredExplosionsHelper(0x70); // 0b01110000
|
||||
checkTriggeredExplosionsHelper(0x30); // 0b00110000
|
||||
checkTriggeredExplosionsHelper(0x10); // 0b00010000
|
||||
checkTriggeredExplosionsHelper(0x00); // 0b00000000
|
||||
|
||||
// last step: wait for expiry
|
||||
if (!waitForData([this]() { return m_ecData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for expiring of area explosion";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "checkTriggeredExplosions end";
|
||||
}
|
||||
|
||||
void TestExplosionCluster::checkTriggeredExplosionsHelper(int bitfield)
|
||||
{
|
||||
// since we've 9 seconds duration and the first hit is at 0, every 2.5sec should be a new TriggeredExplosions telegram
|
||||
QElapsedTimer et;
|
||||
et.start();
|
||||
if (!waitForData([this, bitfield]() { return m_tiData.bitfield()[0] == bitfield; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error while waiting for triggered explosison telegram with bitfield 0x" << QByteArray::number(bitfield, 16);
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// 500ms delay through dds allowed :)
|
||||
if (et.elapsed() > 3000)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Something went wrong - waited more than 3 seconds for next impact trigger";
|
||||
failExit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TestExplosionCluster::explosionClusterChanged(const AreaEffectSimulation::ExplosionCluster &data, DataModification modType)
|
||||
{
|
||||
if (m_ecData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_ecData);
|
||||
}
|
||||
|
||||
void TestExplosionCluster::triggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType)
|
||||
{
|
||||
if (m_ecData.id() != data.aesItemId() || modType == DataModification::eRemoved)
|
||||
return;
|
||||
INFO_LOG(m_logger) << "Got TriggeredImpacts data - bitfield[0] = 0x" << QByteArray::number(static_cast<int>(data.bitfield()[0]), 16);
|
||||
m_tiData = data;
|
||||
}
|
||||
|
||||
void TestExplosionCluster::onExplosionClusterModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestExplosionCluster::onExplosionClusterPauseResumeReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Got pause/resume reply explosion area with id " << replyObject.id()
|
||||
<< ", error = " << replyObject.error()
|
||||
<< " and errorString = '" << replyObject.translated() << "'";
|
||||
m_replyError = replyObject.error();
|
||||
if (m_replyError && !m_bExpectedFailure)
|
||||
ERROR_LOG(m_logger) << "Got pause/resume reply explosion area error: " << replyObject();
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestExplosionCluster; });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestExplosionCluster final : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionClusterPauseResumeReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestExplosionCluster(QObject *parent = nullptr);
|
||||
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { tryCreateExplosionCluster(); }
|
||||
private Q_SLOTS:
|
||||
void tryCreateExplosionCluster();
|
||||
// void tryModifyExplosionCluster();
|
||||
void tryWaitForActivationExplosionCluster();
|
||||
void tryPauseResumeExplosionCluster();
|
||||
void checkTriggeredExplosions();
|
||||
void checkTriggeredExplosionsHelper(int bitfield);
|
||||
protected Q_SLOTS:
|
||||
void explosionClusterChanged(const AreaEffectSimulation::ExplosionCluster &data, DataModification modType);
|
||||
void triggeredImpactsChanged(const AreaEffectSimulation::TriggeredImpacts &data, DataModification modType);
|
||||
protected:
|
||||
void onExplosionClusterModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onExplosionClusterPauseResumeReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
bool checkBaseData(const AreaEffectSimulation::ExplosionCluster &a,
|
||||
const AreaEffectSimulation::ExplosionCluster &b) const;
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::ExplosionCluster m_ecData;
|
||||
AreaEffectSimulation::TriggeredImpacts m_tiData;
|
||||
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_explosion_single.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// must be in pdm.pdm_charge_type
|
||||
// single fire charge types = area fire
|
||||
static const int s_ChargeTypeId1 = 371;
|
||||
static const int s_ChargeTypeId2 = 372;
|
||||
|
||||
TestExplosionSingle::TestExplosionSingle(QObject *parent)
|
||||
: TestBase("Test.ExplosionSingle", parent)
|
||||
{}
|
||||
|
||||
bool TestExplosionSingle::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_dtc->waitForHistoricalDataExplosionSingle();
|
||||
m_esData.id(-1);
|
||||
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::explosionSingleChanged,
|
||||
this, &TestExplosionSingle::explosionSingleChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestExplosionSingle::checkBaseData(const AreaEffectSimulation::ExplosionSingle &a,
|
||||
const AreaEffectSimulation::ExplosionSingle &b) const
|
||||
{
|
||||
if (!checkAesItem(a, b))
|
||||
return false;
|
||||
|
||||
if (a.impactPosition() != b.impactPosition())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "impactPosition does not match: " << a.impactPosition() << " - " << b.impactPosition();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// ExplosionSingle
|
||||
//
|
||||
void TestExplosionSingle::tryCreateExplosionSingle()
|
||||
{
|
||||
m_esData = AreaEffectSimulation::ExplosionSingle();
|
||||
AreaEffectSimulation::ExplosionSingle esData;
|
||||
esData.id(0);
|
||||
esData.name("chris");
|
||||
esData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
esData.chargeStruct().chargeTypeId(345863487);
|
||||
esData.impactPosition(Core::GeoPosition2D(0.16, 0.92));
|
||||
esData.partyId(7);
|
||||
esData.participantId(1234);
|
||||
esData.externalId(1);
|
||||
esData.effectMarkingInTa(false);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send explosionSingleCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->explosionSingleModifyRequest(
|
||||
ExplosionSingleModifyRequest(
|
||||
0,
|
||||
esData.name(),
|
||||
esData.effectStart(),
|
||||
esData.effectSourceId(),
|
||||
esData.chargeStruct().chargeTypeId(),
|
||||
esData.impactPosition(),
|
||||
esData.partyId(),
|
||||
esData.participantId(),
|
||||
esData.fireRequestTime(),
|
||||
esData.altitude(),
|
||||
esData.purpose(),
|
||||
esData.effectMarkingInTa(),
|
||||
esData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during explosionSingleCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// since the chargeTypeId is not valid, we should get an error
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating single explosion object (try with error)";
|
||||
}
|
||||
|
||||
// now with correct charge type
|
||||
m_bExpectedFailure = false;
|
||||
m_expectedAesId = -1;
|
||||
|
||||
esData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
esData.partyId(2);
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->explosionSingleModifyRequest(
|
||||
ExplosionSingleModifyRequest(
|
||||
0,
|
||||
esData.name(),
|
||||
esData.effectStart(),
|
||||
esData.effectSourceId(),
|
||||
esData.chargeStruct().chargeTypeId(),
|
||||
esData.impactPosition(),
|
||||
esData.partyId(),
|
||||
esData.participantId(),
|
||||
esData.fireRequestTime(),
|
||||
esData.altitude(),
|
||||
esData.purpose(),
|
||||
esData.effectMarkingInTa(),
|
||||
esData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during explosionSingleCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_esData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating single explosion object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_esData, esData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestExplosionSingle::tryModifyExplosionSingle);
|
||||
INFO_LOG(m_logger) << "tryCreateExplosionSingle successful";
|
||||
}
|
||||
|
||||
void TestExplosionSingle::tryModifyExplosionSingle()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send modify request";
|
||||
m_esData.name("chris2");
|
||||
m_esData.effectStart(m_esData.effectStart().get() + 2000);
|
||||
m_esData.chargeStruct().chargeTypeId(s_ChargeTypeId2);
|
||||
m_esData.impactPosition(Core::GeoPosition2D(0.17, 0.93));
|
||||
m_esData.partyId(3);
|
||||
m_esData.participantId(1235);
|
||||
const AreaEffectSimulation::ExplosionSingle esData(m_esData);
|
||||
m_esData = AreaEffectSimulation::ExplosionSingle();
|
||||
m_esData.id(esData.id());
|
||||
|
||||
m_bIsCreatedRequest = false;
|
||||
if (!m_ftc->explosionSingleModifyRequest(
|
||||
ExplosionSingleModifyRequest(
|
||||
esData.id(),
|
||||
esData.name(),
|
||||
esData.effectStart(),
|
||||
esData.effectSourceId(),
|
||||
esData.chargeStruct().chargeTypeId(),
|
||||
esData.impactPosition(),
|
||||
esData.partyId(),
|
||||
esData.participantId(),
|
||||
esData.fireRequestTime(),
|
||||
esData.altitude(),
|
||||
esData.purpose(),
|
||||
esData.effectMarkingInTa(),
|
||||
esData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_esData.chargeStruct().chargeTypeId() == s_ChargeTypeId2;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating single explosion object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_esData, esData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Modify data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestExplosionSingle::waitExpireExplosionSingle);
|
||||
INFO_LOG(m_logger) << "tryModifyExplosionSingle successful";
|
||||
}
|
||||
|
||||
void TestExplosionSingle::waitExpireExplosionSingle()
|
||||
{
|
||||
INFO_LOG(m_logger) << "waiting until explosion single expires";
|
||||
|
||||
if (!waitForData([this]() { return m_esData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for expiry of explosion single with id " << m_esData.id();
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "waitExpireExplosionSingle successful";
|
||||
}
|
||||
|
||||
void TestExplosionSingle::explosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType)
|
||||
{
|
||||
if (m_esData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_esData);
|
||||
}
|
||||
|
||||
void TestExplosionSingle::onExplosionSingleModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestExplosionSingle::onExplosionSingleRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
onAesRemoveReply(replyObject);
|
||||
}
|
||||
|
||||
//
|
||||
// TestExplosionSingleTestVWM
|
||||
//
|
||||
TestExplosionSingleTestVWM::TestExplosionSingleTestVWM(QObject *parent)
|
||||
: TestExplosionSingle(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void TestExplosionSingleTestVWM::tryCreateExplosionSingleVWM(const std::string &esName,
|
||||
int ammoId,
|
||||
const Core::GeoPosition2D & position)
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryCreateExplosionSingleVWM"
|
||||
<< " name ='" << esName << "'"
|
||||
<< " ammoId = " << ammoId
|
||||
<< " position = " << position;
|
||||
m_esData = AreaEffectSimulation::ExplosionSingle();
|
||||
AreaEffectSimulation::ExplosionSingle esData;
|
||||
esData.id(0);
|
||||
esData.name(esName);
|
||||
esData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
esData.chargeStruct().chargeTypeId(ammoId);
|
||||
esData.impactPosition(position);
|
||||
esData.partyId(3); // 3 -> blau
|
||||
esData.participantId(1234);
|
||||
esData.externalId(1);
|
||||
esData.effectMarkingInTa(false);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send explosionSingleCreateRequest()";
|
||||
m_replyError = false;
|
||||
|
||||
m_bIsCreatedRequest = true;
|
||||
m_bExpectedFailure = false;
|
||||
m_expectedAesId = -1;
|
||||
|
||||
if (!m_ftc->explosionSingleModifyRequest(
|
||||
ExplosionSingleModifyRequest(
|
||||
0,
|
||||
esData.name(),
|
||||
esData.effectStart(),
|
||||
esData.effectSourceId(),
|
||||
esData.chargeStruct().chargeTypeId(),
|
||||
esData.impactPosition(),
|
||||
esData.partyId(),
|
||||
esData.participantId(),
|
||||
esData.fireRequestTime(),
|
||||
esData.altitude(),
|
||||
esData.purpose(),
|
||||
esData.effectMarkingInTa(),
|
||||
esData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during explosionSingleCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// TestBase::onAesCreateReply should update m_expectedAesId:
|
||||
if (!waitForData([this]() { return m_esData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating single explosion object (try with error)";
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << "got answer, m_replyError=" << m_replyError
|
||||
<< " m_expectedAesId=" << m_expectedAesId;
|
||||
|
||||
std::cerr << "got answer, m_replyError=" << m_replyError
|
||||
<< " m_expectedAesId=" << m_expectedAesId << std::endl;
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
|
||||
}
|
||||
|
||||
void TestExplosionSingleTestVWM::onExplosionSingleCreateReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// LOGGING: log4cxx_aes.props -> ctc_aes.log
|
||||
|
||||
// find name, ammoId, position
|
||||
std::string name;
|
||||
int ammoId = -1;
|
||||
Core::GeoPosition2D position;
|
||||
|
||||
{
|
||||
for (int i=1; i<argc; ++i)
|
||||
{
|
||||
if (strcmp(argv[i], "name") == 0)
|
||||
name = argv[i+1];
|
||||
if (strcmp(argv[i], "ammoId") == 0)
|
||||
ammoId = atoi(argv[i+1]);
|
||||
if (strcmp(argv[i], "x") == 0)
|
||||
position.lon(atof(argv[i+1]));
|
||||
if (strcmp(argv[i], "y") == 0)
|
||||
position.lat(atof(argv[i+1]));
|
||||
}
|
||||
}
|
||||
|
||||
if (!name.empty())
|
||||
{
|
||||
std::cerr << " name = '" << name << "'"
|
||||
<< " ammoId = '" << ammoId
|
||||
<< " position = '" << position << std::endl;
|
||||
|
||||
std::function<AreaEffectSimulation::TestBase*()> createFunc = [name, ammoId, position]() {
|
||||
auto ptr = new AreaEffectSimulation::TestExplosionSingleTestVWM;
|
||||
ptr->setName(name);
|
||||
ptr->setAmmoId(ammoId);
|
||||
ptr->setPosition(position);
|
||||
return ptr;
|
||||
};
|
||||
return AreaEffectSimulation::mainBase(argc, argv, createFunc);
|
||||
} else {
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestExplosionSingle; });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestExplosionSingle : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionSingleModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::ExplosionSingleRemoveReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestExplosionSingle(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { tryCreateExplosionSingle(); }
|
||||
private Q_SLOTS:
|
||||
void tryCreateExplosionSingle();
|
||||
void tryModifyExplosionSingle();
|
||||
void waitExpireExplosionSingle();
|
||||
protected Q_SLOTS:
|
||||
void explosionSingleChanged(const AreaEffectSimulation::ExplosionSingle &data, DataModification modType);
|
||||
protected:
|
||||
void onExplosionSingleModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onExplosionSingleRemoveReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
bool checkBaseData(const AreaEffectSimulation::ExplosionSingle &a,
|
||||
const AreaEffectSimulation::ExplosionSingle &b) const;
|
||||
|
||||
protected:
|
||||
AreaEffectSimulation::ExplosionSingle m_esData;
|
||||
};
|
||||
|
||||
|
||||
class TestExplosionSingleTestVWM final : public TestExplosionSingle
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestExplosionSingleTestVWM(QObject *parent = nullptr);
|
||||
|
||||
void setName(const std::string &name) { m_name = name; }
|
||||
void setAmmoId(int ammoId) { m_ammoId = ammoId; }
|
||||
void setPosition(const Core::GeoPosition2D &position) { m_position = position; }
|
||||
|
||||
|
||||
public Q_SLOTS:
|
||||
void startTest() override
|
||||
{
|
||||
tryCreateExplosionSingleVWM(m_name, m_ammoId, m_position);
|
||||
}
|
||||
|
||||
private Q_SLOTS:
|
||||
void tryCreateExplosionSingleVWM(const std::string &esName = "Norbert",
|
||||
int ammoId = 371,
|
||||
const Core::GeoPosition2D &position = Core::GeoPosition2D(0.202603, 0.916049)
|
||||
);
|
||||
|
||||
void onExplosionSingleCreateReply(const Core::FunctionReplyObject &replyObject);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
int m_ammoId{-1};
|
||||
Core::GeoPosition2D m_position;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_gas_pipe.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
TestGasPipe::TestGasPipe(QObject *parent)
|
||||
: TestBase("Test.GasPipe", parent)
|
||||
, m_refPos(LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32UMD8000090000")))
|
||||
{}
|
||||
|
||||
bool TestGasPipe::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
tryCreateGasPipe();
|
||||
|
||||
m_dtc->waitForHistoricalDataGasPipe();
|
||||
m_esData.id(-1);
|
||||
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::gasPipeChanged,
|
||||
this, &TestGasPipe::gasPipeChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestGasPipe::checkBaseData(const AreaEffectSimulation::GasPipe &a,
|
||||
const AreaEffectSimulation::GasPipe &b) const
|
||||
{
|
||||
if (!checkAesItem(a, b))
|
||||
return false;
|
||||
|
||||
/*if (a.impactPosition() != b.impactPosition())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "impactPosition does not match: " << a.impactPosition() << " - " << b.impactPosition();
|
||||
return false;
|
||||
}*/
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void setPos(std::vector<Core::GeoPosition2D> &cont, const QPointF &pos)
|
||||
{
|
||||
cont.emplace_back(Core::GeoPosition2D(pos.x(), pos.y()));
|
||||
}
|
||||
|
||||
//
|
||||
// GasPipe
|
||||
//
|
||||
void TestGasPipe::tryCreateGasPipe()
|
||||
{
|
||||
AreaEffectSimulation::GasPipeModifyRequest gp;
|
||||
//AreaEffectSimulation::GasPipe gp;
|
||||
gp.id(0);
|
||||
gp.name("GasPipe");
|
||||
gp.partyId(1);
|
||||
|
||||
setPos(gp.segments(), m_refPos.geographic(3, 3));
|
||||
setPos(gp.segments(), m_refPos.geographic(4, 4));
|
||||
setPos(gp.segments(), m_refPos.geographic(5, 3));
|
||||
|
||||
DEBUG_LOG(m_logger) << LOGFUNCTION << " GasPipe created. id: " << gp.id();
|
||||
DEBUG_LOG(m_logger) << "request GasPipe";
|
||||
if (!m_ftc->gasPipeModifyRequest( gp, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during explosionSingleCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void TestGasPipe::tryModifyGasPipe()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryModifyGasPipe successful";
|
||||
}
|
||||
|
||||
void TestGasPipe::waitExpireGasPipe()
|
||||
{
|
||||
INFO_LOG(m_logger) << "waiting until explosion single expires";
|
||||
|
||||
if (!waitForData([this]() { return m_esData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for expiry of explosion single with id " << m_esData.id();
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "waitExpireGasPipe successful";
|
||||
}
|
||||
|
||||
void TestGasPipe::gasPipeChanged(const AreaEffectSimulation::GasPipe &data, DataModification modType)
|
||||
{
|
||||
if (m_esData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_esData);
|
||||
}
|
||||
|
||||
void TestGasPipe::onGasPipeModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestGasPipe::onGasPipeRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
onAesRemoveReply(replyObject);
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestGasPipe; });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <QPointF>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestGasPipe final : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::GasPipeModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::GasPipeRemoveReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestGasPipe(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { tryCreateGasPipe(); }
|
||||
private Q_SLOTS:
|
||||
void tryCreateGasPipe();
|
||||
void tryModifyGasPipe();
|
||||
void waitExpireGasPipe();
|
||||
protected Q_SLOTS:
|
||||
void gasPipeChanged(const AreaEffectSimulation::GasPipe &data, DataModification modType);
|
||||
protected:
|
||||
void onGasPipeModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onGasPipeRemoveReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
bool checkBaseData(const AreaEffectSimulation::GasPipe &a,
|
||||
const AreaEffectSimulation::GasPipe &b) const;
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::GasPipe m_esData;
|
||||
LtsCoordTrans::UtmCoordinate m_refPos;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,734 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_mine_area.h"
|
||||
#include "Utils/polygons.h"
|
||||
#include "qjsonobject.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QJsonDocument>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// must be in pdm.pdm_charge_type
|
||||
static const int s_ChargeTypeId1 = 53; // Virtual AP
|
||||
static const int s_ChargeTypeId2 = 40; // DUS AP
|
||||
static const int s_ChargeTypeId3 = 213; // DUS-Mine
|
||||
static const int s_ChargeTypeId4 = 240; // Concrete-Mine
|
||||
|
||||
TestMineArea::TestMineArea(QObject *parent)
|
||||
: TestBase("Test.MineArea", parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool TestMineArea::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_dtc->waitForHistoricalDataMineArea();
|
||||
m_maData.id(-1);
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::mineAreaChanged, this, &TestMineArea::mineAreaChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
void TestMineArea::startTest()
|
||||
{
|
||||
setSegmentForTesMineData();
|
||||
const auto effectClusterList = m_dtc->effectClusters();
|
||||
m_referencedAesItemId = 0;
|
||||
for (const auto &ec : effectClusterList)
|
||||
{
|
||||
m_referencedAesItemId = ec.id();
|
||||
}
|
||||
|
||||
if (m_testId <= 0)
|
||||
tryCreateMineArea();
|
||||
else
|
||||
{
|
||||
m_currentMineId = 12;
|
||||
// Dus Mine Test
|
||||
if (m_testId == 10)
|
||||
tryCreateMineArea2(s_ChargeTypeId3);
|
||||
// Concrete Mine
|
||||
if (m_testId == 11)
|
||||
tryCreateMineArea2(s_ChargeTypeId4);
|
||||
if (m_testId == 12)
|
||||
tryCreateMineArea2(215, 0.109); // Virt. Mine
|
||||
if (m_testId == 15)
|
||||
testMineData_11(); // Virt. Mine
|
||||
if (m_testId == 16)
|
||||
testAddMineData_11(); // Virt. Mine
|
||||
if (m_testId == 17)
|
||||
testMineData_21(); // Virt. Mine
|
||||
if (m_testId == 18)
|
||||
testAddMineData_21(); // Virt. Mine
|
||||
}
|
||||
}
|
||||
|
||||
bool TestMineArea::checkBaseData(const AreaEffectSimulation::MineArea &a, const AreaEffectSimulation::MineArea &b) const
|
||||
{
|
||||
if (!checkAesItem(a, b))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < a.segments().size() && i < b.segments().size(); ++i)
|
||||
{
|
||||
if (a.segments()[i] != b.segments()[i])
|
||||
{
|
||||
WARNING_LOG(m_logger) << "impactPosition does not match: " << a.segments()[i] << " - " << b.segments()[i];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// MineArea
|
||||
//
|
||||
void TestMineArea::tryCreateMineArea()
|
||||
{
|
||||
ERROR_LOG(m_logger) << " >>>> create Mine Area...";
|
||||
m_maData = AreaEffectSimulation::MineArea();
|
||||
AreaEffectSimulation::MineArea esData;
|
||||
esData.id(0);
|
||||
esData.name("chris");
|
||||
esData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
esData.chargeStruct().chargeTypeId(345863487); // Todo: Is this intended?
|
||||
esData.effectDuration(400 * 1000);
|
||||
esData.density(0.2);
|
||||
esData.width(7.0);
|
||||
esData.partyId(7);
|
||||
esData.participantId(1234);
|
||||
esData.layingProcedureType(AreaEffectSimulation::AesMaLayingProcedureType_def::LptArtillery);
|
||||
esData.isLaidHidden(true);
|
||||
|
||||
std::vector<Core::GeoPosition2D> segments;
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17001, 0.93001));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17002, 0.93002));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17003, 0.93003));
|
||||
|
||||
const double distance = 100.0;
|
||||
INFO_LOG(m_logger) << "trying to send mineAreaCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->mineAreaModifyRequest(MineAreaModifyRequest(0,
|
||||
esData.name(),
|
||||
esData.effectStart(),
|
||||
esData.effectDuration(),
|
||||
esData.effectSourceId(),
|
||||
esData.density(),
|
||||
esData.width(),
|
||||
{esData.chargeStruct().chargeTypeId(), 0, 0},
|
||||
segments,
|
||||
esData.partyId(),
|
||||
esData.participantId(),
|
||||
esData.layingProcedureType(),
|
||||
esData.isLaidHidden(),
|
||||
esData.effectMarkingInTa(),
|
||||
true,
|
||||
distance,
|
||||
esData.externalId(),
|
||||
true),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during mineAreaCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// since the chargeTypeId is not valid, we should get an error
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating mine area object (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// now with correct charge type
|
||||
m_bExpectedFailure = false;
|
||||
m_expectedAesId = -1;
|
||||
m_bIsCreatedRequest = true;
|
||||
esData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
if (!m_ftc->mineAreaModifyRequest(MineAreaModifyRequest(esData.id(),
|
||||
esData.name(),
|
||||
esData.effectStart(),
|
||||
esData.effectDuration(),
|
||||
esData.effectSourceId(),
|
||||
esData.density(),
|
||||
esData.width(),
|
||||
{esData.chargeStruct().chargeTypeId(), 0, 0},
|
||||
segments,
|
||||
esData.partyId(),
|
||||
esData.participantId(),
|
||||
esData.layingProcedureType(),
|
||||
esData.isLaidHidden(),
|
||||
esData.effectMarkingInTa(),
|
||||
true,
|
||||
distance,
|
||||
esData.externalId(),
|
||||
true),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during mineAreaCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_maData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating mine area object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_maData, esData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestMineArea::tryModifyMineArea);
|
||||
INFO_LOG(m_logger) << "tryCreateMineArea successful";
|
||||
}
|
||||
// test Mine Data
|
||||
void TestMineArea::testMineData_11()
|
||||
{
|
||||
if (m_referencedAesItemId == 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << " TESTING ADD MINE DATA WILL NOT BE POSSIBLE. CREATE A EFFECT CLUSTER BEFORE STARTING THIS TEST";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_ftc->isMineAreaReferenceModifyEnabled())
|
||||
{
|
||||
if (!m_ftc->enableMineAreaReferenceModify())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating mine area object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QVector<Database::AesMineAreaSegment> dbsegments;
|
||||
int count = 0;
|
||||
std::vector<Core::GeoPosition2D> addVec;
|
||||
addVec.push_back({0.154111, 0.925984});
|
||||
addVec.push_back({0.154111, 0.925937});
|
||||
addVec.push_back({0.154137, 0.925984});
|
||||
addVec.push_back({0.154137, 0.925937});
|
||||
|
||||
qCritical() << " ---> newSegments Pos count: " << addVec.size();
|
||||
std::vector<MineData> mineData;
|
||||
count = 60;
|
||||
|
||||
QDateTime date = QDateTime::currentDateTime().addDays(7);
|
||||
for (const auto &pos : addVec)
|
||||
{
|
||||
MineData m;
|
||||
// auto dt = QDateTime::fromMSecsSinceEpoch(date.toMSecsSinceEpoch());
|
||||
m.appearenceTime(date.toMSecsSinceEpoch());
|
||||
m.armingTime(date.addDays(count).toMSecsSinceEpoch());
|
||||
m.position() = pos;
|
||||
count += 6;
|
||||
mineData.push_back(m);
|
||||
}
|
||||
|
||||
qCritical() << " ---> final mineAreaReferenceModifyRequest ";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = false;
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->mineAreaReferenceModifyRequest(MineAreaReferenceModifyRequest(m_referencedAesItemId, 216, m_wirkzeitMsec, mineData)))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during mineAreaReferenceModifyRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_replyError == false; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating mine area from mine data with referenced Id: " << m_referencedAesItemId;
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// QTimer::singleShot(3000, this, &TestMineArea::testAddMineData_11);
|
||||
}
|
||||
|
||||
void TestMineArea::testAddMineData_11()
|
||||
{
|
||||
if (m_referencedAesItemId == 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << " TESTING ADD MINE DATA WILL NOT BE POSSIBLE. CREATE A EFFECT CLUSTER BEFORE STARTING THIS TEST";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_ftc->enableMineAreaReferenceModify())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating mine area object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QVector<Database::AesMineAreaSegment> dbsegments;
|
||||
int count = 0;
|
||||
std::vector<Core::GeoPosition2D> addVec;
|
||||
addVec.push_back({0.154111, 0.925937});
|
||||
addVec.push_back({0.154111, 0.925900});
|
||||
addVec.push_back({0.154137, 0.925937});
|
||||
addVec.push_back({0.154137, 0.925900});
|
||||
|
||||
qCritical() << " ---> newSegments Pos count: " << addVec.size();
|
||||
std::vector<MineData> mineData;
|
||||
count = 60;
|
||||
|
||||
QDateTime date = QDateTime::currentDateTime().addDays(7);
|
||||
for (const auto &pos : addVec)
|
||||
{
|
||||
MineData m;
|
||||
// auto dt = QDateTime::fromMSecsSinceEpoch(date.toMSecsSinceEpoch());
|
||||
m.appearenceTime(date.toMSecsSinceEpoch());
|
||||
m.armingTime(date.addDays(count).toMSecsSinceEpoch());
|
||||
m.position() = pos;
|
||||
count += 6;
|
||||
mineData.push_back(m);
|
||||
}
|
||||
|
||||
qCritical() << " ---> final mineAreaReferenceModifyRequest ";
|
||||
if (!m_ftc->mineAreaReferenceModifyRequest(MineAreaReferenceModifyRequest(m_referencedAesItemId, 216, m_wirkzeitMsec, mineData)))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during mineAreaReferenceModifyRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void TestMineArea::testMineData_21()
|
||||
{
|
||||
if (m_referencedAesItemId == 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << " TESTING ADD MINE DATA WILL NOT BE POSSIBLE. CREATE A EFFECT CLUSTER BEFORE STARTING THIS TEST";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_ftc->enableMineAreaReferenceModify())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating mine area object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QVector<Database::AesMineAreaSegment> dbsegments;
|
||||
int count = 0;
|
||||
std::vector<Core::GeoPosition2D> addVec;
|
||||
addVec.push_back({0.153900, 0.925950});
|
||||
addVec.push_back({0.153825, 0.925905});
|
||||
addVec.push_back({0.153850, 0.925890});
|
||||
addVec.push_back({0.153929, 0.925937});
|
||||
|
||||
qCritical() << " ---> newSegments Pos count: " << addVec.size();
|
||||
std::vector<MineData> mineData;
|
||||
count = 60;
|
||||
|
||||
QDateTime date = QDateTime::currentDateTime().addDays(7);
|
||||
for (const auto &pos : addVec)
|
||||
{
|
||||
MineData m;
|
||||
// auto dt = QDateTime::fromMSecsSinceEpoch(date.toMSecsSinceEpoch());
|
||||
m.appearenceTime(date.toMSecsSinceEpoch());
|
||||
m.armingTime(date.addDays(count).toMSecsSinceEpoch());
|
||||
m.position() = pos;
|
||||
count += 6;
|
||||
mineData.push_back(m);
|
||||
}
|
||||
|
||||
qCritical() << " ---> final mineAreaReferenceModifyRequest ";
|
||||
if (!m_ftc->mineAreaReferenceModifyRequest(MineAreaReferenceModifyRequest(m_referencedAesItemId, 216, m_wirkzeitMsec, mineData)))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during mineAreaReferenceModifyRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// QTimer::singleShot(3000, this, &TestMineArea::testAddMineData_21);
|
||||
}
|
||||
void TestMineArea::testAddMineData_21()
|
||||
{
|
||||
|
||||
if (m_referencedAesItemId == 0)
|
||||
{
|
||||
ERROR_LOG(m_logger) << " TESTING ADD MINE DATA WILL NOT BE POSSIBLE. CREATE A EFFECT CLUSTER BEFORE STARTING THIS TEST";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_ftc->enableMineAreaReferenceModify())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating mine area object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QVector<Database::AesMineAreaSegment> dbsegments;
|
||||
int count = 0;
|
||||
std::vector<Core::GeoPosition2D> addVec;
|
||||
addVec.push_back({0.153900, 0.925937});
|
||||
addVec.push_back({0.153955, 0.925937});
|
||||
addVec.push_back({0.153955, 0.925920});
|
||||
addVec.push_back({0.153900, 0.925920});
|
||||
|
||||
qCritical() << " ---> newSegments Pos count: " << addVec.size();
|
||||
std::vector<MineData> mineData;
|
||||
count = 60;
|
||||
|
||||
QDateTime date = QDateTime::currentDateTime().addDays(7);
|
||||
for (const auto &pos : addVec)
|
||||
{
|
||||
MineData m;
|
||||
// auto dt = QDateTime::fromMSecsSinceEpoch(date.toMSecsSinceEpoch());
|
||||
m.appearenceTime(date.toMSecsSinceEpoch());
|
||||
m.armingTime(date.addDays(count).toMSecsSinceEpoch());
|
||||
m.position() = pos;
|
||||
count += 6;
|
||||
mineData.push_back(m);
|
||||
}
|
||||
|
||||
qCritical() << " ---> final mineAreaReferenceModifyRequest ";
|
||||
if (!m_ftc->mineAreaReferenceModifyRequest(MineAreaReferenceModifyRequest(m_referencedAesItemId, 216, m_wirkzeitMsec, mineData)))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during mineAreaReferenceModifyRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
void TestMineArea::setSegmentForTesMineData()
|
||||
{
|
||||
|
||||
std::vector<Core::GeoPosition2D> segments;
|
||||
|
||||
// (form == 1)
|
||||
{
|
||||
std::vector<Core::GeoPosition2D> segments;
|
||||
segments.emplace_back(Core::GeoPosition2D(0.154136, 0.926118));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.154136, 0.926231));
|
||||
m_mapSegmentForm.insert(1, segments);
|
||||
}
|
||||
// (form == 2)
|
||||
{
|
||||
std::vector<Core::GeoPosition2D> segments;
|
||||
segments.emplace_back(Core::GeoPosition2D(0.154215, 0.926000));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.15345, 0.926231));
|
||||
m_mapSegmentForm.insert(1, segments);
|
||||
}
|
||||
// (form == 3)
|
||||
{
|
||||
std::vector<Core::GeoPosition2D> segments;
|
||||
segments.emplace_back(Core::GeoPosition2D(0.153581, 0.926173));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.154500, 0.926126));
|
||||
m_mapSegmentForm.insert(3, segments);
|
||||
}
|
||||
}
|
||||
void TestMineArea::tryModifyMineArea()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send modify request";
|
||||
m_maData.name("chris2");
|
||||
m_maData.effectStart(m_maData.effectStart().get() + 2000);
|
||||
m_maData.chargeStruct().chargeTypeId(s_ChargeTypeId2);
|
||||
m_maData.effectDuration(4 * 1000);
|
||||
m_maData.density(0.2);
|
||||
m_maData.width(7.0);
|
||||
m_maData.partyId(8);
|
||||
m_maData.participantId(1235);
|
||||
m_maData.layingProcedureType(AreaEffectSimulation::AesMaLayingProcedureType_def::LptArtillery);
|
||||
m_maData.isLaidHidden(false);
|
||||
const AreaEffectSimulation::MineArea esData(m_maData);
|
||||
m_maData = AreaEffectSimulation::MineArea();
|
||||
m_maData.id(esData.id());
|
||||
m_maData.effectMarkingInTa(true);
|
||||
|
||||
std::vector<Core::GeoPosition2D> segments;
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17004, 0.93004));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17004, 0.93005));
|
||||
|
||||
const double distance = 100.0;
|
||||
|
||||
m_bIsCreatedRequest = false;
|
||||
if (!m_ftc->mineAreaModifyRequest(MineAreaModifyRequest(esData.id(),
|
||||
esData.name(),
|
||||
esData.effectStart(),
|
||||
esData.effectDuration(),
|
||||
esData.effectSourceId(),
|
||||
esData.density(),
|
||||
esData.width(),
|
||||
{esData.chargeStruct().chargeTypeId(), 0, 0},
|
||||
segments,
|
||||
esData.partyId(),
|
||||
esData.participantId(),
|
||||
esData.layingProcedureType(),
|
||||
esData.isLaidHidden(),
|
||||
esData.effectMarkingInTa(),
|
||||
true,
|
||||
distance,
|
||||
esData.externalId(),
|
||||
true),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_maData.chargeStruct().chargeTypeId() == s_ChargeTypeId2; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating mine area object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// No testing, segments won't match!
|
||||
// if (!checkBaseData(m_maData, esData))
|
||||
// {
|
||||
// ERROR_LOG(m_logger) << "Modify data does not match published data";
|
||||
// failExit();
|
||||
// return;
|
||||
// }
|
||||
QTimer::singleShot(0, this, &TestMineArea::tryCreateAnotherMineArea);
|
||||
INFO_LOG(m_logger) << "tryModifyMineArea successful";
|
||||
}
|
||||
|
||||
//
|
||||
// MineArea
|
||||
//
|
||||
void TestMineArea::tryCreateAnotherMineArea()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to create another area request";
|
||||
AreaEffectSimulation::MineArea esData;
|
||||
esData.id(0);
|
||||
esData.name("chris");
|
||||
esData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
esData.chargeStruct().chargeTypeId(s_ChargeTypeId2);
|
||||
esData.effectDuration(4 * 1000);
|
||||
esData.density(0.2);
|
||||
esData.width(7.0);
|
||||
esData.partyId(7);
|
||||
esData.participantId(1234);
|
||||
esData.layingProcedureType(AreaEffectSimulation::AesMaLayingProcedureType_def::LptArtillery);
|
||||
esData.isLaidHidden(false);
|
||||
|
||||
std::vector<Core::GeoPosition2D> segments;
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17004, 0.93004));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.17005, 0.93004));
|
||||
|
||||
const double distance = 100.0;
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send mineAreaCreateRequest()";
|
||||
m_replyError = true;
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->mineAreaModifyRequest(MineAreaModifyRequest(0,
|
||||
esData.name(),
|
||||
esData.effectStart(),
|
||||
esData.effectDuration(),
|
||||
esData.effectSourceId(),
|
||||
esData.density(),
|
||||
esData.width(),
|
||||
{esData.chargeStruct().chargeTypeId(), 0, 0},
|
||||
segments,
|
||||
esData.partyId(),
|
||||
esData.participantId(),
|
||||
esData.layingProcedureType(),
|
||||
esData.isLaidHidden(),
|
||||
esData.effectMarkingInTa(),
|
||||
true,
|
||||
distance,
|
||||
esData.externalId(),
|
||||
true),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Modify data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_replyError == false; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating mine area object (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, this, &TestMineArea::tryTriggerDusMineInBoth);
|
||||
INFO_LOG(m_logger) << "tryCreateMineArea successful";
|
||||
}
|
||||
|
||||
void TestMineArea::tryCreateMineArea2(int chargeTypeId, double density)
|
||||
{
|
||||
m_maData = AreaEffectSimulation::MineArea();
|
||||
AreaEffectSimulation::MineArea esData;
|
||||
esData.id(0);
|
||||
esData.name("1337Test");
|
||||
esData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
esData.chargeStruct().chargeTypeId(chargeTypeId);
|
||||
esData.effectDuration(400 * 1000);
|
||||
esData.density(density);
|
||||
esData.width(7.0);
|
||||
esData.partyId(7);
|
||||
esData.participantId(1234);
|
||||
esData.layingProcedureType(AreaEffectSimulation::AesMaLayingProcedureType_def::LptArtillery);
|
||||
esData.isLaidHidden(false);
|
||||
|
||||
std::vector<Core::GeoPosition2D> segments;
|
||||
/* Erzeugung der GeoKoordinaten fuer den guez-spezifischen zentralen Bereich (Sueden)
|
||||
QPointF pos = LtsCoordTrans::geographicFromMgrs(QStringLiteral("32UPD 74600 14100"));
|
||||
ERROR_LOG(m_logger) << "pos x: " << pos.x() << ", pos y: " << pos.y();
|
||||
segments.emplace_back(Core::GeoPosition2D(pos.x(), pos.y()));
|
||||
|
||||
pos = LtsCoordTrans::geographicFromMgrs(QStringLiteral("32UPD 77500 14200"));
|
||||
ERROR_LOG(m_logger) << "pos x: " << pos.x() << ", pos y: " << pos.y();
|
||||
segments.emplace_back(Core::GeoPosition2D(pos.x(), pos.y()));
|
||||
|
||||
pos = LtsCoordTrans::geographicFromMgrs(QStringLiteral("32UPD 76100 09150"));
|
||||
ERROR_LOG(m_logger) << "pos x: " << pos.x() << ", pos y: " << pos.y();
|
||||
segments.emplace_back(Core::GeoPosition2D(pos.x(), pos.y()));
|
||||
|
||||
pos = LtsCoordTrans::geographicFromMgrs(QStringLiteral("32UPD 73550 09450"));
|
||||
ERROR_LOG(m_logger) << "pos x: " << pos.x() << ", pos y: " << pos.y();
|
||||
segments.emplace_back(Core::GeoPosition2D(pos.x(), pos.y()));
|
||||
*/
|
||||
|
||||
segments.emplace_back(Core::GeoPosition2D(0.15401, 0.92501));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.15502, 0.92702));
|
||||
segments.emplace_back(Core::GeoPosition2D(0.15603, 0.93003));
|
||||
|
||||
const double distance = 100.0;
|
||||
INFO_LOG(m_logger) << "trying to send mineAreaCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = false;
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->mineAreaModifyRequest(MineAreaModifyRequest(0,
|
||||
esData.name(),
|
||||
esData.effectStart(),
|
||||
esData.effectDuration(),
|
||||
esData.effectSourceId(),
|
||||
esData.density(),
|
||||
esData.width(),
|
||||
{esData.chargeStruct().chargeTypeId(), 0, 0},
|
||||
segments,
|
||||
esData.partyId(),
|
||||
esData.participantId(),
|
||||
esData.layingProcedureType(),
|
||||
esData.isLaidHidden(),
|
||||
esData.effectMarkingInTa(),
|
||||
true,
|
||||
distance,
|
||||
esData.externalId(),
|
||||
true),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during mineAreaCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_replyError == false; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating mine area object with chargeTypeId " << chargeTypeId;
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void TestMineArea::tryTriggerDusMineInBoth()
|
||||
{
|
||||
AreaEffectSimulation::MineTriggeredRequest mtr;
|
||||
mtr.mineAreaId(0); // DUS does not send mine area ID!
|
||||
mtr.mineId(123);
|
||||
mtr.position(Core::GeoPosition2D(0.170041, 0.930041));
|
||||
mtr.chargeTypeId(48);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send mineTriggeredRequest()";
|
||||
m_replyError = true;
|
||||
if (!m_ftc->mineTriggeredRequest(MineTriggeredRequest(mtr.mineAreaId(), mtr.mineId(), mtr.position().get(), mtr.chargeTypeId().get()), this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during mineTriggeredRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// since the chargeTypeId is not valid, we should get an error
|
||||
if (!waitForData([this]() { return m_replyError == false; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error triggering mine (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, this, &TestMineArea::waitExpireMineArea);
|
||||
INFO_LOG(m_logger) << "tryTriggerDusMineInBoth successful";
|
||||
}
|
||||
|
||||
void TestMineArea::waitExpireMineArea()
|
||||
{
|
||||
INFO_LOG(m_logger) << "waiting until mine area expires";
|
||||
|
||||
if (!waitForData([this]() { return m_maData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for expiry of mine area with id " << m_maData.id();
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "waitExpireMineArea successful";
|
||||
}
|
||||
|
||||
void TestMineArea::mineAreaChanged(const AreaEffectSimulation::MineArea &data, DataModification modType)
|
||||
{
|
||||
if (m_maData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_maData);
|
||||
}
|
||||
|
||||
void TestMineArea::onMineAreaModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestMineArea::onMineAreaRemoveReply(const Core::FunctionReplyObject &replyObject) { onAesRemoveReply(replyObject); }
|
||||
|
||||
void TestMineArea::onMineResetReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Got mine reset with id " << replyObject.id() << " and errorString " << replyObject.translated();
|
||||
m_replyError = replyObject.error();
|
||||
if (m_replyError)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Got mine reset reply error: " << replyObject();
|
||||
}
|
||||
}
|
||||
|
||||
void TestMineArea::onMineTriggeredReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Got mine triggered with id " << replyObject.id() << " and errorString " << replyObject.translated();
|
||||
m_replyError = replyObject.error();
|
||||
if (m_replyError)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Got mine triggered reply error: " << replyObject();
|
||||
}
|
||||
}
|
||||
|
||||
void TestMineArea::onMineAreaReferenceModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Modify Mine Area with reference replyObj.id: " << replyObject.id() << " and errorString " << replyObject.translated();
|
||||
m_replyError = replyObject.error();
|
||||
if (m_replyError)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Got mine modify reply error: " << replyObject();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestMineArea; });
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestMineArea final
|
||||
: public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::MineAreaModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::MineAreaRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::MineResetReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::MineTriggeredReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::MineAreaReferenceModifyReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestMineArea(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
public Q_SLOTS:
|
||||
void startTest() override;
|
||||
private Q_SLOTS:
|
||||
void tryCreateMineArea();
|
||||
void testMineData_11();
|
||||
void testAddMineData_11();
|
||||
void testMineData_21();
|
||||
void testAddMineData_21();
|
||||
void setSegmentForTesMineData();
|
||||
void tryModifyMineArea();
|
||||
void waitExpireMineArea();
|
||||
void tryTriggerDusMineInBoth();
|
||||
void tryCreateAnotherMineArea();
|
||||
|
||||
void tryCreateMineArea2(int chargeTypeId, double density = 0.2);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void mineAreaChanged(const AreaEffectSimulation::MineArea &data, DataModification modType);
|
||||
|
||||
protected:
|
||||
void onMineAreaModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onMineAreaRemoveReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onMineResetReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onMineTriggeredReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onMineAreaReferenceModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
bool checkBaseData(const AreaEffectSimulation::MineArea &a, const AreaEffectSimulation::MineArea &b) const;
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::MineArea m_maData;
|
||||
QMap<int, std::vector<Core::GeoPosition2D>> m_mapSegmentForm;
|
||||
int m_referencedAesItemId = 0;
|
||||
int32_t m_wirkzeitMsec = 3 * 10 * 1000; // 30 sec
|
||||
int m_currentMineId = 0;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,320 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_ncontamination.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// must be in pdm.pdm_charge_type
|
||||
static const int s_ChargeTypeId1 = 321;
|
||||
|
||||
TestNContamination::TestNContamination(QObject *parent)
|
||||
: TestBase("Test.NContamination", parent)
|
||||
{}
|
||||
|
||||
bool TestNContamination::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_dtc->waitForHistoricalDataNContamination();
|
||||
m_ncData.id(-1);
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::nContaminationChanged,
|
||||
this, &TestNContamination::nContaminationChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestNContamination::checkBaseData(const AreaEffectSimulation::NContamination &a,
|
||||
const AreaEffectSimulation::NContamination &b) const
|
||||
{
|
||||
if (!checkAesItem(a, b))
|
||||
return false;
|
||||
|
||||
if (a.impactPosition() != b.impactPosition())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "impactPosition does not match: " << a.impactPosition() << " - " << b.impactPosition();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// NContamination
|
||||
//
|
||||
void TestNContamination::tryCreateNContamination()
|
||||
{
|
||||
m_ncData = AreaEffectSimulation::NContamination();
|
||||
AreaEffectSimulation::NContamination ncData;
|
||||
ncData.id(0);
|
||||
ncData.name("ncont1");
|
||||
ncData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
ncData.effectDuration(10000); // 10 sec
|
||||
ncData.chargeStruct().chargeTypeId(345863487);
|
||||
ncData.impactPosition(Core::GeoPosition2D(0.16, 0.92));
|
||||
ncData.borderLengthInner(1000); // 1km
|
||||
ncData.borderLengthOuter(2000); // 2km
|
||||
ncData.impactRadius(500); // 500m
|
||||
ncData.spanAngle(31);
|
||||
ncData.rotationAngle(57);
|
||||
ncData.detonationValue(1000); // kt, only cosmetical
|
||||
ncData.partyId(7);
|
||||
ncData.participantId(1234);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send NContaminationCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
m_bIsCreatedRequest = true;
|
||||
if (!m_ftc->nContaminationModifyRequest(
|
||||
NContaminationModifyRequest(
|
||||
0,
|
||||
ncData.name(),
|
||||
ncData.effectStart(),
|
||||
ncData.effectDuration(),
|
||||
ncData.chargeStruct().chargeTypeId(),
|
||||
ncData.impactPosition(),
|
||||
ncData.borderLengthInner(),
|
||||
ncData.borderLengthOuter(),
|
||||
ncData.impactRadius(),
|
||||
ncData.spanAngle(),
|
||||
ncData.rotationAngle(),
|
||||
ncData.detonationValue(),
|
||||
ncData.weatherSource(),
|
||||
ncData.partyId(),
|
||||
ncData.participantId(),
|
||||
ncData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during NContaminationCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// since the chargeTypeId is not valid, we should get an error
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating ncontamination object (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
m_bExpectedFailure = false;
|
||||
m_expectedAesId = -1;
|
||||
m_bIsCreatedRequest = true;
|
||||
// now with correct charge type
|
||||
ncData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
if (!m_ftc->nContaminationModifyRequest(
|
||||
NContaminationModifyRequest(
|
||||
0,
|
||||
ncData.name(),
|
||||
ncData.effectStart(),
|
||||
ncData.effectDuration(),
|
||||
ncData.chargeStruct().chargeTypeId(),
|
||||
ncData.impactPosition(),
|
||||
ncData.borderLengthInner(),
|
||||
ncData.borderLengthOuter(),
|
||||
ncData.impactRadius(),
|
||||
ncData.spanAngle(),
|
||||
ncData.rotationAngle(),
|
||||
ncData.detonationValue(),
|
||||
ncData.weatherSource(),
|
||||
ncData.partyId(),
|
||||
ncData.participantId(),
|
||||
ncData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during NContaminationCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_ncData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating ncontamination object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_ncData, ncData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestNContamination::tryModifyNContamination);
|
||||
INFO_LOG(m_logger) << "tryCreateNContamination successful";
|
||||
}
|
||||
|
||||
void TestNContamination::tryModifyNContamination()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send modify request";
|
||||
m_ncData.name("ncont2");
|
||||
m_ncData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
m_ncData.effectDuration(3000); // 3 sec
|
||||
m_ncData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
m_ncData.impactPosition(Core::GeoPosition2D(0.162, 0.925));
|
||||
m_ncData.borderLengthInner(1100); // 1.1km
|
||||
m_ncData.borderLengthOuter(1800); // 1.8km
|
||||
m_ncData.impactRadius(600); // 600m
|
||||
m_ncData.spanAngle(14);
|
||||
m_ncData.rotationAngle(187);
|
||||
m_ncData.detonationValue(2000); // kt, only cosmetical
|
||||
m_ncData.partyId(3);
|
||||
m_ncData.participantId(1235);
|
||||
const AreaEffectSimulation::NContamination ncData(m_ncData);
|
||||
m_ncData = AreaEffectSimulation::NContamination();
|
||||
m_ncData.id(ncData.id());
|
||||
|
||||
m_bIsCreatedRequest = false;
|
||||
if (!m_ftc->nContaminationModifyRequest(
|
||||
NContaminationModifyRequest(
|
||||
ncData.id(),
|
||||
ncData.name(),
|
||||
ncData.effectStart(),
|
||||
ncData.effectDuration(),
|
||||
ncData.chargeStruct().chargeTypeId(),
|
||||
ncData.impactPosition(),
|
||||
ncData.borderLengthInner(),
|
||||
ncData.borderLengthOuter(),
|
||||
ncData.impactRadius(),
|
||||
ncData.spanAngle(),
|
||||
ncData.rotationAngle(),
|
||||
ncData.detonationValue(),
|
||||
ncData.weatherSource(),
|
||||
ncData.partyId(),
|
||||
ncData.participantId(),
|
||||
ncData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_ncData.partyId() == 3;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating ncontamination object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_ncData, ncData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Modify data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestNContamination::waitExpireNContamination);
|
||||
INFO_LOG(m_logger) << "tryModifyNContamination successful";
|
||||
}
|
||||
|
||||
void TestNContamination::waitExpireNContamination()
|
||||
{
|
||||
INFO_LOG(m_logger) << "waiting until ncontamination expires";
|
||||
|
||||
if (!waitForData([this]() { return m_ncData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for expiry of ncontamination with id " << m_ncData.id();
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, this, &TestNContamination::tryRemoveNContamination);
|
||||
INFO_LOG(m_logger) << "waitExpireNContamination successful";
|
||||
}
|
||||
|
||||
void TestNContamination::tryRemoveNContamination()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryRemoveNContamination start";
|
||||
|
||||
AreaEffectSimulation::NContamination ncData(m_ncData);
|
||||
ncData.name("RemoveTest");
|
||||
ncData.effectStart(0); // not set
|
||||
m_ncData = AreaEffectSimulation::NContamination();
|
||||
m_expectedAesId = -1;
|
||||
m_bIsCreatedRequest = true;
|
||||
|
||||
if (!m_ftc->nContaminationModifyRequest(
|
||||
NContaminationModifyRequest(
|
||||
0,
|
||||
ncData.name(),
|
||||
ncData.effectStart(),
|
||||
ncData.effectDuration(),
|
||||
ncData.chargeStruct().chargeTypeId(),
|
||||
ncData.impactPosition(),
|
||||
ncData.borderLengthInner(),
|
||||
ncData.borderLengthOuter(),
|
||||
ncData.impactRadius(),
|
||||
ncData.spanAngle(),
|
||||
ncData.rotationAngle(),
|
||||
ncData.detonationValue(),
|
||||
ncData.weatherSource(),
|
||||
ncData.partyId(),
|
||||
ncData.participantId(),
|
||||
ncData.externalId()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during NContaminationCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_ncData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating ncontamination object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
m_expectedAesId = -1;
|
||||
if (!m_ftc->nContaminationRemoveRequest(Core::RemoveElementRequest(m_ncData.id()), this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during NContaminationRemoveRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_ncData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error removing ncontamination object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "tryRemoveNContamination successful";
|
||||
}
|
||||
|
||||
|
||||
void TestNContamination::nContaminationChanged(const AreaEffectSimulation::NContamination &data, DataModification modType)
|
||||
{
|
||||
if (m_ncData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_ncData);
|
||||
}
|
||||
|
||||
void TestNContamination::onNContaminationModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestNContamination::onNContaminationRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
onAesRemoveReply(replyObject);
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestNContamination; });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestNContamination final : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::NContaminationModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::NContaminationRemoveReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestNContamination(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { tryCreateNContamination(); }
|
||||
private Q_SLOTS:
|
||||
void tryCreateNContamination();
|
||||
void tryModifyNContamination();
|
||||
void waitExpireNContamination();
|
||||
void tryRemoveNContamination();
|
||||
protected Q_SLOTS:
|
||||
void nContaminationChanged(const AreaEffectSimulation::NContamination &data, DataModification modType);
|
||||
protected:
|
||||
void onNContaminationModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onNContaminationRemoveReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
bool checkBaseData(const AreaEffectSimulation::NContamination &a,
|
||||
const AreaEffectSimulation::NContamination &b) const;
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::NContamination m_ncData;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,313 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_test_off_route_mine.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// must be in pdm.pdm_charge_type
|
||||
static const int s_ChargeTypeId1 = 253;
|
||||
static const int s_ChargeTypeId2 = 254;
|
||||
|
||||
TestOffRouteMine::TestOffRouteMine(QObject *parent)
|
||||
: TestBase("Test.OffRouteMine", parent)
|
||||
{}
|
||||
|
||||
bool TestOffRouteMine::init(int domainId, int exerciseId, int testId)
|
||||
{
|
||||
if (!TestBase::init(domainId, exerciseId, testId))
|
||||
return false;
|
||||
|
||||
m_dtc->waitForHistoricalDataOffRouteMine();
|
||||
m_ormData.id(-1);
|
||||
connect(m_dtc.get(), &AreaEffectSimulation::Interface::Dtc::offRouteMineChanged,
|
||||
this, &TestOffRouteMine::offRouteMineChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestOffRouteMine::checkBaseData(const AreaEffectSimulation::OffRouteMine &a,
|
||||
const AreaEffectSimulation::OffRouteMine &b) const
|
||||
{
|
||||
if (!checkAesItem(a, b))
|
||||
return false;
|
||||
|
||||
if (a.area().cornerBottomLeft() != b.area().cornerBottomLeft())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "cornerBottomLeft does not match: " << a.area().cornerBottomLeft() << " - " << b.area().cornerBottomLeft();
|
||||
return false;
|
||||
}
|
||||
if (a.impactRadius() != b.impactRadius())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "impactRadius does not match: " << a.impactRadius() << " - " << b.impactRadius();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// OffRouteMine
|
||||
//
|
||||
void TestOffRouteMine::tryCreateOffRouteMine()
|
||||
{
|
||||
m_ormData = AreaEffectSimulation::OffRouteMine();
|
||||
AreaEffectSimulation::OffRouteMine ormData;
|
||||
|
||||
ormData.id(0);
|
||||
ormData.name("OffRouteMine1");
|
||||
ormData.effectStart((time(nullptr) + 4) * 1000); // msec
|
||||
ormData.effectDuration(10234); // msec
|
||||
ormData.chargeStruct().chargeTypeId(3456789);
|
||||
ormData.area().cornerBottomLeft(Core::GeoPosition2D(0.154, 0.926));
|
||||
ormData.area().width(1000);//(20);
|
||||
ormData.area().height(200);//(15);
|
||||
ormData.area().rotation(0.0);//(20.5);
|
||||
ormData.impactRadius(100); // 100m
|
||||
ormData.partyId(2);
|
||||
//ormData.participantId(1234);
|
||||
|
||||
INFO_LOG(m_logger) << "trying to send OffRouteMineCreateRequest()";
|
||||
m_replyError = false;
|
||||
m_bExpectedFailure = true;
|
||||
m_bIsCreatedRequest = true;
|
||||
m_expectedAesId = -1;
|
||||
|
||||
if (!m_ftc->offRouteMineModifyRequest(
|
||||
OffRouteMineModifyRequest(
|
||||
0,
|
||||
ormData.name(),
|
||||
ormData.effectDuration(),
|
||||
ormData.chargeStruct().chargeTypeId(),
|
||||
ormData.area(),
|
||||
ormData.impactRadius().get(),
|
||||
ormData.effectStart().get(),
|
||||
ormData.partyId().get()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during OffRouteMineCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
// since the chargeTypeId is not valid, we should get an error
|
||||
if (!waitForData([this]() { return m_replyError == true; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating off route mine object (try with error)";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
// now with correct charge type
|
||||
m_bExpectedFailure = false;
|
||||
m_bIsCreatedRequest = true;
|
||||
m_expectedAesId = -1;
|
||||
|
||||
ormData.chargeStruct().chargeTypeId(s_ChargeTypeId1);
|
||||
if (!m_ftc->offRouteMineModifyRequest(
|
||||
OffRouteMineModifyRequest(
|
||||
0,
|
||||
ormData.name(),
|
||||
ormData.effectDuration(),
|
||||
ormData.chargeStruct().chargeTypeId(),
|
||||
ormData.area(),
|
||||
ormData.impactRadius().get(),
|
||||
ormData.effectStart().get(),
|
||||
ormData.partyId().get()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during OffRouteMineCreateRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_ormData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating off route mine object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_ormData, ormData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Creation data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestOffRouteMine::tryModifyOffRouteMine);
|
||||
INFO_LOG(m_logger) << "tryCreateOffRouteMine successful";
|
||||
}
|
||||
|
||||
void TestOffRouteMine::tryModifyOffRouteMine()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trying to send modify request";
|
||||
m_ormData.name("OffRouteMine 2");
|
||||
m_ormData.effectStart(m_ormData.effectStart().get() + 2000);
|
||||
m_ormData.effectDuration(3200); // msec
|
||||
m_ormData.chargeStruct().chargeTypeId(s_ChargeTypeId2);
|
||||
m_ormData.area().cornerBottomLeft(Core::GeoPosition2D(0.154, 0.926));
|
||||
m_ormData.area().width(1000);//(50);
|
||||
m_ormData.area().height(200);//(25);
|
||||
m_ormData.area().rotation(90);//(20.5);
|
||||
m_ormData.partyId(3);
|
||||
//m_ormData.participantId(1235);
|
||||
const AreaEffectSimulation::OffRouteMine ormData(m_ormData);
|
||||
m_ormData = AreaEffectSimulation::OffRouteMine();
|
||||
m_ormData.id(ormData.id());
|
||||
|
||||
m_bIsCreatedRequest = false;
|
||||
if (!m_ftc->offRouteMineModifyRequest(
|
||||
OffRouteMineModifyRequest(
|
||||
ormData.id(),
|
||||
ormData.name(),
|
||||
ormData.effectDuration(),
|
||||
ormData.chargeStruct().chargeTypeId(),
|
||||
ormData.area(),
|
||||
ormData.impactRadius().get(),
|
||||
ormData.effectStart().get(),
|
||||
ormData.partyId().get()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting modify data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!waitForData([this]() { return m_ormData.chargeStruct().chargeTypeId() == s_ChargeTypeId2;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error updating off route mine object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
if (!checkBaseData(m_ormData, ormData))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Modify data does not match published data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, &TestOffRouteMine::tryTriggerOffRouteMine);
|
||||
INFO_LOG(m_logger) << "tryModifyOffRouteMine successful";
|
||||
}
|
||||
|
||||
void TestOffRouteMine::tryTriggerOffRouteMine()
|
||||
{
|
||||
INFO_LOG(m_logger) << "trigger off route mine -> expires";
|
||||
|
||||
OffRouteMineTriggerRequest req;
|
||||
req.id(m_ormData.id());
|
||||
req.triggered(true);
|
||||
if (!m_ftc->offRouteMineTriggerRequest(req, this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error requesting trigger data";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, this, &TestOffRouteMine::waitExpireOffRouteMine);
|
||||
INFO_LOG(m_logger) << "waitExpireBoobyTrap successful";
|
||||
}
|
||||
void TestOffRouteMine::waitExpireOffRouteMine()
|
||||
{
|
||||
INFO_LOG(m_logger) << "waiting until off route mine expires";
|
||||
|
||||
if (!waitForData([this]() { return m_ormData.effectStateId() == AreaEffectSimulation::AesEffectState::EsExpired;}))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Timeout waiting for expiry of off route mine with id " << m_ormData.id();
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
//QTimer::singleShot(0, this, &TestOffRouteMine::tryRemoveOffRouteMine);
|
||||
INFO_LOG(m_logger) << "waitExpireOffRouteMine successful";
|
||||
}
|
||||
|
||||
void TestOffRouteMine::tryRemoveOffRouteMine()
|
||||
{
|
||||
INFO_LOG(m_logger) << "tryRemoveOffRouteMine start";
|
||||
|
||||
AreaEffectSimulation::OffRouteMine ormData(m_ormData);
|
||||
ormData.name("RemoveTest");
|
||||
ormData.effectStart(0); // not set
|
||||
m_ormData = AreaEffectSimulation::OffRouteMine();
|
||||
m_expectedAesId = -1;
|
||||
m_bIsCreatedRequest = true;
|
||||
|
||||
if (!m_ftc->offRouteMineModifyRequest(
|
||||
OffRouteMineModifyRequest(
|
||||
0,
|
||||
ormData.name(),
|
||||
ormData.effectDuration(),
|
||||
ormData.chargeStruct().chargeTypeId(),
|
||||
ormData.area(),
|
||||
ormData.impactRadius().get(),
|
||||
ormData.effectStart().get(),
|
||||
ormData.partyId().get()),
|
||||
this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during OffRouteMineModifyRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_ormData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error creating off route mine object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
m_expectedAesId = -1;
|
||||
if (!m_ftc->offRouteMineRemoveRequest(Core::RemoveElementRequest(m_ormData.id()), this))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error during OffRouteMineRemoveRequest()";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData([this]() { return m_ormData.id() == m_expectedAesId; }))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Error removing off route mine object";
|
||||
failExit();
|
||||
return;
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
|
||||
INFO_LOG(m_logger) << "tryRemoveOffRouteMine successful";
|
||||
}
|
||||
|
||||
void TestOffRouteMine::offRouteMineChanged(const AreaEffectSimulation::OffRouteMine &data, DataModification modType)
|
||||
{
|
||||
if (m_ormData.id() == -1)
|
||||
return;
|
||||
onAesChanged(data, modType, m_ormData);
|
||||
}
|
||||
|
||||
void TestOffRouteMine::onOffRouteMineModifyReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (m_bIsCreatedRequest)
|
||||
onAesCreateReply(replyObject);
|
||||
else
|
||||
onAesModifyReply(replyObject);
|
||||
}
|
||||
|
||||
void TestOffRouteMine::onOffRouteMineRemoveReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
onAesRemoveReply(replyObject);
|
||||
}
|
||||
|
||||
void TestOffRouteMine::onOffRouteMineTriggerReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
onAesTriggerReply(replyObject);
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return AreaEffectSimulation::mainBase(argc, argv, []() { return new AreaEffectSimulation::TestOffRouteMine; });
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* AES Function Topic Client test executable
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes_test_base.h"
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestOffRouteMine final : public TestBase
|
||||
, protected AreaEffectSimulation::Interface::Ftc::OffRouteMineModifyReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::OffRouteMineRemoveReplyHandler
|
||||
, protected AreaEffectSimulation::Interface::Ftc::OffRouteMineTriggerReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestOffRouteMine(QObject *parent = nullptr);
|
||||
|
||||
bool init(int domainId, int exerciseId, int testId) override;
|
||||
public Q_SLOTS:
|
||||
void startTest() override { tryCreateOffRouteMine(); }
|
||||
private Q_SLOTS:
|
||||
void tryCreateOffRouteMine();
|
||||
void tryModifyOffRouteMine();
|
||||
void tryTriggerOffRouteMine();
|
||||
void waitExpireOffRouteMine();
|
||||
void tryRemoveOffRouteMine();
|
||||
protected Q_SLOTS:
|
||||
void offRouteMineChanged(const AreaEffectSimulation::OffRouteMine &data, DataModification modType);
|
||||
protected:
|
||||
void onOffRouteMineModifyReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onOffRouteMineRemoveReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onOffRouteMineTriggerReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
bool checkBaseData(const AreaEffectSimulation::OffRouteMine &a,
|
||||
const AreaEffectSimulation::OffRouteMine &b) const;
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::OffRouteMine m_ormData;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
Binary file not shown.
@@ -0,0 +1,73 @@
|
||||
https://devhub.defence-elec.de/jira/browse/E01562-259
|
||||
|
||||
Kontext:
|
||||
|
||||
Die TrajectoryTimeAware besitzt Verweise auf seinen "Verursacher" ("parent")
|
||||
|
||||
Urspruenglich wurden diese mit den Attributen "aesItemId" & "aesTypeId" implementiert - wie es bei AES zu der Zeit typisch war.
|
||||
|
||||
Dieser Verweise soll auf "originatorId," "originatorTypeId" umgestellt werden (zwecks groesserer Flexibilitaet)
|
||||
|
||||
ToDo:
|
||||
|
||||
Code komplett auf die Nutzung von "originatorId," "originatorTypeId" umstellen
|
||||
"aesItemId" & "aesTypeId" aus der aes_service.xml entfernen
|
||||
"aesItemId" & "aesTypeId" im EA entfernen
|
||||
Verifikation:
|
||||
|
||||
"aesItemId" & "aesTypeId" sind komplett entfernt.
|
||||
|
||||
|
||||
Rahmenbedingungen:
|
||||
|
||||
Die meisten AesObjekte haben eine uebergeordnet eindeutige Id.
|
||||
Ausnahme: Derzeit ChargeEffect.
|
||||
Konsequenz: Eine ChargeEffect.id kann gleich sein mit Contamination.id, EffectCluster.id oder ...!
|
||||
StateChangeOriginator::Aes bzw. StateChangeOriginator::ChargeEffect erlaubt dennoch eine Unterscheidung.
|
||||
Als AesType sind u.a. vorgesehen:
|
||||
- AtExplosionClusterSingleTrjajectory
|
||||
- AtEffectClusterSingleTrajectory
|
||||
|
||||
|
||||
Erzeuger des Topic TrajectoryTimeAware:
|
||||
- [B] object_effect_cluster
|
||||
- aesItemId,
|
||||
- aesTypeID = AtEffectClusterSingleTrajectory
|
||||
- neu: OrigId = aesItemId
|
||||
- neu: OrigId = StateChangeOriginator::Aes
|
||||
|
||||
- [C] object_effector -> charge_effect
|
||||
- aesItemId = parent
|
||||
- aesTypeId = AtEffectClusterSingleTrajectory
|
||||
- origId = chargeEffectId,
|
||||
- origType=StateChangeOriginator::ChargeEffect
|
||||
|
||||
- [A] object_explosion_cluster
|
||||
- aesItemId,
|
||||
- aesTypeID = AtExplosionClusterSingleTrajectory
|
||||
- neu: OrigId = aesItemid
|
||||
- neu: OrigId = StateChangeOriginator::Aes
|
||||
|
||||
|
||||
Abnehmer
|
||||
- [C] SitMap: charge_effect_to_map
|
||||
- beschraenkt sich auf StateChangeOriginator::ChargeEffect
|
||||
- Neu: keine Anpassung erforderlich
|
||||
|
||||
- [B] SitMap: effect_cluster_to_map
|
||||
nicht relevant, Gtl wird via topic AesItemView uebertragen.
|
||||
|
||||
- [A] SitMap: explosion_cluster_to_map
|
||||
- beschraenkt sich: AtExplosionClusterSingleTrajectory
|
||||
- Neu: beschraenkt sich auf StateChangeOriginator::aes - doch dann werden
|
||||
|
||||
|
||||
Dialoge:
|
||||
- [A] EditDialog: aes_explosion_edit.cpp
|
||||
- bezieht sich auf ExplosionCluster
|
||||
- beschraenkt sich auf die AesItemId
|
||||
- Neu: beschraenkt sich auf StateChangeOriginator::AES und origId/aesItemId.
|
||||
- [B;C] EditDialog: aes_explosion_edit_adler_standalone
|
||||
- bezieht sich auf EffectCluster
|
||||
- beschraenkt sich auf die AesItemId
|
||||
- Neu: beschraenkt sich auf StateChangeOriginator::ChargeEffect und origId/aesItemId.
|
||||
+509
@@ -0,0 +1,509 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom record/replay functions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_record_replay_plugin_custom.h"
|
||||
|
||||
#include <QElapsedTimer>
|
||||
|
||||
|
||||
static bool OPTIMIZE = true; // GUEZE-3521 "Überarbeitung des Replays zur Performance Steigerung"
|
||||
namespace AreaEffectSimulation {
|
||||
|
||||
RecordReplayPluginCustom::RecordReplayPluginCustom()
|
||||
: m_currentReplayTime(0)
|
||||
{
|
||||
}
|
||||
|
||||
RecordReplayPluginCustom::~RecordReplayPluginCustom()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool RecordReplayPluginCustom::initDts(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector, int exerciseId, bool bCanHandleSchemas, NSqlQuery &query)
|
||||
{
|
||||
RecordReplayPlugin::initDts(ddsConnector, exerciseId, bCanHandleSchemas, query);
|
||||
m_ddsConnector = ddsConnector;
|
||||
m_ddsDts = AreaEffectSimulation::Interface::Dts::create(m_ddsConnector);
|
||||
m_ddsDts->enableAll();
|
||||
//const qint64 startTime = time(nullptr) * 1000LL;
|
||||
DEBUG_LOG(m_logger) << "RecordReplayPluginCustom::initDts successful";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPluginCustom::setReplayStartTime(NSqlQuery &q, qint64 startTime)
|
||||
{
|
||||
|
||||
QElapsedTimer timer;
|
||||
QElapsedTimer timer2;
|
||||
timer2.start();
|
||||
|
||||
INFO_LOG(m_logger) << "setReplayStartTime " << startTime;
|
||||
m_currentReplayTime = 0;
|
||||
timer.start();
|
||||
|
||||
if (!readTrajectoryTimeAwareAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readTrajectoryTimeAwareAt " << startTime << " DONE";
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readTrajectoryTimeAwareAt " << startTime << " before: " << m_trajectoryTimeAwareMap.count();
|
||||
if (OPTIMIZE)
|
||||
{
|
||||
auto copyTW = m_trajectoryTimeAwareMap;
|
||||
for (const auto &key : m_trajectoryTimeAwareMap.keys())
|
||||
{
|
||||
for (const auto &valie : copyTW.values(key))
|
||||
{
|
||||
if (valie.trajectoryStartTime() < startTime - 210*1000)
|
||||
{
|
||||
m_trajectoryTimeAwareMap.remove(key, valie);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readTrajectoryTimeAwareAt " << startTime << " after: " << m_trajectoryTimeAwareMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
|
||||
|
||||
timer.restart();
|
||||
if (!readAirSupportImpactAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readAirSupportImpactAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readAirSupportImpactAt " << startTime << " before: " << m_airSupportImpactMap.count();
|
||||
removeOld(m_airSupportImpactMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readAirSupportImpactAt " << startTime << " after: " << m_airSupportImpactMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
if (!readBCContaminationAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readBCContaminationAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readBCContaminationAt " << startTime << " before: " << m_bCContaminationMap.count();
|
||||
removeOld(m_bCContaminationMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readBCContaminationAt " << startTime << " after: " << m_bCContaminationMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
if (!readBoobyTrapAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readBoobyTrapAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readBoobyTrapAt " << startTime << " before: " << m_boobyTrapMap.count();
|
||||
removeOld(m_boobyTrapMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readBoobyTrapAt " << startTime << " after: " << m_boobyTrapMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
if (!readBorderlineAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readBorderlineAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readBorderlineAt " << startTime << " before: " << m_borderlineMap.count();
|
||||
removeOld(m_borderlineMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readBorderlineAt " << startTime << " after: " << m_borderlineMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
|
||||
|
||||
if (!readChargeAdministrationAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readDynamicParticipantDataAt " << startTime << " DONE";
|
||||
|
||||
|
||||
timer.restart();
|
||||
if (!readDangerAreaAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readDangerAreaAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readDangerAreaAt " << startTime << " before: " << m_dangerAreaMap.count();
|
||||
removeOld(m_dangerAreaMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readDangerAreaAt " << startTime << " after: " << m_dangerAreaMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
if (!readDusMineStateAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readDynamicParticipantDataAt " << startTime << " DONE";
|
||||
|
||||
if (!readDusSingleMineAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readDynamicParticipantDataAt " << startTime << " DONE";
|
||||
|
||||
timer.restart();
|
||||
if (!readExplosionAreaAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readExplosionAreaAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readExplosionAreaAt " << startTime << " before: " << m_explosionAreaMap.count();
|
||||
removeOld(m_explosionAreaMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readExplosionAreaAt " << startTime << " after: " << m_explosionAreaMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
|
||||
if (!readExplosionClusterAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readExplosionClusterAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readExplosionClusterAt " << startTime << " before: " << m_explosionClusterMap.count();
|
||||
removeOld(m_explosionClusterMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readExplosionClusterAt " << startTime << " after: " << m_explosionClusterMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
if (!readExplosionSingleAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readExplosionSingleAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readExplosionSingleAt " << startTime << " before: " << m_explosionSingleMap.count();
|
||||
removeOld(m_explosionSingleMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readExplosionSingleAt " << startTime << " after: " << m_explosionSingleMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
if (!readFunctionalAreaAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readDynamicParticipantDataAt " << startTime << " DONE";
|
||||
|
||||
if (!readGasPipeAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readGasPipeAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readGasPipeAt " << startTime << " before: " << m_gasPipeMap.count();
|
||||
removeOld(m_gasPipeMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readGasPipeAt " << startTime << " after: " << m_gasPipeMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
if (!readMineAreaAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readMineAreaAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readMineAreaAt " << startTime << " before: " << m_mineAreaMap.count();
|
||||
removeOld(m_mineAreaMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readMineAreaAt " << startTime << " after: " << m_mineAreaMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
|
||||
if (!readMineCorridorAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readMineCorridorAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readMineCorridorAt " << startTime << " before: " << m_mineCorridorMap.count();
|
||||
removeOld(m_mineCorridorMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readMineCorridorAt " << startTime << " after: " << m_mineCorridorMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
if (!readNContaminationAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readNContaminationAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readNContaminationAt " << startTime << " before: " << m_nContaminationMap.count();
|
||||
removeOld(m_nContaminationMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readNContaminationAt " << startTime << " after: " << m_nContaminationMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
|
||||
if (!readOffRouteMineAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readOffRouteMineAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readOffRouteMineAt " << startTime << " before: " << m_offRouteMineMap.count();
|
||||
removeOld(m_offRouteMineMap, startTime);
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readOffRouteMineAt " << startTime << " after: " << m_offRouteMineMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
|
||||
if (!readReconAreaAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readDynamicParticipantDataAt " << startTime << " DONE";
|
||||
|
||||
if (!readTechnicalAreaAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readTechnicalAreaAt " << startTime << " DONE";
|
||||
|
||||
if (!readEffectClusterAt(q, startTime))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "setReplayStartTime-readEffectClusterAt " << startTime << " failed";
|
||||
return false;
|
||||
}
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readEffectClusterAt " << startTime << " DONE";
|
||||
|
||||
if (!readChargeEffectAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readChargeEffectAt " << startTime << " DONE";
|
||||
|
||||
|
||||
timer.restart();
|
||||
if (!readTriggeredImpactsAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readTriggeredImpactsAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readTriggeredImpactsAt " << startTime << " before: " << m_triggeredImpactsMap.count();
|
||||
if (OPTIMIZE)
|
||||
{
|
||||
auto copyTI = m_triggeredImpactsMap;
|
||||
for (const auto &key : m_triggeredImpactsMap.keys())
|
||||
{
|
||||
for (const auto &valie : copyTI.values(key))
|
||||
{
|
||||
if (valie.sampleTime() < startTime - 210*1000)
|
||||
m_triggeredImpactsMap.remove(key, valie);
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readTriggeredImpactsAt " << startTime << " after: " << m_triggeredImpactsMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
//take aes item view last
|
||||
timer.restart();
|
||||
if (!readAesItemViewAt(q, startTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
//manual remove_
|
||||
|
||||
|
||||
timer.restart();
|
||||
if (!readEffectsAt(q, startTime)) return false;
|
||||
INFO_LOG(m_logger) << "setReplayStartTime-readEffectsAt " << startTime << " DONE";
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readEffectsAt " << startTime << " before: " << m_effectsMap.count();
|
||||
if (OPTIMIZE)
|
||||
{
|
||||
//find missing aes item vies?!
|
||||
auto copy = m_effectsMap;
|
||||
for (const auto &key : copy.keys())
|
||||
{
|
||||
for (const auto &valie : copy.values(key))
|
||||
{
|
||||
if( m_explosionClusterKeys.find(valie.aesItemId()) != m_explosionClusterKeys.end())
|
||||
{
|
||||
m_effectsMap.remove(key, valie);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readEffectsAt " << startTime << " after: " << m_effectsMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
timer.restart();
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readAesItemViewAt " << startTime << " before: " << m_aesItemViewMap.count();
|
||||
if (OPTIMIZE)
|
||||
{
|
||||
// find missing aes item views?!
|
||||
auto copy = m_aesItemViewMap;
|
||||
for (const auto &key : m_aesItemViewMap.keys())
|
||||
{
|
||||
for (const auto &value : copy.values(key))
|
||||
{
|
||||
if (value.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsCreated
|
||||
|| value.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsFired
|
||||
|| value.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsReceived
|
||||
|| value.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsPrepared
|
||||
|| value.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsActivated
|
||||
)
|
||||
continue;
|
||||
|
||||
// check regarding _Explosion_Cluster
|
||||
{
|
||||
static QVector<AesType_def::type> relavantAesTypeIds = {AesType_def::AtExplosionClusterGunToTargetLine, AesType_def::AtExplosionClusterSingleTrajectory};
|
||||
if (relavantAesTypeIds.contains(value.aesTypeId().underlying()))
|
||||
{
|
||||
if (m_explosionClusterKeys.find(value.aesItemId()) != m_explosionClusterKeys.end() ) //contains not available until cpp 20
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// E01562-E343 EffectCluster: GunToTargetLines fehlen im Replay&Snapshot
|
||||
{
|
||||
static QVector<AesType_def::type> relavantAesTypeIds = {AesType_def::AtEffectClusterGunToTargetLine, AesType_def::AtEffectClusterGunToTargetLine};
|
||||
if (relavantAesTypeIds.contains(value.aesTypeId().underlying()))
|
||||
{
|
||||
if (m_effectClusterKeys.find(value.aesItemId()) != m_effectClusterKeys.end() ) //contains not available until cpp 20
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (value.effectStateId() == AesEffectState_def::EsRemoved || value.effectStart() < startTime - 210*1000)
|
||||
{
|
||||
m_aesItemViewMap.remove(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "setReplayStartTime-readAesItemViewAt " << startTime << " after: " << m_aesItemViewMap.count();
|
||||
DEBUG_LOG(m_logger) << "took " << timer.elapsed();
|
||||
|
||||
DEBUG_LOG(m_logger) << "done db work took " << timer2.elapsed();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RecordReplayPluginCustom::removeOld(QMultiMap<long long, T> &map, qint64 desiredTime)
|
||||
{
|
||||
if (!OPTIMIZE)
|
||||
return;
|
||||
|
||||
auto copy = map;
|
||||
for (const auto &item : copy.keys())
|
||||
{
|
||||
for (const auto &inner : map.values(item))
|
||||
{
|
||||
// Remove delted ones
|
||||
if (inner.isDeleted())
|
||||
{
|
||||
map.remove(item, inner);
|
||||
continue;
|
||||
}
|
||||
// keep planned
|
||||
if (!inner.effectStart().is_set())
|
||||
continue;
|
||||
// Remove to old ones
|
||||
if (inner.effectStart().get()+inner.effectDuration() < desiredTime - 210*1000 )
|
||||
map.remove(item, inner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool RecordReplayPluginCustom::ddsTopicsFromDatabase(NSqlQuery &q, qint64 fromTime, qint64 toTime)
|
||||
{
|
||||
INFO_LOG(m_logger) << "ddsTopicsFromDatabase " << fromTime << " to " << toTime;
|
||||
// if (!readParticipant(q, fromTime, toTime)) return false;
|
||||
bool ret = RecordReplayPlugin::ddsTopicsFromDatabase(q, fromTime, toTime);
|
||||
DEBUG_LOG(m_logger) << "ddsTopicsFromDatabase ret: " << ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool RecordReplayPluginCustom::publishData(qint64 desiredTime)
|
||||
{
|
||||
INFO_LOG(m_logger) << "publishData " << desiredTime;
|
||||
m_currentReplayTime = desiredTime;
|
||||
|
||||
|
||||
QElapsedTimer timer;
|
||||
QElapsedTimer timer2;
|
||||
timer2.start();
|
||||
|
||||
timer.start();
|
||||
DEBUG_LOG(m_logger) << "dispose map =" << m_aesItemViewDisposedMap.size();
|
||||
DEBUG_LOG(m_logger) << "send map =" << m_aesItemViewMap.size();
|
||||
if (!publishAesItemView(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishAesItemView took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishAirSupportImpact(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishAirSupportImpact took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishBCContamination(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishBCContamination took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishBoobyTrap(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishBoobyTrap took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishBorderline(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishBorderline took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishChargeAdministration(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishChargeAdministration took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishDangerArea(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishDangerArea took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishDusMineState(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishDusMineState took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishDusSingleMine(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishDusSingleMine took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishEffects(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishEffects took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishExplosionArea(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishExplosionArea took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishExplosionCluster(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishExplosionCluster took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishExplosionSingle(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishExplosionSingle took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishFunctionalArea(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishFunctionalArea took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishGasPipe(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishGasPipe took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishMineArea(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishMineArea took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishMineCorridor(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishMineCorridor took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishNContamination(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishNContamination took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishOffRouteMine(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishOffRouteMine took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishReconArea(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishReconArea took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishTechnicalArea(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishTechnicalArea took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishEffectCluster(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishEffectCluster took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishChargeEffect(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishtChargeEffect took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishTrajectoryTimeAware(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishTrajectoryTimeAware took " << timer.elapsed();
|
||||
timer.restart();
|
||||
if (!publishTriggeredImpacts(desiredTime)) return false;
|
||||
DEBUG_LOG(m_logger) << "publishTriggeredImpacts took " << timer.elapsed();
|
||||
timer.restart();
|
||||
|
||||
//bool ret = RecordReplayPlugin::publishData(desiredTime);
|
||||
//DEBUG_LOG(m_logger) << "publish ret: " << ret;
|
||||
|
||||
DEBUG_LOG(m_logger) << "publish totally took " << timer2.elapsed();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecordReplayPluginCustom::waitForAsyncOperations(qint64 desiredTime)
|
||||
{
|
||||
Q_UNUSED(desiredTime);
|
||||
|
||||
bool ret = RecordReplayPlugin::waitForAsyncOperations(desiredTime);
|
||||
DEBUG_LOG(m_logger) << "waitForAsyncOperations ret: " << ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RecordReplayPluginCustom::clearData()
|
||||
{
|
||||
RecordReplayPlugin::clearData();
|
||||
}
|
||||
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Custom record/replay functions
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
#pragma once
|
||||
#include <AreaEffectSimulation/aes_record_replay_plugin.h>
|
||||
#include <AreaEffectSimulation/aes_dts.h>
|
||||
// fixup include path on 42.3 -> missing interface
|
||||
#include <../../Common/PluginInterfaces/record_replay_plugin.h>
|
||||
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class AESRECORDREPLAYPLUGIN_EXPORT RecordReplayPluginCustom final : public RecordReplayPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "special:3:recordreplay.aes")
|
||||
Q_INTERFACES(RecordReplay::RecordReplayPlugin)
|
||||
|
||||
public:
|
||||
RecordReplayPluginCustom();
|
||||
~RecordReplayPluginCustom();
|
||||
|
||||
bool initDts(const std::shared_ptr<DDSConnector::DdsConnector> &ddsConnector,
|
||||
int exerciseId,
|
||||
bool bCanHandleSchemas,
|
||||
NSqlQuery &query) override;
|
||||
bool setReplayStartTime(NSqlQuery &q, qint64 startTime) override;
|
||||
bool ddsTopicsFromDatabase(NSqlQuery &q, qint64 fromTime, qint64 toTime) override;
|
||||
bool publishData(qint64 desiredTime) override;
|
||||
bool waitForAsyncOperations(qint64 desiredTime) override;
|
||||
void clearData() override;
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
void removeOld(QMultiMap<long long int , T> &map, qint64 desiredTime);
|
||||
|
||||
|
||||
private:
|
||||
std::shared_ptr<AreaEffectSimulation::Interface::Dts> m_ddsDts;
|
||||
qint64 m_currentReplayTime;
|
||||
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,38 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
NGL_ADD_LIBRARY2(WS SV HLA Trajectory SHARED
|
||||
trajectory_generator.cpp
|
||||
trajectory_generator.h
|
||||
trajectory_helper.cpp
|
||||
trajectory_helper.h
|
||||
trajectory_generator_vulcano.cpp
|
||||
trajectory_generator_vulcano.h
|
||||
trajectory_point.h
|
||||
trajectory_transform.cpp
|
||||
trajectory_transform.h
|
||||
../logger.cpp
|
||||
../logger.h
|
||||
)
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES(Trajectory
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
)
|
||||
NGL_TARGET_LINK_LIBRARIES(Trajectory
|
||||
PRIVATE
|
||||
NGLLogger
|
||||
AsmDataPluginInterface
|
||||
ExmDataPluginInterface
|
||||
PUBLIC
|
||||
LtsElevation
|
||||
LtsUtilsCore
|
||||
LtsCoordTrans
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
)
|
||||
|
||||
ADD_SUBDIRECTORY(UnitTest_Trajectory)
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(LinkedSources
|
||||
log4cxxTrajectoryUnitTest.props
|
||||
)
|
||||
|
||||
SET(UnitTestSources
|
||||
trajectory_unit_test.cpp
|
||||
trajectory_unit_test.h
|
||||
)
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
ADD_EXECUTABLE(aesUnitTestTrajectory ${LinkedSources} ${UnitTestSources} )
|
||||
|
||||
TARGET_LINK_LIBRARIES(aesUnitTestTrajectory
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
svcAesCommon
|
||||
Qt5::Core
|
||||
Qt5::Gui
|
||||
Qt5::Test)
|
||||
|
||||
ADD_TEST(NAME aesUnitTestTrajectory COMMAND $<TARGET_FILE:aesUnitTestTrajectory>)
|
||||
|
||||
SET(LOG4CXX_PROPS_FILE log4cxxTrajectoryUnitTest.props)
|
||||
ADD_CUSTOM_COMMAND(TARGET aesUnitTestTrajectory POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${LOG4CXX_PROPS_FILE} $<TARGET_FILE_DIR:aesUnitTestTrajectory>/${LOG4CXX_PROPS_FILE}
|
||||
)
|
||||
|
||||
ENDIF()
|
||||
Executable
+129
@@ -0,0 +1,129 @@
|
||||
log4j.reset=true
|
||||
log4j.rootLogger=INFO, file, stdout
|
||||
|
||||
# SituationMap
|
||||
###########################################################
|
||||
#log4j.logger.SituationMap.SitMapUnitTest=DEBUG
|
||||
#log4j.logger.SituationMap.SitMap=WARN
|
||||
|
||||
log4j.logger.SituationMap.LoggingTest=ERROR
|
||||
log4j.logger.SituationMap.LoggingTest.Chan1=INFO
|
||||
log4j.logger.SituationMap.LoggingTest.Chan2=ERROR
|
||||
|
||||
#log4j.logger.SituationMap.MapImpl=WARN
|
||||
#log4j.logger.SituationMap.LayerFactoryImpl=INFO
|
||||
#log4j.logger.SituationMap.CoordTranslationFunctorImpl=INFO
|
||||
#log4j.logger.SituationMap.GridImpl=WARN
|
||||
#log4j.logger.SituationMap.ObjectFactory=WARN
|
||||
#log4j.logger.SituationMap.IdGenerator=TRACE
|
||||
#log4j.logger.SituationMap.ObjectContainer=TRACE
|
||||
#log4j.logger.SituationMap.ObjectContainerCTC=TRACE
|
||||
#log4j.logger.SituationMap.ViewshedImpl=INFO
|
||||
#log4j.logger.SituationMap.ViewshedBase=INFO
|
||||
#log4j.logger.SituationMap.SymbolDictionary=WARN
|
||||
#log4j.logger.SituationMap.SymbolDictionaryImpl=WARN
|
||||
#log4j.logger.SituationMap.Sidc2525Delta=WARN
|
||||
|
||||
#log4j.logger.SituationMap.AbstractMapObjectImpl=INFO
|
||||
#log4j.logger.SituationMap.AbstractEffectSimulationImpl=INFO
|
||||
#log4j.logger.SituationMap.OriginTranslated=INFO
|
||||
#log4j.logger.SituationMap.PositionsTranslated=INFO
|
||||
#log4j.logger.SituationMap.AbstractMultiPointMapObjectImpl=INFO
|
||||
#log4j.logger.SituationMap.AbstractSinglePointMapObjectImpl=INFO
|
||||
#log4j.logger.SituationMap.BasicPathObjectImpl=INFO
|
||||
#log4j.logger.SituationMap.IndicationContainer=INFO
|
||||
|
||||
#log4j.logger.SituationMap.AreaFireImpl=INFO
|
||||
#log4j.logger.SituationMap.BiologicalAgentImpl=INFO
|
||||
#log4j.logger.SituationMap.BuildingOutlineImpl=INFO
|
||||
#log4j.logger.SituationMap.ChemicalAgentImpl=INFO
|
||||
#log4j.logger.SituationMap.DangerAreaImpl=INFO
|
||||
#log4j.logger.SituationMap.FunctionalAreaImpl=INFO
|
||||
#log4j.logger.SituationMap.HitLineImpl=INFO
|
||||
#log4j.logger.SituationMap.MineImpl=INFO
|
||||
#log4j.logger.SituationMap.NuclearAgentImpl=INFO
|
||||
#log4j.logger.SituationMap.ParticipantImpl=INFO
|
||||
#log4j.logger.SituationMap.SingleFireImpl=INFO
|
||||
|
||||
#log4j.logger.SituationMap.AbstractGraphicalObject=WARN
|
||||
#log4j.logger.SituationMap.GraphicalObjectEllipse=WARN
|
||||
#log4j.logger.SituationMap.GraphicalObjectPath=WARN
|
||||
#log4j.logger.SituationMap.GraphicalObjectMultiPath=WARN
|
||||
#log4j.logger.SituationMap.GraphicalObjectPictureMarker=WARN
|
||||
#log4j.logger.SituationMap.GraphicalObjectText=WARN
|
||||
#log4j.logger.SituationMap.TacticalAppearance=INFO
|
||||
#log4j.logger.SituationMap.MessageBase=INFO
|
||||
|
||||
|
||||
# Appnd_File
|
||||
###########################################################
|
||||
log4j.appender.file=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.file.MaxFileSize=1MB
|
||||
log4j.appender.file.MaxBackupIndex=9
|
||||
log4j.appender.file.file=${LOG4QT_LOGDIR}/${LOG4QT_USER}_SituationMap.log
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern=%d %-5p %c |#| %m (%.50F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Console
|
||||
###########################################################
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern= %d %-5p %c{1} |#| %m (%-.30F:%L) %n
|
||||
|
||||
#log4j.appender.stdout.layout.ConversionPattern= %d %-5p %-30c |#| %m (%-.30F:%L) %n
|
||||
|
||||
|
||||
# Appnd_Syslog
|
||||
###########################################################
|
||||
log4j.appender.syslog=org.apache.log4j.SyslogAppender
|
||||
log4j.appender.syslog.Threshold=ERROR
|
||||
log4j.appender.syslog.SysLogHost=localhost
|
||||
log4j.appender.syslog.Facility=LOCAL7
|
||||
log4j.appender.syslog.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.syslog.layout.ConversionPattern= %-4r %-5p %c %x - %m
|
||||
log4j.appender.syslog.LevelRangeFilter.AcceptOnMatch=true
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMin=INFO
|
||||
log4j.appender.syslog.LevelRangeFilter.LevelMax=FATAL
|
||||
|
||||
|
||||
###########################################################
|
||||
###########################################################
|
||||
###########################################################
|
||||
# 1) Available Levels in LOG4CXX Version 0.10.0:
|
||||
# TRACE,
|
||||
# DEBUG,
|
||||
# INFO,
|
||||
# WARN,
|
||||
# ERROR
|
||||
# FATAL
|
||||
#
|
||||
# d = date/time
|
||||
# p = priority (Level)
|
||||
# c = category/channel
|
||||
# m = message
|
||||
# F = file
|
||||
# L = line
|
||||
# n = platform dependent line separator character or characters.
|
||||
# ....
|
||||
#
|
||||
# Examples for console:
|
||||
# a)
|
||||
# %d %p %c #%m# (%.50F:%L)%n
|
||||
# date/time
|
||||
# priority
|
||||
# category/channel
|
||||
# #message#
|
||||
# (Maximal 50Character des Filename von rechts:Line)
|
||||
# line separator
|
||||
#
|
||||
# b)
|
||||
# %d (%.15F:%L) %-5p %c |#| %m%n
|
||||
# date/time
|
||||
# (Maximal 15Character des Filename von rechts:Line)
|
||||
# priority, Right pad with spaces if the priority name is less than 5 characters long.
|
||||
# category/channel
|
||||
# message
|
||||
# line separator
|
||||
#
|
||||
|
||||
Executable
+1009
File diff suppressed because it is too large.
Load diff
+83
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Unittest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QtTest/QTest>
|
||||
#include <NGLLogger/INGLLogger.h>
|
||||
|
||||
using LOGGER_T = NGL::INGLLogger&;
|
||||
|
||||
|
||||
class UnitTestTrajectory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UnitTestTrajectory();
|
||||
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
// void init();
|
||||
|
||||
|
||||
void test_copy_long_vector();
|
||||
|
||||
void test_duration();
|
||||
void test_calcDuration();
|
||||
void test_calcDuration2();
|
||||
|
||||
void test_calcPeak();
|
||||
void test_calcPeak2();
|
||||
|
||||
void test_calcPeak3_continuity();
|
||||
|
||||
void test_calcTimeToPeakAndBack();
|
||||
|
||||
void test_calcDuration_realistic40km();
|
||||
|
||||
void test_calcDuration_differentDistances();
|
||||
|
||||
void test_calcDuration_downToZero();
|
||||
|
||||
// for context AirSupport:
|
||||
void test_realStartPoint_data();
|
||||
void test_realStartPoint();
|
||||
|
||||
// generateTrajectoryBiedziak
|
||||
void test_generateTrajectoryBiedziak();
|
||||
|
||||
|
||||
// Vulcano:
|
||||
void test_vulcano_beta_Abschusswinkel();
|
||||
void test_vulcano_apogaeumCosmos();
|
||||
|
||||
void test_vulcano_apogaeum_data();
|
||||
void test_vulcano_apogaeum();
|
||||
|
||||
void test_vulcano_apogaeumStrich_data();
|
||||
void test_vulcano_apogaeumStrich();
|
||||
|
||||
void test_vulcano_tap_data();
|
||||
void test_vulcano_tap();
|
||||
|
||||
void test_vulcano_ballisticCurve_data();
|
||||
void test_vulcano_ballisticCurve();
|
||||
|
||||
void test_vulcano_trajectory_data();
|
||||
void test_vulcano_trajectory();
|
||||
|
||||
// void cleanup();
|
||||
|
||||
private:
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,383 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* LTS - logging facility
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, SLTE, 2023-11-08
|
||||
*/
|
||||
|
||||
#include "trajectory_generator.h"
|
||||
#include "trajectory_generator_vulcano.h"
|
||||
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
|
||||
#include <Plugins/AssetManagement/asm_data_plugin_interface.h>
|
||||
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
|
||||
#ifdef NEVER // for csv file
|
||||
# include <QFile>
|
||||
# include <QDateTime>
|
||||
# include <QTextStream>
|
||||
#endif // NEVER
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
static TrajectoryGenerator *s_trajectoryGenerator = nullptr;
|
||||
|
||||
|
||||
TrajectoryGenerator::TrajectoryGenerator()
|
||||
: m_logger(getLogger(QStringLiteral("TrajectoryGenerator")))
|
||||
{
|
||||
}
|
||||
|
||||
TrajectoryGenerator *TrajectoryGenerator::getInstance(int exerciseId,
|
||||
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc)
|
||||
{
|
||||
// Be aware: ONE TrajectoryGenerator per process, not per exercise
|
||||
// That feature has to be added!
|
||||
// In that case, have a look at LtsElevationManager::createInstance() and createInstanceForTrainingAreaId()
|
||||
|
||||
if (!s_trajectoryGenerator)
|
||||
{
|
||||
LOGGER_T logger = getLogger(QStringLiteral("TrajectoryGenerator"));
|
||||
|
||||
s_trajectoryGenerator = new TrajectoryGenerator();
|
||||
qAddPostRoutine(&TrajectoryGenerator::cleanup);
|
||||
|
||||
// assign LtsElevationManager:
|
||||
LtsElevation::LTS_ELEVATION_MANAGER_TYPE ltsElevationManager = LtsElevation::LtsElevationManager::createInstance(exerciseId, exmDtc, asmDtc);
|
||||
#ifndef LTS_DEBUG
|
||||
Q_ASSERT_X(ltsElevationManager, "LtsElevationManager", "createInstance failed");
|
||||
#endif // LTS_DEBUG
|
||||
|
||||
if (ltsElevationManager)
|
||||
{
|
||||
ltsElevationManager->waitForInitialization();
|
||||
DEBUG_LOG(logger) << LOGFUNCTION << ", ltsElevationManager->waitForInitialization() ... DONE, isValid = " << ltsElevationManager->isValid();
|
||||
}
|
||||
s_trajectoryGenerator->initElevation(ltsElevationManager);
|
||||
}
|
||||
return s_trajectoryGenerator;
|
||||
}
|
||||
|
||||
TrajectoryGenerator *TrajectoryGenerator::getInstance()
|
||||
{
|
||||
if (!s_trajectoryGenerator)
|
||||
{
|
||||
s_trajectoryGenerator = new TrajectoryGenerator();
|
||||
qAddPostRoutine(&TrajectoryGenerator::cleanup);
|
||||
}
|
||||
return s_trajectoryGenerator;
|
||||
}
|
||||
|
||||
void TrajectoryGenerator::cleanup()
|
||||
{
|
||||
delete s_trajectoryGenerator;
|
||||
}
|
||||
|
||||
void TrajectoryGenerator::initElevation(LtsElevation::LtsElevationManager *ltsElevationManager)
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
m_ltsElevationManager = ltsElevationManager;
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
}
|
||||
|
||||
LtsElevation::LtsElevationManager *TrajectoryGenerator::getElevationManager()
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
return m_ltsElevationManager;
|
||||
}
|
||||
|
||||
bool TrajectoryGenerator::hasElevationManager() const
|
||||
{
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
|
||||
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
|
||||
return m_ltsElevationManager;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Ideal ballistic curve, but with time values:
|
||||
bool TrajectoryGenerator::generateTrajectoryBiedziak(const LtsUtils::QPoint3D &originatorPosition_geo,
|
||||
const LtsUtils::QPoint3D &idealHit_geo,
|
||||
double elevation_angle_degree,
|
||||
TrajectoryGeoPosition &trajectoryOut)
|
||||
{
|
||||
return generateTrajectoryBiedziak<std::vector<Core::GeoPosition>>(originatorPosition_geo,
|
||||
idealHit_geo,
|
||||
elevation_angle_degree,
|
||||
trajectoryOut);
|
||||
}
|
||||
|
||||
//
|
||||
// Vulcano
|
||||
//
|
||||
bool TrajectoryGenerator::generateTrajectoryVulcano(const QPoint3D &originatorPosition_geo, const QPoint3D &idealHit_geo,
|
||||
double v0, double betaRad,
|
||||
double alphaRad, double tapTimeSec,
|
||||
TrajectoryGeneratorVulcano::Options options,
|
||||
TrajectoryGeoPositionRelTime &trajectoryTimeAwareOut,
|
||||
Core::GeoPosition &idealTapAbsoluteGeoOut,
|
||||
QString *reasonOut)
|
||||
{
|
||||
LOGGER_T logger = getLogger(QStringLiteral("TrajectoryGenerator"));
|
||||
|
||||
// use zone of idealHit:
|
||||
INFO_LOG(logger) << " orgPos geo " << originatorPosition_geo;
|
||||
INFO_LOG(logger) << " iHPos geo " << idealHit_geo;
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate &idealHitUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(idealHit_geo.toPointF());
|
||||
const LtsCoordTrans::UtmCoordinate &originUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(originatorPosition_geo.toPointF(), idealHitUtm.zone);
|
||||
INFO_LOG(logger) << " originUtm " << originUtm.mgrs();
|
||||
INFO_LOG(logger) << " idealHitUtm " << idealHitUtm.mgrs();
|
||||
|
||||
|
||||
TRAJECTORY_METRIC trajectoryMetricOut;
|
||||
|
||||
const QPoint3D origin_metric (originUtm.x, originUtm.y, originatorPosition_geo.z());
|
||||
const QPoint3D idealHit_metric(idealHitUtm.x, idealHitUtm.y, idealHit_geo.z());
|
||||
|
||||
double vGlidingOut = 1;
|
||||
double vFallingOut = 1;
|
||||
TrajectoryGeneratorVulcano::getSpeedPerPhase(v0, betaRad, vGlidingOut, vFallingOut);
|
||||
|
||||
QString localReasonOut;
|
||||
|
||||
QPoint3D idealTapAbsoluteOut;
|
||||
|
||||
const bool success =
|
||||
TrajectoryGeneratorVulcano::trajectoryVulcano(origin_metric, idealHit_metric,
|
||||
v0, betaRad,
|
||||
vGlidingOut,
|
||||
vFallingOut, alphaRad, tapTimeSec,
|
||||
options,
|
||||
trajectoryMetricOut,
|
||||
idealTapAbsoluteOut,
|
||||
&localReasonOut);
|
||||
|
||||
if (!localReasonOut.isEmpty())
|
||||
WARNING_LOG(logger) << " trajectoryVulcano failed, reasonOut = '" << localReasonOut << "'";
|
||||
|
||||
//
|
||||
// for documentation, it may be helpful to write the trajectoryMetric to a csv file
|
||||
//
|
||||
|
||||
#ifdef NEVER
|
||||
{
|
||||
static QString filePath(QStringLiteral("/tmp/trajectory_dump.csv"));
|
||||
QFile data(filePath);
|
||||
QTextStream output(&data);
|
||||
|
||||
if (data.open(QFile::WriteOnly | QIODevice::Append |QFile::Truncate))
|
||||
{
|
||||
output.setRealNumberPrecision(3);
|
||||
output.setRealNumberNotation(QTextStream::RealNumberNotation::FixedNotation);
|
||||
|
||||
output << "TrajectoryVulcano at: " << QDateTime::currentDateTime().toString(QStringLiteral("yyyy.MM.dd hh:mm::ss")) << "\n";
|
||||
output << "v0: " << v0 << "\n";
|
||||
output << "betaDeg: " << betaRad*LtsCoordTrans::rad2deg() << "\n";
|
||||
output << "vGlidingOut: " << vGlidingOut << "\n";
|
||||
output << "vFallingOut: " << vFallingOut << "\n";
|
||||
output << "alphaDeg: " << alphaRad*LtsCoordTrans::rad2deg() << "\n";
|
||||
output << "tapTimeSec: " << tapTimeSec << "\n";
|
||||
|
||||
const double distance = (origin_metric - idealHit_metric).length();
|
||||
output << "distance: " << distance << "\n";
|
||||
|
||||
|
||||
output << "x_rel ; y_rel ; z ; relativeTime" << "\n";
|
||||
|
||||
if (!trajectoryMetricOut.isEmpty())
|
||||
{
|
||||
QPoint4D startPoint = trajectoryMetricOut.first();
|
||||
|
||||
for (const QPoint4D &p4D : qAsConst(trajectoryMetricOut))
|
||||
{
|
||||
output << p4D.x() - startPoint.x() << ";"
|
||||
<< p4D.y() - startPoint.y() << ";"
|
||||
<< p4D.z() << ";"
|
||||
<< p4D.time() << ";"
|
||||
<< "\n";
|
||||
} // for
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif // NEVER
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
// convert metric to geo/wgs84
|
||||
{
|
||||
LtsCoordTrans::UtmCoordinate tapUtm(idealHitUtm.zone, idealTapAbsoluteOut.x(), idealTapAbsoluteOut.y());
|
||||
const QPointF &tapGeo = tapUtm.geographic();
|
||||
idealTapAbsoluteGeoOut = Core::GeoPosition(tapGeo.x(), tapGeo.y(), idealTapAbsoluteOut.z());
|
||||
}
|
||||
|
||||
|
||||
trajectoryTimeAwareOut.clear();
|
||||
trajectoryTimeAwareOut.reserve(trajectoryMetricOut.size());
|
||||
|
||||
for (const QPoint4D& pnt4d : qAsConst(trajectoryMetricOut))
|
||||
{
|
||||
LtsCoordTrans::UtmCoordinate pntUtm(idealHitUtm.zone, pnt4d.x(), pnt4d.y());
|
||||
const QPointF &pntGeo = pntUtm.geographic();
|
||||
|
||||
// !!! relativeTime is in msec!!!
|
||||
trajectoryTimeAwareOut.emplace_back( Core::GeoPositionRelativeTime(pntGeo.x(), pntGeo.y(), pnt4d.z(), pnt4d.time()*1000.0) );
|
||||
}
|
||||
|
||||
|
||||
if (reasonOut)
|
||||
*reasonOut = localReasonOut;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// real implementation
|
||||
//
|
||||
|
||||
|
||||
inline void addItemTo(std::vector<Core::GeoPosition> &cont,
|
||||
double x, double y, double z)
|
||||
{
|
||||
cont.emplace_back(Core::GeoPosition(x, y, z));
|
||||
}
|
||||
|
||||
|
||||
template<typename CONT_T>
|
||||
bool TrajectoryGenerator::generateTrajectoryBiedziak(const LtsUtils::QPoint3D &originatorPosition_geo,
|
||||
const LtsUtils::QPoint3D &impactPosition_geo,
|
||||
double elevation_angle_degree,
|
||||
CONT_T &trajectoryOut)
|
||||
{
|
||||
// use zone of impact:
|
||||
INFO_LOG(m_logger) << " oPosition geo " << originatorPosition_geo.x() << " - " << originatorPosition_geo.y();
|
||||
INFO_LOG(m_logger) << " iPosition geo " << impactPosition_geo.x() << " - " << impactPosition_geo.y();
|
||||
|
||||
const LtsCoordTrans::UtmCoordinate &iPosition = LtsCoordTrans::UtmCoordinate::fromGeographic(impactPosition_geo.toPointF());
|
||||
const LtsCoordTrans::UtmCoordinate &oPosition = LtsCoordTrans::UtmCoordinate::fromGeographic(originatorPosition_geo.toPointF(), iPosition.zone);
|
||||
|
||||
INFO_LOG(m_logger) << " oPosition " << oPosition.mgrs();
|
||||
INFO_LOG(m_logger) << " iPosition " << iPosition.mgrs();
|
||||
|
||||
const double distance = sqrt(pow(iPosition.x - oPosition.x, 2.) + pow(iPosition.y - oPosition.y, 2.));
|
||||
|
||||
double oHeight = originatorPosition_geo.z();
|
||||
double iHeight = impactPosition_geo.z();
|
||||
|
||||
if (std::isnan(oHeight) && m_ltsElevationManager)
|
||||
{
|
||||
oHeight = m_ltsElevationManager ? m_ltsElevationManager->elevation(originatorPosition_geo.x(), originatorPosition_geo.y()) : 0;
|
||||
if (oHeight < 300)
|
||||
oHeight = 100;
|
||||
INFO_LOG(m_logger) << " oPosition " << oPosition << " has no zValue provided (NaN), update via ltsElevationManager...";
|
||||
}
|
||||
if (std::isnan(iHeight) && m_ltsElevationManager)
|
||||
{
|
||||
iHeight = m_ltsElevationManager ? m_ltsElevationManager->elevation(impactPosition_geo.x(), impactPosition_geo.y()) : 0;
|
||||
if (iHeight < 300)
|
||||
iHeight = 100;
|
||||
INFO_LOG(m_logger) << " iPosition " << iPosition << " has no zValue provided (NaN), update via ltsElevationManager.. ";
|
||||
}
|
||||
|
||||
INFO_LOG(m_logger) << " oPosition " << oPosition << " ; oHeight=" << oHeight;
|
||||
INFO_LOG(m_logger) << " iPosition " << iPosition << " ; iHeight=" << iHeight;
|
||||
|
||||
// z-Values:
|
||||
const QVector<double> &zValues = this->trajectoryBiedziak(distance, iHeight - oHeight, elevation_angle_degree);
|
||||
|
||||
if (zValues.isEmpty())
|
||||
return false;
|
||||
|
||||
trajectoryOut.clear();
|
||||
|
||||
|
||||
const QPointF &oPositionGeo = oPosition.geographic();
|
||||
|
||||
addItemTo(trajectoryOut,
|
||||
oPositionGeo.x(), oPositionGeo.y(), oHeight);
|
||||
|
||||
const QPointF &step = (QPointF(iPosition.x, iPosition.y) - QPointF(oPosition.x, oPosition.y)) / (zValues.size() - 1);
|
||||
QPointF runner;
|
||||
for (int i = 1; i < zValues.size(); ++i)
|
||||
{
|
||||
runner += step;
|
||||
const QPointF &p2D = oPosition.geographic(runner);
|
||||
addItemTo(trajectoryOut,
|
||||
p2D.x(), p2D.y(), oHeight + zValues[i]); // x, y, z
|
||||
} // for
|
||||
|
||||
//// DEBUG_LOG(m_logger) << string4poly(geo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QVector<double> TrajectoryGenerator::trajectoryBiedziak(const double &distance,
|
||||
const double &heightOffset,
|
||||
double elevation_angle_degree,
|
||||
int steps)
|
||||
{
|
||||
const double coefLinear = tan(elevation_angle_degree * LtsCoordTrans::deg2rad());
|
||||
const double coefSquare = (heightOffset - distance * coefLinear) / pow(distance, 2.0);
|
||||
const double delta = distance / steps;
|
||||
|
||||
double x = 0.;
|
||||
QVector<double> yValues; // later interpreted as z-Values
|
||||
yValues.reserve(steps);
|
||||
yValues << 0.0;
|
||||
for (int i = 0; i < steps; ++i)
|
||||
{
|
||||
x += delta;
|
||||
yValues << (coefLinear * x + coefSquare * pow(x, 2.));
|
||||
} // for
|
||||
return yValues;
|
||||
}
|
||||
|
||||
const QString TrajectoryGenerator::string4poly(const QPair<QPolygonF, QVector<double> > &pair)
|
||||
{
|
||||
if (pair.first.isEmpty())
|
||||
return (QStringLiteral("Empty Polygon!"));
|
||||
int zone = LtsCoordTrans::UtmCoordinate::fromGeographic(pair.first[0]).zone;
|
||||
QStringList pointSl;
|
||||
pointSl.reserve(pair.first.size());
|
||||
for (int i = 0; i < pair.first.size(); ++i)
|
||||
pointSl << QString(QStringLiteral("utm=%1 h=%2")).arg(LtsCoordTrans::UtmCoordinate::fromGeographic(pair.first[i], zone).mgrs(), QString::number(pair.second[i], 'f', 1));
|
||||
return QStringLiteral("%1 Values (%2)").arg(pair.first.count()).arg(pointSl.join(QStringLiteral(" # ")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//const QString TrajectoryGenerator::string4poly(const TrajectoryPoint3D &trajectory)
|
||||
//{
|
||||
// if (trajectory.isEmpty())
|
||||
// return (QStringLiteral("Empty Polygon!"));
|
||||
|
||||
// const Point3D &p3D = trajectory.first();
|
||||
// int zone = LtsCoordTrans::UtmCoordinate::fromGeographic(p3D.toPointF()).zone;
|
||||
// QStringList pointSl;
|
||||
// pointSl.reserve(trajectory.size());
|
||||
// for (int i = 0; i < trajectory.size(); ++i)
|
||||
// pointSl << QString(QStringLiteral("utm=%1 h=%2")).arg(LtsCoordTrans::UtmCoordinate::fromGeographic(p3D.toPointF(), zone).mgrs(), QString::number(p3D.z(), 'f', 1));
|
||||
// return QStringLiteral("%1 Values (%2)").arg(trajectory.count()).arg(pointSl.join(QStringLiteral(" # ")));
|
||||
//}
|
||||
|
||||
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* TrajectoryGenerator
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, SLTE, 2023-11-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../logger.h"
|
||||
#include "trajectory_generator_vulcano.h"
|
||||
#include <Core/core.hpp> // Lts/DDS/Core/core.hpp for Core::GeoPosition
|
||||
#include <LtsElevation/lts_elevation_manager.h>
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
#include <Trajectory/trajectory_export.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QPolygonF>
|
||||
|
||||
#include <vector>
|
||||
|
||||
// forward
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
} // namespace ExerciseManagement
|
||||
|
||||
namespace AssetManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
} // namespace AssetManagement
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// version 1
|
||||
using TrajectoryGeoPosition = std::vector<Core::GeoPosition>;
|
||||
// version 2
|
||||
using TrajectoryGeoPositionRelTime = std::vector<Core::GeoPositionRelativeTime>;
|
||||
|
||||
using QPoint3D = LtsUtils::QPoint3D;
|
||||
|
||||
//
|
||||
// class TrajectoryGenerator
|
||||
//
|
||||
class TRAJECTORY_EXPORT TrajectoryGenerator : public QObject
|
||||
{
|
||||
public:
|
||||
/*QT_DEPRECATED*/ static TrajectoryGenerator *getInstance(int exerciseId,
|
||||
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
||||
const std::shared_ptr<AssetManagement::Interface::Dtc> &asmDtc);
|
||||
|
||||
static TrajectoryGenerator *getInstance();
|
||||
|
||||
static void cleanup();
|
||||
|
||||
void initElevation(LtsElevation::LtsElevationManager *ltsElevationManager);
|
||||
LtsElevation::LtsElevationManager *getElevationManager();
|
||||
bool hasElevationManager() const;
|
||||
|
||||
~TrajectoryGenerator() = default;
|
||||
|
||||
/*! \name Ideal trajectory using Core::GeoPosition at return trajectory ... */
|
||||
//@{
|
||||
bool generateTrajectoryBiedziak(const LtsUtils::QPoint3D &originatorPosition_geo,
|
||||
const LtsUtils::QPoint3D &idealHit_geo,
|
||||
double elevation_angle_degree, // aka beta
|
||||
TrajectoryGeoPosition &trajectoryOut);
|
||||
//@}
|
||||
|
||||
static bool generateTrajectoryVulcano(const QPoint3D &originatorPosition_geo,
|
||||
const QPoint3D &idealHit_geo,
|
||||
double v0,
|
||||
double betaRad, // Abschussgeschwindigkeit, -winkel ( betaRad ~ elevation_angle_degree
|
||||
double alphaRad,
|
||||
double tapTimeSec, // Fallwinkel, -geschwindigkeit, -zeit
|
||||
TrajectoryGeneratorVulcano::Options options,
|
||||
TrajectoryGeoPositionRelTime &trajectoryTimeAwareOut,
|
||||
Core::GeoPosition &idealTapAbsoluteGeoOut,
|
||||
QString *reasonOut);
|
||||
|
||||
protected:
|
||||
/*! \name Ideal trajectory */
|
||||
template <typename CONT_T>
|
||||
bool generateTrajectoryBiedziak(const LtsUtils::QPoint3D &originatorPosition_geo,
|
||||
const LtsUtils::QPoint3D &impactPosition_geo,
|
||||
double elevation_angle_degree,
|
||||
CONT_T &trajectoryOut);
|
||||
|
||||
protected:
|
||||
explicit TrajectoryGenerator();
|
||||
|
||||
public:
|
||||
// For UnitTest:
|
||||
friend class UnitTestTrajectoryHelper;
|
||||
|
||||
// calculate the z-Values of the trajectory:
|
||||
static QVector<double> trajectoryBiedziak(const double &distance, const double &heightOffset, double elevation_angle_degree, int steps = 72);
|
||||
|
||||
static const QString string4poly(const QPair<QPolygonF, QVector<double>> &pair);
|
||||
|
||||
LtsElevation::LtsElevationManager *m_ltsElevationManager{nullptr};
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
+676
@@ -0,0 +1,676 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* LTS - logging facility
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, SLTE, 2023-11-08
|
||||
*/
|
||||
|
||||
#include "trajectory_generator_vulcano.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointF>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
//#define G 9.80665
|
||||
#define G 9.81
|
||||
|
||||
inline void addItemLocal(TRAJECTORY_METRIC &trajectoryRef, const QPoint3D &point, double time = 0.0)
|
||||
{
|
||||
trajectoryRef.push_back(QPoint4D(point.x(), point.y(), point.z(), time));
|
||||
}
|
||||
|
||||
|
||||
LOGGER_T getLocalLogger()
|
||||
{
|
||||
return getLogger(QStringLiteral("TrajectoryGeneratorVulcano"));
|
||||
}
|
||||
|
||||
|
||||
bool TrajectoryGeneratorVulcano::trajectoryVulcano(const QPoint3D &origin, const QPoint3D &idealHit,
|
||||
double v0, double betaRad,
|
||||
double vGliding,
|
||||
double vFalling, double alphaRad, double tapTimeSec,
|
||||
TrajectoryGeneratorVulcano::Options options,
|
||||
TRAJECTORY_METRIC &trajectoryOut,
|
||||
QPoint3D &idealTapAbsoluteOut,
|
||||
QString *reasonOut)
|
||||
{
|
||||
LOGGER_T logger = getLocalLogger();
|
||||
|
||||
DEBUG_LOG(logger) << LOGFUNCTION
|
||||
<< ", origin " << origin << ", idealHit " << idealHit
|
||||
<< ", v0=" << v0 << ", betaDeg=" << betaRad*LtsCoordTrans::rad2deg()
|
||||
<< ", vGliding=" << vGliding
|
||||
<< ", vFalling=" << vFalling << ", alphaDeg=" << alphaRad*LtsCoordTrans::rad2deg() << ", tapTimeSec=" << tapTimeSec
|
||||
<< ", options " << options;
|
||||
|
||||
idealTapAbsoluteOut = QPoint3D();
|
||||
|
||||
// OptRasterTapHit
|
||||
//
|
||||
// very simple check:
|
||||
//
|
||||
const QVector2D dist = QVector2D(idealHit.toPointF() - origin.toPointF());
|
||||
|
||||
if (dist.length() < 100)
|
||||
{
|
||||
|
||||
WARNING_LOG(logger) << LOGFUNCTION << ", dist is very small (100m)";
|
||||
|
||||
if (reasonOut)
|
||||
*reasonOut = QObject::tr("DistanceError(%1 > %2)").arg(dist.length()).arg(100);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (v0 < vFalling)
|
||||
{
|
||||
WARNING_LOG(logger) << LOGFUNCTION << ", v0 ist less than vFalling";
|
||||
|
||||
if (reasonOut)
|
||||
*reasonOut = QObject::tr("SpeedError(v0=%1 ; vF %2)").arg(v0).arg(vFalling);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// line between origin and idealHit:
|
||||
//
|
||||
const QVector2D &distHitAndOrigin = QVector2D(idealHit.toPointF() - origin.toPointF());
|
||||
const double length = distHitAndOrigin.length();
|
||||
|
||||
const double factorX = distHitAndOrigin.x() / length;
|
||||
const double factorY = distHitAndOrigin.y() / length;
|
||||
|
||||
|
||||
//
|
||||
// Apo
|
||||
//
|
||||
const QPointF &apo2D = XY::calculateApogaeum(v0, betaRad);
|
||||
|
||||
// translate from XY to XYZ
|
||||
QPoint3D apoAbs(apo2D.x() * factorX, // .x() !!
|
||||
apo2D.x() * factorY, // .x() !!
|
||||
apo2D.y());
|
||||
apoAbs += origin;
|
||||
|
||||
// check origin -> apo -> idealHit
|
||||
if (!checkSimple(origin, apoAbs, idealHit, reasonOut))
|
||||
{
|
||||
WARNING_LOG(logger) << LOGFUNCTION << ", checkOriginApoHit failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// TAP
|
||||
//
|
||||
// vFalling is maybe slightly smaller than v0;
|
||||
// tapTime is typically 8 sec
|
||||
const QPointF &tapRelToImpact = XY::calculateTapRelToIdealHit(vFalling, alphaRad, tapTimeSec);
|
||||
|
||||
// translate from XY to XYZ
|
||||
QPoint3D tapAbs(tapRelToImpact.x() * factorX, // .x() !!
|
||||
tapRelToImpact.x() * factorY, // .x() !!
|
||||
tapRelToImpact.y());
|
||||
tapAbs += idealHit;
|
||||
|
||||
// set out value:
|
||||
idealTapAbsoluteOut = tapAbs;
|
||||
|
||||
// check origin -> apo -> TAP - >idealHit
|
||||
if (!checkSimple(origin, apoAbs, tapAbs, idealHit, reasonOut))
|
||||
{
|
||||
WARNING_LOG(logger) << LOGFUNCTION << " checkOriginApoTapHit failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// raster phase 1 (ballistic curve)
|
||||
//
|
||||
// try to generate a value each second:
|
||||
//
|
||||
double x_distancePhase1 = apo2D.x(); // maybe move to Apo' in future (intersection between ballisitic curve an line to TAP)
|
||||
|
||||
// does not work: const double x_distancePhase1Strich = XY::calculateApogaeumStrichEval(origin.toPointF(), idealHit.toPointF(), v0, betaRad, tapAbs.toPointF());
|
||||
// so create temoporary originTemp, idealHitTemp: // ignoring the zValue
|
||||
// {
|
||||
// const QPointF originTemp;
|
||||
// const QPointF idealHitTemp(dist.length(), 0);
|
||||
// const QPointF tapTemp = idealHitTemp + tapRelToImpact;
|
||||
|
||||
// double x_distancePhase1Strich = XY::calculateApogaeumStrichEval(originTemp, idealHitTemp, v0, betaRad, tapTemp);
|
||||
|
||||
// ERROR_LOG(logger) << " x_distancePhase1a = " << x_distancePhase1;
|
||||
// ERROR_LOG(logger) << " x_distancePhase1b = " << x_distancePhase1Strich;
|
||||
|
||||
// if (!std::isnan(x_distancePhase1Strich) && (x_distancePhase1Strich > x_distancePhase1))
|
||||
// x_distancePhase1 = x_distancePhase1Strich;
|
||||
|
||||
// ERROR_LOG(logger) << " apo2D.x() = " << apo2D.x()
|
||||
// << ", x_distancePhase1Strich = " << x_distancePhase1Strich
|
||||
// << ", finally use: x_distancePhase1 = " << x_distancePhase1;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
const double secPerIntervall = 1;
|
||||
double x_delta_per_step_out = -1;
|
||||
double secPerIntervall_out = -1;
|
||||
const QVector<QPointF> &phase1_bal = XY::generateBallisticCurveUntil(v0, betaRad, x_distancePhase1, secPerIntervall,
|
||||
&x_delta_per_step_out, &secPerIntervall_out);
|
||||
|
||||
|
||||
|
||||
trajectoryOut.clear();
|
||||
trajectoryOut.reserve(phase1_bal.size()+5);
|
||||
|
||||
int cnt = 0;
|
||||
for (const QPointF &xyVertex : qAsConst(phase1_bal))
|
||||
{
|
||||
// translate from XY to XYZ
|
||||
const QPoint3D p3d_offset(xyVertex.x() * factorX, // xyVertex.x()
|
||||
xyVertex.x() * factorY, // xyVertex.x()
|
||||
xyVertex.y());
|
||||
// is relative to origin (gun)
|
||||
addItemLocal(trajectoryOut, p3d_offset+origin, (secPerIntervall_out*cnt));
|
||||
++cnt;
|
||||
} // for
|
||||
|
||||
|
||||
// ToDo: Check!!!
|
||||
|
||||
// const double distPhase1 = apo2D.x();
|
||||
// const double timeSpanForPhase1Sec = distPhase1 / v0 * cos(betaRad); // / xy-Anteil der Abschussgeschwindigkeit
|
||||
const double timeSpanForPhase1Sec = trajectoryOut.last().time();
|
||||
double timeSpanForPhase2Sec = -1;
|
||||
double timeSpanForPhase3Sec = -1;
|
||||
|
||||
INFO_LOG(logger) << "PHASE 1: generateBallisticCurveUntil: "
|
||||
<< ", phase1_bal.size() = " << phase1_bal.size()
|
||||
<< ", x_delta_per_step_out = " << x_delta_per_step_out
|
||||
<< ", secPerIntervall_out = " << secPerIntervall_out
|
||||
<< ", v0 * cos(betaRad) = " << v0 * cos(betaRad)
|
||||
<< ", timeSpanForPhase1Sec = " << timeSpanForPhase1Sec;
|
||||
|
||||
|
||||
//
|
||||
// add gliding phase / tap
|
||||
//
|
||||
|
||||
double timeOffset = 0;
|
||||
|
||||
const double distPhase2 = (apoAbs - tapAbs).length();
|
||||
timeSpanForPhase2Sec = distPhase2 / vGliding;
|
||||
INFO_LOG(logger) << " continue with PHASE 2"
|
||||
<< ", distPhase2 = " << distPhase2
|
||||
<< ", timeSpanForPhase2Sec = " << timeSpanForPhase2Sec;
|
||||
|
||||
// continue rastering?
|
||||
if (options.testFlag(Option::OptRasterApoTap))
|
||||
{
|
||||
// which kind of rastering?
|
||||
if (options.testFlag(Option::OptRasterMetrical))
|
||||
{
|
||||
// dist from APO (or APO') to TAP: ( apoAbs , tapAbs )
|
||||
double realDelta_xy_out = -1;
|
||||
rasterLineByDistance(apoAbs, tapAbs, x_delta_per_step_out, trajectoryOut, &realDelta_xy_out);
|
||||
DEBUG_LOG(logger) << " rastering was done for line ApoTap: realDelta_xy_out " << realDelta_xy_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we can use x_delta_per_step_out and or secPerIntervall_out
|
||||
double realDeltaTime_out = -1;
|
||||
rasterLineByTime(apoAbs, tapAbs,
|
||||
timeSpanForPhase1Sec, vGliding, 1,
|
||||
trajectoryOut, &realDeltaTime_out);
|
||||
|
||||
DEBUG_LOG(logger) << " rastering was done for line ApoTap: "
|
||||
<< ", distPhase2 =" << distPhase2
|
||||
<< ", timeSpanForPhase2Sec =" << timeSpanForPhase2Sec
|
||||
<< ", realDeltaTime_out " << realDeltaTime_out;
|
||||
}
|
||||
} else {
|
||||
// TabAbs has to be added in any case!!!
|
||||
addItemLocal(trajectoryOut, tapAbs, timeSpanForPhase1Sec + timeSpanForPhase2Sec);
|
||||
}
|
||||
|
||||
// prepare timeOffset for next phase:
|
||||
const QPoint4D &pnt4DRef = trajectoryOut.back();
|
||||
timeOffset = pnt4DRef.time();
|
||||
|
||||
//
|
||||
// add falling phase / idealHit
|
||||
//
|
||||
if (options.testFlag(Option::OptIncludeIdealHit))
|
||||
{
|
||||
const double distPhase3 = (idealHit - tapAbs).length();
|
||||
timeSpanForPhase3Sec = distPhase3 / vFalling;
|
||||
INFO_LOG(logger) << " continue with PHASE 3"
|
||||
<< ", distPhase3 = " << distPhase3
|
||||
<< ", timeSpanForPhase3Sec = " << timeSpanForPhase3Sec;
|
||||
|
||||
if (options.testFlag(Option::OptRasterTapHit))
|
||||
{
|
||||
// which kind of rastering?
|
||||
if (options.testFlag(Option::OptRasterMetrical))
|
||||
{
|
||||
// we can use x_delta_per_step_out and or secPerIntervall_out
|
||||
// dist from TAP to hit: ( tapAbs , idealHit )
|
||||
double realDelta_xy_out = -1;
|
||||
rasterLineByDistance(tapAbs, idealHit, x_delta_per_step_out, trajectoryOut, &realDelta_xy_out);
|
||||
DEBUG_LOG(logger) << " rastering was done for line TapHit: realDelta_xy_out " << realDelta_xy_out;
|
||||
} else {
|
||||
double realDeltaTime_out = -1;
|
||||
rasterLineByTime(tapAbs, idealHit,
|
||||
timeOffset, vFalling, 1,
|
||||
trajectoryOut, &realDeltaTime_out);
|
||||
|
||||
DEBUG_LOG(logger) << " rastering was done for line TapHit: realDeltaTime_out " << realDeltaTime_out
|
||||
<< ", distPhase3 = " << distPhase3
|
||||
<< ", vFalling = " << vFalling
|
||||
<< ", timeSpanForPhase3Sec = " << timeSpanForPhase3Sec;
|
||||
}
|
||||
} else {
|
||||
// simply add single point:
|
||||
addItemLocal(trajectoryOut, idealHit, timeSpanForPhase1Sec + timeSpanForPhase2Sec + timeSpanForPhase3Sec);
|
||||
}
|
||||
}
|
||||
|
||||
const double timeSpanComplete = timeSpanForPhase1Sec + timeSpanForPhase2Sec + timeSpanForPhase3Sec;
|
||||
const double diffTime = trajectoryOut.last().time() - timeSpanComplete;
|
||||
INFO_LOG(logger) << " rastering was done"
|
||||
<< ", timeSpanForPhase1Sec = " << timeSpanForPhase1Sec
|
||||
<< ", timeSpanForPhase2Sec = " << timeSpanForPhase2Sec
|
||||
<< ", timeSpanForPhase3Sec = " << timeSpanForPhase3Sec
|
||||
<< ", timeSpanComplete = " << timeSpanComplete
|
||||
<< " ### diffTime related to .last() = " << diffTime;
|
||||
|
||||
Q_ASSERT(diffTime < 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TrajectoryGeneratorVulcano::checkSimple(const QPoint3D &origin,
|
||||
const QPoint3D &apoAbs,
|
||||
const QPoint3D &idealHit,
|
||||
QString *reasonOut)
|
||||
{
|
||||
LOGGER_T logger = getLocalLogger();
|
||||
|
||||
DEBUG_LOG(logger) << ", origin = " << origin
|
||||
<< ", apoAbs = " << apoAbs
|
||||
<< ", idealHit = " << idealHit;
|
||||
|
||||
const QVector2D hitDist = QVector2D(idealHit.toPointF() - origin.toPointF());
|
||||
const QVector2D apoDist = QVector2D(apoAbs.toPointF() - origin.toPointF());
|
||||
|
||||
// apo dist must be less than the half of (idealHit-origin)
|
||||
if (apoDist.length() > (hitDist.length() / 2.0))
|
||||
{
|
||||
WARNING_LOG(logger) << LOGFUNCTION << ", apo dist must be less than the half of (idealHit-origin)"
|
||||
<< ", origin = " << origin
|
||||
<< ", apoAbs = " << apoAbs
|
||||
<< ", idealHit = " << idealHit
|
||||
<< ", apoDist.length() = " << apoDist.length()
|
||||
<< ", hitDist.length()/2 = " << hitDist.length()/2;
|
||||
if (reasonOut)
|
||||
*reasonOut = QObject::tr("DistanceError(apogaeumDistance=%1 = impactDistance/2=%2)").arg(apoDist.length()).arg((hitDist.length() / 2.0));
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(logger) << LOGFUNCTION << ", apo dist OKAY :-) the half of (idealHit-origin)"
|
||||
<< ", origin = " << origin
|
||||
<< ", apoAbs = " << apoAbs
|
||||
<< ", idealHit = " << idealHit
|
||||
<< ", apoDist.length() = " << apoDist.length()
|
||||
<< ", hitDist.length()/2 = " << hitDist.length()/2;
|
||||
|
||||
if (apoAbs.z() < idealHit.z())
|
||||
{
|
||||
ERROR_LOG(logger) << LOGFUNCTION << ", apoAbs.z() is less than idealHit.z()"
|
||||
<< "( apoAbs=" << apoAbs
|
||||
<< "; idealHit=" << idealHit << ")";
|
||||
if (reasonOut)
|
||||
*reasonOut = QObject::tr("HeigthError(apogaeum.z=%1 >= impact.z=%2)").arg(apoAbs.z()).arg(idealHit.z());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TrajectoryGeneratorVulcano::checkSimple(const QPoint3D &origin,
|
||||
const QPoint3D &apoAbs,
|
||||
const QPoint3D &tabAbs,
|
||||
const QPoint3D &idealHit, QString *reasonOut)
|
||||
{
|
||||
LOGGER_T logger = getLocalLogger();
|
||||
|
||||
DEBUG_LOG(logger) << LOGFUNCTION
|
||||
<< ", origin = " << origin
|
||||
<< ", apoAbs = " << apoAbs
|
||||
<< ", tabAbs = " << tabAbs
|
||||
<< ", idealHit = " << idealHit;
|
||||
|
||||
// apo dist must be less than the half of (idealHit-origin)
|
||||
if (apoAbs.z() < tabAbs.z())
|
||||
{
|
||||
WARNING_LOG(logger) << LOGFUNCTION << ", apo.z() dist must higher than tab.z()"
|
||||
<< "( apoAbs=" << apoAbs
|
||||
<< "; tabAbs=" << tabAbs << ")";
|
||||
if (reasonOut)
|
||||
*reasonOut = QObject::tr("HeigthError(apogaeum.z=%1 >= tap.z=%2)").arg(apoAbs.z()).arg(tabAbs.z());
|
||||
return false;
|
||||
}
|
||||
|
||||
// tabAbs must 'between' apo and idealHit;
|
||||
const QVector2D apoDist = QVector2D(apoAbs.toPointF() - origin.toPointF());
|
||||
const QVector2D tabDist = QVector2D(tabAbs.toPointF() - origin.toPointF());
|
||||
const QVector2D hitDist = QVector2D(idealHit.toPointF() - origin.toPointF());
|
||||
|
||||
if (tabDist.length() < apoDist.length())
|
||||
{
|
||||
WARNING_LOG(logger) << LOGFUNCTION << ", tab dist must be less than apo dist"
|
||||
<< "( apoAbs=" << apoAbs
|
||||
<< "; tabAbs=" << tabAbs
|
||||
<< "; idealHit=" << idealHit << ")";
|
||||
if (reasonOut)
|
||||
*reasonOut = QObject::tr("DistanceError(tabDist=%1 >= apoDist=%2)").arg(tabDist.length()).arg(apoDist.length());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hitDist.length() < tabDist.length())
|
||||
{
|
||||
WARNING_LOG(logger) << LOGFUNCTION << ", hitDist dist must be less than tabDist dist"
|
||||
<< "( apoAbs=" << apoAbs
|
||||
<< "; tabAbs=" << tabAbs
|
||||
<< "; idealHit=" << idealHit << ")";
|
||||
if (reasonOut)
|
||||
*reasonOut = QObject::tr("DistanceError(hitDist=%1 >= tabDist=%2)").arg(hitDist.length()).arg(tabDist.length());
|
||||
return false;
|
||||
}
|
||||
|
||||
INFO_LOG(logger) << LOGFUNCTION
|
||||
<< ", apoAbs=" << apoAbs
|
||||
<< ", tabAbs=" << tabAbs
|
||||
<< ", idealHit=" << idealHit;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TrajectoryGeneratorVulcano::getSpeedPerPhase(double v0_in, double betaRad,
|
||||
double &vGlidingOut, double &vFallingOut)
|
||||
{
|
||||
LOGGER_T logger = getLocalLogger();
|
||||
|
||||
Q_UNUSED(betaRad);
|
||||
|
||||
vGlidingOut = 700; // Gleitgeschwindigkeit
|
||||
vFallingOut = 375; // 3000m Höhe bei TapT=8 sec -> 375 m/s // Fallgeschwindigkeit
|
||||
|
||||
DEBUG_LOG(logger) << " v0_in " << v0_in
|
||||
<< ", betaDeg " << betaRad * LtsCoordTrans::rad2deg()
|
||||
<< ", vGlidingOut " << vGlidingOut << ", vFallingOut " << vFallingOut;
|
||||
}
|
||||
|
||||
void TrajectoryGeneratorVulcano::rasterLineByDistance(const QPoint3D &p0, const QPoint3D &p1,
|
||||
double desiredDelta_xy,
|
||||
TRAJECTORY_METRIC &trajectoryOut, double *realDelta_xy_out)
|
||||
{
|
||||
LOGGER_T logger = getLocalLogger();
|
||||
|
||||
// we can use x_delta_per_step_out and maybe secPerIntervall_out
|
||||
// dist from APO (or APO') to TAP: ( apoAbs , tapAbs )
|
||||
// DistXY:
|
||||
const double distMeter = QVector2D( p1.toPointF() - p0.toPointF() ).length();
|
||||
|
||||
const int steps = (distMeter/desiredDelta_xy); // implicit round
|
||||
const double realDelta_x = distMeter / steps;
|
||||
|
||||
DEBUG_LOG(logger) << LOGFUNCTION
|
||||
<< " desiredDelta_xy " << desiredDelta_xy
|
||||
<< ", distMeter " << distMeter
|
||||
<< ", steps " << steps
|
||||
<< ", realDelta_x " << realDelta_x;
|
||||
|
||||
// split 3dim Vector between both points according step:
|
||||
const QPoint3D &dist3D = p1 - p0; // keep in mind: tapAbs - apoAbs
|
||||
|
||||
// step by distance
|
||||
for (int i=1; i <= steps; ++i) // use 'i <= steps'
|
||||
{
|
||||
// try to avoid to much calculation, like:
|
||||
// const QPoint3D &curPointAbs = p0 + (dist3D * i / steps);
|
||||
// very small neg values may occur: item (30000,70,2.27374e-13)
|
||||
// ^^^^^^^^^^^
|
||||
const QPoint3D curPointAbs = (i==steps) ? p0 + dist3D : p0 + (dist3D * i / steps);
|
||||
// DEBUG_LOG(logger) << " i " << i
|
||||
// << ", curPointAbs = " << curPointAbs;
|
||||
addItemLocal(trajectoryOut, curPointAbs);
|
||||
} // for
|
||||
|
||||
if (realDelta_xy_out)
|
||||
*realDelta_xy_out = realDelta_x;
|
||||
}
|
||||
|
||||
void TrajectoryGeneratorVulcano::rasterLineByTime(const QPoint3D &p0, const QPoint3D &p1,
|
||||
double timeOffsetSec, double speedMeterPerSec, double desiredDeltaTime,
|
||||
TRAJECTORY_METRIC &trajectoryOut, double *realDeltaTime_out)
|
||||
{
|
||||
LOGGER_T logger = getLocalLogger();
|
||||
|
||||
const QPoint3D &dist3D = p1 - p0; // keep in mind: tapAbs - apoAbs
|
||||
const double timeSpanForDistance = dist3D.length() / speedMeterPerSec;
|
||||
|
||||
Q_ASSERT(timeSpanForDistance > 1);
|
||||
|
||||
const int steps = timeSpanForDistance / desiredDeltaTime; // implicit round;
|
||||
const double realDeltaTime = timeSpanForDistance / steps;
|
||||
|
||||
Q_ASSERT(realDeltaTime > 0);
|
||||
|
||||
DEBUG_LOG(logger) << LOGFUNCTION
|
||||
<< " timeOffsetSec " << timeOffsetSec
|
||||
<< ", speedMeterPerSec " << speedMeterPerSec
|
||||
<< ", desiredDeltaTime " << desiredDeltaTime
|
||||
<< ", dist3D.length " << dist3D.length()
|
||||
<< ", steps " << steps
|
||||
<< ", realDeltaTime " << realDeltaTime;
|
||||
|
||||
// split 3dim Vector between both points according step:
|
||||
|
||||
// step by time:
|
||||
for (int i=1; i <= steps; ++i) // use 'i <= steps'
|
||||
{
|
||||
// try to avoid to much calculation, like:
|
||||
// const QPoint3D &curPointAbs = p0 + (dist3D * i / steps);
|
||||
// very small neg values may occur: item (30000,70,2.27374e-13)
|
||||
// ^^^^^^^^^^^
|
||||
const QPoint3D &curPointAbs = (i==steps) ? p0 + dist3D : p0 + (dist3D * i / steps);
|
||||
double timeAbsToOffset = timeOffsetSec + (i*realDeltaTime);
|
||||
// DEBUG_LOG(logger) << " i " << i
|
||||
// << ", curPointAbs " << curPointAbs
|
||||
// << " - " << " timeAbsToOffset: " << timeAbsToOffset;
|
||||
addItemLocal(trajectoryOut, curPointAbs, timeAbsToOffset);
|
||||
} // for
|
||||
|
||||
if (realDeltaTime_out)
|
||||
*realDeltaTime_out = realDeltaTime;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// some helper
|
||||
//
|
||||
namespace XY
|
||||
{
|
||||
double calculateBetaRad(double v0, double peakHeightRelToOrigin, QString *reasonOut)
|
||||
{
|
||||
LOGGER_T logger = getLocalLogger();
|
||||
|
||||
DEBUG_LOG(logger) << LOGFUNCTION << ", v0 = " << v0 << ", peakHeightRelToOrigin = " << peakHeightRelToOrigin;
|
||||
|
||||
const double betaRad = asin(sqrt(2.0 * G * peakHeightRelToOrigin / (v0 * v0)));
|
||||
|
||||
DEBUG_LOG(logger) << LOGFUNCTION << ", v0 = " << v0 << ", peakHeightRelToOrigin = " << peakHeightRelToOrigin
|
||||
<< " -> betaRad = " << betaRad << " betaDeg = " << betaRad * LtsCoordTrans::rad2deg();
|
||||
|
||||
if (std::isnan(betaRad))
|
||||
{
|
||||
ERROR_LOG(logger) << LOGFUNCTION << ", v0 = " << v0 << ", peakHeightRelToOrigin = " << peakHeightRelToOrigin
|
||||
<< " -> betaRad = " << betaRad << " betaDeg = " << betaRad * LtsCoordTrans::rad2deg();
|
||||
|
||||
if (reasonOut)
|
||||
*reasonOut = QObject::tr("calculate angle beta failed(v0=%1 ; pH %2 ; beta=%3)").arg(v0).arg(peakHeightRelToOrigin).arg(betaRad);
|
||||
}
|
||||
|
||||
return betaRad;
|
||||
}
|
||||
|
||||
QPointF calculateApogaeum(double v0, double betaRad)
|
||||
{
|
||||
LOGGER_T logger = getLocalLogger();
|
||||
TRACE_LOG(logger) << LOGFUNCTION << ", v0 = " << v0 << ", betaRad = " << betaRad << ", betaDeg = " << betaRad * LtsCoordTrans::rad2deg();
|
||||
|
||||
QPointF apogaeum;
|
||||
|
||||
apogaeum.rx() = v0 * v0 * sin(2.0 * betaRad) / (2.0 * G);
|
||||
apogaeum.ry() = v0 * v0 * sin(betaRad) * sin(betaRad) / (2.0 * G);
|
||||
|
||||
INFO_LOG(logger) << LOGFUNCTION << ", v0 = " << v0 << ", betaRad = " << betaRad << ", betaDeg = " << betaRad * LtsCoordTrans::rad2deg()
|
||||
<< ", apogaeum = " << apogaeum.x() << " # " << apogaeum.y();
|
||||
|
||||
return apogaeum;
|
||||
}
|
||||
|
||||
double calculateApogaeumStrichEval(const QPointF &origin, const QPointF &idealHit,
|
||||
double v0, double betaRad, const QPointF &tap_relToOrigin)
|
||||
{
|
||||
LOGGER_T logger = getLocalLogger();
|
||||
DEBUG_LOG(logger) << LOGFUNCTION
|
||||
<< ", origin = " << origin
|
||||
<< ", idealHit = " << idealHit
|
||||
<< ", v0 = " << v0 << ", betaRad = " << betaRad << ", betaDeg = " << betaRad * LtsCoordTrans::rad2deg()
|
||||
<< ", tap_relToOrigin = " << tap_relToOrigin;
|
||||
|
||||
// Berechnung Flugzeit T_ApoStrich vom Start bis APO'
|
||||
const double a = - G / 2.0;
|
||||
const double b = v0 * sin(betaRad);
|
||||
const double h_TAP = tap_relToOrigin.y(); // y-Koordinate (Höhe) vom TAP
|
||||
|
||||
// Unter der nur hier getroffenen Annahme, dass das Geschoss über den
|
||||
// gesamten Verlauf der Fluggkurve mit einer konstanten Geschwindigkeit bewegt:
|
||||
const double T_TAP = tap_relToOrigin.x() / v0; // Flugzeit des Geschosses vom Abschuss bis zum TAP
|
||||
|
||||
double temp = a * (T_TAP * ( a * T_TAP + b) - h_TAP);
|
||||
|
||||
if (temp < 0)
|
||||
FATAL_LOG(logger) << " temp NEGATIVE! " << temp;
|
||||
else
|
||||
DEBUG_LOG(logger) << " temp POSITIVE! " << temp;
|
||||
|
||||
|
||||
// const double T_ApoStrich = T_TAP + sqrt(a * (T_TAP * ( a* T_TAP + b) - h_TAP)) / a;
|
||||
const double T_ApoStrich = T_TAP + sqrt(a * (T_TAP * ( a* T_TAP + b) - h_TAP)) / a;
|
||||
|
||||
// Berechnung Strecke vom Start bis APO' (aka distancePhase1a)
|
||||
const double apoStrich_x = v0 * cos(betaRad) * T_ApoStrich;
|
||||
|
||||
DEBUG_LOG(logger) << LOGFUNCTION << ", T_TAP = " << T_TAP
|
||||
<< ", temp = " << temp
|
||||
<< ", T_ApoStrich = " << T_ApoStrich
|
||||
<< ", apoStrich_x = " << apoStrich_x;
|
||||
return apoStrich_x;
|
||||
}
|
||||
|
||||
QPointF calculateTapRelToIdealHit(double vFalling, double alphaRad, double timeTapT_sec)
|
||||
{
|
||||
LOGGER_T logger = getLocalLogger();
|
||||
DEBUG_LOG(logger) << LOGFUNCTION << ", v0 = " << vFalling
|
||||
<< ", alphaRad = " << alphaRad << ", alphaDeg = " << alphaRad * LtsCoordTrans::rad2deg()
|
||||
<< ", timeTapT_sec = " << timeTapT_sec;
|
||||
|
||||
QPointF tap;
|
||||
|
||||
tap.rx() = timeTapT_sec * vFalling * cos(alphaRad) * -1; // *-1 : move left to impact
|
||||
tap.ry() = timeTapT_sec * vFalling * sin(alphaRad);
|
||||
|
||||
#ifdef LTS_DEBUG
|
||||
const double lengthVec = QVector2D(tap).length();
|
||||
const double lengthProduct = timeTapT_sec * vFalling;
|
||||
|
||||
const double quot = fabs(lengthVec / lengthProduct);
|
||||
Q_ASSERT((quot-1.0) < 0.1);
|
||||
#endif
|
||||
|
||||
return tap;
|
||||
}
|
||||
|
||||
QVector<QPointF> generateBallisticCurveUntil(double v0, double betaRad,
|
||||
double max_x_distance, double secPerIntervall,
|
||||
double *deltaXperStep_out, double *secPerIntervall_out)
|
||||
{
|
||||
LOGGER_T logger = getLocalLogger();
|
||||
|
||||
QVector<QPointF> points;
|
||||
|
||||
const double perfectDelta_x = secPerIntervall * v0 * cos(betaRad);
|
||||
const double distancePhase1 = max_x_distance; // similar to Apo
|
||||
|
||||
const int steps = (distancePhase1/perfectDelta_x); // implicit round
|
||||
const double realDelta_x = distancePhase1 / steps;
|
||||
|
||||
INFO_LOG(logger) << LOGFUNCTION
|
||||
<< ", betaDeg = " << betaRad*LtsCoordTrans::rad2deg()
|
||||
<< ", max_x_distance = " << max_x_distance
|
||||
<< ", perfectDelta_x = " << perfectDelta_x
|
||||
<< ", realDelta_x = " << realDelta_x
|
||||
<< ", steps = " << steps;
|
||||
|
||||
points.reserve(steps+5);
|
||||
for (int curStep=0; curStep <= steps; ++curStep)
|
||||
{
|
||||
double x_val = curStep * realDelta_x;
|
||||
double time = x_val / (v0 * cos(betaRad));
|
||||
double h = v0 * time * sin(betaRad) - G * time * time / 2.0;
|
||||
|
||||
INFO_LOG(logger) << LOGFUNCTION
|
||||
<< ", x_valx " << x_val
|
||||
<< ", distancePhase1 " << distancePhase1
|
||||
<< ", time " << time
|
||||
<< ", h " << h;
|
||||
|
||||
points.append( QPointF(x_val, h) );
|
||||
};
|
||||
|
||||
// Out-vars:
|
||||
if (deltaXperStep_out)
|
||||
*deltaXperStep_out = realDelta_x;
|
||||
|
||||
if (secPerIntervall_out)
|
||||
*secPerIntervall_out = realDelta_x / (v0 * cos(betaRad));
|
||||
|
||||
INFO_LOG(logger) << LOGFUNCTION
|
||||
<< ", betaDeg = " << betaRad*LtsCoordTrans::rad2deg()
|
||||
<< ", max_x_distance = " << max_x_distance
|
||||
<< ", perfectDelta_x = " << perfectDelta_x
|
||||
<< ", realDelta_x = " << realDelta_x
|
||||
<< ", steps = " << steps
|
||||
<< ", points.size() = " << points.size()
|
||||
<< ", expectedDuration = " << points.size()* (realDelta_x / (v0 * cos(betaRad)))
|
||||
;
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
QPointF calculateTapRelToOrigin(const QPointF &idealHit, const QPointF &tap_relToIdealHit)
|
||||
{
|
||||
return idealHit + tap_relToIdealHit;
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
} // namespace AreaEffectSimulation
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* TrajectoryGenerator for Vulcano
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, SLTE, 2024-04-16
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../logger.h"
|
||||
#include <Trajectory/trajectory_export.h>
|
||||
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
#include <QVector>
|
||||
#include <QVector2D>
|
||||
|
||||
#include <cmath>
|
||||
#include <iomanip> // std::setprecision
|
||||
|
||||
|
||||
/*
|
||||
LTD Laser Target Designator
|
||||
SAL Semi Active Laser
|
||||
TAP Target Acquisition Point
|
||||
OTL Oberserver Target Line
|
||||
GTL Gun Target Line
|
||||
PTL Projectile Target Line
|
||||
PRF Pulse Repitition Frequency
|
||||
|
||||
|
||||
Part 1: Ballistische Flugphase
|
||||
calcBalPhase
|
||||
|
||||
Part 2: Gleitphase
|
||||
calcTapPhase ??
|
||||
|
||||
Part 3: EndAnflugPhase
|
||||
calcSalPhase ???
|
||||
|
||||
unklar:
|
||||
calcTAP
|
||||
calcSalPhase
|
||||
isSalTarget
|
||||
|
||||
Wichtige Notizen:
|
||||
ETB-Bericht Rev. A
|
||||
In der SAL-Endanflugphase beginnt die Zielerfassung mit dem SAL-Sensor.
|
||||
Hierzu wird bei Erreichen des TAP in einer Höhe von ca. 3500m
|
||||
die ballistische Haube des Geschosses abgesprengt, so dass der SAL-Sensor
|
||||
freie Sicht hat.
|
||||
*/
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
/*
|
||||
zwei-dimensionale Betrachtung
|
||||
y
|
||||
| Apogaeum / Scheitelpunkt
|
||||
| |
|
||||
| _
|
||||
| / \ ----- gliding
|
||||
| / ----- gliding, continued until TAP (TargetAcquisitionPoint)
|
||||
| / \
|
||||
| / \
|
||||
|/ beta alpha \
|
||||
---------------------------------------------------------- x
|
||||
^ originator/gun ^ ideal impact / hit
|
||||
*/
|
||||
|
||||
using QPoint3D = LtsUtils::QPoint3D;
|
||||
|
||||
class QPoint4D : public QPoint3D
|
||||
{
|
||||
public:
|
||||
explicit QPoint4D(double xpos=0.0, double ypos=0.0, double zpos=0.0, double time=0.0)
|
||||
: QPoint3D(xpos, ypos, zpos)
|
||||
, m_time(time)
|
||||
{}
|
||||
void setTime(double time ) { m_time = time; }
|
||||
double time() const { return m_time; }
|
||||
private:
|
||||
double m_time;
|
||||
};
|
||||
inline std::ostream& operator<< (std::ostream& stream, const QPoint4D& pos)
|
||||
{
|
||||
stream << "(" << QString::number(pos.x(), 'f', 3)
|
||||
<< ", " << QString::number(pos.y(), 'f', 3)
|
||||
<< ", " << QString::number(pos.z(), 'f', 3)
|
||||
<< ", t=" << QString::number(pos.time(), 'f', 3) << ")";
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
using TRAJECTORY_METRIC = QVector<QPoint4D>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The TrajectoryGeneratorVulcano class provides methods to generate a vulcano flight curve.
|
||||
* All calculations are using metrical coordinates.
|
||||
*/
|
||||
|
||||
//
|
||||
// 2-dim operation:
|
||||
//
|
||||
namespace XY
|
||||
{
|
||||
// speed/v [m/sec]
|
||||
// distance [m]
|
||||
|
||||
TRAJECTORY_EXPORT double calculateBetaRad(double v0, double peakHeightRelToOrigin, QString *reasonOut = nullptr);
|
||||
|
||||
TRAJECTORY_EXPORT QPointF calculateApogaeum(double v0, double betaRad);
|
||||
|
||||
|
||||
TRAJECTORY_EXPORT double calculateApogaeumStrichEval(const QPointF &origin, const QPointF &idealHit,
|
||||
double v0, double betaRad, const QPointF &tap_relToOrigin);
|
||||
|
||||
TRAJECTORY_EXPORT QPointF calculateTapRelToIdealHit(double vFalling, double alphaRad, double timeTapT_sec);
|
||||
TRAJECTORY_EXPORT QPointF calculateTapRelToOrigin(const QPointF &idealHit, const QPointF &tap_relToIdealHit);
|
||||
|
||||
TRAJECTORY_EXPORT QVector<QPointF> generateBallisticCurveUntil(double v0, double betaRad,
|
||||
double max_x_distance, double secPerIntervall,
|
||||
double *deltaXperStep_out = nullptr, double *secPerIntervall_out = nullptr);
|
||||
};
|
||||
|
||||
|
||||
|
||||
class TRAJECTORY_EXPORT TrajectoryGeneratorVulcano
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
// defaults:
|
||||
static inline double defaultTapTimeSec() { return 8; } // sec
|
||||
static inline double defaultv0() { return 870; } // m/sec , 730 ; _870_ ; 1020 , 1100
|
||||
|
||||
|
||||
// Options:
|
||||
enum Option {
|
||||
OptRasterApoTap = 1, // 0000001
|
||||
OptRasterApoTapTime = 2, // 0000010
|
||||
OptIncludeIdealHit = 4, // 0000100
|
||||
OptRasterTapHit = 8, // 0001000
|
||||
OptRasterMetrical = 16, // 0010000
|
||||
// OptFutureUse1 = 32,
|
||||
// OptFutureUse2 = 64,
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Option)
|
||||
|
||||
|
||||
//
|
||||
// main:
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief trajectoryVulcano generate vulcano flight curve.
|
||||
* phase 1: ballistic; phase 2: gliding from peak (APO|APO') to TAP; [ phase 3: TAP to ideal hit ]
|
||||
* All calculations are using metrical coordinates.
|
||||
* @param origin metrical coordinates
|
||||
* @param idealHit metrical coordinates
|
||||
* @param v0 Abschussgeschwindigkeit
|
||||
* @param betaRad Abschussgeschwindigkeit
|
||||
* @param vGliding Gleitgeschwindigkeit
|
||||
* @param vFalling Fallgeschwindigkeit
|
||||
* @param alphaRad Fallwinkel
|
||||
* @param tapTime Fallzeit
|
||||
* @param options
|
||||
* @param trajectoryOut metric, relativ to origin , time starts be zero
|
||||
* @return true on success, otherwise false
|
||||
*/
|
||||
static bool trajectoryVulcano(const QPoint3D &origin, const QPoint3D &idealHit,
|
||||
double v0, double betaRad, // Abschussgeschwindigkeit, -winkel
|
||||
double vGliding,
|
||||
double vFalling , double alphaRad, double tapTimeSec, // Fallwinkel, -geschwindigkeit, -zeit
|
||||
TrajectoryGeneratorVulcano::Options options,
|
||||
TRAJECTORY_METRIC &trajectoryOut,
|
||||
QPoint3D &idealTapOut,
|
||||
QString *reasonOut);
|
||||
|
||||
|
||||
//
|
||||
// checks:
|
||||
//
|
||||
static bool checkSimple(const QPoint3D &origin, const QPoint3D &apoAbs, const QPoint3D &idealHit, QString *reasonOut);
|
||||
static bool checkSimple(const QPoint3D &origin, const QPoint3D &apoAbs, const QPoint3D &tabAbs, const QPoint3D &idealHit, QString *reasonOut);
|
||||
|
||||
|
||||
//
|
||||
// helper:
|
||||
//
|
||||
|
||||
// get speed for every seperate phase
|
||||
static void getSpeedPerPhase(double v0_in, double betaRad,
|
||||
double &vGlidingOut, double &vFallingOut);
|
||||
|
||||
|
||||
static void rasterLineByDistance(const QPoint3D &p0, const QPoint3D &p1,
|
||||
double desiredDelta_xy,
|
||||
TRAJECTORY_METRIC &trajectoryOut, double *realDelta_xy_out);
|
||||
|
||||
static void rasterLineByTime(const QPoint3D &p0, const QPoint3D &p1,
|
||||
double timeOffsetSec, double speedMeterPerSec, double desiredDeltaTime,
|
||||
TRAJECTORY_METRIC &trajectoryOut, double *realDeltaTime_out);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
// empty
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(TrajectoryGeneratorVulcano::Options)
|
||||
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Trajectory Helper
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, SLTE, 2023-11-08
|
||||
*/
|
||||
|
||||
#include "trajectory_helper.h"
|
||||
#include "../logger.h"
|
||||
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
double TrajectoryHelper::flightDurationSec(const LtsUtils::QPoint3D &posStart, const LtsUtils::QPoint3D &posEnd, double peakHeightAbs,
|
||||
double *betaRadiantOut, double *vOut,
|
||||
QString *reasonOut)
|
||||
{
|
||||
if ((posStart.z() > peakHeightAbs) || (posEnd.z() > peakHeightAbs))
|
||||
{
|
||||
if (reasonOut)
|
||||
{
|
||||
//: "Höhenfehler"
|
||||
*reasonOut = QObject::tr("HeightElevationError(%1 %2 %3)").arg(posStart.z()).arg(peakHeightAbs).arg(posEnd.z());
|
||||
}
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
|
||||
double z = posEnd.z() - posStart.z();
|
||||
double h = peakHeightAbs - posStart.z();
|
||||
|
||||
|
||||
double x = posEnd.x() - posStart.x();
|
||||
double y = posEnd.y() - posStart.y();
|
||||
double r = sqrt(x * x + y * y);
|
||||
if (r < 0.01)
|
||||
{
|
||||
if (reasonOut)
|
||||
{
|
||||
//: "StartEndeAbstandsfehler"
|
||||
*reasonOut = QObject::tr("StartEndDistanceError(%1)").arg(r);
|
||||
}
|
||||
return 0.0; // No distance -> no duration -> 0.0
|
||||
}
|
||||
|
||||
double beta; // Abschusswinkel / elevation_angle in radiant
|
||||
double v;
|
||||
|
||||
if (fabs(z) < 0.01)
|
||||
{
|
||||
beta = atan(4.0 * h / r);
|
||||
v = sqrt(9.81 * r / sin(2.0 * beta));
|
||||
}
|
||||
else
|
||||
{
|
||||
double b;
|
||||
double p = - 4.0 * h / r;
|
||||
double q = 4.0 * h * z / (r * r); // ehemals double q = - 4.0 * h * z / (r * r);
|
||||
if (p * p / 4.0 > q)
|
||||
b = - (p / 2.0) + sqrt(p * p / 4.0 - q);
|
||||
else
|
||||
return -1.0;
|
||||
beta = atan(b);
|
||||
double a = b * b / (4.0 * h);
|
||||
double rh = b / a;
|
||||
v = sqrt(9.81 * rh / sin(2.0 * beta));
|
||||
}
|
||||
|
||||
// handle optional values:
|
||||
if (betaRadiantOut)
|
||||
*betaRadiantOut = beta;
|
||||
if (vOut)
|
||||
*vOut = v;
|
||||
|
||||
const double result = r / (v * cos(beta));
|
||||
if ((result < 0) && reasonOut)
|
||||
{
|
||||
//: "FlugzeitFehlerUnbekannt"
|
||||
*reasonOut = QObject::tr("FlightDurationSecErrorUnknown(%1)").arg(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double TrajectoryHelper::peakHeightAbs(const LtsUtils::QPoint3D &posStart, const LtsUtils::QPoint3D &posEnd, double timeSec,
|
||||
double *betaRadiantOut, double *vOut,
|
||||
QString *reasonOut)
|
||||
{
|
||||
double x = posEnd.x() - posStart.x();
|
||||
double y = posEnd.y() - posStart.y();
|
||||
double r = sqrt(x * x + y * y);
|
||||
if (r < 0.01)
|
||||
{
|
||||
if (reasonOut)
|
||||
{
|
||||
//: "StartEndeAbstandsfehler"
|
||||
*reasonOut = QObject::tr("StartEndDistanceError(%1)").arg(r);
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double v, rh;
|
||||
double t2 = timeSec * timeSec;
|
||||
double z = posEnd.z() - posStart.z();
|
||||
if (fabs(z) < 0.01)
|
||||
{
|
||||
v = sqrt((9.81 * 9.81 * t2 / 4.0) + (r * r / t2));
|
||||
rh = r;
|
||||
}
|
||||
else
|
||||
{
|
||||
double vx = r / timeSec;
|
||||
double vy = (9.81 * timeSec * timeSec / 2.0 + z) / timeSec;
|
||||
v = sqrt(vx * vx + vy * vy);
|
||||
rh = 2.0 * r * sqrt((v * v - r * r / t2)) / (9.81 * timeSec);
|
||||
}
|
||||
|
||||
double arcSin = 9.81 * rh / (v * v);
|
||||
if (arcSin > 1.0)
|
||||
{
|
||||
if (reasonOut)
|
||||
{
|
||||
//: "45GradSchuss"
|
||||
*reasonOut = QObject::tr("45DegreeShot(%1)").arg(arcSin);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// beta: Abschusswinkel / elevationsWinkel in radiant
|
||||
double beta;
|
||||
|
||||
if (fabs(9.81 * rh - v * v) < 0.0001)
|
||||
{
|
||||
beta = M_PI_4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (9.81 * rh > (v * v))
|
||||
{
|
||||
if (reasonOut)
|
||||
{
|
||||
//: "GipfelhöhenFehlerUnbekannt"
|
||||
*reasonOut = QObject::tr("PeakHeightUnknownError(rh=%1,v=%2)").arg(rh).arg(v);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
beta = asin( 9.81 * rh / (v * v)) / 2.0;
|
||||
}
|
||||
|
||||
// [GUEZE-2472] Inkonsitente Werte bei der Berechnung der Gipfelhöhe (peakHeight)
|
||||
// Es gibt nur eine Flugzeit zu einer maximalen Höhe h bei Vorgabe der Zielentfernung.
|
||||
// if (beta < M_PI_2)
|
||||
// {
|
||||
// if (trajMode == TrajectoryMode::TrajectoryModeHigh)
|
||||
// beta = M_PI_2 - beta;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (trajMode == TrajectoryMode::TrajectoryModeLow)
|
||||
// beta = M_PI_2 - beta;
|
||||
// }
|
||||
|
||||
double beta2;
|
||||
if (beta < M_PI_2)
|
||||
beta2 = M_PI_2 - beta;
|
||||
else
|
||||
beta2 = M_PI_2 + beta;
|
||||
|
||||
if (fabs((timeSec * v) * cos(beta) - r) > fabs((timeSec * v) * cos(beta2) - r))
|
||||
beta = beta2;
|
||||
|
||||
|
||||
double h = v * v * sin(beta) * sin(beta) / (2.0 * 9.81);
|
||||
h += posStart.z();
|
||||
|
||||
// handle optional values:
|
||||
if (betaRadiantOut)
|
||||
*betaRadiantOut = beta;
|
||||
if (vOut)
|
||||
*vOut = v;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
LtsUtils::QPoint3D TrajectoryHelper::realStartPoint(const LtsUtils::QPoint3D &apogaeum, const LtsUtils::QPoint3D &endPos)
|
||||
{
|
||||
LtsUtils::QPoint3D realStart = apogaeum - (endPos-apogaeum);
|
||||
realStart.setZ(endPos.z());
|
||||
return realStart;
|
||||
}
|
||||
|
||||
//const QString TrajectoryGenerator::string4poly(const TrajectoryPoint3D &trajectory)
|
||||
//{
|
||||
// if (trajectory.isEmpty())
|
||||
// return (QStringLiteral("Empty Polygon!"));
|
||||
|
||||
// const Point3D &p3D = trajectory.first();
|
||||
// int zone = LtsCoordTrans::UtmCoordinate::fromGeographic(p3D.toPointF()).zone;
|
||||
// QStringList pointSl;
|
||||
// pointSl.reserve(trajectory.size());
|
||||
// for (int i = 0; i < trajectory.size(); ++i)
|
||||
// pointSl << QString(QStringLiteral("utm=%1 h=%2")).arg(LtsCoordTrans::UtmCoordinate::fromGeographic(p3D.toPointF(), zone).mgrs(), QString::number(p3D.z(), 'f', 1));
|
||||
// return QStringLiteral("%1 Values (%2)").arg(trajectory.count()).arg(pointSl.join(QStringLiteral(" # ")));
|
||||
//}
|
||||
|
||||
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Trajectory Helper
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, SLTE, 2023-11-08
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AreaEffectSimulation/aes_export.h>
|
||||
#include <Trajectory/trajectory_export.h>
|
||||
|
||||
// Forward
|
||||
namespace LtsUtils {
|
||||
class QPoint3D;
|
||||
}
|
||||
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
class TRAJECTORY_EXPORT TrajectoryHelper
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief TrajectoryHelper::flightDurationSec
|
||||
* @param posStart start of the curve
|
||||
* @param posEnd end of the curve
|
||||
* @param peakHeightAbs absolute peak of the curve value
|
||||
* @param betaRadiantOut start angle
|
||||
* @param vOut firing speed
|
||||
* @param reasonOut error information
|
||||
* @return Flugzeit in Sekunden (Rueckgabewert -1 bei Eingabe zu kleiner Hoehe / -2 bei Hoehenunterschieden)
|
||||
*/
|
||||
static double flightDurationSec(const LtsUtils::QPoint3D &posStart, const LtsUtils::QPoint3D &posEnd, double peakHeightAbs,
|
||||
double *betaRadiantOut = nullptr, double *vOut = nullptr,
|
||||
QString *reasonOut = nullptr);
|
||||
|
||||
enum class TrajectoryMode
|
||||
{
|
||||
TrajectoryModeLow = 0, // flat
|
||||
TrajectoryModeHigh
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief TrajectoryHelper::peakHeightAbs
|
||||
* @param posStart start of the curve
|
||||
* @param posEnd end of the curve
|
||||
* @param timeSec flightDuration in seconds
|
||||
* @param trajMode LOW (0) or HIGH (1) curve
|
||||
* @param betaRadiantOut start angle
|
||||
* @param vOut firing speed
|
||||
* @param reasonOut error information
|
||||
* @return absolute peak
|
||||
*/
|
||||
static double peakHeightAbs(const LtsUtils::QPoint3D &posStart, const LtsUtils::QPoint3D &posEnd, double timeSec,
|
||||
double *betaRadiantOut = nullptr, double *vOut = nullptr,
|
||||
QString *reasonOut = nullptr);
|
||||
|
||||
/**
|
||||
* @brief calculate realStartPoint based on apogaeum and endpos (more of less mirroring)
|
||||
* @param apogaeum of ideal parabel
|
||||
* @param posEnd impact position
|
||||
* @return mirrored point (z values of posEnd is taken)
|
||||
*/
|
||||
static LtsUtils::QPoint3D realStartPoint(const LtsUtils::QPoint3D &apogaeum, const LtsUtils::QPoint3D &endPos);
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Commom base types * $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, ESVG, 2026-05-19
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QVector>
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
#include <Trajectory/trajectory_export.h>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The TrajectoryPoint class was introduced for ADLER / SAA
|
||||
* initially the positions are metrical and relative.
|
||||
*/
|
||||
class TrajectoryPoint
|
||||
{
|
||||
public:
|
||||
TrajectoryPoint() = default;
|
||||
|
||||
TrajectoryPoint(double x, double y, double z, double _time = -1)
|
||||
: position(x,y,z), time (_time)
|
||||
{}
|
||||
|
||||
TrajectoryPoint(const LtsUtils::QPoint3D &_position, double _time)
|
||||
: position(_position), time (_time)
|
||||
{}
|
||||
|
||||
LtsUtils::QPoint3D position; // x,y are relative, z is above sea level; both metrical
|
||||
double time {-1.0}; // relative
|
||||
};
|
||||
|
||||
Q_DECL_CONSTEXPR inline bool operator==(const TrajectoryPoint &p1, const TrajectoryPoint &p2)
|
||||
{
|
||||
return p1.position == p2.position && p1.time == p2.time;
|
||||
}
|
||||
Q_DECL_CONSTEXPR inline bool operator!=(const TrajectoryPoint &p1, const TrajectoryPoint &p2)
|
||||
{
|
||||
return p1.position != p2.position || p1.time != p2.time;
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
|
||||
// at global namespace:
|
||||
TRAJECTORY_EXPORT std::ostream &operator<< (std::ostream &stream, const AreaEffectSimulation::TrajectoryPoint &value);
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* TrajectoryTransform
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Gerlinde Rudolphus, ESZS, 2026
|
||||
*/
|
||||
|
||||
#include "trajectory_transform.h"
|
||||
|
||||
// Algorithmus: Zeitgewichtete Bézier-Korrektur (empfohlen)
|
||||
// Kerngedanke
|
||||
// Die ursprüngliche Trajektorie bleibt die Basis
|
||||
// Eine glatte Korrekturkurve wird addiert
|
||||
// Die Korrektur ist:
|
||||
// 0 am Start
|
||||
// maximal am Ziel
|
||||
// zeitlich C¹-stetig
|
||||
// Formel
|
||||
// Für jeden Punkt:
|
||||
// Pneu(t) = Palt(t) + w(t) · ΔZ
|
||||
// mit
|
||||
// ΔZ = Zneu − Zalt
|
||||
// w(t) = 3s² − 2s³ (smoothstep)
|
||||
// s = (t − t0) / (tEnd − t0)
|
||||
// Dadurch:
|
||||
// Start bleibt exakt gleich
|
||||
// Zielpunkt wird exakt erreicht
|
||||
// Bewegung bleibt glatt
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
namespace TrajectoryTransform
|
||||
{
|
||||
|
||||
|
||||
double smoothStep(double x)
|
||||
{
|
||||
return x * x * (3.0 - 2.0 * x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T clamp(T v, T lo, T hi) {
|
||||
return (v < lo) ? lo : (v > hi) ? hi : v; }
|
||||
|
||||
|
||||
|
||||
QVector<TrajectoryPoint> transformToNewTarget(
|
||||
const QVector<TrajectoryPoint>& originalTrajMetrical,
|
||||
const LtsUtils::QPoint3D& newTargetMetrical)
|
||||
{
|
||||
if (originalTrajMetrical.size() < 2)
|
||||
return originalTrajMetrical;
|
||||
|
||||
QVector<TrajectoryPoint> result = originalTrajMetrical;
|
||||
|
||||
const LtsUtils::QPoint3D &oldTarget = originalTrajMetrical.last().position;
|
||||
const LtsUtils::QPoint3D &delta = newTargetMetrical - oldTarget;
|
||||
|
||||
const double t0 = originalTrajMetrical.first().time;
|
||||
const double tEnd = originalTrajMetrical.last().time;
|
||||
const double dt = tEnd - t0;
|
||||
|
||||
for (int i = 0; i < result.size(); ++i)
|
||||
{
|
||||
double s = (result[i].time - t0) / dt;
|
||||
s = clamp(s, 0.0, 1.0);
|
||||
|
||||
double w = smoothStep(s);
|
||||
result[i].position += delta * w;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace TrajectoryTransform
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
|
||||
std::ostream &operator<< (std::ostream &stream, const AreaEffectSimulation::TrajectoryPoint &value)
|
||||
{
|
||||
stream << "TrajectoryPoint(" << "position=" << value.position << "; time=" << value.time;
|
||||
return stream;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "trajectory_point.h"
|
||||
#include <Trajectory/trajectory_export.h>
|
||||
|
||||
#include <QVector>
|
||||
#include <LtsUtilsCore/qpoint3d.h>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// prefer namespace instead of class with static member:
|
||||
// https://stackoverflow.com/questions/1434937/namespace-functions-versus-static-methods-on-a-class
|
||||
// https://stackoverflow.com/questions/1434937/namespace-functions-versus-static-methods-on-a-class#:~:text=You%20should%20use%20a%20namespace,can%20using%20a%20namespace%20member
|
||||
|
||||
|
||||
namespace TrajectoryTransform
|
||||
{
|
||||
TRAJECTORY_EXPORT QVector<TrajectoryPoint> transformToNewTarget(const QVector<TrajectoryPoint>& originalTrajMetrical,
|
||||
const LtsUtils::QPoint3D& newTargetMetrical);
|
||||
}
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
ADD_SUBDIRECTORY(UnitTest_TrajectorySplitter)
|
||||
Loaded 100 of 16245 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user