Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+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)
|
||||
@@ -0,0 +1,124 @@
|
||||
{ "xRelativ": 0, "yRelativ": 87, "zRelativ": 0, "zeit": 0 } { "xRelativ":
|
||||
264.92901384887057, "yRelativ": 174.47292577550235, "zRelativ": 0.02662089743508293, "zeit": 0.42316757561829477 } { "xRelativ": 527.817117836265,
|
||||
"yRelativ": 259.39749108373843, "zRelativ": 0.10711867810716591, "zeit": 0.8671332156643488 } { "xRelativ": 788.7136308929233, "yRelativ":
|
||||
341.7537090754077, "zRelativ": 0.24257733886856256, "zeit": 1.317025093437079 } { "xRelativ": 1047.6615285149353, "yRelativ": 421.51802443336, "zRelativ":
|
||||
0.4341458137452195, "zeit": 1.7729216456145016 } { "xRelativ": 1272.670456388367, "yRelativ": 489.16424954886634, "zRelativ": 0.648743912367082,
|
||||
"zeit": 2.175420509369112 } { "xRelativ": 1496.1617588664074, "yRelativ": 554.7638718196823, "zRelativ": 0.9079763526756811, "zeit": 2.580929441712794 }
|
||||
{ "xRelativ": 1718.0422067916973, "yRelativ": 618.2656482647882, "zRelativ": 1.2125072432874477, "zeit": 2.9908190774616394 } { "xRelativ":
|
||||
1938.330944134444, "yRelativ": 679.6520331535114, "zRelativ": 1.5631256945293488, "zeit": 3.405114349100484 } { "xRelativ": 2157.044359965948, "yRelativ":
|
||||
738.9042569599119, "zRelativ": 1.9606317053734932, "zeit": 3.8238343302505746 } { "xRelativ": 2374.179454251386, "yRelativ": 795.9981045121799,
|
||||
"zRelativ": 2.4057001489064205, "zeit": 4.246959426288938 } { "xRelativ": 2589.7075746926794, "yRelativ": 850.9031532411445,
|
||||
"zRelativ": 2.8988951350823706, "zeit": 4.674416976133513 } { "xRelativ": 2803.625245250845, "yRelativ": 903.5962127427072,
|
||||
"zRelativ": 3.4408242962627167, "zeit": 5.106179504182334 } { "xRelativ": 3015.753395193171, "yRelativ": 954.0134750176439,
|
||||
"zRelativ": 4.0315840043246425, "zeit": 5.541857190559005 } { "xRelativ": 3226.04018172054, "yRelativ": 1002.1263109737092, "zRelativ": 4.671491724277319,
|
||||
"zeit": 5.981306785503242 } { "xRelativ": 3434.503695723219, "yRelativ": 1047.9235062132045, "zRelativ": 5.361047083221246, "zeit": 6.424524728114267 } {
|
||||
"xRelativ": 3641.159218345649, "yRelativ": 1091.3931626499334, "zRelativ": 6.100752704963098, "zeit": 6.87150067202138 } { "xRelativ": 3846.0195490859824,
|
||||
"yRelativ": 1132.5229007478931, "zRelativ": 6.891111327028094, "zeit": 7.322217861888602 } { "xRelativ": 4049.0953248019264, "yRelativ":
|
||||
1171.3000490713105, "zRelativ": 7.73262312147463, "zeit": 7.776653548451646 } { "xRelativ": 4250.395329938128, "yRelativ": 1207.7118204515107,
|
||||
"zRelativ": 8.62578323430379, "zeit": 8.234779443194908 } { "xRelativ": 4449.9039507029875, "yRelativ": 1241.7416941206964, "zRelativ": 9.570963177466668,
|
||||
"zeit": 8.696509201569398 } { "xRelativ": 4647.484925820487, "yRelativ": 1273.35579439689, "zRelativ": 10.567796577492881, "zeit": 9.161470612161173 } {
|
||||
"xRelativ": 4815.295806413785, "yRelativ": 1298.5235324118603, "zRelativ": 11.463385441541586, "zeit": 9.562509460890828 } { "xRelativ":
|
||||
4981.693048622579, "yRelativ": 1321.9069836272317, "zRelativ": 12.397105821249431, "zeit": 9.965840845672002 } { "xRelativ": 5146.687445822314,
|
||||
"yRelativ": 1343.5036375846614, "zRelativ": 13.36908702977499, "zeit": 10.371448875731526 } { "xRelativ": 5310.289247221179, "yRelativ":
|
||||
1363.3110214569886, "zRelativ": 14.379455555652042, "zeit": 10.779316221496169 } { "xRelativ": 5472.508280876805, "yRelativ": 1381.32673988717,
|
||||
"zRelativ": 15.428334686559369, "zeit": 11.189424416135394 } { "xRelativ": 5633.3540705338055, "yRelativ": 1397.5485073966336,
|
||||
"zRelativ": 16.515844254274977, "zeit": 11.60175416482782 } { "xRelativ": 5792.918488561989, "yRelativ": 1411.9812057614772,
|
||||
"zRelativ": 17.642695945593214, "zeit": 12.016500348251098 } { "xRelativ": 5951.602993266749, "yRelativ": 1424.649459083988,
|
||||
"zRelativ": 18.812027905606268, "zeit": 12.434673896701511 } { "xRelativ": 6109.436505497795, "yRelativ": 1435.5373424624672,
|
||||
"zRelativ": 20.024545582829482, "zeit": 12.856329450140114 } { "xRelativ": 6266.509511696176, "yRelativ": 1444.6310496431215,
|
||||
"zRelativ": 21.28146507192771, "zeit": 13.28169203569395 } { "xRelativ": 6423.704767078978, "yRelativ": 1451.9452196648554,
|
||||
"zRelativ": 22.590782872547205, "zeit": 13.713151591402328 } { "xRelativ": 6581.511294764046, "yRelativ": 1457.4420159446634,
|
||||
"zRelativ": 23.958181651576584, "zeit": 14.152081584408341 } { "xRelativ": 6740.708204467678, "yRelativ": 1461.063997699184,
|
||||
"zRelativ": 25.392696730677216, "zeit": 14.60069300198115 } { "xRelativ": 6901.974936945717, "yRelativ": 1462.7127400025756,
|
||||
"zRelativ": 26.90355408049825, "zeit": 15.060978072354045 } { "xRelativ": 7065.931914784388, "yRelativ": 1462.2520863694708,
|
||||
"zRelativ": 28.50045932326631, "zeit": 15.534773332435343 } { "xRelativ": 7204.3899296521095, "yRelativ": 1460.1465791292762,
|
||||
"zRelativ": 29.89774175801777, "zeit": 15.939311665982192 } { "xRelativ": 7344.310327774728, "yRelativ": 1456.3886585442183,
|
||||
"zRelativ": 31.35592735710163, "zeit": 16.3521166282013 } { "xRelativ": 7485.506385757768, "yRelativ": 1450.9036028742253, "zRelativ": 32.875180047653885,
|
||||
"zeit": 16.7726404680203 } { "xRelativ": 7627.7846984507705, "yRelativ": 1443.6243527953839, "zRelativ": 34.45522654617, "zeit": 17.200295887629697 } {
|
||||
"xRelativ": 7770.96783657639, "yRelativ": 1434.490934439522, "zRelativ": 36.095593855551805, "zeit": 17.63452550541688 } { "xRelativ": 7914.891572427645,
|
||||
"yRelativ": 1423.4503767882618, "zRelativ": 37.79571974304789, "zeit": 18.07479676390447 } { "xRelativ": 8059.403915188324, "yRelativ": 1410.456436242184,
|
||||
"zRelativ": 39.5549601209268, "zeit": 18.52060181849778 } { "xRelativ": 8204.366506351464, "yRelativ": 1395.4690478428847, "zRelativ": 41.37262014144733,
|
||||
"zeit": 18.971464479435113 } { "xRelativ": 8349.655456359758, "yRelativ": 1378.453653736664, "zRelativ": 43.24798279390431, "zeit": 19.426945432815643 }
|
||||
{ "xRelativ": 8495.161679455245, "yRelativ": 1359.3804541368684, "zRelativ": 45.180334266378004, "zeit": 19.886645813789276 } { "xRelativ":
|
||||
8640.790802339236, "yRelativ": 1338.2236212923929, "zRelativ": 47.16898568033212, "zeit": 20.350209288555977 } { "xRelativ": 8786.462730602496,
|
||||
"yRelativ": 1314.9605102311587, "zRelativ": 49.2132910994555, "zeit": 20.81732285371174 } { "xRelativ": 8932.110956878605, "yRelativ": 1289.5708924959679,
|
||||
"zRelativ": 51.312661940457964, "zeit": 21.287716585014074 } { "xRelativ": 9077.682313654632, "yRelativ": 1262.0361113438485,
|
||||
"zRelativ": 53.46659106527009, "zeit": 21.761164607415193 } { "xRelativ": 9223.15299564122, "yRelativ": 1232.334925946738, "zRelativ": 55.67514660103901,
|
||||
"zeit": 22.237539310761296 } { "xRelativ": 9368.499044808717, "yRelativ": 1200.4481097398589, "zRelativ": 57.938683482733126, "zeit": 22.71671693082566 }
|
||||
{ "xRelativ": 9513.696966361245, "yRelativ": 1166.3580456065579, "zRelativ": 60.25749995488794, "zeit": 23.19857964224667 } { "xRelativ":
|
||||
9658.731690049053, "yRelativ": 1130.0465954717768, "zRelativ": 62.63193322853328, "zeit": 23.683042287890338 } { "xRelativ": 9803.595681312554,
|
||||
"yRelativ": 1091.4946627331606, "zRelativ": 65.06236075273098, "zeit": 24.17005024564265 } { "xRelativ": 9948.288068488084, "yRelativ":
|
||||
1050.6818120718194, "zRelativ": 67.54920058086417, "zeit": 24.659577214566927 } { "xRelativ": 10092.813834134578, "yRelativ": 1007.5859338231913,
|
||||
"zRelativ": 70.09291151720386, "zeit": 25.151623100713145 } { "xRelativ": 10237.183074859822, "yRelativ": 962.1829474248021,
|
||||
"zRelativ": 72.69399312942286, "zeit": 25.64621203834946 } { "xRelativ": 10381.410330438524, "yRelativ": 914.4465384758553, "zRelativ": 75.35298568895132,
|
||||
"zeit": 26.143390568795883 } { "xRelativ": 10525.276790425323, "yRelativ": 864.4323748374304, "zRelativ": 78.06594706166167, "zeit": 26.64240073362623 }
|
||||
{ "xRelativ": 10668.292565257545, "yRelativ": 812.3118170374198, "zRelativ": 80.82322553052114, "zeit": 27.14152290057901 } { "xRelativ":
|
||||
10810.450109000809, "yRelativ": 758.1014590452174, "zRelativ": 83.6238919660965, "zeit": 27.64070006753179 } { "xRelativ": 10951.756580024134, "yRelativ":
|
||||
701.8127436432027, "zRelativ": 86.4672527220736, "zeit": 28.13993223448457 } { "xRelativ": 11004.943335671449, "yRelativ": 679.9994989836455,
|
||||
"zRelativ": 87.55287154361422, "zeit": 28.32863291589727 } { "xRelativ": 11024.335485058064, "yRelativ": 671.9830718180636, "zRelativ": 87.92903026884116,
|
||||
"zeit": 28.420639771216415 } { "xRelativ": 11100.21984616728, "yRelativ": 639.7392557756232, "zRelativ": 89.40212615944367, "zeit": 28.821882126373755 }
|
||||
{ "xRelativ": 11152.742165081048, "yRelativ": 616.0529483568182, "zRelativ": 90.42341406537633, "zeit": 29.226286071708532 } { "xRelativ":
|
||||
11193.271852123562, "yRelativ": 596.3408074418735, "zRelativ": 91.21278397948197, "zeit": 29.631428430972147 } { "xRelativ": 11226.28500991867,
|
||||
"yRelativ": 578.8210033928916, "zRelativ": 91.85675684807502, "zeit": 30.03540991971389 } { "xRelativ": 11254.227157001867, "yRelativ": 562.5123550319646,
|
||||
"zRelativ": 92.4026108289216, "zeit": 30.438482771707214 } { "xRelativ": 11278.594301262206, "yRelativ": 546.7919561769685, "zRelativ": 92.87927865140509,
|
||||
"zeit": 30.8420332938371 } { "xRelativ": 11300.357097851796, "yRelativ": 531.2266409087222, "zRelativ": 93.30553868133093, "zeit": 31.24781331532016 } {
|
||||
"xRelativ": 11319.794086200334, "yRelativ": 515.8078371851949, "zRelativ": 93.68667708034342, "zeit": 31.64938614114135 } { "xRelativ":
|
||||
11337.989362305336, "yRelativ": 499.7997097923123, "zRelativ": 94.04382573010889, "zeit": 32.060973130558004 } { "xRelativ": 11354.447034153147,
|
||||
"yRelativ": 483.7648081358486, "zRelativ": 94.36714405385955, "zeit": 32.46462420892174 } { "xRelativ": 11370.473778499521, "yRelativ": 466.4902966169071,
|
||||
"zRelativ": 94.68221569173885, "zeit": 32.88797252052937 } { "xRelativ": 11384.89101884696, "yRelativ": 449.33805886194824, "zRelativ": 94.96579170236389,
|
||||
"zeit": 33.29598001219888 } { "xRelativ": 11395.981469933671, "yRelativ": 434.96545697335347, "zRelativ": 95.18399600505616, "zeit": 33.62863291589727 }
|
||||
{ "xRelativ": 11409.236947977843, "yRelativ": 416.29617224851137, "zRelativ": 95.44482733206365, "zeit": 34.04082881539747 } { "xRelativ":
|
||||
11411.285518092966, "yRelativ": 413.26044882799937, "zRelativ": 95.48513715974597, "zeit": 34.10532899875924 } { "xRelativ": 11419.459782669115,
|
||||
"yRelativ": 400.45101207953184, "zRelativ": 95.64597096552859, "zeit": 34.50706881576209 } { "xRelativ": 11423.734861523346, "yRelativ":
|
||||
392.5118315876584, "zRelativ": 95.73005916380147, "zeit": 34.910235145415434 } { "xRelativ": 11426.49578154897, "yRelativ": 386.0591251966,
|
||||
"zRelativ": 95.78432184334547, "zeit": 35.314853248312566 } { "xRelativ": 11428.434132450526, "yRelativ": 380.1405848375414,
|
||||
"zRelativ": 95.82235658843106, "zeit": 35.72479461543669 } { "xRelativ": 11429.826693932191, "yRelativ": 374.4631097940547, "zRelativ": 95.8496034725259,
|
||||
"zeit": 36.13686244791632 } { "xRelativ": 11430.858784299904, "yRelativ": 368.76345688039686, "zRelativ": 95.86970170148653, "zeit": 36.55950145263015 }
|
||||
{ "xRelativ": 11431.58968493453, "yRelativ": 363.2663541915362, "zRelativ": 95.88383019968666, "zeit": 36.97094102626642 } { "xRelativ":
|
||||
11432.162550220839, "yRelativ": 357.3343031965715, "zRelativ": 95.89477793773139, "zeit": 37.416671227566354 } { "xRelativ": 11432.57453933342,
|
||||
"yRelativ": 351.35486425071315, "zRelativ": 95.9025105233024, "zeit": 37.86665234292258 } { "xRelativ": 11432.877837647795, "yRelativ":
|
||||
345.10909634518674, "zRelativ": 95.90804515577143, "zeit": 38.33692802395387 } { "xRelativ": 11433.09846822694, "yRelativ": 338.517286188265,
|
||||
"zRelativ": 95.91189045274999, "zeit": 38.833363879071 } { "xRelativ": 11433.248677646154, "yRelativ": 331.87916060955405, "zRelativ": 95.91431459190422,
|
||||
"zeit": 39.333363879071 } { "xRelativ": 11433.348882570777, "yRelativ": 325.2422397338318, "zRelativ": 95.91572983853065, "zeit": 39.833363879071 } {
|
||||
"xRelativ": 11433.414518760721, "yRelativ": 318.60681330888696, "zRelativ": 95.91644574367233, "zeit": 40.333363879070994 } { "xRelativ":
|
||||
11433.456260054918, "yRelativ": 311.973114406024, "zRelativ": 95.91667699041493, "zeit": 40.833363879070994 } { "xRelativ": 11433.481486984167,
|
||||
"yRelativ": 305.3412990458193, "zRelativ": 95.9165724557235, "zeit": 41.333363879070994 } { "xRelativ": 11433.495302253918, "yRelativ":
|
||||
298.71146245908585, "zRelativ": 95.9162353668241, "zeit": 41.83336387907099 } { "xRelativ": 11433.500548152258, "yRelativ": 293.4090555920253,
|
||||
"zRelativ": 95.91584714678909, "zeit": 42.23336387907099 } { "xRelativ": 11433.501967204562, "yRelativ": 286.7829015145368, "zRelativ": 95.91525679993751,
|
||||
"zeit": 42.733363879070986 } { "xRelativ": 11433.499335919818, "yRelativ": 280.15882375525115, "zRelativ": 95.91458354139951, "zeit": 43.233363879070986
|
||||
} { "xRelativ": 11433.493907953312, "yRelativ": 273.536830677164, "zRelativ": 95.91385300842985, "zeit": 43.733363879070986 } { "xRelativ":
|
||||
11433.486549507788, "yRelativ": 266.91692553984, "zRelativ": 95.9130829647681, "zeit": 44.23336387907098 } { "xRelativ": 11433.479681686724, "yRelativ":
|
||||
261.6225051311806, "zRelativ": 95.91244688984187, "zeit": 44.633363879070984 } { "xRelativ": 11433.47022997119, "yRelativ": 255.00635849002902,
|
||||
"zRelativ": 95.91163415590303, "zeit": 45.13336387907098 } { "xRelativ": 11433.460096115776, "yRelativ": 248.39229789577348,
|
||||
"zRelativ": 95.91080763291724, "zeit": 45.63336387907098 }
|
||||
|
||||
{ "xRelativ": 11004.943335671449, "yRelativ": 679.9994989836455, "zRelativ": 87.55287154361422,
|
||||
"zeit": 28.32863291589727 } { "xRelativ": 11043.727634444678, "yRelativ": 663.9667038330389, "zRelativ": 88.3051889940681, "zeit": 28.506460354460955 } {
|
||||
"xRelativ": 11119.006328411935, "yRelativ": 631.7585823372341, "zRelativ": 89.76652640827223, "zeit": 28.906818574224253 } { "xRelativ":
|
||||
11171.917972657753, "yRelativ": 607.7540924048816, "zRelativ": 90.79537083018761, "zeit": 29.308956641395085 } { "xRelativ": 11213.546941861956,
|
||||
"yRelativ": 587.4288634353316, "zRelativ": 91.60613181351381, "zeit": 29.71415104903123 } { "xRelativ": 11247.924664954591, "yRelativ": 569.1686105331734,
|
||||
"zRelativ": 92.27670528358261, "zeit": 30.11865680553989 } { "xRelativ": 11277.473529493598, "yRelativ": 551.9745945754645, "zRelativ": 92.85393305216392,
|
||||
"zeit": 30.523192972002366 } { "xRelativ": 11303.510356440383, "yRelativ": 535.3123986302426, "zRelativ": 93.36325360985394, "zeit": 30.92682745026673 }
|
||||
{ "xRelativ": 11327.577437716074, "yRelativ": 518.3252752102593, "zRelativ": 93.83464803213366, "zeit": 31.341524665217197 } { "xRelativ":
|
||||
11349.641672687, "yRelativ": 501.12144249545435, "zRelativ": 94.26732562403264, "zeit": 31.75855034515161 } { "xRelativ": 11369.765284326642, "yRelativ":
|
||||
483.8130803812575, "zRelativ": 94.66236165678039, "zeit": 32.17127410388573 } { "xRelativ": 11388.327099857737, "yRelativ": 466.24971891921405,
|
||||
"zRelativ": 95.02706541088766, "zeit": 32.58116552646909 } { "xRelativ": 11406.017762440957, "yRelativ": 447.8622790882401, "zRelativ": 95.37491218944194,
|
||||
"zeit": 33.00003479838909 } { "xRelativ": 11422.674212587985, "yRelativ": 428.8630725613948, "zRelativ": 95.70261568950436, "zeit": 33.42202695039745 } {
|
||||
"xRelativ": 11438.234029710628, "yRelativ": 409.42577037021096, "zRelativ": 96.00886727478525, "zeit": 33.84307821894881 } { "xRelativ":
|
||||
11452.689275337752, "yRelativ": 389.7031408150357, "zRelativ": 96.29343689359482, "zeit": 34.26021424776057 } { "xRelativ": 11464.71710783156, "yRelativ":
|
||||
371.909984788195, "zRelativ": 96.5302211066025, "zeit": 34.62863291589727 } { "xRelativ": 11477.755322713407, "yRelativ": 351.04268351808685,
|
||||
"zRelativ": 96.78684636252149, "zeit": 35.044035435387514 } { "xRelativ": 11478.71814942543, "yRelativ": 349.43379687939347,
|
||||
"zRelativ": 96.80579361537536, "zeit": 35.07509661563648 } { "xRelativ": 11486.513069239078, "yRelativ": 335.7661291318016, "zRelativ": 96.95915516430225,
|
||||
"zeit": 35.47517459504593 } { "xRelativ": 11490.518074724874, "yRelativ": 327.5136024325229, "zRelativ": 97.03790090782059, "zeit": 35.87820118223462 } {
|
||||
"xRelativ": 11493.064658354193, "yRelativ": 320.96043709953466, "zRelativ": 97.08791443049023, "zeit": 36.27933906477598 } { "xRelativ":
|
||||
11494.837446546813, "yRelativ": 315.0483179389918, "zRelativ": 97.12266178839167, "zeit": 36.68279449934332 } { "xRelativ": 11496.119408344146,
|
||||
"yRelativ": 309.3783634813608, "zRelativ": 97.14770566200089, "zeit": 37.09088182111604 } { "xRelativ": 11497.070857247425, "yRelativ": 303.7024052820246,
|
||||
"zRelativ": 97.1661941532448, "zeit": 37.51012220397199 } { "xRelativ": 11497.736335528018, "yRelativ": 298.322652240787, "zRelativ": 97.17902200050501,
|
||||
"zeit": 37.91231871352893 } { "xRelativ": 11498.249863869263, "yRelativ": 292.667249805557, "zRelativ": 97.18880249154032, "zeit": 38.33749091881605 } {
|
||||
"xRelativ": 11498.606515498383, "yRelativ": 287.28931803609777, "zRelativ": 97.19547534066456, "zeit": 38.74284195244496 } { "xRelativ":
|
||||
11498.907073677967, "yRelativ": 280.9474775583367, "zRelativ": 97.2009434860124, "zeit": 39.221425986209404 } { "xRelativ": 11499.121563240604,
|
||||
"yRelativ": 274.34404243874127, "zRelativ": 97.20466256494127, "zeit": 39.720062770644574 } { "xRelativ": 11499.266493362005, "yRelativ":
|
||||
267.7249346365973, "zRelativ": 97.2069814590229, "zeit": 40.22006277064457 } { "xRelativ": 11499.362911009477, "yRelativ": 261.1076959097998,
|
||||
"zRelativ": 97.20832226297901, "zeit": 40.72006277064457 } { "xRelativ": 11499.42583300566, "yRelativ": 254.49226735111273, "zRelativ": 97.20898592381488,
|
||||
"zeit": 41.22006277064457 } { "xRelativ": 11499.465060791077, "yRelativ": 248.00000032681314, "zRelativ": 97.20918057242068, "zeit": 41.710891614207426 }
|
||||
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(UnitTestSources
|
||||
../trajectory_splitter.cpp
|
||||
../trajectory_splitter.h
|
||||
trajectory_splitter_unit_test.cpp
|
||||
trajectory_splitter_unit_test.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP( UnitTestSources FILES ${UnitTestSources} )
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
ADD_EXECUTABLE(aesUnitTestTrajectorySplitter ${LinkedSources} ${UnitTestSources} )
|
||||
|
||||
TARGET_LINK_LIBRARIES(aesUnitTestTrajectorySplitter
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
svcAesCommon
|
||||
)
|
||||
|
||||
ADD_TEST(NAME aesUnitTestTrajectorySplitter COMMAND $<TARGET_FILE:aesUnitTestTrajectorySplitter>)
|
||||
|
||||
ENDIF()
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Unittest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "trajectory_splitter_unit_test.h"
|
||||
#include "../trajectory_splitter.h"
|
||||
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace AreaEffectSimulation;
|
||||
//
|
||||
//
|
||||
// This class is an UnitTest with values taken from the TNE.
|
||||
// That was created while Michael Moetje was implementing that code at the TNE (PlayerUnit)
|
||||
//
|
||||
//
|
||||
|
||||
static TrajectoryType getExampleData()
|
||||
{
|
||||
TrajectoryType vector;
|
||||
|
||||
// trunk (size = 5)
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 1));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 2));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 3));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 4));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 5));
|
||||
|
||||
// branch 1 (size = 3)
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(1.1, 0.2, 0.3, 6));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(1.1, 0.2, 0.3, 7));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(1.1, 0.2, 0.3, 8));
|
||||
|
||||
// branch 2 (size = 4)
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 6));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 7));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 8));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 9));
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
static TrajectoryType getRealTrunk()
|
||||
{
|
||||
TrajectoryType vector;
|
||||
// trunk (size = 5)
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 1));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 2));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 3));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 4));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 5));
|
||||
return vector;
|
||||
}
|
||||
static TrajectoryType getRealBranch1()
|
||||
{
|
||||
TrajectoryType vector;
|
||||
// branch 1 (size = 3)
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(1.1, 0.2, 0.3, 6));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(1.1, 0.2, 0.3, 7));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(1.1, 0.2, 0.3, 8));
|
||||
return vector;
|
||||
}
|
||||
static TrajectoryType getRealBranch2()
|
||||
{
|
||||
TrajectoryType vector;
|
||||
// branch 2 (size = 4)
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 6));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 7));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 8));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 9));
|
||||
return vector;
|
||||
}
|
||||
|
||||
static TrajectoryType getRealTrajectory1()
|
||||
{
|
||||
TrajectoryType vector;
|
||||
// trunk (size = 5)
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 1));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 2));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 3));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 4));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 5));
|
||||
|
||||
// branch 1 (size = 3)
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(1.1, 0.2, 0.3, 6));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(1.1, 0.2, 0.3, 7));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(1.1, 0.2, 0.3, 8));
|
||||
return vector;
|
||||
}
|
||||
|
||||
static TrajectoryType getRealTrajectory2()
|
||||
{
|
||||
TrajectoryType vector;
|
||||
// trunk (size = 5)
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 1));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 2));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 3));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 4));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(0.1, 0.2, 0.3, 5));
|
||||
|
||||
// branch 2 (size = 4)
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 6));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 7));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 8));
|
||||
vector.emplace_back(Core::GeoPositionRelativeTime(2.1, 0.2, 0.3, 9));
|
||||
return vector;
|
||||
}
|
||||
|
||||
// TrajectorySplitter::init is protected.
|
||||
// To gain access, create a temporary class and enable access:
|
||||
class MyLocalTrajectorySplitter : public TrajectorySplitter<std::vector<Core::GeoPositionRelativeTime>>
|
||||
{
|
||||
public:
|
||||
using BaseClass = TrajectorySplitter;
|
||||
|
||||
explicit MyLocalTrajectorySplitter(const TrajectoryType &trajectory)
|
||||
: BaseClass(trajectory)
|
||||
{}
|
||||
|
||||
bool init() const
|
||||
{
|
||||
return BaseClass::init();
|
||||
}
|
||||
|
||||
size_t rawTrajectorySize() const
|
||||
{
|
||||
return BaseClass::rawTrajectorySize();
|
||||
}
|
||||
|
||||
|
||||
static qint64 findDuplicateTimeInternal(const TrajectoryType &trajectory) { return BaseClass::findDuplicateTimeInternal(trajectory);}
|
||||
static int findDuplicateBranchIndexInternal(const TrajectoryType &trajectory) { return BaseClass::findDuplicateBranchIndexInternal(trajectory);}
|
||||
static int findIndexOfEndOfFirstBranchInternal(const TrajectoryType &trajectory) { return BaseClass::findIndexOfEndOfFirstBranchInternal(trajectory);}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
void UnitTestTrajectorySplitter::init()
|
||||
{
|
||||
m_trajectory = getExampleData();
|
||||
}
|
||||
|
||||
void UnitTestTrajectorySplitter::test_rawTrajectorySize()
|
||||
{
|
||||
QCOMPARE(m_trajectory.size(), 12);
|
||||
|
||||
MyLocalTrajectorySplitter splitter(m_trajectory);
|
||||
QCOMPARE(splitter.rawTrajectorySize(), 12);
|
||||
}
|
||||
|
||||
void UnitTestTrajectorySplitter::test_findDuplicateTimeInternal()
|
||||
{
|
||||
const int value = MyLocalTrajectorySplitter::findDuplicateTimeInternal(m_trajectory);
|
||||
QCOMPARE(value, 6);
|
||||
}
|
||||
void UnitTestTrajectorySplitter::test_findDuplicateTimeInternalFailure()
|
||||
{
|
||||
const int value = MyLocalTrajectorySplitter::findDuplicateTimeInternal(getRealTrunk());
|
||||
QCOMPARE(value, -1);
|
||||
}
|
||||
|
||||
|
||||
void UnitTestTrajectorySplitter::test_findDuplicateBranchIndexInternal()
|
||||
{
|
||||
const int idx = MyLocalTrajectorySplitter::findDuplicateBranchIndexInternal(m_trajectory);
|
||||
QCOMPARE(idx, 5);
|
||||
}
|
||||
void UnitTestTrajectorySplitter::test_findDuplicateBranchIndexInternalFailure()
|
||||
{
|
||||
const int idx = MyLocalTrajectorySplitter::findDuplicateBranchIndexInternal(getRealTrunk());
|
||||
QCOMPARE(idx, -1);
|
||||
}
|
||||
|
||||
void UnitTestTrajectorySplitter::test_init()
|
||||
{
|
||||
{
|
||||
MyLocalTrajectorySplitter splitter({});
|
||||
QCOMPARE(splitter.init(), false);
|
||||
}
|
||||
{
|
||||
MyLocalTrajectorySplitter splitter(m_trajectory);
|
||||
QCOMPARE(splitter.rawTrajectorySize(), 12);
|
||||
QCOMPARE(splitter.init(), true);
|
||||
QCOMPARE(splitter.init(), true); // execute a second time
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestTrajectorySplitter::test_findIndexOfEndOfFirstBranchInternal()
|
||||
{
|
||||
const int idx = MyLocalTrajectorySplitter::findIndexOfEndOfFirstBranchInternal(m_trajectory);
|
||||
QCOMPARE(idx, 7);
|
||||
}
|
||||
|
||||
void UnitTestTrajectorySplitter::test_trunk()
|
||||
{
|
||||
MyLocalTrajectorySplitter splitter(m_trajectory);
|
||||
QCOMPARE(splitter.rawTrajectorySize(), 12);
|
||||
|
||||
const auto trunk = splitter.getTrunk();
|
||||
QCOMPARE(trunk.size(), 5);
|
||||
|
||||
const auto realTrunk = getRealTrunk();
|
||||
QCOMPARE(trunk, realTrunk);
|
||||
}
|
||||
|
||||
void UnitTestTrajectorySplitter::test_branch1()
|
||||
{
|
||||
MyLocalTrajectorySplitter splitter(m_trajectory);
|
||||
QCOMPARE(splitter.rawTrajectorySize(), 12);
|
||||
|
||||
const auto br1 = splitter.getBranch1();
|
||||
QCOMPARE(br1.size(), 3);
|
||||
|
||||
const auto &realBranch1 = getRealBranch1();
|
||||
QCOMPARE(br1, realBranch1);
|
||||
}
|
||||
|
||||
void UnitTestTrajectorySplitter::test_branch2()
|
||||
{
|
||||
MyLocalTrajectorySplitter splitter(m_trajectory);
|
||||
QCOMPARE(splitter.rawTrajectorySize(), 12);
|
||||
|
||||
const auto br2 = splitter.getBranch2();
|
||||
QCOMPARE(br2.size(), 4);
|
||||
|
||||
const auto &realBranch2 = getRealBranch2();
|
||||
QCOMPARE(br2, realBranch2);
|
||||
}
|
||||
|
||||
void UnitTestTrajectorySplitter::test_trajectory1()
|
||||
{
|
||||
MyLocalTrajectorySplitter splitter(m_trajectory);
|
||||
QCOMPARE(splitter.rawTrajectorySize(), 12);
|
||||
|
||||
const auto traj1 = splitter.getTrajectory1();
|
||||
QCOMPARE(traj1.size(), 8);
|
||||
|
||||
const auto &getRealTraj1 = getRealTrajectory1();
|
||||
QCOMPARE(traj1, getRealTraj1);
|
||||
}
|
||||
void UnitTestTrajectorySplitter::test_trajectory2()
|
||||
{
|
||||
MyLocalTrajectorySplitter splitter(m_trajectory);
|
||||
QCOMPARE(splitter.rawTrajectorySize(), 12);
|
||||
|
||||
const auto tra2 = splitter.getTrajectory2();
|
||||
QCOMPARE(tra2.size(), 9);
|
||||
|
||||
const auto &getRealTraj2 = getRealTrajectory2();
|
||||
QCOMPARE(tra2, getRealTraj2);
|
||||
}
|
||||
|
||||
void UnitTestTrajectorySplitter::test_failure()
|
||||
{
|
||||
MyLocalTrajectorySplitter splitter(getRealTrunk());
|
||||
QCOMPARE(splitter.rawTrajectorySize(), 5);
|
||||
|
||||
QCOMPARE(splitter.init(), false);
|
||||
|
||||
QCOMPARE(splitter.getTrunk().size(), 0);
|
||||
QCOMPARE(splitter.getBranch1().size(), 0);
|
||||
QCOMPARE(splitter.getBranch2().size(), 0);
|
||||
QCOMPARE(splitter.getTrajectory1().size(), 0);
|
||||
QCOMPARE(splitter.getTrajectory2().size(), 0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("UnitTest_TrajectorySplitter", "log4cxxUnitTest.props");
|
||||
|
||||
UnitTestTrajectorySplitter tc;
|
||||
return QTest::qExec(&tc, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Unittest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
#include <Core/core.hpp>
|
||||
|
||||
using TrajectoryType = std::vector<Core::GeoPositionRelativeTime>;
|
||||
|
||||
/**
|
||||
* @brief This class is an UnitTest with values taken from the TNE.
|
||||
* That was created while Michael Moetje was implementing that code at the TNE (PlayerUnit)
|
||||
*/
|
||||
class UnitTestTrajectorySplitter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
void init();
|
||||
|
||||
void test_rawTrajectorySize();
|
||||
|
||||
void test_findDuplicateTimeInternal();
|
||||
void test_findDuplicateTimeInternalFailure();
|
||||
void test_findDuplicateBranchIndexInternal();
|
||||
void test_findDuplicateBranchIndexInternalFailure();
|
||||
void test_init();
|
||||
void test_findIndexOfEndOfFirstBranchInternal();
|
||||
|
||||
void test_trunk();
|
||||
void test_branch1();
|
||||
void test_branch2();
|
||||
|
||||
void test_trajectory1();
|
||||
void test_trajectory2();
|
||||
|
||||
void test_failure();
|
||||
|
||||
// void cleanup();
|
||||
|
||||
private:
|
||||
TrajectoryType m_trajectory;
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
cat RealExampleData.json | jq
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* TrajectorySplitter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, ESVG, 2026-04-10
|
||||
*/
|
||||
|
||||
|
||||
#include "trajectory_splitter.h"
|
||||
|
||||
#include <QVector>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
#ifdef NEVER
|
||||
{ "xRelativ": 0, "yRelativ": 87, "zRelativ": 0, "zeit": 0 }
|
||||
{ "xRelativ": 264.92901384887057, "yRelativ": 174.47292577550235, "zRelativ": 0.02662089743508293, "zeit": 0.42316757561829477 }
|
||||
{ "xRelativ": 527.817117836265, "yRelativ": 259.39749108373843, "zRelativ": 0.10711867810716591, "zeit": 0.8671332156643488 }
|
||||
{ "xRelativ": 788.7136308929233, "yRelativ": 341.7537090754077, "zRelativ": 0.24257733886856256, "zeit": 1.317025093437079 }
|
||||
{ "xRelativ": 1047.6615285149353, "yRelativ": 421.51802443336, "zRelativ": 0.4341458137452195, "zeit": 1.7729216456145016 }
|
||||
|
||||
...
|
||||
{ "xRelativ": 10668.292565257545, "yRelativ": 812.3118170374198, "zRelativ": 80.82322553052114, "zeit": 27.14152290057901 }
|
||||
{ "xRelativ": 10810.450109000809, "yRelativ": 758.1014590452174, "zRelativ": 83.6238919660965, "zeit": 27.64070006753179 }
|
||||
{ "xRelativ": 10951.756580024134, "yRelativ": 701.8127436432027, "zRelativ": 86.4672527220736, "zeit": 28.13993223448457 }
|
||||
{ "xRelativ": 11004.943335671449, "yRelativ": 679.9994989836455, "zRelativ": 87.55287154361422, "zeit": 28.32863291589727 } <- "zeit": 28.32863291589727
|
||||
{ "xRelativ": 11024.335485058064, "yRelativ": 671.9830718180636, "zRelativ": 87.92903026884116, "zeit": 28.420639771216415 }
|
||||
{ "xRelativ": 11100.21984616728, "yRelativ": 639.7392557756232, "zRelativ": 89.40212615944367, "zeit": 28.821882126373755 }
|
||||
|
||||
...
|
||||
|
||||
{ "xRelativ": 11433.493907953312, "yRelativ": 273.536830677164, "zRelativ": 95.91385300842985, "zeit": 43.733363879070986 }
|
||||
{ "xRelativ": 11433.486549507788, "yRelativ": 266.91692553984, "zRelativ": 95.9130829647681, "zeit": 44.23336387907098 }
|
||||
{ "xRelativ": 11433.479681686724, "yRelativ": 261.6225051311806, "zRelativ": 95.91244688984187, "zeit": 44.633363879070984 }
|
||||
{ "xRelativ": 11433.47022997119, "yRelativ": 255.00635849002902, "zRelativ": 95.91163415590303, "zeit": 45.13336387907098 }
|
||||
{ "xRelativ": 11433.460096115776, "yRelativ": 248.39229789577348, "zRelativ": 95.91080763291724, "zeit": 45.63336387907098 }
|
||||
// { "xRelativ": 11004.943335671449, "yRelativ": 679.9994989836455, "zRelativ": 87.55287154361422,"zeit": 28.32863291589727 } <- "zeit": 28.32863291589727
|
||||
// { "xRelativ": 11043.727634444678, "yRelativ": 663.9667038330389, "zRelativ": 88.3051889940681, "zeit": 28.506460354460955 }
|
||||
// { "xRelativ": 11119.006328411935, "yRelativ": 631.7585823372341, "zRelativ": 89.76652640827223, "zeit": 28.906818574224253 }
|
||||
|
||||
...
|
||||
|
||||
{ "xRelativ": 11499.121563240604, "yRelativ": 274.34404243874127, "zRelativ": 97.20466256494127, "zeit": 39.720062770644574 }
|
||||
{ "xRelativ": 11499.266493362005, "yRelativ": 267.7249346365973, "zRelativ": 97.2069814590229, "zeit": 40.22006277064457 }
|
||||
{ "xRelativ": 11499.362911009477, "yRelativ": 261.1076959097998, "zRelativ": 97.20832226297901, "zeit": 40.72006277064457 }
|
||||
{ "xRelativ": 11499.42583300566, "yRelativ": 254.49226735111273, "zRelativ": 97.20898592381488, "zeit": 41.22006277064457 }
|
||||
{ "xRelativ": 11499.465060791077, "yRelativ": 248.00000032681314, "zRelativ": 97.20918057242068, "zeit": 41.710891614207426 }
|
||||
#endif // NEVER
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Approach Malte Diets, 2026-05-19
|
||||
|
||||
template <typename T> std::vector<std::vector<T>> getIndividualPaths(const std::vector<T> &flatTree)
|
||||
{
|
||||
if (flatTree.empty())
|
||||
return {};
|
||||
|
||||
std::vector<std::vector<T>> allPaths;
|
||||
std::vector<T> currentPath;
|
||||
std::map<T, size_t> elementIndices;
|
||||
|
||||
for (const auto &element : flatTree)
|
||||
{
|
||||
auto it = elementIndices.find(element);
|
||||
|
||||
if (it != elementIndices.end())
|
||||
{
|
||||
allPaths.push_back(currentPath);
|
||||
|
||||
size_t splitIndex = it->second;
|
||||
|
||||
for (size_t i = splitIndex + 1; i < currentPath.size(); ++i)
|
||||
elementIndices.erase(currentPath[i]);
|
||||
|
||||
currentPath.erase(currentPath.begin() + (splitIndex + 1), currentPath.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
elementIndices[element] = currentPath.size();
|
||||
currentPath.push_back(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentPath.empty())
|
||||
allPaths.push_back(std::move(currentPath));
|
||||
|
||||
return allPaths;
|
||||
}
|
||||
*/
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* TrajectorySplitter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Norbert Thoden, ESVG, 2026-04-10
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include <LtsCoordinate/ltscoordinate_export.h>
|
||||
|
||||
#include <Core/core.hpp>
|
||||
#include <QVector>
|
||||
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
// E01562-294: Falsche Darstellung Flugkurve SMArt
|
||||
// At SMArt ADLER (or SAA?) generates a polyline which is "dividing":
|
||||
// x x
|
||||
// x x
|
||||
// x x x
|
||||
// x x x
|
||||
// | Start | T1 | T2 (Target 1 & Target 2)
|
||||
// Same diagram, but with order
|
||||
// x4 x5
|
||||
// x3 x6 (duplicate)
|
||||
// x2 x7 x10
|
||||
// x1 x8 x11
|
||||
// x12
|
||||
// The relativeTime step backward between x8 and x10.
|
||||
|
||||
//using TRAJECTORY_POINT_TYPE = Core::RelativePositionRelativeTime;
|
||||
//using TRAJECTORY_TYPE = std::vector<Core::RelativePositionRelativeTime>;
|
||||
|
||||
//!
|
||||
//! \brief The TrajectorySplitter class splits a combined/special vector into single trajectories.
|
||||
//! See UnitTestTrajectorySplitter
|
||||
//!
|
||||
template<typename TRAJECTORY_TYPE>
|
||||
class TrajectorySplitter
|
||||
{
|
||||
public:
|
||||
|
||||
// friend class UnitTestTrajectorySplitter;
|
||||
|
||||
explicit TrajectorySplitter(const TRAJECTORY_TYPE &trajectory)
|
||||
: m_trajectory(trajectory)
|
||||
{}
|
||||
|
||||
TRAJECTORY_TYPE getTrunk() const
|
||||
{
|
||||
if (!init())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
TRAJECTORY_TYPE trunk(m_trajectory.begin(), m_trajectory.begin()+m_branchIndex);
|
||||
return trunk;
|
||||
}
|
||||
|
||||
TRAJECTORY_TYPE getBranch1() const
|
||||
{
|
||||
if (!init())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const int idx = findIndexOfEndOfFirstBranchInternal(m_trajectory);
|
||||
|
||||
const TRAJECTORY_TYPE branch1(m_trajectory.begin()+m_branchIndex, m_trajectory.begin()+idx+1);
|
||||
return branch1;
|
||||
}
|
||||
|
||||
TRAJECTORY_TYPE getBranch2() const
|
||||
{
|
||||
if (!init())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const int idx = findIndexOfEndOfFirstBranchInternal(m_trajectory);
|
||||
|
||||
const TRAJECTORY_TYPE branch2(m_trajectory.begin()+idx+1, m_trajectory.end());
|
||||
return branch2;
|
||||
}
|
||||
|
||||
TRAJECTORY_TYPE getTrajectory1() const
|
||||
{
|
||||
if (!init())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto complete = getTrunk();
|
||||
const auto &branch = getBranch1();
|
||||
complete.insert(complete.end(), branch.begin(), branch.end());
|
||||
return complete;
|
||||
}
|
||||
|
||||
TRAJECTORY_TYPE getTrajectory2() const
|
||||
{
|
||||
if (!init())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto complete = getTrunk();
|
||||
const auto &branch = getBranch2();
|
||||
complete.insert(complete.end(), branch.begin(), branch.end());
|
||||
return complete;
|
||||
}
|
||||
|
||||
size_t rawTrajectorySize() const { return m_trajectory.size(); }
|
||||
|
||||
protected:
|
||||
static qint64 findDuplicateTimeInternal(const TRAJECTORY_TYPE &trajectory)
|
||||
{
|
||||
// extract relativeTimes, sort, find adjacent duplicates
|
||||
QVector<qint64> relativeTimes;
|
||||
relativeTimes.reserve(static_cast<int>(trajectory.size()));
|
||||
|
||||
for (const auto &posTimeAware : trajectory)
|
||||
{
|
||||
relativeTimes.append(posTimeAware.relativeTime());
|
||||
}
|
||||
|
||||
std::sort(relativeTimes.begin(), relativeTimes.end());
|
||||
|
||||
auto it = std::adjacent_find(relativeTimes.begin(), relativeTimes.end());
|
||||
|
||||
if (it == relativeTimes.end())
|
||||
{
|
||||
return -1; // not found
|
||||
}
|
||||
|
||||
const qint64 duplicateRelativeTime = *it;
|
||||
return duplicateRelativeTime;
|
||||
}
|
||||
static int findDuplicateBranchIndexInternal(const TRAJECTORY_TYPE &trajectory)
|
||||
{
|
||||
const qint64 duplicateRelativeTime = findDuplicateTimeInternal(trajectory);
|
||||
|
||||
if (duplicateRelativeTime < 0)
|
||||
{
|
||||
return -1; // not found
|
||||
}
|
||||
|
||||
// find first occurance:
|
||||
int idx = 0;
|
||||
{
|
||||
for (const auto &posTimeAware : trajectory)
|
||||
{
|
||||
const qint64 currentTime = posTimeAware.relativeTime();
|
||||
|
||||
if (duplicateRelativeTime == currentTime)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++idx;
|
||||
} // for
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
static int findIndexOfEndOfFirstBranchInternal(const TRAJECTORY_TYPE &trajectory)
|
||||
{
|
||||
int idx = -1;
|
||||
{
|
||||
qint64 currentTime = std::numeric_limits<qint64>::min();
|
||||
for (const auto &posTimeAware : trajectory)
|
||||
{
|
||||
if (posTimeAware.relativeTime() < currentTime)
|
||||
{
|
||||
break;
|
||||
}
|
||||
currentTime = posTimeAware.relativeTime();
|
||||
++idx;
|
||||
} // for
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
bool init() const
|
||||
{
|
||||
// already calculated?
|
||||
if (m_branchIndex > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// sanity check:
|
||||
if (m_trajectory.size() < 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_branchIndex = findDuplicateBranchIndexInternal(m_trajectory);
|
||||
|
||||
return (m_branchIndex >= 0);
|
||||
}
|
||||
|
||||
private:
|
||||
TRAJECTORY_TYPE m_trajectory;
|
||||
mutable int m_branchIndex{0};
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(UnitTestSources
|
||||
aes_test_fire_automaton.cpp
|
||||
aes_test_fire_automaton.h
|
||||
)
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
ADD_EXECUTABLE(aesUnitTestFireAutomaton ${LinkedSources} ${UnitTestSources} )
|
||||
|
||||
TARGET_LINK_LIBRARIES(aesUnitTestFireAutomaton
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
LtsCommandLineParser
|
||||
LtsCoordinate
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
ddsconnector
|
||||
svcAesCommon
|
||||
svcAesClient
|
||||
svcBldClient
|
||||
svcExmClient
|
||||
svcIsmClient
|
||||
svcPdmClient
|
||||
svcPpmClient
|
||||
)
|
||||
|
||||
ADD_TEST(NAME aesUnitTestFireAutomaton COMMAND $<TARGET_FILE:aesUnitTestFireAutomaton>)
|
||||
ENDIF()
|
||||
+413
@@ -0,0 +1,413 @@
|
||||
/**
|
||||
* AES module test fire automaton
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QTest>
|
||||
#include <QVector>
|
||||
#include <QSignalSpy>
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <AreaEffectSimulation/Utils/fire_automaton.h>
|
||||
#include <AreaEffectSimulation/logger.h>
|
||||
|
||||
#include "aes_test_fire_automaton.h"
|
||||
|
||||
using namespace AreaEffectSimulation;
|
||||
|
||||
void TestFireAutomaton::initTestCase()
|
||||
{ }
|
||||
|
||||
void TestFireAutomaton::init()
|
||||
{
|
||||
m_receivedFire.clear();
|
||||
m_finishedTime = 0;
|
||||
}
|
||||
|
||||
void TestFireAutomaton::fireReceived(int32_t id)
|
||||
{
|
||||
m_receivedFire.append({QDateTime::currentMSecsSinceEpoch(), id});
|
||||
}
|
||||
|
||||
/*
|
||||
Test basic pattern with fire slots = rounds
|
||||
*/
|
||||
void TestFireAutomaton::testSchedule_0()
|
||||
{
|
||||
int32_t effectDurationMSecs = 500;
|
||||
int32_t cadence = 100;
|
||||
int32_t numberOfRounds = 6;
|
||||
QVector<int32_t> effectorIds = {1};
|
||||
QString pattern = QStringLiteral("all, next, all, next, all, next");
|
||||
|
||||
QVector<qint64> expectedDelays = {0, 100, 200, 300, 400, 500};
|
||||
QVector<QVector<int32_t>> expectedSchedule = {{1}, {1}, {1}, {1}, {1}, {1}};
|
||||
|
||||
testScheduling(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
||||
testScheduling(cadence, FireAutomaton::TimeType::Cadence, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
||||
testStepping(numberOfRounds, effectorIds, pattern, expectedSchedule);
|
||||
}
|
||||
|
||||
/*
|
||||
Test pattern with fill element
|
||||
*/
|
||||
void TestFireAutomaton::testSchedule_1()
|
||||
{
|
||||
int32_t effectDurationMSecs = 800;
|
||||
int32_t cadence = 100;
|
||||
int32_t numberOfRounds = 13;
|
||||
QVector<int32_t> effectorIds = {1, 2, 3};
|
||||
QString pattern = QStringLiteral("all,next*,all");
|
||||
|
||||
QVector<qint64> expectedDelays = {0, 0, 0, 100, 200, 300, 400, 500, 600, 700, 800, 800, 800};
|
||||
QVector<QVector<int32_t>> expectedSchedule = {{1, 2, 3}, {1}, {2}, {3}, {1}, {2}, {3}, {1}, {1, 2, 3}};
|
||||
|
||||
testScheduling(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
||||
testScheduling(cadence, FireAutomaton::TimeType::Cadence, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
||||
testStepping(numberOfRounds, effectorIds, pattern, expectedSchedule);
|
||||
}
|
||||
|
||||
/*
|
||||
Test fill pattern element with 0 fill
|
||||
*/
|
||||
void TestFireAutomaton::testSchedule_2()
|
||||
{
|
||||
int32_t effectDurationMSecs = 200;
|
||||
int32_t cadence = 200;
|
||||
int32_t numberOfRounds = 6;
|
||||
QVector<int32_t> effectorIds = {1, 2, 3};
|
||||
QString pattern = QStringLiteral("all,all*,all");
|
||||
|
||||
QVector<qint64> expectedDelays = {0, 0, 0, 200, 200, 200};
|
||||
QVector<QVector<int32_t>> expectedSchedule = {{1,2,3}, {1,2,3}};
|
||||
|
||||
testScheduling(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
||||
testScheduling(cadence, FireAutomaton::TimeType::Cadence, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
||||
testStepping(numberOfRounds, effectorIds, pattern, expectedSchedule);
|
||||
}
|
||||
|
||||
/*
|
||||
Test pattern with fire slots > rounds
|
||||
*/
|
||||
void TestFireAutomaton::testSchedule_3()
|
||||
{
|
||||
int32_t effectDurationMSecs = 200;
|
||||
int32_t cadence = 200;
|
||||
int32_t numberOfRounds = 5;
|
||||
QVector<int32_t> effectorIds = {1, 2, 3, 4};
|
||||
QString pattern = QStringLiteral("all,all");
|
||||
|
||||
QVector<qint64> expectedDelays = {0, 0, 0, 0, 200};
|
||||
QVector<QVector<int32_t>> expectedSchedule = {{1, 2, 3, 4}, {1}};
|
||||
|
||||
testScheduling(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
||||
testScheduling(cadence, FireAutomaton::TimeType::Cadence, numberOfRounds, effectorIds, pattern, expectedDelays, expectedSchedule);
|
||||
testStepping(numberOfRounds, effectorIds, pattern, expectedSchedule);
|
||||
}
|
||||
|
||||
/*
|
||||
Test pattern with rounds > fire slots
|
||||
*/
|
||||
void TestFireAutomaton::testSchedule_4()
|
||||
{
|
||||
int32_t effectDurationMSecs = 100;
|
||||
int32_t numberOfRounds = 5;
|
||||
QVector<int32_t> effectorIds = {1};
|
||||
QString pattern = QStringLiteral("next, next");
|
||||
|
||||
QVector<qint64> expectedDelays = {0, 100};
|
||||
QVector<QVector<int32_t>> expectedSchedule = {{1}, {1}};
|
||||
|
||||
FireAutomaton automaton;
|
||||
QVERIFY(!automaton.init(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, pattern));
|
||||
}
|
||||
|
||||
void TestFireAutomaton::testScheduling(int32_t time, FireAutomaton::TimeType type, int32_t numberOfRounds, const QVector<int32_t>& effectorIds,
|
||||
const QString& pattern, QVector<qint64> expectedDelays, QVector<QVector<int32_t>> expectedSchedule)
|
||||
{
|
||||
FireAutomaton automaton;
|
||||
QVERIFY(automaton.init(time, type, numberOfRounds, effectorIds, pattern));
|
||||
|
||||
QSignalSpy spyFire(&automaton, SIGNAL(fire(int32_t)));
|
||||
QVERIFY(spyFire.isValid());
|
||||
|
||||
QSignalSpy spyFinished(&automaton, SIGNAL(finished()));
|
||||
QVERIFY(spyFinished.isValid());
|
||||
|
||||
connect(&automaton, &FireAutomaton::fire, this, &TestFireAutomaton::fireReceived);
|
||||
|
||||
qint64 startTimeMSecs = QDateTime::currentMSecsSinceEpoch();
|
||||
automaton.start();
|
||||
|
||||
QVERIFY(spyFinished.wait(1000));
|
||||
QVERIFY(withinTolerance(QDateTime::currentMSecsSinceEpoch() - startTimeMSecs, expectedDelays.last(), 50));
|
||||
|
||||
int32_t expectedShots = 0;
|
||||
for(const auto& tick : expectedSchedule)
|
||||
expectedShots += tick.size();
|
||||
|
||||
QCOMPARE(spyFire.count(), expectedShots);
|
||||
|
||||
for(int32_t i=0; i < numberOfRounds; i++) {
|
||||
withinTolerance(QDateTime::currentMSecsSinceEpoch() - startTimeMSecs, expectedDelays.last(), 50);
|
||||
}
|
||||
|
||||
QVector<QVector<int32_t>> schedule;
|
||||
QVector<int32_t> tickIds;
|
||||
qint64 firstFireTime = m_receivedFire[0].time;
|
||||
|
||||
if(expectedDelays.size() != m_receivedFire.size())
|
||||
{
|
||||
QVERIFY(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// first fire time is basis for delays
|
||||
for(int i=0; i < m_receivedFire.size(); i++)
|
||||
{
|
||||
m_receivedFire[i].time = m_receivedFire[i].time - firstFireTime;
|
||||
QVERIFY(withinTolerance(m_receivedFire[i].time, expectedDelays[i], 50));
|
||||
}
|
||||
|
||||
tickIds.clear();
|
||||
tickIds.append(m_receivedFire[0].id);
|
||||
|
||||
for(int i=1; i < m_receivedFire.size(); i++)
|
||||
{
|
||||
if(withinTolerance(m_receivedFire[i - 1].time, m_receivedFire[i].time, 50))
|
||||
{
|
||||
tickIds.append(m_receivedFire[i].id);
|
||||
} else {
|
||||
schedule.append(tickIds);
|
||||
tickIds.clear();
|
||||
tickIds.append(m_receivedFire[i].id);
|
||||
}
|
||||
}
|
||||
|
||||
schedule.append(tickIds);
|
||||
|
||||
QVERIFY(schedule.size() == expectedSchedule.size());
|
||||
|
||||
for(int i=0; i < schedule.size(); i++)
|
||||
{
|
||||
QVERIFY(schedule[i] == expectedSchedule[i]);
|
||||
}
|
||||
|
||||
m_receivedFire.clear();
|
||||
}
|
||||
|
||||
void TestFireAutomaton::testStepping(int32_t numberOfRounds, const QVector<int32_t>& effectorIds,
|
||||
const QString& pattern, QVector<QVector<int32_t>> expectedSchedule)
|
||||
{
|
||||
FireAutomaton automaton;
|
||||
QVERIFY(automaton.init(0, FireAutomaton::TimeType::Cadence, numberOfRounds, effectorIds, pattern));
|
||||
QSignalSpy spyFire(&automaton, SIGNAL(fire(int32_t)));
|
||||
QVERIFY(spyFire.isValid());
|
||||
QSignalSpy spyFinished(&automaton, SIGNAL(finished()));
|
||||
QVERIFY(spyFinished.isValid());
|
||||
connect(&automaton, &FireAutomaton::fire, this, &TestFireAutomaton::fireReceived);
|
||||
|
||||
for(int i=0; i < expectedSchedule.size(); i++)
|
||||
{
|
||||
QVERIFY(automaton.performStep());
|
||||
QTest::qWait(100);
|
||||
}
|
||||
|
||||
QVERIFY(spyFinished.count() == 1);
|
||||
|
||||
QVector<QVector<int32_t>> schedule;
|
||||
QVector<int32_t> tickIds;
|
||||
qint64 firstFireTime = m_receivedFire[0].time;
|
||||
|
||||
// first fire time is basis for delays
|
||||
for(int i=0; i < m_receivedFire.size(); i++)
|
||||
{
|
||||
m_receivedFire[i].time = m_receivedFire[i].time - firstFireTime;
|
||||
}
|
||||
|
||||
tickIds.clear();
|
||||
tickIds.append(m_receivedFire[0].id);
|
||||
|
||||
for(int i=1; i < m_receivedFire.size(); i++)
|
||||
{
|
||||
if(withinTolerance(m_receivedFire[i - 1].time, m_receivedFire[i].time, 50))
|
||||
{
|
||||
tickIds.append(m_receivedFire[i].id);
|
||||
} else {
|
||||
schedule.append(tickIds);
|
||||
tickIds.clear();
|
||||
tickIds.append(m_receivedFire[i].id);
|
||||
}
|
||||
}
|
||||
|
||||
schedule.append(tickIds);
|
||||
|
||||
QVERIFY(schedule.size() == expectedSchedule.size());
|
||||
|
||||
for(int i=0; i < schedule.size(); i++)
|
||||
{
|
||||
QVERIFY(schedule[i] == expectedSchedule[i]);
|
||||
}
|
||||
|
||||
m_receivedFire.clear();
|
||||
}
|
||||
|
||||
|
||||
void TestFireAutomaton::testResumePaused()
|
||||
{
|
||||
QVector<int32_t> effectorIds = {1};
|
||||
int32_t effectDurationMSecs = 1000;
|
||||
int32_t numberOfRounds = 2;
|
||||
|
||||
FireAutomaton automaton;
|
||||
QVERIFY(automaton.init(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, QStringLiteral("all*")));
|
||||
|
||||
QSignalSpy spyFire(&automaton, SIGNAL(fire(int32_t)));
|
||||
QVERIFY(spyFire.isValid());
|
||||
|
||||
QSignalSpy spyFinished(&automaton, SIGNAL(finished()));
|
||||
QVERIFY(spyFinished.isValid());
|
||||
|
||||
qint64 startTimeMSecs = QDateTime::currentMSecsSinceEpoch();
|
||||
QVERIFY(automaton.start());
|
||||
|
||||
QTest::qWait(100);
|
||||
|
||||
automaton.pause();
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Paused);
|
||||
qint64 pauseTimeMSecs = QDateTime::currentMSecsSinceEpoch();
|
||||
QVERIFY(spyFire.count() == 1);
|
||||
|
||||
QTest::qWait(100);
|
||||
|
||||
qint64 resumeTimeMSecs = QDateTime::currentMSecsSinceEpoch();
|
||||
automaton.resume();
|
||||
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Running);
|
||||
QVERIFY(spyFinished.wait(2000));
|
||||
|
||||
qint64 measuredDuration = (QDateTime::currentMSecsSinceEpoch() - startTimeMSecs) - resumeTimeMSecs + pauseTimeMSecs;
|
||||
|
||||
QVERIFY(spyFinished.count() == 1);
|
||||
QVERIFY(withinTolerance(measuredDuration, effectDurationMSecs, 100));
|
||||
QVERIFY(spyFire.count() == numberOfRounds);
|
||||
}
|
||||
|
||||
void TestFireAutomaton::testStop()
|
||||
{
|
||||
QVector<int32_t> effectorIds = {1, 2, 3, 4, 5, 6};
|
||||
int32_t effectDurationMSecs = 500;
|
||||
int32_t numberOfRounds = 10;
|
||||
|
||||
FireAutomaton automaton;
|
||||
QVERIFY(automaton.init(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, QStringLiteral("next*")));
|
||||
|
||||
QTest::qWait(10);
|
||||
|
||||
QSignalSpy spyFire(&automaton, SIGNAL(fire(int32_t)));
|
||||
QVERIFY(spyFire.isValid());
|
||||
|
||||
QSignalSpy spyFinished(&automaton, SIGNAL(finished()));
|
||||
QVERIFY(spyFinished.isValid());
|
||||
|
||||
QVERIFY(automaton.start());
|
||||
|
||||
QTest::qWait(100);
|
||||
|
||||
automaton.stop();
|
||||
|
||||
int32_t fireCount = spyFire.count();
|
||||
QVERIFY(!spyFinished.wait(1000)); // expected to timeout
|
||||
QCOMPARE(spyFire.count(), fireCount); // expected to not have changed
|
||||
QVERIFY(spyFire.count() < numberOfRounds);
|
||||
|
||||
// start to finish
|
||||
qint64 startTimeMSecs = QDateTime::currentMSecsSinceEpoch();
|
||||
QVERIFY(automaton.start());
|
||||
|
||||
QVERIFY(spyFinished.wait(1000));
|
||||
QVERIFY(spyFire.count() - fireCount == numberOfRounds);
|
||||
QVERIFY(withinTolerance(QDateTime::currentMSecsSinceEpoch() - startTimeMSecs, effectDurationMSecs, 50));
|
||||
}
|
||||
|
||||
void TestFireAutomaton::testStates()
|
||||
{
|
||||
QVector<int32_t> effectorIds = {11, 10};
|
||||
int32_t effectDurationMSecs = 500;
|
||||
int32_t numberOfRounds = 10;
|
||||
|
||||
FireAutomaton automaton;
|
||||
|
||||
QSignalSpy spyFinished(&automaton, SIGNAL(finished()));
|
||||
QVERIFY(spyFinished.isValid());
|
||||
|
||||
// init
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Uninitialized);
|
||||
QVERIFY(!automaton.start());
|
||||
QVERIFY(!automaton.pause());
|
||||
QVERIFY(!automaton.resume());
|
||||
|
||||
QVERIFY(automaton.init(effectDurationMSecs, FireAutomaton::TimeType::Duration, numberOfRounds, effectorIds, QStringLiteral("all*")));
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
||||
QVERIFY(!automaton.pause());
|
||||
QVERIFY(!automaton.resume());
|
||||
|
||||
// start -> pause -> resume -> stop
|
||||
QVERIFY(automaton.start());
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Running);
|
||||
QVERIFY(!automaton.start());
|
||||
QVERIFY(!automaton.resume());
|
||||
|
||||
QVERIFY(automaton.pause());
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Paused);
|
||||
QVERIFY(!automaton.start());
|
||||
QVERIFY(!automaton.pause());
|
||||
|
||||
QVERIFY(automaton.resume());
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Running);
|
||||
|
||||
QVERIFY(spyFinished.wait(1000));
|
||||
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
||||
QVERIFY(!automaton.pause());
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
||||
QVERIFY(!automaton.resume());
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
||||
|
||||
// start -> stop
|
||||
QVERIFY(automaton.start());
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Running);
|
||||
QVERIFY(!automaton.start());
|
||||
QVERIFY(!automaton.resume());
|
||||
|
||||
QVERIFY(spyFinished.wait(1000));
|
||||
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
||||
|
||||
// start -> finish
|
||||
QVERIFY(automaton.start());
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Running);
|
||||
QVERIFY(!automaton.start());
|
||||
QVERIFY(!automaton.resume());
|
||||
|
||||
QVERIFY(spyFinished.wait(1000));
|
||||
QCOMPARE(automaton.getState(), FireAutomaton::State::Stopped);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
qRegisterMetaType<int32_t>("int32_t");
|
||||
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("UnitTest_FireAutomaton", "log4cxx_aes.props");
|
||||
|
||||
TestFireAutomaton testCase;
|
||||
return QTest::qExec(&testCase, argc, argv);
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* AES unit test fire automaton
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <QtCore>
|
||||
#include <QMetaType>
|
||||
|
||||
#include <AreaEffectSimulation/Utils/fire_automaton.h>
|
||||
|
||||
Q_DECLARE_METATYPE(int32_t)
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class TestFireAutomaton: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void init();
|
||||
|
||||
void testResumePaused();
|
||||
void testStop();
|
||||
void testStates();
|
||||
void testSchedule_0();
|
||||
void testSchedule_1();
|
||||
void testSchedule_2();
|
||||
void testSchedule_3();
|
||||
void testSchedule_4();
|
||||
|
||||
private:
|
||||
struct FireEvent
|
||||
{
|
||||
qint64 time;
|
||||
int32_t id;
|
||||
};
|
||||
|
||||
void testScheduling(int32_t time, FireAutomaton::TimeType type, int32_t numberOfRounds, const QVector<int32_t>& effectorIds,
|
||||
const QString& pattern, QVector<qint64> expectedDelays, QVector<QVector<int32_t>> expectedSchedule);
|
||||
void testStepping(int32_t numberOfRounds, const QVector<int32_t>& effectorIds, const QString& pattern, QVector<QVector<int32_t>> expectedSchedule);
|
||||
void fireReceived(int32_t id);
|
||||
|
||||
QVector<FireEvent> m_receivedFire;
|
||||
qint64 m_finishedTime;
|
||||
};
|
||||
|
||||
static bool withinTolerance(qint64 measured, qint64 expected, qint64 tolerance) {
|
||||
return qAbs(measured-expected) <= tolerance;
|
||||
};
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
@@ -0,0 +1,48 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
NGL_ADD_EXECUTABLE(AAR SV NO_TRANSLATION aes_statemachine_test
|
||||
aes_statemachine_test.cpp
|
||||
aes_statemachine_test.h
|
||||
../object_base.cpp
|
||||
../object_base.h
|
||||
../dds_handler.cpp
|
||||
../dds_handler.h
|
||||
../special_area_provider.cpp
|
||||
../special_area_provider.h
|
||||
)
|
||||
|
||||
NGL_TARGET_INCLUDE_DIRECTORIES( aes_statemachine_test
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_BINARY_DIR}/..
|
||||
)
|
||||
|
||||
|
||||
NGL_TARGET_LINK_LIBRARIES(aes_statemachine_test
|
||||
ddsconnector
|
||||
nglcoreapplication
|
||||
svcAesClient
|
||||
svcAesServer
|
||||
svcCesClient
|
||||
svcCoreClient
|
||||
svcPdmClient
|
||||
svcPpmClient
|
||||
svcTabClient
|
||||
svcIsmClient
|
||||
svcAsmClient
|
||||
svcExmClient
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
)
|
||||
NGL_TARGET_COMPILE_DEFINITIONS(aes_statemachine_test PRIVATE AES_STATEMACHINE_TEST)
|
||||
IF(TARGET aes_statemachine_test)
|
||||
ADD_TEST(NAME aes_statemachine_test COMMAND $<TARGET_FILE:aes_statemachine_test>)
|
||||
ENDIF()
|
||||
|
||||
ADD_SUBDIRECTORY(UnitTest_Basics)
|
||||
ADD_SUBDIRECTORY(UnitTest_TneAlgo)
|
||||
ADD_SUBDIRECTORY(UnitTest_Polygons)
|
||||
@@ -0,0 +1,29 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(UnitTestSources
|
||||
basics_unit_test.cpp
|
||||
basics_unit_test.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP( UnitTestSources FILES ${UnitTestSources} )
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
ADD_EXECUTABLE(aesUnitTestBasics ${LinkedSources} ${UnitTestSources} )
|
||||
|
||||
TARGET_LINK_LIBRARIES(aesUnitTestBasics
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
LtsCoordTrans
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
svcAesCommon
|
||||
)
|
||||
|
||||
ADD_TEST(NAME aesUnitTestBasics COMMAND $<TARGET_FILE:aesUnitTestTneAlgorithmen>)
|
||||
|
||||
ENDIF()
|
||||
+427
@@ -0,0 +1,427 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Unittest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "basics_unit_test.h"
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <AreaEffectSimulation/aes.hpp>
|
||||
#include <QtTest/QTest>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <QtTest/QSignalSpy>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
using namespace AreaEffectSimulation;
|
||||
|
||||
|
||||
UnitTestBasics::UnitTestBasics()
|
||||
: m_logger(getLogger("UnitTest"))
|
||||
{}
|
||||
|
||||
void UnitTestBasics::test_isNull_isNaN()
|
||||
{
|
||||
QPointF point1(1.1, 1.2);
|
||||
QVERIFY2(point1.isNull() == false, "QPointF isNull failed");
|
||||
|
||||
QPointF point2;
|
||||
QVERIFY2(point2.isNull() == true, "QPointF isNull failed");
|
||||
|
||||
QPointF point3(0, 0);
|
||||
QVERIFY2(point3.isNull() == true, "QPointF isNull failed");
|
||||
|
||||
QPointF point4(1, 2);
|
||||
point4.ry() = 0;
|
||||
QVERIFY2(point4.isNull() == false, "QPointF isNull failed");
|
||||
|
||||
QPointF point5(1, 2);
|
||||
point5.rx() = std::nan("");
|
||||
point5.ry() = std::nan("");
|
||||
|
||||
// !!! nan is not detected be isNull !!!
|
||||
QVERIFY2(point5.isNull() == false, "QPointF isNull failed");
|
||||
|
||||
// Qt::5.14.1: mit isNull() wird NaN nicht erkannt.
|
||||
// Eine separate Prüfung ergibt Sinn!
|
||||
}
|
||||
|
||||
void UnitTestBasics::test_operator_equal_1()
|
||||
{
|
||||
|
||||
// Some cases the operator == recognizes a difference, but i don´t know why.
|
||||
// crate this testCase:
|
||||
|
||||
AesItemView aesItem1, aesItem2;
|
||||
QVERIFY2(aesItem1 == aesItem2, "AesItemView::operator== failed");
|
||||
|
||||
aesItem1.id(1);
|
||||
aesItem2.id(1);
|
||||
QVERIFY2(aesItem1 == aesItem2, "AesItemView::operator== failed");
|
||||
|
||||
|
||||
std::vector<Core::GeoPosition> formVec;
|
||||
formVec.reserve(100);
|
||||
for (int i=1; i< 100; ++i)
|
||||
formVec.emplace_back(Core::GeoPosition(i*0.001, 100/i, 100/i));
|
||||
|
||||
aesItem1.aesItemId(12);
|
||||
aesItem1.sampleTime(12345567);
|
||||
aesItem1.chargeStruct().chargeTypeId(123);
|
||||
aesItem1.effectStart(123456789);
|
||||
aesItem1.form(formVec);
|
||||
aesItem1.boundingBoxBottomLeft(Core::GeoPosition2D(0.1, 0.2));
|
||||
aesItem1.boundingBoxTopRight(Core::GeoPosition2D(1.1, 1.2));
|
||||
aesItem1.aesTypeId(AreaEffectSimulation::AesType_def::AtBoobyTrap);
|
||||
aesItem1.effectStateId(AreaEffectSimulation::AesEffectState_def::EsActivated);
|
||||
aesItem1.partyId(2);
|
||||
|
||||
aesItem1.setId(2334);
|
||||
|
||||
aesItem2 = aesItem1;
|
||||
QVERIFY2(aesItem1 == aesItem2, "AesItemView::operator== failed");
|
||||
}
|
||||
|
||||
void foo(const std::vector<QPoint> &vec)
|
||||
{
|
||||
qCritical() << " foo: number of elements = " << vec.size();
|
||||
|
||||
// copy data to tele
|
||||
|
||||
for (unsigned int i = 0; i < 4; ++i)
|
||||
{
|
||||
int offsetX = -1;
|
||||
int offsetY = -1;
|
||||
|
||||
// qCritical() << " foo: vec.size()-1 = " << vec.size()-1;
|
||||
|
||||
if (i <= vec.size()-1)
|
||||
{
|
||||
offsetX = vec[i].x();
|
||||
offsetY = vec[i].y();
|
||||
}
|
||||
|
||||
// instead of writing data to telegram, use qCritical() to print:
|
||||
qCritical() << " i=" << i
|
||||
<< " # offset [x-y]=" << offsetX << " # " << offsetY;
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestBasics::test_container()
|
||||
{
|
||||
// Define source data
|
||||
std::vector<QPoint> sourcePointVec;
|
||||
sourcePointVec.push_back(QPoint(1, 1));
|
||||
sourcePointVec.push_back(QPoint(2, 2));
|
||||
|
||||
// call foo
|
||||
foo(sourcePointVec);
|
||||
}
|
||||
|
||||
|
||||
// https://medium.com/@sidbhasin82/c-templates-what-is-std-enable-if-and-how-to-use-it-fd76d3abbabe
|
||||
|
||||
class ObjectBASE
|
||||
{
|
||||
public:
|
||||
int32_t memberBaseINT{0};
|
||||
int32_t getMemberInt() { return 11; }
|
||||
};
|
||||
|
||||
class ObjectINT : public ObjectBASE
|
||||
{
|
||||
public:
|
||||
int32_t memberINT{0};
|
||||
|
||||
int32_t getMemberInt() { return memberINT; }
|
||||
|
||||
};
|
||||
class ObjectDOUBLE : public ObjectBASE
|
||||
{
|
||||
public:
|
||||
double memberDOUBLE{0.0};
|
||||
};
|
||||
|
||||
|
||||
template <class C>
|
||||
class HasRequestId
|
||||
{
|
||||
template <class T>
|
||||
static std::true_type testSignature(const int32_t &(T::*)() const);
|
||||
template <class T>
|
||||
static std::true_type testSignature(int32_t (T::*)() const);
|
||||
|
||||
template <class T>
|
||||
static decltype(testSignature(&T::getMemberInt)) test(std::nullptr_t);
|
||||
|
||||
template <class T>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
using type = decltype(test<C>(nullptr));
|
||||
static const bool value = type::value;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct has_memberDouble {
|
||||
static const bool value = false; //Compile time Constant
|
||||
};
|
||||
template<>
|
||||
struct has_memberDouble<ObjectINT> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template < typename T, typename std::enable_if < has_memberDouble<T>::value, int >::type = 0 >
|
||||
void getFilterType(const T &obj)
|
||||
{
|
||||
qCritical() << " HasRequestId";
|
||||
// sendErrorInternal(request.errorSlot, reason, request.uniqueId, request.sample.data().requestId());
|
||||
}
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template < typename T, typename std::enable_if < !has_memberDouble<T>::value, int >::type = 0 >
|
||||
void getFilterType(const T &obj)
|
||||
{
|
||||
qCritical() << " ! HasRequestId";
|
||||
// sendErrorInternal(request.errorSlot, reason, request.uniqueId, -1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class worker
|
||||
{
|
||||
public:
|
||||
virtual void do_stuff()
|
||||
{
|
||||
qCritical() << "**** do_stuff: this" << typeid(*this).name();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void UnitTestBasics::test_SFINAE()
|
||||
{
|
||||
worker<ObjectINT> inst1;
|
||||
inst1.do_stuff();
|
||||
|
||||
worker<ObjectDOUBLE> inst2;
|
||||
inst2.do_stuff();
|
||||
|
||||
|
||||
ObjectINT oInt;
|
||||
getFilterType(oInt);
|
||||
|
||||
ObjectDOUBLE oDouble;
|
||||
getFilterType(oDouble);
|
||||
|
||||
}
|
||||
|
||||
void UnitTestBasics::test_fireTimer10()
|
||||
{
|
||||
FiringTimer ft(QStringLiteral("TestEnv10"));
|
||||
|
||||
QStringList logSl = ft.getLogHistorie();
|
||||
QVERIFY2(logSl.size() == 0, "getCommandHistorie failed");
|
||||
|
||||
{
|
||||
bool success = ft.startFiring();
|
||||
QVERIFY2(!success, "startFiring not failed");
|
||||
}
|
||||
|
||||
{
|
||||
ft.init(10*1000, 5, 2.567*1000); // effectDuration, ammoCount, ammoFlightDuration
|
||||
|
||||
bool success = ft.startFiring();
|
||||
QVERIFY2(success, "startFiring failed");
|
||||
success = ft.startFiring();
|
||||
QVERIFY2(!success, "startFiring failed");
|
||||
QStringList logSl1 = ft.getLogHistorie();
|
||||
QVERIFY2(logSl1.size() == 1, "getCommandHistorie failed");
|
||||
|
||||
for (const auto &log : qAsConst(logSl1))
|
||||
NOTICE_LOG(m_logger) << "log ='" << log << "'";
|
||||
}
|
||||
|
||||
{
|
||||
ft.reset();
|
||||
QStringList logSl2 = ft.getLogHistorie();
|
||||
QVERIFY2(logSl2.size() == 0, "getCommandHistorie failed");
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestBasics::test_fireTimer15()
|
||||
{
|
||||
FiringTimer ft(QStringLiteral("TestEnv15"));
|
||||
|
||||
ft.init(10*1000, 5, 0.0); // effectDurationMsec, ammoFlightDurationMsec
|
||||
|
||||
// count firing
|
||||
QSignalSpy spyFiring(&ft, &FiringTimer::firing);
|
||||
|
||||
ft.startFiring(); // with this, the very first signal 'firing' will be emitted
|
||||
|
||||
// count firingFinished
|
||||
QSignalSpy spyFinished(&ft, &FiringTimer::firingFinished);
|
||||
QSignalSpy spyFinishedPlus(&ft, &FiringTimer::firingFinishedPlus);
|
||||
QSignalSpy spyStateChanged(&ft, &FiringTimer::stateChangeDelayedAsInt);
|
||||
spyFinishedPlus.wait(20000);
|
||||
// call wait twice (wait for CMD_EXPIRED, CMD_EXPIRED_PLUS)
|
||||
spyStateChanged.wait(5000);
|
||||
spyStateChanged.wait(5000);
|
||||
|
||||
// Verify at end:
|
||||
QVERIFY2(spyFiring.count() == 5, "FiringTimer: signalCount failed, spyFiring");
|
||||
QVERIFY2(spyFinished.count() == 1, "FiringTimer: signalCount failed, spyFinished");
|
||||
QVERIFY2(spyFinishedPlus.count() == 1, "FiringTimer: signalCount failed, spyFinishedPlus");
|
||||
QVERIFY2(spyStateChanged.count() == 3, "FiringTimer: signalCount failed, spyStateChanged");
|
||||
|
||||
NOTICE_LOG(m_logger) << " spyStateChanged.count() " << spyStateChanged.count();
|
||||
|
||||
// check order of signal paramter:
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[0][0].toInt()) == FiringTimer::CMD::CMD_START, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[1][0].toInt()) == FiringTimer::CMD::CMD_EXPIRED, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[2][0].toInt()) == FiringTimer::CMD::CMD_EXPIRED_PLUS, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
}
|
||||
|
||||
void UnitTestBasics::test_fireTimer20()
|
||||
{
|
||||
FiringTimer ft(QStringLiteral("TestEnv20"));
|
||||
|
||||
ft.init(10*1000, 5, 2.567*1000); // effectDurationMsec, ammoFlightDurationMsec
|
||||
|
||||
// count firing
|
||||
QSignalSpy spyFiring(&ft, &FiringTimer::firing);
|
||||
|
||||
ft.startFiring(); // with this, the very first signal 'firing' will be emitted
|
||||
|
||||
// count firingFinished
|
||||
QSignalSpy spyFinished(&ft, &FiringTimer::firingFinished);
|
||||
QSignalSpy spyFinishedPlus(&ft, &FiringTimer::firingFinishedPlus);
|
||||
QSignalSpy spyStateChanged(&ft, &FiringTimer::stateChangeDelayedAsInt);
|
||||
spyFinishedPlus.wait(20000);
|
||||
// call wait twice (wait for CMD_EXPIRED, CMD_EXPIRED_PLUS)
|
||||
spyStateChanged.wait(5000);
|
||||
spyStateChanged.wait(5000);
|
||||
|
||||
// Verify at end:
|
||||
QVERIFY2(spyFiring.count() == 5, "FiringTimer: signalCount failed, spyFiring");
|
||||
QVERIFY2(spyFinished.count() == 1, "FiringTimer: signalCount failed, spyFinished");
|
||||
QVERIFY2(spyFinishedPlus.count() == 1, "FiringTimer: signalCount failed, spyFinishedPlus");
|
||||
QVERIFY2(spyStateChanged.count() == 3, "FiringTimer: signalCount failed, spyStateChanged");
|
||||
|
||||
// QList<QVariant> arguments = spyStateChanged.takeFirst(); // take the first signal
|
||||
// NOTICE_LOG(m_logger) << " spyStateChanged.count() " << spyStateChanged.count();
|
||||
// for (const QList<QVariant> &argument : qAsConst(spyStateChanged))
|
||||
// NOTICE_LOG(m_logger) << " spyStateChanged . argument " << argument.first().toInt();
|
||||
|
||||
// check order of signal paramter:
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[0][0].toInt()) == FiringTimer::CMD::CMD_START, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[1][0].toInt()) == FiringTimer::CMD::CMD_EXPIRED, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[2][0].toInt()) == FiringTimer::CMD::CMD_EXPIRED_PLUS, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
}
|
||||
|
||||
void UnitTestBasics::test_fireTimer21()
|
||||
{
|
||||
FiringTimer ft(QStringLiteral("TestEnv21"));
|
||||
|
||||
ft.init(10*1000, 5, 2.567*1000); // effectDuration, ammoCount, ammoFlightDuration
|
||||
|
||||
ft.startFiring();
|
||||
|
||||
QTimer::singleShot(3000, this, [this, &ft]() {
|
||||
NOTICE_LOG(m_logger) << " trigger pauseFiring...";
|
||||
ft.pauseFiring();
|
||||
});
|
||||
|
||||
QSignalSpy spyFinished(&ft, &FiringTimer::firingFinished);
|
||||
QSignalSpy spyFinishedPlus(&ft, &FiringTimer::firingFinishedPlus);
|
||||
QSignalSpy spyStateChanged(&ft, &FiringTimer::stateChangeDelayedAsInt);
|
||||
spyFinishedPlus.wait(10000);
|
||||
// call wait twice (wait for CMD_EXPIRED, CMD_EXPIRED_PLUS)
|
||||
spyStateChanged.wait(5000);
|
||||
spyStateChanged.wait(5000);
|
||||
|
||||
|
||||
// Verify at end:
|
||||
QVERIFY2(spyFinished.count() == 0, "FiringTimer: signalCount failed, spyFinished");
|
||||
QVERIFY2(spyFinishedPlus.count() == 0, "FiringTimer: signalCount failed, spyFinishedPlus");
|
||||
QVERIFY2(spyStateChanged.count() == 2, "FiringTimer: signalCount failed, spyStateChanged");
|
||||
|
||||
// check order of signal paramter:
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[0][0].toInt()) == FiringTimer::CMD::CMD_START, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[1][0].toInt()) == FiringTimer::CMD::CMD_PAUSE, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
// !! no finished !!
|
||||
}
|
||||
|
||||
void UnitTestBasics::test_fireTimer22()
|
||||
{
|
||||
FiringTimer ft(QStringLiteral("TestEnv22"));
|
||||
|
||||
ft.init(10*1000, 5, 3.000*1000); // effectDuration, ammoCount, ammoFlightDuration
|
||||
|
||||
// count firing
|
||||
QSignalSpy spyFiring(&ft, &FiringTimer::firing);
|
||||
|
||||
ft.startFiring();
|
||||
|
||||
// !! Attention: do pauseFiring() WITHIN the intervall will reduce amount of time the firing is active !!
|
||||
QTimer::singleShot(3000, this, [this, &ft]() {
|
||||
NOTICE_LOG(m_logger) << " trigger pauseFiring...";
|
||||
ft.pauseFiring();
|
||||
});
|
||||
|
||||
QTimer::singleShot(5123, this, [this, &ft]() {
|
||||
NOTICE_LOG(m_logger) << " trigger (re)StartFiring / Resume ...";
|
||||
ft.startFiring();
|
||||
});
|
||||
|
||||
|
||||
QSignalSpy spyFinished(&ft, &FiringTimer::firingFinished);
|
||||
QSignalSpy spyFinishedPlus(&ft, &FiringTimer::firingFinishedPlus);
|
||||
QSignalSpy spyStateChanged(&ft, &FiringTimer::stateChangeDelayedAsInt);
|
||||
spyFinishedPlus.wait(20000);
|
||||
// call wait twice (wait for CMD_EXPIRED, CMD_EXPIRED_PLUS)
|
||||
spyStateChanged.wait(5000);
|
||||
spyStateChanged.wait(5000);
|
||||
|
||||
// Verify at end:
|
||||
QVERIFY2(spyFiring.count() == 5, "FiringTimer: signalCount failed, spyFiring");
|
||||
QVERIFY2(spyFinished.count() == 1, "FiringTimer: signalCount failed, spyFinished");
|
||||
QVERIFY2(spyFinishedPlus.count() == 1, "FiringTimer: signalCount failed, spyFinishedPlus");
|
||||
QVERIFY2(spyStateChanged.count() == 5, "FiringTimer: signalCount failed, spyStateChanged");
|
||||
|
||||
// check order of signal paramter:
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[0][0].toInt()) == FiringTimer::CMD::CMD_START, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[1][0].toInt()) == FiringTimer::CMD::CMD_PAUSE, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[2][0].toInt()) == FiringTimer::CMD::CMD_RESUME, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[3][0].toInt()) == FiringTimer::CMD::CMD_EXPIRED, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
QVERIFY2(static_cast<FiringTimer::CMD>(spyStateChanged[4][0].toInt()) == FiringTimer::CMD::CMD_EXPIRED_PLUS, "FiringTimer: StateChanged.argument failed, spyStateChanged");
|
||||
|
||||
|
||||
// !! Attention: do pauseFiring() WITHIN the intervall will reduce amount of time the firing is active !!
|
||||
// stop firing2 after [ms]: 5999, m_activeMsec in total = 8902, m_pausedMsec in total = 2000
|
||||
// ^^^^ maybe you expect 10000
|
||||
// !! Attention: do pauseFiring() WITHIN the intervall will reduce amount of time the firing is active !!
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("UnitTest_TNE-ALOG", "log4cxxUnitTest.props");
|
||||
|
||||
UnitTestBasics tc;
|
||||
return QTest::qExec(&tc, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Unittest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <../../logger.h>
|
||||
#include <QCoreApplication>
|
||||
#include <QtTest/QTest>
|
||||
#include <AreaEffectSimulation/Utils/firing_timer.h>
|
||||
|
||||
|
||||
|
||||
class UnitTestBasics : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
UnitTestBasics();
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
// void init();
|
||||
|
||||
void test_isNull_isNaN();
|
||||
|
||||
void test_operator_equal_1();
|
||||
|
||||
void test_container();
|
||||
|
||||
void test_SFINAE();
|
||||
|
||||
|
||||
void test_fireTimer10();
|
||||
|
||||
void test_fireTimer15();
|
||||
|
||||
void test_fireTimer20();
|
||||
void test_fireTimer21();
|
||||
void test_fireTimer22();
|
||||
|
||||
|
||||
// void cleanup();
|
||||
|
||||
private:
|
||||
AreaEffectSimulation::LOGGER_T &m_logger;
|
||||
};
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(UnitTestSources
|
||||
polygons_unit_test.cpp
|
||||
polygons_unit_test.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP( UnitTestSources FILES ${UnitTestSources} )
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
ADD_EXECUTABLE(aesUnitTestPolygons ${LinkedSources} ${UnitTestSources} )
|
||||
|
||||
TARGET_LINK_LIBRARIES(aesUnitTestPolygons
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
LtsCoordTrans
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
svcAesCommon
|
||||
)
|
||||
|
||||
ADD_TEST(NAME aesUnitTestPolygons COMMAND $<TARGET_FILE:aesUnitTestTneAlgorithmen>)
|
||||
|
||||
ENDIF()
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Unittest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "polygons_unit_test.h"
|
||||
#include <Services/AreaEffectSimulation/Utils/polygons.h>
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <LtsCoordTrans/lts_coord_trans.h>
|
||||
#include <QTransform>
|
||||
#include <QTextStream> //
|
||||
#include <QtTest/QTest>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace AreaEffectSimulation;
|
||||
|
||||
double distanceMeter(const LtsCoordTrans::UtmCoordinate utmCoord1, const LtsCoordTrans::UtmCoordinate &utmCoord2)
|
||||
{
|
||||
double dist = LtsCoordTrans::distance(utmCoord1, utmCoord2);
|
||||
qCritical() << " dist" << dist;
|
||||
return dist;
|
||||
}
|
||||
|
||||
double distanceMeter(const QPointF &geoCoord1, const LtsCoordTrans::UtmCoordinate &utmCoord2)
|
||||
{
|
||||
const LtsCoordTrans::UtmCoordinate &utmCoord1 = LtsCoordTrans::UtmCoordinate::fromGeographic(geoCoord1);
|
||||
double dist = LtsCoordTrans::distance(utmCoord1, utmCoord2);
|
||||
qCritical() << " dist" << dist;
|
||||
return dist;
|
||||
}
|
||||
|
||||
|
||||
void UnitTestPolygons::test_QTrans()
|
||||
{
|
||||
QPolygonF poly;
|
||||
poly.reserve(3);
|
||||
poly.append(QPointF(0, 0));
|
||||
poly.append(QPointF(1, 0));
|
||||
poly.append(QPointF(2, 0));
|
||||
|
||||
//rotate
|
||||
{
|
||||
QTransform trans;
|
||||
trans.rotate(90);
|
||||
|
||||
QPolygonF poly2a = trans.map(poly);
|
||||
qCritical() << "poly2a = " << poly2a;
|
||||
|
||||
QVERIFY2(poly2a.first() == QPointF(0, 0), "QTransform failed");
|
||||
QVERIFY2(poly2a.last() == QPointF(0, 2), "QTransform failed; vec.last()");
|
||||
}
|
||||
|
||||
{
|
||||
QPolygonF poly2b = QTransform().rotate(90).map(poly); // squence in a single line
|
||||
|
||||
qCritical() << "poly2b = " << poly2b;
|
||||
|
||||
QVERIFY2(poly2b.first() == QPointF(0, 0), "QTransform failed");
|
||||
QVERIFY2(poly2b.last() == QPointF(0, 2), "QTransform failed; vec.last()");
|
||||
}
|
||||
}
|
||||
|
||||
void printAbl(const Polygons::AreaBottomLeft &obj)
|
||||
{
|
||||
qCritical() << " AreaBottomLeft = "
|
||||
<< ", cornerBL=" << obj.m_cornerBottomLeft
|
||||
<< ", m_width=" << obj.m_width
|
||||
<< ", m_height=" << obj.m_height
|
||||
<< ", m_height=" << obj.m_height;
|
||||
}
|
||||
|
||||
|
||||
void UnitTestPolygons::test_explosionClusterAddTla()
|
||||
{
|
||||
double width = 1000; // x
|
||||
double height = 100; // y
|
||||
double rotation_deg = 0;
|
||||
const Polygons::AreaBottomLeft boundaryOrg(QPointF(123, 123), width, height, rotation_deg);
|
||||
printAbl(boundaryOrg);
|
||||
|
||||
|
||||
{
|
||||
int zog = 0;
|
||||
const Polygons::AreaBottomLeft areaBlWithZog = Polygons::explosionClusterAddTla(boundaryOrg, zog);
|
||||
printAbl(areaBlWithZog);
|
||||
QVERIFY2(areaBlWithZog.m_cornerBottomLeft == boundaryOrg.m_cornerBottomLeft, "m_cornerBottomLeft failed");
|
||||
QVERIFY2(areaBlWithZog.m_width == boundaryOrg.m_width, "m_width failed");
|
||||
QVERIFY2(areaBlWithZog.m_height == boundaryOrg.m_height, "m_height failed");
|
||||
QVERIFY2(areaBlWithZog.m_rotation_deg == boundaryOrg.m_rotation_deg, "m_rotation_deg failed");
|
||||
}
|
||||
|
||||
{
|
||||
int zog = 10;
|
||||
const Polygons::AreaBottomLeft areaBlWithZog = Polygons::explosionClusterAddTla(boundaryOrg, zog);
|
||||
printAbl(areaBlWithZog);
|
||||
QVERIFY2(areaBlWithZog.m_cornerBottomLeft == QPointF(113, 113), "m_cornerBottomLeft failed");
|
||||
QVERIFY2(areaBlWithZog.m_width == boundaryOrg.m_width+(2*zog), "m_width failed");
|
||||
QVERIFY2(areaBlWithZog.m_height == boundaryOrg.m_height+(2*zog), "m_height failed");
|
||||
QVERIFY2(areaBlWithZog.m_rotation_deg == boundaryOrg.m_rotation_deg, "m_rotation_deg failed");
|
||||
}
|
||||
|
||||
{
|
||||
double rotation_deg = 30;
|
||||
const Polygons::AreaBottomLeft boundaryOrgRot(QPointF(123, 123), width, height, rotation_deg);
|
||||
int zog = 10;
|
||||
const Polygons::AreaBottomLeft areaBlWithZog = Polygons::explosionClusterAddTla(boundaryOrgRot, zog);
|
||||
printAbl(areaBlWithZog);
|
||||
|
||||
QVERIFY2((areaBlWithZog.m_cornerBottomLeft - QPointF(109.34, 119.34)).manhattanLength() < 1, "m_cornerBottomLeft failed");
|
||||
QVERIFY2(areaBlWithZog.m_width == boundaryOrgRot.m_width+(2*zog), "m_width failed");
|
||||
QVERIFY2(areaBlWithZog.m_height == boundaryOrgRot.m_height+(2*zog), "m_height failed");
|
||||
QVERIFY2(areaBlWithZog.m_rotation_deg == boundaryOrgRot.m_rotation_deg, "m_rotation_deg failed");
|
||||
}
|
||||
}
|
||||
|
||||
void UnitTestPolygons::test_explosionClusterAreaToMtpsRelativeToBottomLeft_noRotation()
|
||||
{
|
||||
double width = 1000; // x
|
||||
double height = 100; // y
|
||||
double rotation_deg = 0;
|
||||
const Polygons::AreaBottomLeft boundary(QPointF(123, 123), width, height, rotation_deg);
|
||||
|
||||
const int numberOfMTPs = 4;
|
||||
double singleWidthOut = 0;
|
||||
double singleHeightOut = 0;
|
||||
|
||||
QVector<QPointF> vec = Polygons::explosionClusterAreaToMtpsRelativeToBottomLeft(boundary, numberOfMTPs, &singleWidthOut, &singleHeightOut);
|
||||
|
||||
qCritical() << "vec = " << vec;
|
||||
qCritical() << "singleWidthOut = " << singleWidthOut;
|
||||
qCritical() << "singleHeightOut = " << singleHeightOut;
|
||||
|
||||
// independent on rotation
|
||||
QVERIFY2(vec.size() == numberOfMTPs, "noRotation failed; numberOfMTPs");
|
||||
QVERIFY2(singleWidthOut == width/4, "noRotation failed; singleWidthOut");
|
||||
QVERIFY2(singleHeightOut == height, "noRotation failed; singleHeightOut");
|
||||
|
||||
// depending on rotation
|
||||
QVERIFY2(vec.first() == QPointF(125.0, 50), "noRotation failed");
|
||||
QVERIFY2(vec[1] == QPointF(375.0, 50), "noRotation failed");
|
||||
QVERIFY2(vec[2] == QPointF(625.0, 50), "noRotation failed");
|
||||
QVERIFY2(vec.last() == QPointF(875.0, 50), "noRotation failed");
|
||||
}
|
||||
|
||||
void UnitTestPolygons::test_explosionClusterAreaToMtpsRelativeToBottomLeft_withRotation()
|
||||
{
|
||||
double width = 1000; // x
|
||||
double height = 100; // y
|
||||
double rotation_deg = -90;
|
||||
const Polygons::AreaBottomLeft boundary(QPointF(123, 123), width, height, rotation_deg);
|
||||
|
||||
const int numberOfMTPs = 4;
|
||||
double singleWidthOut = 0;
|
||||
double singleHeightOut = 0;
|
||||
|
||||
QVector<QPointF> vec = Polygons::explosionClusterAreaToMtpsRelativeToBottomLeft(boundary, numberOfMTPs, &singleWidthOut, &singleHeightOut);
|
||||
|
||||
qCritical() << "vec = " << vec;
|
||||
qCritical() << "singleWidthOut = " << singleWidthOut;
|
||||
qCritical() << "singleHeightOut = " << singleHeightOut;
|
||||
|
||||
// independent on rotation
|
||||
QVERIFY2(vec.size() == numberOfMTPs, "withRotation failed; numberOfMTPs");
|
||||
QVERIFY2(singleWidthOut == width/4, "withRotation failed; singleWidthOut");
|
||||
QVERIFY2(singleHeightOut == height, "withRotation failed; singleHeightOut");
|
||||
|
||||
// depending on rotation
|
||||
QVERIFY2(vec.first() == QPointF(-50, 125), "withRotation failed");
|
||||
QVERIFY2(vec[1] == QPointF(-50, 375), "withRotation failed");
|
||||
QVERIFY2(vec[2] == QPointF(-50, 625), "withRotation failed");
|
||||
QVERIFY2(vec.last() == QPointF(-50, 875), "withRotation failed");
|
||||
}
|
||||
|
||||
void UnitTestPolygons::test_explosionClusterSingleExplosionsGAUSS_Mtp()
|
||||
{
|
||||
Database::AesExplosionCluster explosionClusterDb;
|
||||
|
||||
double width = 1000; // x
|
||||
double height = 100; // y
|
||||
double rotation_deg = 0;
|
||||
|
||||
LtsCoordTrans::UtmCoordinate UTM = LtsCoordTrans::UtmCoordinate::fromMgrs(QLatin1String("32UMD100000100000")); // 32U MD 100000 100000
|
||||
|
||||
const Polygons::AreaBottomLeft boundary(UTM.geographic(), width, height, rotation_deg);
|
||||
|
||||
explosionClusterDb.id = 1;
|
||||
|
||||
explosionClusterDb.impactPosition = boundary.m_cornerBottomLeft;
|
||||
explosionClusterDb.impactLength = boundary.m_height;
|
||||
explosionClusterDb.impactWidth = boundary.m_width;
|
||||
explosionClusterDb.rotationAngle = boundary.m_rotation_deg;
|
||||
|
||||
explosionClusterDb.zog = 0;
|
||||
|
||||
explosionClusterDb.impactCount = 8;
|
||||
explosionClusterDb.mhpCountRequest = 4;
|
||||
|
||||
// rotation = 0
|
||||
{
|
||||
double mtpRotationNorthDegree = explosionClusterDb.rotationAngle;
|
||||
const QVector<QPointF> &singleExplosions = Polygons::explosionClusterSingleExplosionsGAUSS_Mtp(explosionClusterDb, mtpRotationNorthDegree);
|
||||
|
||||
qCritical() << "rotation_deg = " << rotation_deg
|
||||
<< ", mtpRotationNorthDegree = " << mtpRotationNorthDegree
|
||||
<< ", explosionClusterDb = " << singleExplosions;
|
||||
for (const auto &singleExplosion : qAsConst(singleExplosions))
|
||||
qDebug() << "singleExUtm: " << LtsCoordTrans::UtmCoordinate::fromGeographic(singleExplosion).mgrs();
|
||||
|
||||
size_t i = 0;
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10029 10048"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10298 10042"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10682 10046"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10908 10055"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10101 10076"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10386 10022"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10581 10032"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10828 10065"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
}
|
||||
|
||||
// rotation = -90
|
||||
rotation_deg = -90;
|
||||
const Polygons::AreaBottomLeft boundary2(UTM.geographic(), width, height, rotation_deg);
|
||||
|
||||
explosionClusterDb.id = 1;
|
||||
|
||||
explosionClusterDb.impactPosition = boundary2.m_cornerBottomLeft;
|
||||
explosionClusterDb.impactLength = boundary2.m_height;
|
||||
explosionClusterDb.impactWidth = boundary2.m_width;
|
||||
explosionClusterDb.rotationAngle = boundary2.m_rotation_deg;
|
||||
{
|
||||
double mtpRotationNorthDegree = explosionClusterDb.rotationAngle;
|
||||
const QVector<QPointF> &singleExplosions = Polygons::explosionClusterSingleExplosionsGAUSS_Mtp(explosionClusterDb, mtpRotationNorthDegree);
|
||||
|
||||
qCritical() << "rotation_deg = " << rotation_deg
|
||||
<< ", mtpRotationNorthDegree = " << mtpRotationNorthDegree
|
||||
<< " explosionClusterDb = " << singleExplosions;
|
||||
for (const auto &singleExplosion : qAsConst(singleExplosions))
|
||||
qCritical() << "singleExUtm: " << LtsCoordTrans::UtmCoordinate::fromGeographic(singleExplosion).mgrs();
|
||||
|
||||
size_t i = 0;
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 09952 10029"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 09958 10298"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 09954 10682"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 09945 10908"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 09924 10101"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 09978 10386"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 09968 10581"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 09935 10828"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
}
|
||||
|
||||
// rotation = -45
|
||||
rotation_deg = -45;
|
||||
int zog = 100;
|
||||
|
||||
const Polygons::AreaBottomLeft boundary3(UTM.geographic(), width, height, rotation_deg);
|
||||
|
||||
explosionClusterDb.id = 1;
|
||||
|
||||
explosionClusterDb.impactPosition = boundary3.m_cornerBottomLeft;
|
||||
explosionClusterDb.impactLength = boundary3.m_height;
|
||||
explosionClusterDb.impactWidth = boundary3.m_width;
|
||||
explosionClusterDb.rotationAngle = boundary3.m_rotation_deg;
|
||||
|
||||
explosionClusterDb.zog = zog;
|
||||
{
|
||||
double mtpRotationNorthDegree = explosionClusterDb.rotationAngle;
|
||||
const QVector<QPointF> &singleExplosions = Polygons::explosionClusterSingleExplosionsGAUSS_Mtp(explosionClusterDb, mtpRotationNorthDegree);
|
||||
|
||||
qCritical() << "rotation_deg = " << rotation_deg
|
||||
<< ", zog = " << zog
|
||||
<< ", mtpRotationNorthDegree = " << mtpRotationNorthDegree
|
||||
<< " explosionClusterDb = " << singleExplosions;
|
||||
for (const auto &singleExplosion : qAsConst(singleExplosions))
|
||||
qCritical() << "singleExUtm: " << LtsCoordTrans::UtmCoordinate::fromGeographic(singleExplosion).mgrs();
|
||||
|
||||
size_t i = 0;
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 09923 09984"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10164 10200"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10480 10536"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10654 10746"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 09925 10104"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10281 10233"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10426 10419"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
QVERIFY2(distanceMeter(singleExplosions[i++], LtsCoordTrans::UtmCoordinate::fromMgrs(QStringLiteral("32U MD 10565 10699"))) < 1, "ERROR, distanceMeter failed!!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("UnitTest_TNE-ALOG", "log4cxxUnitTest.props");
|
||||
|
||||
UnitTestPolygons tc;
|
||||
return QTest::qExec(&tc, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Unittest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
|
||||
|
||||
class UnitTestPolygons : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
// void init();
|
||||
|
||||
void test_QTrans();
|
||||
void test_explosionClusterAddTla();
|
||||
void test_explosionClusterAreaToMtpsRelativeToBottomLeft_noRotation();
|
||||
void test_explosionClusterAreaToMtpsRelativeToBottomLeft_withRotation();
|
||||
|
||||
void test_explosionClusterSingleExplosionsGAUSS_Mtp();
|
||||
|
||||
// void cleanup();
|
||||
|
||||
private:
|
||||
};
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#
|
||||
# @RDE_HEADER@
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(UnitTestSources
|
||||
tne_algo_unit_test.cpp
|
||||
tne_algo_unit_test.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP( UnitTestSources FILES ${UnitTestSources} )
|
||||
|
||||
IF(BUILD_TESTING)
|
||||
ADD_EXECUTABLE(aesUnitTestTneAlgorithmen ${LinkedSources} ${UnitTestSources} )
|
||||
|
||||
TARGET_LINK_LIBRARIES(aesUnitTestTneAlgorithmen
|
||||
NGLLogger
|
||||
nglcoreapplication
|
||||
Qt5::Core
|
||||
Qt5::Test
|
||||
svcAesCommon
|
||||
)
|
||||
|
||||
ADD_TEST(NAME aesUnitTestTneAlgorithmen COMMAND $<TARGET_FILE:aesUnitTestTneAlgorithmen>)
|
||||
|
||||
ENDIF()
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Unittest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "tne_algo_unit_test.h"
|
||||
#include <Services/AreaEffectSimulation/Utils/tne_algorithmen.h>
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <QtTest/QTest>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
using namespace AreaEffectSimulation;
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// This class is an UnitTest with values taken from the TNE.
|
||||
// That was created while Michael Moetje was implementing that code at the TNE (PlayerUnit)
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
void UnitTestVerteilung::test_long()
|
||||
{
|
||||
int size = sizeof(int);
|
||||
std::cout << " sizeof 'int' " << size << std::endl;
|
||||
|
||||
size = sizeof(long);
|
||||
std::cout << " sizeof 'long' " << size << std::endl;
|
||||
|
||||
size = sizeof(long long);
|
||||
std::cout << " sizeof 'long long' " << size << std::endl;
|
||||
|
||||
size = sizeof(qint32);
|
||||
std::cout << " sizeof 'qint32g' " << size << std::endl;
|
||||
}
|
||||
|
||||
void UnitTestVerteilung::test_xorshift32()
|
||||
{
|
||||
// 1
|
||||
ULONG pxInOut = 123;
|
||||
|
||||
ushort ret = TNE_ALGORITHMEN::xorshift32(&pxInOut);
|
||||
std::cout << " test_xorshift32 ret: " << ret << std::endl;
|
||||
QVERIFY2(ret == 28668, "xorshift32 failed");
|
||||
}
|
||||
|
||||
void UnitTestVerteilung::test_xorshift32_nv()
|
||||
{
|
||||
ULONG _generator = 123;
|
||||
short _bereich = 500;
|
||||
|
||||
// _generator = 123, _bereich = 500 => laut Moetje: -73, 93, -79, -321, -25
|
||||
|
||||
int ret = TNE_ALGORITHMEN::xorshift32_nv(&_generator, _bereich, 3);
|
||||
std::cout << " xorshift32_nv ret: " << ret << std::endl;
|
||||
QVERIFY2(ret == -73, "xorshift32_nv failed");
|
||||
|
||||
ret = TNE_ALGORITHMEN::xorshift32_nv(&_generator, _bereich, 3);
|
||||
std::cout << " xorshift32_nv ret: " << ret << std::endl;
|
||||
QVERIFY2(ret == 93, "xorshift32_nv failed");
|
||||
|
||||
ret = TNE_ALGORITHMEN::xorshift32_nv(&_generator, _bereich, 3);
|
||||
std::cout << " xorshift32_nv ret: " << ret << std::endl;
|
||||
QVERIFY2(ret == -79, "xorshift32_nv failed");
|
||||
|
||||
ret = TNE_ALGORITHMEN::xorshift32_nv(&_generator, _bereich, 3);
|
||||
std::cout << " xorshift32_nv ret: " << ret << std::endl;
|
||||
QVERIFY2(ret == -321, "xorshift32_nv failed");
|
||||
|
||||
ret = TNE_ALGORITHMEN::xorshift32_nv(&_generator, _bereich, 3);
|
||||
std::cout << " xorshift32_nv ret: " << ret << std::endl;
|
||||
QVERIFY2(ret == -25, "xorshift32_nv failed");
|
||||
}
|
||||
|
||||
void UnitTestVerteilung::test_xorshift32_nv_saveToFile()
|
||||
{
|
||||
ULONG _generator = 123;
|
||||
SHORT _bereich = 500;
|
||||
|
||||
QString tempDir = QDir::tempPath();
|
||||
QFile file(tempDir + QDir::separator() + QStringLiteral("tne_algorithmen_xorshift32_nv_data.txt"));
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
return;
|
||||
|
||||
QTextStream out(&file);
|
||||
|
||||
out << "Test vom Algorithmus 'xorshift32_nv'" << "\n";
|
||||
out << "_generator = " << _generator << "\n";
|
||||
out << "_bereich = " << _bereich << "\n";
|
||||
out << " Start " << "\n";
|
||||
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
out << "_generator = " << _generator;
|
||||
|
||||
int ret = TNE_ALGORITHMEN::xorshift32_nv(&_generator, _bereich, 3);
|
||||
std::cout << " test_xorshift32_nv ret: " << ret << std::endl;
|
||||
|
||||
out << " -> erzeugter Wert = " << ret << "\n";
|
||||
}
|
||||
out << "Ende :-)" << "\n";
|
||||
}
|
||||
|
||||
void UnitTestVerteilung::test_areaExlosionGAUSS()
|
||||
{
|
||||
const int wirkfeldKennung = 4711;
|
||||
const int breite_m = 500; // Vielfaches von 5m
|
||||
const int tiefe_m = 50; // Vielfaches von 5m
|
||||
const int anzahl_einschlaege = 10;
|
||||
|
||||
QVector<QPointF> impacts = TNE_ALGORITHMEN::areaExlosionsGAUSS(wirkfeldKennung,
|
||||
breite_m, tiefe_m,
|
||||
anzahl_einschlaege);
|
||||
|
||||
QVERIFY2(impacts.size() == anzahl_einschlaege, "test_areaExlosionGAUSS failed");
|
||||
|
||||
QVERIFY2(impacts[0] == QPointF(206, 29), "test_areaExlosionGAUSS failed");
|
||||
QVERIFY2(impacts[1] == QPointF(252, 42), "test_areaExlosionGAUSS failed");
|
||||
QVERIFY2(impacts[2] == QPointF(110, 21), "test_areaExlosionGAUSS failed");
|
||||
QVERIFY2(impacts[3] == QPointF(209, 32), "test_areaExlosionGAUSS failed");
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("UnitTest_TNE-ALOG", "log4cxxUnitTest.props");
|
||||
|
||||
UnitTestVerteilung tc;
|
||||
return QTest::qExec(&tc, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Unittest
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
|
||||
|
||||
using ULONG = quint32;
|
||||
using LONG = qint32;
|
||||
using SHORT = qint32;
|
||||
|
||||
|
||||
/**
|
||||
* @brief This class is an UnitTest with values taken from the TNE.
|
||||
* That was created while Michael Moetje was implementing that code at the TNE (PlayerUnit)
|
||||
*/
|
||||
class UnitTestVerteilung : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
// void init();
|
||||
|
||||
void test_long();
|
||||
|
||||
void test_xorshift32();
|
||||
void test_xorshift32_nv();
|
||||
void test_xorshift32_nv_saveToFile();
|
||||
|
||||
void test_areaExlosionGAUSS();
|
||||
|
||||
|
||||
// void cleanup();
|
||||
|
||||
private:
|
||||
};
|
||||
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Unittest for testing the statemachine for aes objects
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_statemachine_test.h"
|
||||
#include <QDebug>
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
|
||||
using namespace AreaEffectSimulation;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
NGLCoreApplication app(argc, argv);
|
||||
app.createLogger("StateMachineTest", "log4cxx_AreaEffectSimulation.props");
|
||||
|
||||
StateMachineTest *test = new StateMachineTest;
|
||||
int retCode = QTest::qExec(test, argc, argv);
|
||||
delete test;
|
||||
|
||||
return retCode;
|
||||
}
|
||||
|
||||
namespace QTest
|
||||
{
|
||||
template<>
|
||||
char *toString(const AesEffectState &s) { std::ostringstream str; str << s; return strdup(str.str().c_str()); }
|
||||
}
|
||||
|
||||
DummyAesObject::DummyAesObject(QObject *parent)
|
||||
: ObjectBaseTmpl(nullptr, QStringLiteral("DummyAesObject"), parent)
|
||||
{}
|
||||
|
||||
QPolygonF DummyAesObject::generateForm()
|
||||
{
|
||||
return QPolygonF();
|
||||
}
|
||||
|
||||
StateMachineTest::StateMachineTest()
|
||||
: m_dummyAesObject(new DummyAesObject(this))
|
||||
{}
|
||||
|
||||
StateMachineTest::~StateMachineTest()
|
||||
{
|
||||
delete m_dummyAesObject;
|
||||
}
|
||||
|
||||
void StateMachineTest::staticTests()
|
||||
{
|
||||
const time_t tNow = time(nullptr);
|
||||
|
||||
// newly created, nothing set -> checkEnterNewState() should switch to created
|
||||
QCOMPARE(m_dummyAesObject->checkEnterNewState().underlying(), AesEffectState::EsCreated);
|
||||
|
||||
// now we set a activation time -> Prepared
|
||||
m_dummyAesObject->setActivationTime(tNow + 5);
|
||||
QCOMPARE(m_dummyAesObject->checkEnterNewState().underlying(), AesEffectState::EsPrepared);
|
||||
|
||||
// now back to created
|
||||
m_dummyAesObject->setActivationTime(0);
|
||||
QCOMPARE(m_dummyAesObject->checkEnterNewState().underlying(), AesEffectState::EsCreated);
|
||||
|
||||
// directly to activated
|
||||
m_dummyAesObject->setActivationTime(tNow);
|
||||
QCOMPARE(m_dummyAesObject->checkEnterNewState().underlying(), AesEffectState::EsActivated);
|
||||
|
||||
// pause not possible
|
||||
m_dummyAesObject->setSupportsPausing(false);
|
||||
QCOMPARE(m_dummyAesObject->trySwitchToPaused(), false);
|
||||
|
||||
// now possible
|
||||
m_dummyAesObject->setSupportsPausing(true);
|
||||
QCOMPARE(m_dummyAesObject->trySwitchToPaused(), true);
|
||||
|
||||
// and back to activated
|
||||
QCOMPARE(m_dummyAesObject->isActivationTimeReached(), true); // sanity
|
||||
QCOMPARE(m_dummyAesObject->trySwitchToActivated(), true);
|
||||
|
||||
// set end time
|
||||
m_dummyAesObject->setActivationTime(tNow);
|
||||
m_dummyAesObject->setDurationSec(1);
|
||||
|
||||
// wait 1.5sec (100 * QTest::qWait(15))
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
QTest::qWait(15);
|
||||
}
|
||||
QCOMPARE(m_dummyAesObject->checkEnterNewState().underlying(), AesEffectState::EsExpired);
|
||||
|
||||
// try to delete it
|
||||
QCOMPARE(m_dummyAesObject->trySwitchToRemoved(), false);
|
||||
m_dummyAesObject->setActivationTime(0);
|
||||
m_dummyAesObject->setDurationSec(0);
|
||||
m_dummyAesObject->setAesEffectState(AesEffectState::EsUnknown);
|
||||
QCOMPARE(m_dummyAesObject->trySwitchToRemoved(), false);
|
||||
m_dummyAesObject->setAesEffectState(AesEffectState::EsCreated);
|
||||
QCOMPARE(m_dummyAesObject->trySwitchToRemoved(), true);
|
||||
m_dummyAesObject->setAesEffectState(AesEffectState::EsPaused);
|
||||
QCOMPARE(m_dummyAesObject->trySwitchToRemoved(), true);
|
||||
// an active/paused object must not set to deleted but to expired
|
||||
QCOMPARE(m_dummyAesObject->effectState().underlying(), AesEffectState::EsExpired);
|
||||
QCOMPARE(m_dummyAesObject->trySwitchToCreated(), false);
|
||||
}
|
||||
|
||||
void StateMachineTest::dynamicTests()
|
||||
{
|
||||
const time_t tNow = time(nullptr);
|
||||
|
||||
QSignalSpy spy(m_dummyAesObject, &DummyAesObject::effectStateChanged);
|
||||
|
||||
m_dummyAesObject->setAesEffectState(AesEffectState::EsUnknown);
|
||||
// set activation time
|
||||
m_dummyAesObject->setActivationTime(tNow + 1);
|
||||
QCOMPARE(m_dummyAesObject->isActivationTimeSet(), true);
|
||||
|
||||
// set end time
|
||||
m_dummyAesObject->setDurationSec(2);
|
||||
QCOMPARE(m_dummyAesObject->isEndTimeSet(), true);
|
||||
|
||||
QCOMPARE(m_dummyAesObject->checkEnterNewState().underlying(), AesEffectState::EsPrepared);
|
||||
QCOMPARE(spy.count(), 2); // Created, Prepared
|
||||
spy.clear();
|
||||
|
||||
qDebug() << "Waiting for activation time";
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
QTest::qWait(15); // wait until the object is Activated
|
||||
if (m_dummyAesObject->effectState() == AesEffectState::EsActivated)
|
||||
break;
|
||||
}
|
||||
QCOMPARE(m_dummyAesObject->effectState().underlying(), AesEffectState::EsActivated);
|
||||
|
||||
qDebug() << "Waiting for end time";
|
||||
for (int i = 0; i < 200; ++i)
|
||||
{
|
||||
QTest::qWait(15); // wait until the object is Expired
|
||||
if (m_dummyAesObject->effectState() == AesEffectState::EsExpired)
|
||||
break;
|
||||
}
|
||||
AreaEffectSimulation::AesEffectState state = m_dummyAesObject->effectState();
|
||||
QCOMPARE(state.underlying(), AesEffectState::EsExpired);
|
||||
|
||||
QCOMPARE(spy.count(), 2); // Activated, Done
|
||||
spy.clear();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Unittest for testing the statemachine for aes objects
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AreaEffectSimulation/object_base.h>
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
class DummyAesObject final: public ObjectBaseTmpl<Database::AesNContamination>
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DummyAesObject(QObject *parent = nullptr);
|
||||
|
||||
void setAesEffectState(AesEffectState newState) { m_data.effectStateId = newState; }
|
||||
void setSupportsPausing(bool bSupportsPausing) { m_bSupportsPausing = bSupportsPausing; }
|
||||
void setActivationTime(time_t actTime)
|
||||
{
|
||||
if (actTime)
|
||||
m_data.effectStart = QDateTime::fromMSecsSinceEpoch(actTime * 1000LL);
|
||||
else
|
||||
m_data.effectStart = QDateTime();
|
||||
}
|
||||
void setDurationSec(int durationSec)
|
||||
{
|
||||
m_data.effectDuration = durationSec * 1000;
|
||||
}
|
||||
qint64 partitionTimeMSec() const override
|
||||
{
|
||||
return partitionTime().toMSecsSinceEpoch();
|
||||
}
|
||||
QDateTime partitionTime() const override
|
||||
{
|
||||
return QDateTime::currentDateTimeUtc();
|
||||
}
|
||||
std::vector<Core::GeoPosition> form() const override { return {}; }
|
||||
QPolygonF generateForm() override;
|
||||
AesType aesType() const override { return AesType::AtUnknown; }
|
||||
bool isCentral() const override { return m_data.isCentral; }
|
||||
};
|
||||
|
||||
class StateMachineTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
StateMachineTest();
|
||||
~StateMachineTest();
|
||||
private Q_SLOTS:
|
||||
void staticTests();
|
||||
void dynamicTests();
|
||||
|
||||
private:
|
||||
DummyAesObject *m_dummyAesObject;
|
||||
};
|
||||
} // namespace AreaEffectSimulation
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Some helper classes / functions for AES
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#include "aes_helper.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
|
||||
|
||||
namespace AreaEffectSimulation
|
||||
{
|
||||
|
||||
//
|
||||
// class HandledImpactsStorage::Private
|
||||
//
|
||||
class HandledImpactsStorage::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
~Private() = default;
|
||||
|
||||
// data:
|
||||
QHash<int, QSet<int>> m_aesItemId2Index; // Key = aesItemId ; processed/calculated index
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// class HandledImpactsStorage
|
||||
//
|
||||
HandledImpactsStorage::HandledImpactsStorage()
|
||||
: d(new Private)
|
||||
{}
|
||||
|
||||
HandledImpactsStorage::~HandledImpactsStorage()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void HandledImpactsStorage::setIndexProcessed(int aesItemId, int index)
|
||||
{
|
||||
d->m_aesItemId2Index[aesItemId].insert(index);
|
||||
}
|
||||
|
||||
bool HandledImpactsStorage::isIndexProcessed(int aesItemId, int index)
|
||||
{
|
||||
return d->m_aesItemId2Index[aesItemId].contains(index);
|
||||
}
|
||||
|
||||
void HandledImpactsStorage::removeAesItem(int aesItemId)
|
||||
{
|
||||
d->m_aesItemId2Index.remove(aesItemId);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
} // namespace AreaEffectSimulation
|
||||
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