first commit
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
# CMake module includes.
|
||||
include(SetupFGFSEmbeddedResources)
|
||||
include(SetupFGFSIncludes)
|
||||
include(SetupFGFSLibraries)
|
||||
include(SetupMSVCGrouping)
|
||||
|
||||
# Add each test suite category.
|
||||
foreach(test_category
|
||||
gui_tests
|
||||
simgear_tests
|
||||
system_tests
|
||||
unit_tests
|
||||
fgdata_tests
|
||||
)
|
||||
add_subdirectory(${test_category})
|
||||
endforeach(test_category)
|
||||
|
||||
# Add the testing API.
|
||||
add_subdirectory(FGTestApi)
|
||||
|
||||
# Add all test suite sources and headers.
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
bootstrap.cxx
|
||||
dataStore.cxx
|
||||
fgCompilerOutputter.cxx
|
||||
fgTestListener.cxx
|
||||
fgTestRunner.cxx
|
||||
formatting.cxx
|
||||
logging.cxx
|
||||
testSuite.cxx
|
||||
)
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
dataStore.hxx
|
||||
fgCompilerOutputter.hxx
|
||||
fgTestListener.hxx
|
||||
fgTestRunner.hxx
|
||||
formatting.hxx
|
||||
logging.hxx
|
||||
)
|
||||
|
||||
# The test suite output directory.
|
||||
set(TESTSUITE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
# Get the CppUnit sources and headers to be built into the test suite.
|
||||
if (NOT SYSTEM_CPPUNIT)
|
||||
message(STATUS "CppUnit: Building the FlightGear supplied CppUnit library")
|
||||
|
||||
get_property(CPPUNIT_SOURCES GLOBAL PROPERTY CPPUNIT_SOURCES)
|
||||
get_property(CPPUNIT_HEADERS GLOBAL PROPERTY CPPUNIT_HEADERS)
|
||||
|
||||
|
||||
add_library(CppUnitLib STATIC ${CPPUNIT_SOURCES} ${CPPUNIT_HEADERS})
|
||||
|
||||
target_include_directories(CppUnitLib PUBLIC "${PROJECT_SOURCE_DIR}/3rdparty/cppunit/include")
|
||||
|
||||
set(CPPUNIT_LIBRARIES CppUnitLib)
|
||||
else()
|
||||
message(STATUS "CppUnit: Linking to the system supplied CppUnit library")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Set up all test suites as CTests.
|
||||
|
||||
# Activation.
|
||||
include(Dart)
|
||||
|
||||
# System test suites.
|
||||
add_test(AeroMeshSystemTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -s AeroMeshTests)
|
||||
#add_test(GPSSystemTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -s GPSTests)
|
||||
#add_test(NavaidsSystemTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -s NavaidsTests)
|
||||
|
||||
# Unit test suites.
|
||||
add_test(AddonManagementUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u AddonManagementTests)
|
||||
add_test(AeroElementUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u AeroElementTests)
|
||||
add_test(AircraftPerformanceUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u AircraftPerformanceTests)
|
||||
add_test(AutosaveMigrationUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u AutosaveMigrationTests)
|
||||
add_test(FlightplanUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u FlightplanTests)
|
||||
add_test(FPNasalUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u FPNasalTests)
|
||||
add_test(GPSUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u GPSTests)
|
||||
add_test(HoldControllerUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u HoldControllerTests)
|
||||
if(ENABLE_HID_INPUT)
|
||||
add_test(HIDInputUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u HIDInputTests)
|
||||
endif()
|
||||
add_test(LaRCSimMatrixUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u LaRCSimMatrixTests)
|
||||
add_test(MktimeUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u MktimeTests)
|
||||
add_test(NasalSysUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u NasalSysTests)
|
||||
add_test(NavaidsUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u NavaidsTests)
|
||||
add_test(NavRadioUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u NavRadioTests)
|
||||
add_test(PosInitUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u PosInitTests)
|
||||
add_test(RNAVProcedureUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u RNAVProcedureTests)
|
||||
add_test(RouteManagerUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u RouteManagerTests)
|
||||
add_test(YASimAtmosphereUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -u YASimAtmosphereTests)
|
||||
|
||||
# GUI test suites.
|
||||
|
||||
# Simgear unit test suites.
|
||||
add_test(CanvasSimgearUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -m CanvasTests)
|
||||
add_test(MathGeodesySimgearUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -m MathGeodesyTests)
|
||||
add_test(SimgearPropsSimgearUnitTests ${TESTSUITE_OUTPUT_DIR}/fgfs_test_suite --ctest -m SimgearPropsTests)
|
||||
|
||||
# FGData test suites.
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Set up the binary.
|
||||
|
||||
# Set up the embedded resources.
|
||||
setup_fgfs_embedded_resources()
|
||||
|
||||
# Sort the sources and headers for MSVC.
|
||||
setup_msvc_grouping()
|
||||
|
||||
# most object files come from fgfsObjects target: this property
|
||||
# contains all the sources which need to be compiled seperately
|
||||
# for the test-suite, becuase they depend on BUILDING_TESTSUTIE define
|
||||
# we setup below via target_compile_definitions
|
||||
|
||||
get_property(TEST_SOURCES GLOBAL PROPERTY FG_TEST_SOURCES)
|
||||
|
||||
# Set up the separate executable for running the test suite.
|
||||
add_executable(fgfs_test_suite
|
||||
${TEST_SOURCES}
|
||||
${TESTSUITE_SOURCES}
|
||||
${TESTSUITE_HEADERS}
|
||||
$<TARGET_OBJECTS:fgfsObjects>
|
||||
)
|
||||
|
||||
add_dependencies(fgfs_test_suite buildId)
|
||||
set_target_properties(fgfs_test_suite
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${TESTSUITE_OUTPUT_DIR}"
|
||||
)
|
||||
if(ENABLE_AUTOTESTING)
|
||||
set(TEST_SUITE_COMMAND "fgfs_test_suite")
|
||||
set(TEST_SUITE_COMMENT "Running the full FlightGear test suite")
|
||||
else()
|
||||
set(TEST_SUITE_COMMENT "Building the FlightGear test suite.")
|
||||
endif(ENABLE_AUTOTESTING)
|
||||
|
||||
# Set up the target links.
|
||||
setup_fgfs_libraries(fgfs_test_suite)
|
||||
# Additional search paths for includes.
|
||||
setup_fgfs_includes(fgfs_test_suite)
|
||||
|
||||
# test codce includes its headers as test_suite/foo.h, so we need this
|
||||
target_include_directories(fgfs_test_suite PUBLIC ${PROJECT_SOURCE_DIR})
|
||||
|
||||
target_compile_definitions(fgfs_test_suite PUBLIC BUILDING_TESTSUITE)
|
||||
|
||||
# Additional libraries just for the test suite.
|
||||
target_link_libraries(fgfs_test_suite ${CPPUNIT_LIBRARIES})
|
||||
|
||||
# target to run the tests
|
||||
if (MSVC)
|
||||
file(TO_NATIVE_PATH "${FG_QT_BIN_DIR}" _qt5_bin_dir_native)
|
||||
file(TO_NATIVE_PATH "${FINAL_MSVC_3RDPARTY_DIR}/bin" _msvc_3rdparty_bin_dir)
|
||||
file(TO_NATIVE_PATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}" _install_bin_dir)
|
||||
|
||||
set(CMAKE_MSVCIDE_RUN_PATH "${_install_bin_dir};${_msvc_3rdparty_bin_dir};${_qt5_bin_dir_native}")
|
||||
endif()
|
||||
|
||||
if (FG_QT_ROOT_DIR)
|
||||
# for QtPlatformHeaders
|
||||
target_include_directories(fgfs_test_suite PRIVATE ${FG_QT_ROOT_DIR}/include)
|
||||
endif()
|
||||
|
||||
|
||||
add_custom_target(test_suite
|
||||
${TEST_SUITE_COMMAND}
|
||||
DEPENDS fgfs_test_suite
|
||||
COMMENT ${TEST_SUITE_COMMENT}
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testGlobals.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/NavDataCache.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/PrivateAccessorFDM.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/scene_graph.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestPilot.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/NasalUnitTesting_TestSuite.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestDataLogger.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testApis.cxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testGlobals.hxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/NavDataCache.hxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/PrivateAccessorFDM.hxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/scene_graph.hxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestPilot.hxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestDataLogger.hxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,131 @@
|
||||
// Unit-test API for nasal
|
||||
//
|
||||
// There are two versions of this module, and we load one or the other
|
||||
// depending on if we're running the test_suite (using CppUnit) or
|
||||
// the normal simulator. The logic is that aircraft-developers and
|
||||
// people hacking Nasal likely don't have a way to run the test-suite,
|
||||
// whereas core-developers and Jenksin want a way to run all tests
|
||||
// through the standard CppUnit mechanim. So we have a consistent
|
||||
// Nasal API, but different implement in fgfs_test_suite vs
|
||||
// normal fgfs executable.
|
||||
//
|
||||
// Copyright (C) 2020 James Turner
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/util.hxx>
|
||||
|
||||
#include <Scripting/NasalSys.hxx>
|
||||
#include <Scripting/NasalSys_private.hxx>
|
||||
|
||||
#include <cppunit/TestAssert.h>
|
||||
|
||||
#include <simgear/nasal/cppbind/from_nasal.hxx>
|
||||
#include <simgear/nasal/cppbind/to_nasal.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalHash.hxx>
|
||||
#include <simgear/nasal/cppbind/Ghost.hxx>
|
||||
|
||||
static CppUnit::SourceLine nasalSourceLine(const nasal::CallContext& ctx)
|
||||
{
|
||||
const string fileName = ctx.from_nasal<string>(naGetSourceFile(ctx.c_ctx(), 0));
|
||||
const int lineNumber = naGetLine(ctx.c_ctx(), 0);
|
||||
return CppUnit::SourceLine(fileName, lineNumber);
|
||||
}
|
||||
|
||||
static naRef f_assert(const nasal::CallContext& ctx )
|
||||
{
|
||||
bool pass = ctx.requireArg<bool>(0);
|
||||
auto msg = ctx.getArg<string>(1, "assert failed:");
|
||||
|
||||
CppUnit::Asserter::failIf(!pass, "assertion failed:" + msg, nasalSourceLine(ctx));
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_fail(const nasal::CallContext& ctx )
|
||||
{
|
||||
auto msg = ctx.getArg<string>(0);
|
||||
|
||||
CppUnit::Asserter::fail("assertion failed:" + msg,
|
||||
nasalSourceLine(ctx));
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_assert_equal(const nasal::CallContext& ctx )
|
||||
{
|
||||
naRef argA = ctx.requireArg<naRef>(0);
|
||||
naRef argB = ctx.requireArg<naRef>(1);
|
||||
auto msg = ctx.getArg<string>(2, "assert_equal failed");
|
||||
|
||||
bool same = nasalStructEqual(ctx.c_ctx(), argA, argB);
|
||||
if (!same) {
|
||||
|
||||
string aStr = ctx.from_nasal<string>(argA);
|
||||
string bStr = ctx.from_nasal<string>(argB);
|
||||
msg += "; expected:" + aStr + ", actual:" + bStr;
|
||||
|
||||
CppUnit::Asserter::fail(msg, nasalSourceLine(ctx));
|
||||
}
|
||||
|
||||
return naNil();
|
||||
}
|
||||
|
||||
static naRef f_equal(const nasal::CallContext& ctx)
|
||||
{
|
||||
naRef argA = ctx.requireArg<naRef>(0);
|
||||
naRef argB = ctx.requireArg<naRef>(1);
|
||||
|
||||
bool same = nasalStructEqual(ctx.c_ctx(), argA, argB);
|
||||
return naNum(same);
|
||||
}
|
||||
|
||||
static naRef f_assert_doubles_equal(const nasal::CallContext& ctx )
|
||||
{
|
||||
double argA = ctx.requireArg<double>(0);
|
||||
double argB = ctx.requireArg<double>(1);
|
||||
double tolerance = ctx.requireArg<double>(2);
|
||||
|
||||
auto msg = ctx.getArg<string>(3, "assert_doubles_equal failed");
|
||||
|
||||
const bool same = fabs(argA - argB) < tolerance;
|
||||
if (!same) {
|
||||
msg += "; expected:" + std::to_string(argA) + ", actual:" + std::to_string(argB);
|
||||
CppUnit::Asserter::fail(msg, nasalSourceLine(ctx));
|
||||
}
|
||||
|
||||
return naNil();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
naRef initNasalUnitTestCppUnit(naRef nasalGlobals, naContext c)
|
||||
{
|
||||
nasal::Hash globals_module(nasalGlobals, c),
|
||||
unitTest = globals_module.createHash("unitTest");
|
||||
|
||||
unitTest.set("assert", f_assert);
|
||||
unitTest.set("fail", f_fail);
|
||||
unitTest.set("assert_equal", f_assert_equal);
|
||||
unitTest.set("equal", f_equal);
|
||||
unitTest.set("assert_doubles_equal", f_assert_doubles_equal);
|
||||
|
||||
return naNil();
|
||||
}
|
||||
|
||||
void shutdownNasalUnitTestInSim()
|
||||
{
|
||||
// stub
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "NavDataCache.hxx"
|
||||
|
||||
#include <Navaids/NavDataCache.hxx>
|
||||
|
||||
|
||||
namespace FGTestApi {
|
||||
|
||||
namespace setUp {
|
||||
|
||||
void initNavDataCache()
|
||||
{
|
||||
if (flightgear::NavDataCache::instance())
|
||||
return;
|
||||
|
||||
flightgear::NavDataCache* cache = flightgear::NavDataCache::createInstance();
|
||||
if (cache->isRebuildRequired()) {
|
||||
std::cerr << "Navcache rebuild for testing" << std::flush;
|
||||
|
||||
while (cache->rebuild() != flightgear::NavDataCache::REBUILD_DONE) {
|
||||
SGTimeStamp::sleepForMSec(1000);
|
||||
std::cerr << "." << std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace setUp.
|
||||
|
||||
} // End of namespace FGTestApi.
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FG_NAV_DATA_CACHE_TEST_HELPERS_HXX
|
||||
#define FG_NAV_DATA_CACHE_TEST_HELPERS_HXX
|
||||
|
||||
namespace FGTestApi {
|
||||
|
||||
namespace setUp {
|
||||
|
||||
|
||||
void initNavDataCache();
|
||||
|
||||
} // End of namespace setUp.
|
||||
|
||||
} // End of namespace FGTestApi.
|
||||
|
||||
#endif // of FG_NAV_DATA_CACHE_TEST_HELPERS_HXX
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "PrivateAccessorFDM.hxx"
|
||||
|
||||
#include <FDM/AIWake/AIWakeGroup.hxx>
|
||||
#include <FDM/AIWake/AircraftMesh.hxx>
|
||||
#include <FDM/AIWake/WakeMesh.hxx>
|
||||
#include <FDM/YASim/Atmosphere.hpp>
|
||||
|
||||
|
||||
|
||||
// Access variables from src/FDM/AIWake/AIWakeGroup.hxx.
|
||||
WakeMesh*
|
||||
FGTestApi::PrivateAccessor::FDM::Accessor::read_FDM_AIWake_AIWakeGroup_aiWakeData(AIWakeGroup* instance, int i)
|
||||
{
|
||||
return instance->_aiWakeData[i].mesh;
|
||||
}
|
||||
|
||||
|
||||
// Access variables from src/FDM/AIWake/AircraftMesh.hxx.
|
||||
const std::vector<SGVec3d>
|
||||
FGTestApi::PrivateAccessor::FDM::Accessor::read_FDM_AIWake_AircraftMesh_collPt(AircraftMesh* instance) const
|
||||
{
|
||||
return instance->collPt;
|
||||
}
|
||||
|
||||
const std::vector<SGVec3d>
|
||||
FGTestApi::PrivateAccessor::FDM::Accessor::read_FDM_AIWake_AircraftMesh_midPt(AircraftMesh* instance) const
|
||||
{
|
||||
return instance->midPt;
|
||||
}
|
||||
|
||||
|
||||
// Access variables from src/FDM/AIWake/WakeMesh.hxx.
|
||||
const std::vector<AeroElement_ptr>
|
||||
FGTestApi::PrivateAccessor::FDM::Accessor::read_FDM_AIWake_WakeMesh_elements(WakeMesh* instance) const
|
||||
{
|
||||
return instance->elements;
|
||||
}
|
||||
|
||||
int
|
||||
FGTestApi::PrivateAccessor::FDM::Accessor::read_FDM_AIWake_WakeMesh_nelm(WakeMesh* instance) const
|
||||
{
|
||||
return instance->nelm;
|
||||
}
|
||||
|
||||
double **
|
||||
FGTestApi::PrivateAccessor::FDM::Accessor::read_FDM_AIWake_WakeMesh_Gamma(WakeMesh* instance) const
|
||||
{
|
||||
return instance->Gamma;
|
||||
}
|
||||
|
||||
|
||||
// Access variables from src/FDM/YASim/Atmosphere.hxx.
|
||||
float
|
||||
FGTestApi::PrivateAccessor::FDM::Accessor::read_FDM_YASim_Atmosphere_numColumns(std::unique_ptr<yasim::Atmosphere> &instance) const
|
||||
{
|
||||
return instance->numColumns;
|
||||
}
|
||||
|
||||
float
|
||||
FGTestApi::PrivateAccessor::FDM::Accessor::read_FDM_YASim_Atmosphere_data(std::unique_ptr<yasim::Atmosphere> &instance, int i, int j) const
|
||||
{
|
||||
return instance->data[i][j];
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef _FG_PRIVATE_ACCESSOR_FDM_HXX
|
||||
#define _FG_PRIVATE_ACCESSOR_FDM_HXX
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
|
||||
// Forward declarations for src/FDM/AIWake.
|
||||
class AIWakeData;
|
||||
class AIWakeGroup;
|
||||
class AircraftMesh;
|
||||
class WakeMesh;
|
||||
class AeroElement;
|
||||
typedef SGSharedPtr<AeroElement> AeroElement_ptr;
|
||||
|
||||
// Forward declaration for: src/FDM/YASim.
|
||||
namespace yasim {
|
||||
class Atmosphere;
|
||||
}
|
||||
|
||||
|
||||
namespace FGTestApi {
|
||||
namespace PrivateAccessor {
|
||||
namespace FDM {
|
||||
|
||||
class Accessor
|
||||
{
|
||||
public:
|
||||
// Access variables from src/FDM/AIWake/AIWakeGroup.hxx.
|
||||
WakeMesh* read_FDM_AIWake_AIWakeGroup_aiWakeData(AIWakeGroup* instance, int i);
|
||||
|
||||
// Access variables from src/FDM/AIWake/AircraftMesh.hxx.
|
||||
const std::vector<SGVec3d> read_FDM_AIWake_AircraftMesh_collPt(AircraftMesh* instance) const;
|
||||
const std::vector<SGVec3d> read_FDM_AIWake_AircraftMesh_midPt(AircraftMesh* instance) const;
|
||||
|
||||
// Access variables from src/FDM/AIWake/WakeMesh.hxx.
|
||||
const std::vector<AeroElement_ptr> read_FDM_AIWake_WakeMesh_elements(WakeMesh* instance) const;
|
||||
int read_FDM_AIWake_WakeMesh_nelm(WakeMesh* instance) const;
|
||||
double **read_FDM_AIWake_WakeMesh_Gamma(WakeMesh* instance) const;
|
||||
|
||||
// Access variables from src/FDM/YASim/Atmosphere.hxx.
|
||||
float read_FDM_YASim_Atmosphere_numColumns(std::unique_ptr<yasim::Atmosphere> &instance) const;
|
||||
float read_FDM_YASim_Atmosphere_data(std::unique_ptr<yasim::Atmosphere> &instance, int i, int j) const;
|
||||
};
|
||||
|
||||
} // End of namespace FDM.
|
||||
} // End of namespace PrivateAccessor.
|
||||
} // End of namespace FGTestApi.
|
||||
|
||||
#endif // _FG_PRIVATE_ACCESSOR_FDM_HXX
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (C) 2020 James Turner
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TestDataLogger.hxx"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include <simgear/io/iostreams/sgstream.hxx>
|
||||
|
||||
#include "Main/globals.hxx"
|
||||
|
||||
namespace FGTestApi {
|
||||
|
||||
using DoubleVec = std::vector<double>;
|
||||
|
||||
static std::unique_ptr<DataLogger> static_instance;
|
||||
|
||||
class DataLogger::DataLoggerPrivate
|
||||
{
|
||||
public:
|
||||
sg_ofstream _stream;
|
||||
|
||||
struct SampleInfo {
|
||||
int column;
|
||||
std::string name;
|
||||
// range / units info, later
|
||||
SGPropertyNode_ptr property;
|
||||
};
|
||||
|
||||
double _currentTimeBase;
|
||||
std::vector<SampleInfo> _samples;
|
||||
DoubleVec _openRow;
|
||||
bool _didHeader = false;
|
||||
|
||||
void writeCurrentRow()
|
||||
{
|
||||
if (!_didHeader) {
|
||||
writeHeader();
|
||||
_didHeader = true;
|
||||
}
|
||||
|
||||
// capture property values into the open row data
|
||||
std::for_each(_samples.begin(), _samples.end(), [this](const SampleInfo& info) {
|
||||
if (info.property) {
|
||||
_openRow[info.column] = info.property->getDoubleValue();
|
||||
}
|
||||
});
|
||||
|
||||
// write time base
|
||||
_stream << globals->get_sim_time_sec() << ",";
|
||||
|
||||
for (const auto v : _openRow) {
|
||||
if (std::isnan(v)) {
|
||||
_stream << ","; // skip this data point
|
||||
} else {
|
||||
_stream << v << ",";
|
||||
}
|
||||
}
|
||||
|
||||
_stream << "\n";
|
||||
|
||||
std::fill(_openRow.begin(), _openRow.end(), std::numeric_limits<double>::quiet_NaN());
|
||||
}
|
||||
|
||||
void writeHeader()
|
||||
{
|
||||
_stream << "sim-time, ";
|
||||
std::for_each(_samples.begin(), _samples.end(), [this](const SampleInfo& info) {
|
||||
_stream << info.name << ", ";
|
||||
});
|
||||
|
||||
_stream << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
DataLogger::DataLogger()
|
||||
{
|
||||
d.reset(new DataLoggerPrivate);
|
||||
}
|
||||
|
||||
DataLogger::~DataLogger()
|
||||
{
|
||||
d->_stream.close();
|
||||
}
|
||||
|
||||
bool DataLogger::isActive()
|
||||
{
|
||||
return static_instance != nullptr;
|
||||
}
|
||||
|
||||
DataLogger* DataLogger::instance()
|
||||
{
|
||||
if (!static_instance) {
|
||||
static_instance.reset(new DataLogger);
|
||||
}
|
||||
|
||||
return static_instance.get();
|
||||
}
|
||||
|
||||
void DataLogger::initTest(const std::string& testName)
|
||||
{
|
||||
d->_stream = sg_ofstream(testName + "_trace.csv");
|
||||
}
|
||||
|
||||
void DataLogger::tearDown()
|
||||
{
|
||||
if (static_instance) {
|
||||
static_instance.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void DataLogger::writeRecord()
|
||||
{
|
||||
d->writeCurrentRow();
|
||||
}
|
||||
|
||||
void DataLogger::recordProperty(const std::string& name, SGPropertyNode_ptr prop)
|
||||
{
|
||||
int index = static_cast<int>(d->_samples.size());
|
||||
DataLoggerPrivate::SampleInfo info{index, name, prop};
|
||||
d->_samples.push_back(info);
|
||||
|
||||
if (d->_openRow.size() <= index) {
|
||||
d->_openRow.resize(index + 1, std::numeric_limits<double>::quiet_NaN());
|
||||
}
|
||||
}
|
||||
|
||||
void DataLogger::recordSamplePoint(const std::string& name, double value)
|
||||
{
|
||||
auto it = std::find_if(d->_samples.begin(), d->_samples.end(), [&name](const DataLoggerPrivate::SampleInfo& sample) {
|
||||
return name == sample.name;
|
||||
});
|
||||
|
||||
int index = 0;
|
||||
if (it == d->_samples.end()) {
|
||||
index = static_cast<int>(d->_samples.size());
|
||||
DataLoggerPrivate::SampleInfo info{index, name};
|
||||
d->_samples.push_back(info);
|
||||
} else {
|
||||
index = it->column;
|
||||
}
|
||||
|
||||
// grow _openRow as required
|
||||
if (d->_openRow.size() <= index) {
|
||||
d->_openRow.resize(index + 1, std::numeric_limits<double>::quiet_NaN());
|
||||
}
|
||||
|
||||
d->_openRow[index] = value;
|
||||
}
|
||||
|
||||
} // namespace FGTestApi
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2020 James Turner
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
namespace FGTestApi {
|
||||
|
||||
class DataLogger
|
||||
{
|
||||
public:
|
||||
~DataLogger();
|
||||
|
||||
static DataLogger* instance();
|
||||
static bool isActive();
|
||||
|
||||
void initTest(const std::string& testName);
|
||||
|
||||
void recordProperty(const std::string& name, SGPropertyNode_ptr prop);
|
||||
|
||||
void setUp();
|
||||
|
||||
void tearDown();
|
||||
|
||||
void recordSamplePoint(const std::string& name, double value);
|
||||
|
||||
void writeRecord();
|
||||
|
||||
private:
|
||||
DataLogger();
|
||||
|
||||
class DataLoggerPrivate;
|
||||
std::unique_ptr<DataLoggerPrivate> d;
|
||||
};
|
||||
|
||||
|
||||
} // namespace FGTestApi
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (C) 2019 James Turner
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TestPilot.hxx"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <simgear/math/SGGeodesy.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/math/SGGeod.hxx>
|
||||
|
||||
#include <Aircraft/AircraftPerformance.hxx> // for formulae
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
#include "TestDataLogger.hxx"
|
||||
|
||||
namespace FGTestApi {
|
||||
|
||||
TestPilot::TestPilot(SGPropertyNode_ptr props) :
|
||||
_propRoot(props)
|
||||
{
|
||||
if (!_propRoot) {
|
||||
// use default properties
|
||||
_propRoot = globals->get_props();
|
||||
}
|
||||
|
||||
_latProp = _propRoot->getNode("position/latitude-deg", true);
|
||||
_lonProp = _propRoot->getNode("position/longitude-deg", true);
|
||||
_altitudeProp = _propRoot->getNode("position/altitude-ft", true);
|
||||
_headingProp = _propRoot->getNode("orientation/heading-deg", true);
|
||||
_speedKnotsProp = _propRoot->getNode("velocities/airspeed-kt", true);
|
||||
_speedMachProp = _propRoot->getNode("velocities/mach", true);
|
||||
_groundspeedKnotsProp = _propRoot->getNode("velocities/groundspeed-kt", true);
|
||||
_verticalFPMProp = _propRoot->getNode("velocities/vertical-fpm", true);
|
||||
|
||||
globals->add_subsystem("flight", this, SGSubsystemMgr::FDM);
|
||||
}
|
||||
|
||||
TestPilot::~TestPilot()
|
||||
{
|
||||
}
|
||||
|
||||
void TestPilot::resetAtPosition(const SGGeod& pos)
|
||||
{
|
||||
_turnActive = false;
|
||||
setPosition(pos);
|
||||
}
|
||||
|
||||
void TestPilot::init()
|
||||
{
|
||||
_vspeedFPM = 1200;
|
||||
}
|
||||
|
||||
void TestPilot::update(double dt)
|
||||
{
|
||||
updateValues(dt);
|
||||
}
|
||||
|
||||
void TestPilot::setSpeedKts(double knots)
|
||||
{
|
||||
_speedKnots = knots;
|
||||
}
|
||||
|
||||
void TestPilot::setVerticalFPM(double fpm)
|
||||
{
|
||||
_vspeedFPM = fpm;
|
||||
}
|
||||
|
||||
void TestPilot::setCourseTrue(double deg)
|
||||
{
|
||||
_trueCourseDeg = deg;
|
||||
}
|
||||
|
||||
void TestPilot::turnToCourse(double deg)
|
||||
{
|
||||
_turnActive = true;
|
||||
_targetCourseDeg = deg;
|
||||
}
|
||||
|
||||
void TestPilot::flyHeading(double hdg)
|
||||
{
|
||||
_lateralMode = LateralMode::Heading;
|
||||
_turnActive = true;
|
||||
_targetCourseDeg = hdg;
|
||||
}
|
||||
|
||||
void TestPilot::flyGPSCourse(GPS *gps)
|
||||
{
|
||||
_gps = gps;
|
||||
_gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||
_gpsLegCourse = _gpsNode->getNode("wp/leg-true-course-deg", true);
|
||||
_courseErrorNm = _gpsNode->getNode("wp/wp[1]/course-error-nm", true);
|
||||
|
||||
_lateralMode = LateralMode::GPSCourse;
|
||||
_turnActive = false;
|
||||
}
|
||||
|
||||
void TestPilot::flyGPSCourseOffset(GPS *gps, double offsetNm)
|
||||
{
|
||||
_gps = gps;
|
||||
_gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||
_gpsLegCourse = _gpsNode->getNode("wp/leg-true-course-deg", true);
|
||||
_courseErrorNm = _gpsNode->getNode("wp/wp[1]/course-error-nm", true);
|
||||
|
||||
_lateralMode = LateralMode::GPSOffset;
|
||||
_courseOffsetNm = offsetNm;
|
||||
_turnActive = false;
|
||||
}
|
||||
|
||||
void TestPilot::flyDirectTo(const SGGeod& target)
|
||||
{
|
||||
_lateralMode = LateralMode::Direct;
|
||||
_targetPos = target;
|
||||
}
|
||||
|
||||
void TestPilot::updateValues(double dt)
|
||||
{
|
||||
auto dl = DataLogger::instance();
|
||||
|
||||
if (_gps && (_lateralMode == LateralMode::GPSCourse)) {
|
||||
_targetCourseDeg = _gpsLegCourse->getDoubleValue();
|
||||
|
||||
// set how aggressively we try to correct our course
|
||||
double courseCorrectionFactor = 64.0;
|
||||
double crossTrack = _courseErrorNm->getDoubleValue();
|
||||
|
||||
dl->recordSamplePoint("TP-error-nm", crossTrack);
|
||||
|
||||
SG_CLAMP_RANGE(crossTrack, -2.0, 2.0); // clamp to 2nm deviation
|
||||
double correction = courseCorrectionFactor * crossTrack;
|
||||
const double maxCorrectionAngle = 45;
|
||||
|
||||
dl->recordSamplePoint("TP-base-correction-deg", correction);
|
||||
|
||||
// within 1nm of the desired course, start to bias
|
||||
// based on heading error. This is to reduce overshooting
|
||||
// while still keeping the responsiveness high
|
||||
if (fabs(crossTrack) < 1.0) {
|
||||
// compensate for heading
|
||||
double headingError = _targetCourseDeg - _trueCourseDeg;
|
||||
SG_NORMALIZE_RANGE(headingError, -180.0, 180.0);
|
||||
if (fabs(headingError) > 90.0) {
|
||||
// we're pointing the wrong way, don't compensate
|
||||
// otherwise we get into knots trying to make the
|
||||
// turn back the right way
|
||||
} else {
|
||||
const double p = 1.0 - fabs(crossTrack);
|
||||
const double headingErrorFactor = 0.6;
|
||||
correction += p * headingError * headingErrorFactor;
|
||||
}
|
||||
}
|
||||
|
||||
dl->recordSamplePoint("TP-correction-deg", correction);
|
||||
|
||||
SG_CLAMP_RANGE(correction, -maxCorrectionAngle, maxCorrectionAngle);
|
||||
_targetCourseDeg += correction;
|
||||
|
||||
dl->recordSamplePoint("TP-target-deg", _targetCourseDeg);
|
||||
|
||||
SG_NORMALIZE_RANGE(_targetCourseDeg, 0.0, 360.0);
|
||||
if (!_turnActive &&(fabs(_trueCourseDeg - _targetCourseDeg) > 0.5)) {
|
||||
_turnActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_gps && (_lateralMode == LateralMode::GPSOffset)) {
|
||||
_targetCourseDeg = _gpsLegCourse->getDoubleValue();
|
||||
|
||||
double crossTrack = _courseErrorNm->getDoubleValue();
|
||||
double offsetError = crossTrack - _courseOffsetNm;
|
||||
|
||||
const double offsetCorrectionFactor = 25.0;
|
||||
const double correction = offsetError * offsetCorrectionFactor;
|
||||
_targetCourseDeg += correction;
|
||||
|
||||
SG_NORMALIZE_RANGE(_targetCourseDeg, 0.0, 360.0);
|
||||
if (!_turnActive &&(fabs(_trueCourseDeg - _targetCourseDeg) > 0.5)) {
|
||||
_turnActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_lateralMode == LateralMode::Direct) {
|
||||
_targetCourseDeg = SGGeodesy::courseDeg(globals->get_aircraft_position(), _targetPos);
|
||||
SG_NORMALIZE_RANGE(_targetCourseDeg, 0.0, 360.0);
|
||||
if (!_turnActive && (fabs(_trueCourseDeg - _targetCourseDeg) > 0.5)) {
|
||||
_turnActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_turnActive) {
|
||||
if (fabs(_targetCourseDeg - _trueCourseDeg) < 0.1) {
|
||||
_trueCourseDeg = _targetCourseDeg;
|
||||
_turnActive = false;
|
||||
} else {
|
||||
// standard 2-minute turn, 180-deg min, thus 3-degrees per second
|
||||
|
||||
double turnDeg = 5.0 * dt;
|
||||
double errorDeg = _targetCourseDeg - _trueCourseDeg;
|
||||
SG_NORMALIZE_RANGE(errorDeg, -180.0, 180.0);
|
||||
|
||||
// clamp turn to error value
|
||||
turnDeg = std::min(turnDeg, fabs(errorDeg));
|
||||
|
||||
// and now ensure we follow the correct sign
|
||||
turnDeg = copysign(turnDeg, errorDeg);
|
||||
|
||||
// simple integral
|
||||
_trueCourseDeg += turnDeg;
|
||||
SG_NORMALIZE_RANGE(_trueCourseDeg, 0.0, 360.0);
|
||||
}
|
||||
}
|
||||
|
||||
SGGeod currentPos = globals->get_aircraft_position();
|
||||
|
||||
const double M = flightgear::AircraftPerformance::machForCAS(currentPos.getElevationFt(), _speedKnots);
|
||||
_speedMachProp->setDoubleValue(M);
|
||||
const double gs = flightgear::AircraftPerformance::groundSpeedForMach(currentPos.getElevationFt(), M);
|
||||
_groundspeedKnotsProp->setDoubleValue(gs);
|
||||
double d = gs * SG_KT_TO_MPS * dt;
|
||||
SGGeod newPos = SGGeodesy::direct(currentPos, _trueCourseDeg, d);
|
||||
|
||||
if (_altActive) {
|
||||
if (fabs(_targetAltitudeFt - currentPos.getElevationFt()) < 1) {
|
||||
_altActive = false;
|
||||
newPos.setElevationFt(_targetAltitudeFt);
|
||||
} else {
|
||||
double errorFt = _targetAltitudeFt - currentPos.getElevationFt();
|
||||
double vspeed = std::min(fabs(errorFt),_vspeedFPM * dt / 60.0);
|
||||
double dv = copysign(vspeed, errorFt);
|
||||
newPos.setElevationFt(currentPos.getElevationFt() + dv);
|
||||
}
|
||||
}
|
||||
|
||||
setPosition(newPos);
|
||||
}
|
||||
|
||||
void TestPilot::setPosition(const SGGeod& pos)
|
||||
{
|
||||
_latProp->setDoubleValue(pos.getLatitudeDeg());
|
||||
_lonProp->setDoubleValue(pos.getLongitudeDeg());
|
||||
_altitudeProp->setDoubleValue(pos.getElevationFt());
|
||||
|
||||
_headingProp->setDoubleValue(_trueCourseDeg);
|
||||
_speedKnotsProp->setDoubleValue(_speedKnots);
|
||||
_verticalFPMProp->setDoubleValue(_vspeedFPM);
|
||||
}
|
||||
|
||||
void TestPilot::setTargetAltitudeFtMSL(double altFt)
|
||||
{
|
||||
_targetAltitudeFt = altFt;
|
||||
_altActive = true;
|
||||
}
|
||||
|
||||
bool TestPilot::isOnHeading(double heading) const
|
||||
{
|
||||
const double hdgDelta = (_trueCourseDeg - heading);
|
||||
return fabs(hdgDelta) < 0.5;
|
||||
}
|
||||
|
||||
double TestPilot::trueCourseDeg() const
|
||||
{
|
||||
return _trueCourseDeg;
|
||||
}
|
||||
|
||||
|
||||
} // of namespace
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2019 James Turner
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FGTEST_API_TEST_PILOT_HXX
|
||||
#define _FGTEST_API_TEST_PILOT_HXX
|
||||
|
||||
#include <simgear/props/propsfwd.hxx>
|
||||
#include <simgear/math/SGMathFwd.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/math/SGGeod.hxx>
|
||||
|
||||
class GPS;
|
||||
|
||||
namespace FGTestApi {
|
||||
|
||||
/**
|
||||
* @brief simulation of the user (pilot) fying in a particular way
|
||||
* around the world. Standard property tree values are updated
|
||||
* (position / orientation / velocity)
|
||||
*/
|
||||
class TestPilot : public SGSubsystem
|
||||
{
|
||||
public:
|
||||
TestPilot(SGPropertyNode_ptr props = {});
|
||||
~TestPilot();
|
||||
|
||||
void resetAtPosition(const SGGeod& pos);
|
||||
|
||||
void setSpeedKts(double knots);
|
||||
|
||||
void setCourseTrue(double deg);
|
||||
void turnToCourse(double deg);
|
||||
|
||||
void setVerticalFPM(double fpm);
|
||||
void setTargetAltitudeFtMSL(double altFt);
|
||||
|
||||
// void setTurnRateDegSec();
|
||||
|
||||
void init() override;
|
||||
void update(double dT) override;
|
||||
|
||||
void flyHeading(double hdg);
|
||||
void flyDirectTo(const SGGeod& target);
|
||||
void flyGPSCourse(GPS *gps);
|
||||
|
||||
void flyGPSCourseOffset(GPS *gps, double offsetNm);
|
||||
|
||||
bool isOnHeading(double heading) const;
|
||||
|
||||
double trueCourseDeg() const;
|
||||
private:
|
||||
enum class LateralMode
|
||||
{
|
||||
Heading,
|
||||
Direct,
|
||||
GPSCourse,
|
||||
GPSOffset
|
||||
};
|
||||
|
||||
void updateValues(double dt);
|
||||
void setPosition(const SGGeod& pos);
|
||||
|
||||
SGPropertyNode_ptr _propRoot;
|
||||
|
||||
double _trueCourseDeg = 0.0;
|
||||
double _speedKnots = 0.0; // IAS
|
||||
double _vspeedFPM = 0.0;
|
||||
|
||||
bool _turnActive = false;
|
||||
bool _altActive = false;
|
||||
double _targetCourseDeg = 0.0;
|
||||
double _targetAltitudeFt = 0.0;
|
||||
|
||||
LateralMode _lateralMode = LateralMode::Heading;
|
||||
SGGeod _targetPos;
|
||||
GPS* _gps = nullptr;
|
||||
double _courseOffsetNm =0.0;
|
||||
|
||||
SGPropertyNode_ptr _latProp;
|
||||
SGPropertyNode_ptr _lonProp;
|
||||
SGPropertyNode_ptr _altitudeProp;
|
||||
SGPropertyNode_ptr _headingProp;
|
||||
SGPropertyNode_ptr _speedKnotsProp;
|
||||
SGPropertyNode_ptr _verticalFPMProp;
|
||||
SGPropertyNode_ptr _groundspeedKnotsProp;
|
||||
SGPropertyNode_ptr _speedMachProp;
|
||||
|
||||
SGPropertyNode_ptr _gpsNode;
|
||||
SGPropertyNode_ptr _gpsLegCourse;
|
||||
SGPropertyNode_ptr _courseErrorNm;
|
||||
};
|
||||
|
||||
} // of namespace FGTestApi
|
||||
|
||||
#endif // of _FGTEST_API_TEST_PILOT_HXX
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "scene_graph.hxx"
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/locale.hxx>
|
||||
#include <Scenery/scenery.hxx>
|
||||
#include <Viewer/renderer.hxx>
|
||||
#include <Viewer/FGEventHandler.hxx>
|
||||
|
||||
|
||||
namespace FGTestApi {
|
||||
namespace setUp {
|
||||
|
||||
void initScenery()
|
||||
{
|
||||
// Read the global defaults from $FG_ROOT/defaults.xml (needed by the renderer).
|
||||
SGPath defaultsXML = globals->get_fg_root() / "defaults.xml";
|
||||
if (!defaultsXML.exists())
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Cannot read the global defaults from \"" << defaultsXML.utf8Str() << "\".");
|
||||
fgLoadProps("defaults.xml", globals->get_props());
|
||||
|
||||
// otherwise fgSplashProgress will assert
|
||||
globals->get_locale()->selectLanguage({});
|
||||
|
||||
// Set up the renderer.
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
|
||||
FGRenderer* render = globals->get_renderer();
|
||||
render->init();
|
||||
render->setView(viewer.get());
|
||||
|
||||
// Start up the scenery subsystem.
|
||||
globals->add_new_subsystem<FGScenery>(SGSubsystemMgr::DISPLAY);
|
||||
globals->get_scenery()->init();
|
||||
globals->get_scenery()->bind();
|
||||
}
|
||||
|
||||
} // End of namespace setUp.
|
||||
} // End of namespace FGTestApi.
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FG_TEST_SCENE_GRAPH_HXX
|
||||
#define FG_TEST_SCENE_GRAPH_HXX
|
||||
|
||||
namespace FGTestApi {
|
||||
namespace setUp {
|
||||
|
||||
void initScenery();
|
||||
|
||||
} // End of namespace setUp.
|
||||
} // End of namespace FGTestApi.
|
||||
|
||||
#endif // FG_TEST_SCENE_GRAPH_HXX
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// implement various test-only methods on classes
|
||||
|
||||
#include <Airports/groundnetwork.hxx>
|
||||
#include <Airports/airport.hxx>
|
||||
#include <Airports/xmlloader.hxx>
|
||||
#include <Navaids/procedure.hxx>
|
||||
|
||||
void FGAirport::testSuiteInjectGroundnetXML(const SGPath& path)
|
||||
{
|
||||
_groundNetwork.reset(new FGGroundNetwork(const_cast<FGAirport*>(this)));
|
||||
XMLLoader::loadFromPath(_groundNetwork.get(), path);
|
||||
_groundNetwork->init();
|
||||
}
|
||||
|
||||
void FGAirport::testSuiteInjectProceduresXML(const SGPath& path)
|
||||
{
|
||||
if (mProceduresLoaded) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Procedures already loaded for" << ident());
|
||||
mSIDs.clear();
|
||||
mSTARs.clear();
|
||||
mApproaches.clear();
|
||||
}
|
||||
|
||||
mProceduresLoaded = true;
|
||||
flightgear::RouteBase::loadAirportProcedures(path, const_cast<FGAirport*>(this));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,476 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test_suite/dataStore.hxx"
|
||||
#include <ctime>
|
||||
|
||||
#include "TestDataLogger.hxx"
|
||||
#include "testGlobals.hxx"
|
||||
|
||||
#include <simgear/io/iostreams/sgstream.hxx>
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
#include <GUI/QtLauncher.hxx>
|
||||
#endif
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/options.hxx>
|
||||
#include <Main/util.hxx>
|
||||
#include <Main/FGInterpolator.hxx>
|
||||
#include <Main/locale.hxx>
|
||||
|
||||
#include <Time/TimeManager.hxx>
|
||||
|
||||
#include <simgear/structure/event_mgr.hxx>
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
#include <simgear/timing/sg_time.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
|
||||
#include <Airports/airport.hxx>
|
||||
#include <Navaids/FlightPlan.hxx>
|
||||
#include <Navaids/waypoint.hxx>
|
||||
#include <Navaids/routePath.hxx>
|
||||
|
||||
#include <Scripting/NasalSys.hxx>
|
||||
|
||||
using namespace flightgear;
|
||||
|
||||
namespace FGTestApi {
|
||||
|
||||
bool global_loggingToKML = false;
|
||||
sg_ofstream global_kmlStream;
|
||||
bool global_lineStringOpen = false;
|
||||
|
||||
namespace setUp {
|
||||
|
||||
void initTestGlobals(const std::string& testName)
|
||||
{
|
||||
assert(globals == nullptr);
|
||||
globals = new FGGlobals;
|
||||
|
||||
DataStore &data = DataStore::get();
|
||||
if (!data.getFGRoot().exists()) {
|
||||
data.findFGRoot("");
|
||||
}
|
||||
globals->set_fg_root(data.getFGRoot());
|
||||
|
||||
// current dir
|
||||
SGPath homePath = SGPath::fromUtf8(FGBUILDDIR) / "test_home";
|
||||
if (!homePath.exists()) {
|
||||
(homePath / "dummyFile").create_dir(0755);
|
||||
}
|
||||
|
||||
globals->set_fg_home(homePath);
|
||||
auto props = globals->get_props();
|
||||
props->setStringValue("sim/fg-home", homePath.utf8Str());
|
||||
|
||||
// Activate headless mode.
|
||||
globals->set_headless(true);
|
||||
|
||||
fgSetDefaults();
|
||||
|
||||
auto t = globals->add_new_subsystem<TimeManager>(SGSubsystemMgr::INIT);
|
||||
t->bind();
|
||||
t->init(); // establish mag-var data
|
||||
|
||||
/**
|
||||
* Both the event manager and subsystem manager are initialised by the
|
||||
* FGGlobals ctor, but only the subsystem manager is destroyed by the dtor.
|
||||
* Here the event manager is added to the subsystem manager so it can be
|
||||
* destroyed via the subsystem manager.
|
||||
*/
|
||||
globals->add_subsystem("events", globals->get_event_mgr(), SGSubsystemMgr::DISPLAY);
|
||||
|
||||
// necessary to avoid asserts: mark FGLocale as initialized
|
||||
globals->get_locale()->selectLanguage({});
|
||||
}
|
||||
|
||||
bool logPositionToKML(const std::string& testName)
|
||||
{
|
||||
// clear any previous state
|
||||
if (global_loggingToKML) {
|
||||
global_kmlStream.close();
|
||||
global_lineStringOpen = false;
|
||||
}
|
||||
|
||||
SGPath p = SGPath::desktop() / (testName + ".kml");
|
||||
global_kmlStream.open(p);
|
||||
if (!global_kmlStream.is_open()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "unable to open:" << p);
|
||||
return false;
|
||||
}
|
||||
|
||||
// pre-amble
|
||||
global_kmlStream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
|
||||
"<Document>\n";
|
||||
// need more precision for doubles when specifying lat/lon, see
|
||||
// https://xkcd.com/2170/ :)
|
||||
global_kmlStream.precision(12);
|
||||
|
||||
global_loggingToKML = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool logLinestringsToKML(const std::string& testName)
|
||||
{
|
||||
// clear any previous state
|
||||
if (global_loggingToKML) {
|
||||
global_kmlStream.close();
|
||||
global_lineStringOpen = false;
|
||||
}
|
||||
|
||||
SGPath p = SGPath::desktop() / (testName + ".kml");
|
||||
global_kmlStream.open(p);
|
||||
if (!global_kmlStream.is_open()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "unable to open:" << p);
|
||||
return false;
|
||||
}
|
||||
|
||||
// pre-amble
|
||||
global_kmlStream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
|
||||
"<Document>\n";
|
||||
// need more precision for doubles when specifying lat/lon, see
|
||||
// https://xkcd.com/2170/ :)
|
||||
global_kmlStream.precision(12);
|
||||
|
||||
global_loggingToKML = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void initStandardNasal(bool withCanvas)
|
||||
{
|
||||
fgInitAllowedPaths();
|
||||
|
||||
auto nasalNode = globals->get_props()->getNode("nasal", true);
|
||||
|
||||
// load loadpriority.xml, for default modules load order
|
||||
|
||||
auto nasalLoadPriority = globals->get_props()->getNode("/sim/nasal-load-priority",true);
|
||||
readProperties(globals->get_fg_root() / "Nasal/loadpriority.xml", nasalLoadPriority);
|
||||
|
||||
// set various props to reduce Nasal errors
|
||||
auto props = globals->get_props();
|
||||
props->setStringValue("sim/flight-model", "null");
|
||||
props->setStringValue("sim/aircraft", "test-suite-aircraft");
|
||||
|
||||
props->setDoubleValue("sim/current-view/config/default-field-of-view-deg", 90.0);
|
||||
// ensure /sim/view/config exists
|
||||
props->setBoolValue("sim/view/config/foo", false);
|
||||
|
||||
props->setBoolValue("sim/rendering/precipitation-gui-enable", false);
|
||||
props->setBoolValue("sim/rendering/precipitation-aircraft-enable", false);
|
||||
|
||||
// disable various larger modules
|
||||
nasalNode->setBoolValue("canvas/enabled", withCanvas);
|
||||
nasalNode->setBoolValue("jetways/enabled", false);
|
||||
nasalNode->setBoolValue("jetways_edit/enabled", false);
|
||||
nasalNode->setBoolValue("local_weather/enabled", false);
|
||||
|
||||
// Nasal needs the interpolator running
|
||||
globals->add_subsystem("prop-interpolator", new FGInterpolator, SGSubsystemMgr::INIT);
|
||||
|
||||
// will be inited, since we already did that
|
||||
globals->add_new_subsystem<FGNasalSys>(SGSubsystemMgr::INIT);
|
||||
}
|
||||
|
||||
void populateFPWithoutNasal(flightgear::FlightPlanRef f,
|
||||
const std::string& depICAO, const std::string& depRunway,
|
||||
const std::string& destICAO, const std::string& destRunway,
|
||||
const std::string& waypoints)
|
||||
{
|
||||
FGAirportRef depApt = FGAirport::getByIdent(depICAO);
|
||||
f->setDeparture(depApt->getRunwayByIdent(depRunway));
|
||||
|
||||
|
||||
FGAirportRef destApt = FGAirport::getByIdent(destICAO);
|
||||
f->setDestination(destApt->getRunwayByIdent(destRunway));
|
||||
|
||||
// since we don't have the Nasal route-manager delegate, insert the
|
||||
// runway waypoints manually
|
||||
|
||||
auto depRwy = new RunwayWaypt(f->departureRunway(), f);
|
||||
depRwy->setFlag(WPT_DEPARTURE);
|
||||
f->insertWayptAtIndex(depRwy, -1);
|
||||
|
||||
for (auto ws : simgear::strutils::split(waypoints)) {
|
||||
WayptRef wpt = f->waypointFromString(ws);
|
||||
if (!wpt) {
|
||||
SG_LOG(SG_NAVAID, SG_ALERT, "No waypoint created for:" << ws);
|
||||
continue;
|
||||
}
|
||||
f->insertWayptAtIndex(wpt, -1);
|
||||
}
|
||||
|
||||
|
||||
auto destRwy = f->destinationRunway();
|
||||
f->insertWayptAtIndex(new BasicWaypt(destRwy->pointOnCenterline(-8 * SG_NM_TO_METER),
|
||||
destRwy->ident() + "-8", f), -1);
|
||||
f->insertWayptAtIndex(new RunwayWaypt(destRwy, f), -1);
|
||||
}
|
||||
|
||||
void populateFPWithNasal(flightgear::FlightPlanRef f,
|
||||
const std::string& depICAO, const std::string& depRunway,
|
||||
const std::string& destICAO, const std::string& destRunway,
|
||||
const std::string& waypoints)
|
||||
{
|
||||
FGAirportRef depApt = FGAirport::getByIdent(depICAO);
|
||||
f->setDeparture(depApt->getRunwayByIdent(depRunway));
|
||||
|
||||
FGAirportRef destApt = FGAirport::getByIdent(destICAO);
|
||||
f->setDestination(destApt->getRunwayByIdent(destRunway));
|
||||
|
||||
// insert after the last departure waypoint
|
||||
int insertIndex = 1;
|
||||
|
||||
for (auto ws : simgear::strutils::split(waypoints)) {
|
||||
WayptRef wpt = f->waypointFromString(ws);
|
||||
f->insertWayptAtIndex(wpt, insertIndex++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace setUp.
|
||||
|
||||
void beginLineString(const std::string& ident)
|
||||
{
|
||||
global_lineStringOpen = true;
|
||||
global_kmlStream << "<Placemark>\n";
|
||||
if (!ident.empty()) {
|
||||
global_kmlStream << "<name>" << ident << "</name>\n";
|
||||
}
|
||||
global_kmlStream << "<LineString>\n";
|
||||
global_kmlStream << "<tessellate>1</tessellate>\n";
|
||||
global_kmlStream << "<coordinates>\n";
|
||||
}
|
||||
|
||||
void logCoordinate(const SGGeod& pos)
|
||||
{
|
||||
if (!global_lineStringOpen) {
|
||||
beginLineString({});
|
||||
}
|
||||
|
||||
global_kmlStream << pos.getLongitudeDeg() << "," << pos.getLatitudeDeg() << " " << endl;
|
||||
}
|
||||
|
||||
void rawLogCoordinate(const SGGeod& pos)
|
||||
{
|
||||
global_kmlStream << pos.getLongitudeDeg() << "," << pos.getLatitudeDeg() << " " << endl;
|
||||
}
|
||||
|
||||
void endCurrentLineString()
|
||||
{
|
||||
global_lineStringOpen = false;
|
||||
global_kmlStream <<
|
||||
"</coordinates>\n"
|
||||
"</LineString>\n"
|
||||
"</Placemark>\n" << endl;
|
||||
}
|
||||
|
||||
void setPosition(const SGGeod& g)
|
||||
{
|
||||
if (global_loggingToKML) {
|
||||
if (global_lineStringOpen) {
|
||||
endCurrentLineString();
|
||||
}
|
||||
|
||||
logCoordinate(g);
|
||||
}
|
||||
|
||||
globals->get_props()->setDoubleValue("position/latitude-deg", g.getLatitudeDeg());
|
||||
globals->get_props()->setDoubleValue("position/longitude-deg", g.getLongitudeDeg());
|
||||
globals->get_props()->setDoubleValue("position/altitude-ft", g.getElevationFt());
|
||||
}
|
||||
|
||||
const SGGeod getPosition()
|
||||
{
|
||||
return SGGeod::fromDegFt(
|
||||
globals->get_props()->getDoubleValue("position/latitude-deg"),
|
||||
globals->get_props()->getDoubleValue("position/longitude-deg"),
|
||||
globals->get_props()->getDoubleValue("position/altitude-ft"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setPositionAndStabilise(const SGGeod& g)
|
||||
{
|
||||
setPosition(g);
|
||||
for (int i=0; i<60; ++i) {
|
||||
globals->get_subsystem_mgr()->update(0.015);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void runForTime(double t)
|
||||
{
|
||||
const int tickHz = 30;
|
||||
const double tickDuration = 1.0 / tickHz;
|
||||
|
||||
int ticks = static_cast<int>(t * tickHz);
|
||||
assert(ticks > 0);
|
||||
|
||||
const int logInterval = 0.5 * tickHz;
|
||||
int nextLog = 0;
|
||||
|
||||
long startTime = globals->get_time_params()->get_cur_time();
|
||||
|
||||
for (int t = 0; t < ticks; ++t) {
|
||||
globals->inc_sim_time_sec(tickDuration);
|
||||
globals->get_time_params()->update(globals->get_view_position(), startTime, t * tickDuration);
|
||||
globals->get_subsystem_mgr()->update(tickDuration);
|
||||
|
||||
if (nextLog == 0) {
|
||||
if (global_loggingToKML) {
|
||||
logCoordinate(globals->get_aircraft_position());
|
||||
}
|
||||
|
||||
if (DataLogger::isActive()) {
|
||||
DataLogger::instance()->writeRecord();
|
||||
}
|
||||
nextLog = logInterval;
|
||||
} else {
|
||||
nextLog--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool runForTimeWithCheck(double t, RunCheck check)
|
||||
{
|
||||
const int tickHz = 30;
|
||||
const double tickDuration = 1.0 / tickHz;
|
||||
|
||||
int ticks = static_cast<int>(t * tickHz);
|
||||
assert(ticks > 0);
|
||||
const int logInterval = 0.5 * tickHz;
|
||||
int nextLog = 0;
|
||||
|
||||
for (int t = 0; t < ticks; ++t) {
|
||||
globals->inc_sim_time_sec(tickDuration);
|
||||
globals->get_subsystem_mgr()->update(tickDuration);
|
||||
|
||||
if (nextLog == 0) {
|
||||
if (global_loggingToKML) {
|
||||
logCoordinate(globals->get_aircraft_position());
|
||||
}
|
||||
|
||||
if (DataLogger::isActive()) {
|
||||
DataLogger::instance()->writeRecord();
|
||||
}
|
||||
nextLog = logInterval;
|
||||
} else {
|
||||
nextLog--;
|
||||
}
|
||||
|
||||
bool done = check();
|
||||
if (done) {
|
||||
if (global_loggingToKML) {
|
||||
endCurrentLineString();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void adjustSimulationWorldTime(time_t desiredUnixTime)
|
||||
{
|
||||
int timeOffset = desiredUnixTime - time(nullptr);
|
||||
globals->get_props()->setIntValue("/sim/time/cur-time-override", 0);
|
||||
globals->get_props()->setIntValue("/sim/time/warp", timeOffset);
|
||||
|
||||
globals->get_subsystem<TimeManager>()->update(0.0);
|
||||
}
|
||||
|
||||
void writeFlightPlanToKML(flightgear::FlightPlanRef fp)
|
||||
{
|
||||
if (!global_loggingToKML)
|
||||
return;
|
||||
|
||||
RoutePath rpath(fp);
|
||||
|
||||
for (int i=0; i<fp->numLegs(); ++i) {
|
||||
SGGeodVec legPath = rpath.pathForIndex(i);
|
||||
auto wp = fp->legAtIndex(i)->waypoint();
|
||||
|
||||
writeGeodsToKML("FP-leg-" + wp->ident(), legPath);
|
||||
|
||||
SGGeod legWPPosition = wp->position();
|
||||
writePointToKML("WP " + wp->ident(), legWPPosition);
|
||||
}
|
||||
}
|
||||
|
||||
void writeGeodsToKML(const std::string &label, const flightgear::SGGeodVec& geods)
|
||||
{
|
||||
if (global_lineStringOpen) {
|
||||
endCurrentLineString();
|
||||
}
|
||||
|
||||
beginLineString(label);
|
||||
|
||||
for (const auto& g : geods) {
|
||||
logCoordinate(g);
|
||||
}
|
||||
|
||||
endCurrentLineString();
|
||||
}
|
||||
|
||||
void writePointToKML(const std::string& ident, const SGGeod& pos)
|
||||
{
|
||||
global_kmlStream << "<Placemark>\n";
|
||||
global_kmlStream << "<name>" << ident << "</name>\n";
|
||||
global_kmlStream << "<Point>\n";
|
||||
global_kmlStream << "<coordinates>\n";
|
||||
rawLogCoordinate(pos);
|
||||
global_kmlStream << "</coordinates>\n";
|
||||
global_kmlStream << "</Point>\n";
|
||||
global_kmlStream << "</Placemark>\n";
|
||||
}
|
||||
|
||||
bool executeNasal(const std::string& code)
|
||||
{
|
||||
auto nasal = globals->get_subsystem<FGNasalSys>();
|
||||
if (!nasal) {
|
||||
throw sg_exception("Nasal not available");
|
||||
}
|
||||
|
||||
nasal->getAndClearErrorList();
|
||||
std::string output, parseErrors;
|
||||
bool ok = nasal->parseAndRunWithOutput(code, output, parseErrors);
|
||||
if (!parseErrors.empty()) {
|
||||
SG_LOG(SG_NASAL, SG_ALERT, "Errors running Nasal:" << parseErrors);
|
||||
return false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
namespace tearDown {
|
||||
|
||||
void shutdownTestGlobals()
|
||||
{
|
||||
// The QApplication instance must be destroyed before exit() begins, see
|
||||
// <https://bugreports.qt.io/browse/QTBUG-48709> (otherwise, segfault).
|
||||
#if defined(HAVE_QT)
|
||||
flightgear::shutdownQtApp();
|
||||
#endif
|
||||
|
||||
delete globals;
|
||||
globals = nullptr;
|
||||
|
||||
if (global_kmlStream) {
|
||||
if (global_lineStringOpen) {
|
||||
endCurrentLineString();
|
||||
}
|
||||
// post-amble
|
||||
global_kmlStream << "</Document>\n"
|
||||
"</kml>" << endl;
|
||||
global_kmlStream.close();
|
||||
global_loggingToKML = false;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace tearDown.
|
||||
|
||||
} // End of namespace FGTestApi.
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef FG_TEST_GLOBALS_HELPERS_HXX
|
||||
#define FG_TEST_GLOBALS_HELPERS_HXX
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <simgear/math/SGGeod.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
class FlightPlan;
|
||||
typedef SGSharedPtr<FlightPlan> FlightPlanRef;
|
||||
|
||||
typedef std::vector<SGGeod> SGGeodVec;
|
||||
}
|
||||
|
||||
namespace FGTestApi {
|
||||
|
||||
namespace setUp {
|
||||
|
||||
void initTestGlobals(const std::string& testName);
|
||||
|
||||
bool logPositionToKML(const std::string& testName);
|
||||
/**Don't log aircraft positions*/
|
||||
bool logLinestringsToKML(const std::string& testName);
|
||||
|
||||
void initStandardNasal(bool withCanvas = false);
|
||||
|
||||
void populateFPWithoutNasal(flightgear::FlightPlanRef f,
|
||||
const std::string& depICAO, const std::string& depRunway,
|
||||
const std::string& destICAO, const std::string& destRunway,
|
||||
const std::string& waypoints);
|
||||
|
||||
void populateFPWithNasal(flightgear::FlightPlanRef f,
|
||||
const std::string& depICAO, const std::string& depRunway,
|
||||
const std::string& destICAO, const std::string& destRunway,
|
||||
const std::string& waypoints);
|
||||
|
||||
} // End of namespace setUp.
|
||||
|
||||
// helpers during tests
|
||||
|
||||
const SGGeod getPosition();
|
||||
void setPosition(const SGGeod& g);
|
||||
void setPositionAndStabilise(const SGGeod& g);
|
||||
|
||||
void runForTime(double t);
|
||||
|
||||
/**
|
||||
@brief set the simulation date/time clock to 'time'
|
||||
*/
|
||||
void adjustSimulationWorldTime(time_t time);
|
||||
|
||||
using RunCheck = std::function<bool(void)>;
|
||||
|
||||
bool runForTimeWithCheck(double t, RunCheck check);
|
||||
|
||||
void writeFlightPlanToKML(flightgear::FlightPlanRef fp);
|
||||
|
||||
void writeGeodsToKML(const std::string &label, const flightgear::SGGeodVec& geods);
|
||||
void writePointToKML(const std::string& ident, const SGGeod& pos);
|
||||
|
||||
bool executeNasal(const std::string& code);
|
||||
|
||||
namespace tearDown {
|
||||
|
||||
void shutdownTestGlobals();
|
||||
|
||||
} // End of namespace tearDown.
|
||||
|
||||
} // End of namespace FGTestApi.
|
||||
|
||||
#endif // of FG_TEST_GLOBALS_HELPERS_HXX
|
||||
@@ -0,0 +1 @@
|
||||
This is a collection of ancient testing code.
|
||||
@@ -0,0 +1,318 @@
|
||||
/* -*- mode: C; tab-width:8; c-basic-offset:8 -*-
|
||||
* vi:set ts=8:
|
||||
*
|
||||
* alcinfo.x
|
||||
*
|
||||
* alcinfo display info about a ALC extension and OpenAL renderer
|
||||
*
|
||||
* This file is in the Public Domain and comes with no warranty.
|
||||
* Erik Hofman <erik@ehofman.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <OpenAL/al.h>
|
||||
# include <OpenAL/alc.h>
|
||||
#else
|
||||
# include <AL/al.h>
|
||||
# include <AL/alc.h>
|
||||
# include <AL/alext.h>
|
||||
#endif
|
||||
|
||||
#ifndef AL_VERSION_1_1
|
||||
# ifdef __APPLE__
|
||||
# include <OpenAL/altypes.h>
|
||||
# include <OpenAL/alctypes.h>
|
||||
#else
|
||||
# include <AL/altypes.h>
|
||||
# include <AL/alctypes.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
using std::string;
|
||||
|
||||
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
||||
# define ALC_ALL_DEVICES_SPECIFIER 0x1013
|
||||
#endif
|
||||
|
||||
#define MAX_DATA 16
|
||||
static const int indentation = 4;
|
||||
static const int maxmimumWidth = 79;
|
||||
|
||||
void printExtensions (const char *, char, const char *);
|
||||
void displayDevices(const char *, const char *);
|
||||
char *getDeviceName(int, char **);
|
||||
void testForError(void *, const string&);
|
||||
void testForALCError(ALCdevice *);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ALCint data[MAX_DATA];
|
||||
ALCdevice *device = NULL;
|
||||
ALCcontext *context = NULL;
|
||||
ALenum error;
|
||||
char *s;
|
||||
|
||||
if (alcIsExtensionPresent(NULL, "ALC_enumeration_EXT") == AL_TRUE)
|
||||
{
|
||||
if (alcIsExtensionPresent(NULL, "ALC_enumerate_all_EXT") == AL_FALSE)
|
||||
s = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
||||
else
|
||||
s = (char *)alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
|
||||
displayDevices("output", s);
|
||||
|
||||
s = (char *)alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
|
||||
displayDevices("input", s);
|
||||
}
|
||||
|
||||
s = getDeviceName(argc, argv);
|
||||
device = alcOpenDevice(s);
|
||||
testForError(device, "Audio device not available.");
|
||||
|
||||
context = alcCreateContext(device, NULL);
|
||||
testForError(context, "Unable to create a valid context.");
|
||||
|
||||
alcMakeContextCurrent(context);
|
||||
testForALCError(device);
|
||||
|
||||
s = (char *)alcGetString(device, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||
printf("default output device: %s\n", s);
|
||||
testForALCError(device);
|
||||
|
||||
error = alcIsExtensionPresent(device, "ALC_EXT_capture");
|
||||
if (error)
|
||||
{
|
||||
s = (char *)alcGetString(device, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
|
||||
printf("default input device: %s\n", s);
|
||||
testForALCError(device);
|
||||
}
|
||||
printf("capture support: %s\n", (error) ? "yes" : "no");
|
||||
|
||||
alcGetIntegerv(device, ALC_FREQUENCY, 1, data);
|
||||
printf("mixer frequency: %u hz\n", data[0]);
|
||||
testForALCError(device);
|
||||
|
||||
alcGetIntegerv(device, ALC_REFRESH, 1, data+1);
|
||||
printf("refresh rate : %u hz\n", data[0]/data[1]);
|
||||
testForALCError(device);
|
||||
|
||||
data[0] = 0;
|
||||
alcGetIntegerv(device, ALC_MONO_SOURCES, 1, data);
|
||||
error = alcGetError(device);
|
||||
if (error == AL_NONE) {
|
||||
printf("supported sources; mono: %u, ", data[0]);
|
||||
|
||||
data[0] = 0;
|
||||
alcGetIntegerv(device, ALC_STEREO_SOURCES, 1, data);
|
||||
printf("stereo: %u\n", data[0]);
|
||||
testForALCError(device);
|
||||
}
|
||||
|
||||
printf("ALC version: ");
|
||||
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, data);
|
||||
printf("%i.", *data);
|
||||
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, data);
|
||||
printf("%i\n", *data);
|
||||
testForALCError(device);
|
||||
|
||||
s = (char *)alcGetString(device, ALC_EXTENSIONS);
|
||||
printExtensions ("ALC extensions", ' ', s);
|
||||
testForALCError(device);
|
||||
|
||||
s = (char *)alGetString(AL_VENDOR);
|
||||
error = alGetError();
|
||||
if ((error = alGetError()) != AL_NO_ERROR)
|
||||
printf("Error #%x: %s\n", error, alGetString(error));
|
||||
else
|
||||
printf("OpenAL vendor string: %s\n", s);
|
||||
|
||||
s = (char *)alGetString(AL_RENDERER);
|
||||
if ((error = alGetError()) != AL_NO_ERROR)
|
||||
printf("Error #%x: %s\n", error, alGetString(error));
|
||||
else
|
||||
printf("OpenAL renderer string: %s\n", s);
|
||||
|
||||
s = (char *)alGetString(AL_VERSION);
|
||||
if ((error = alGetError()) != AL_NO_ERROR)
|
||||
printf("Error #%x: %s\n", error, alGetString(error));
|
||||
else if (!s)
|
||||
printf("Querying AL_VERSION returned NULL pointer!\n");
|
||||
else
|
||||
printf("OpenAL version string: %s\n", s);
|
||||
|
||||
s = (char *)alGetString(AL_EXTENSIONS);
|
||||
printExtensions ("OpenAL extensions", ' ', s);
|
||||
testForALCError(device);
|
||||
|
||||
if (alcMakeContextCurrent(NULL) == 0)
|
||||
printf("alcMakeContextCurrent failed.\n");
|
||||
|
||||
device = alcGetContextsDevice(context);
|
||||
alcDestroyContext(context);
|
||||
testForALCError(device);
|
||||
|
||||
if (alcCloseDevice(device) == 0)
|
||||
printf("alcCloseDevice failed.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void
|
||||
printChar (int c, int *width)
|
||||
{
|
||||
putchar (c);
|
||||
*width = (c == '\n') ? 0 : (*width + 1);
|
||||
}
|
||||
|
||||
void
|
||||
indent (int *width)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < indentation; i++)
|
||||
{
|
||||
printChar (' ', width);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
printExtensions (const char *header, char separator, const char *extensions)
|
||||
{
|
||||
int width = 0, start = 0, end = 0;
|
||||
|
||||
printf ("%s:\n", header);
|
||||
if (extensions == NULL || extensions[0] == '\0')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
indent (&width);
|
||||
while (1)
|
||||
{
|
||||
if (extensions[end] == separator || extensions[end] == '\0')
|
||||
{
|
||||
if (width + end - start + 2 > maxmimumWidth)
|
||||
{
|
||||
printChar ('\n', &width);
|
||||
indent (&width);
|
||||
}
|
||||
while (start < end)
|
||||
{
|
||||
printChar (extensions[start], &width);
|
||||
start++;
|
||||
}
|
||||
if (extensions[end] == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
start++;
|
||||
end++;
|
||||
if (extensions[end] == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
printChar (',', &width);
|
||||
printChar (' ', &width);
|
||||
}
|
||||
end++;
|
||||
}
|
||||
printChar ('\n', &width);
|
||||
}
|
||||
|
||||
char *
|
||||
getCommandLineOption(int argc, char **argv, const string& option)
|
||||
{
|
||||
int slen = option.size();
|
||||
char *rv = 0;
|
||||
int i;
|
||||
|
||||
for (i=0; i<argc; i++)
|
||||
{
|
||||
if (strncmp(argv[i], option.c_str(), slen) == 0)
|
||||
{
|
||||
i++;
|
||||
if (i<argc) rv = argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
char *
|
||||
getDeviceName(int argc, char **argv)
|
||||
{
|
||||
static char devname[255];
|
||||
int len = 255;
|
||||
char *s;
|
||||
|
||||
s = getCommandLineOption(argc, argv, "-d");
|
||||
if (s)
|
||||
{
|
||||
strncpy((char *)&devname, s, len);
|
||||
len -= strlen(s);
|
||||
|
||||
s = getCommandLineOption(argc, argv, "-r");
|
||||
if (s)
|
||||
{
|
||||
strncat((char *)&devname, " on ", len);
|
||||
len -= 4;
|
||||
|
||||
strncat((char *)&devname, s, len);
|
||||
}
|
||||
s = (char *)&devname;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
displayDevices(const char *type, const char *list)
|
||||
{
|
||||
ALCchar *ptr, *nptr;
|
||||
|
||||
ptr = (ALCchar *)list;
|
||||
printf("list of all available %s devices:\n", type);
|
||||
if (!list)
|
||||
{
|
||||
printf("none\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
nptr = ptr;
|
||||
while (*(nptr += strlen(ptr)+1) != 0)
|
||||
{
|
||||
printf(" %s\n", ptr);
|
||||
ptr = nptr;
|
||||
}
|
||||
printf(" %s\n", ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testForError(void *p, const string& s)
|
||||
{
|
||||
if (p == NULL)
|
||||
{
|
||||
printf("\nError: %s\n\n", s.c_str());
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testForALCError(ALCdevice *device)
|
||||
{
|
||||
ALenum error;
|
||||
error = alcGetError(device);
|
||||
if (error != ALC_NO_ERROR)
|
||||
printf("\nALC Error %x occurred: %s\n", error, alcGetString(device, error));
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#if defined( __APPLE__)
|
||||
# include <OpenGL/OpenGL.h>
|
||||
#else
|
||||
# include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
GLfloat a, t;
|
||||
|
||||
a = 1.0;
|
||||
|
||||
do {
|
||||
printf("a = %.10f\n", a);
|
||||
a = a / 2.0;
|
||||
t = 1.0 + a;
|
||||
} while ( t > 1.0 );
|
||||
|
||||
a = a + a;
|
||||
|
||||
printf("Estimated GLfloat epsilon = %.10f\n", a);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
From: Steve Baker <sbaker@link.com>
|
||||
Sender: root@fatcity.com
|
||||
To: OPENGL-GAMEDEV-L <OPENGL-GAMEDEV-L@fatcity.com>
|
||||
Subject: Re: Win32 OpenGL Resource Page
|
||||
Date: Fri, 24 Apr 1998 07:33:51 -0800
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#if defined( __APPLE__)
|
||||
# include <OpenGL/OpenGL.h>
|
||||
# include <GLUT/glut.h>
|
||||
#else
|
||||
# include <GL/gl.h>
|
||||
# ifdef HAVE_GLUT_H
|
||||
# include <GL/glut.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
void getPrints ( GLenum token, char *string )
|
||||
{
|
||||
printf ( "%s = \"%s\"\n", string, glGetString ( token ) ) ;
|
||||
}
|
||||
|
||||
void getPrint2f ( GLenum token, char *string )
|
||||
{
|
||||
GLfloat f[2] ;
|
||||
glGetFloatv ( token, f ) ;
|
||||
printf ( "%s = %g,%g\n", string, f[0],f[1] ) ;
|
||||
}
|
||||
|
||||
void getPrintf ( GLenum token, char *string )
|
||||
{
|
||||
GLfloat f ;
|
||||
glGetFloatv ( token, &f ) ;
|
||||
printf ( "%s = %g\n", string, f ) ;
|
||||
}
|
||||
|
||||
void getPrint2i ( GLenum token, char *string )
|
||||
{
|
||||
GLint i[2] ;
|
||||
glGetIntegerv ( token, i ) ;
|
||||
printf ( "%s = %d,%d\n", string, i[0],i[1] ) ;
|
||||
}
|
||||
|
||||
void getPrinti ( GLenum token, char *string )
|
||||
{
|
||||
GLint i ;
|
||||
glGetIntegerv ( token, &i ) ;
|
||||
printf ( "%s = %d\n", string, i ) ;
|
||||
}
|
||||
|
||||
int main ( int argc, char **argv )
|
||||
{
|
||||
#ifdef HAVE_GLUT_H
|
||||
glutInit ( &argc, argv ) ;
|
||||
glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ) ;
|
||||
glutCreateWindow ( "You should never see this window!" ) ;
|
||||
|
||||
getPrints ( GL_VENDOR , "GL_VENDOR" ) ;
|
||||
getPrints ( GL_RENDERER , "GL_RENDERER" ) ;
|
||||
getPrints ( GL_VERSION , "GL_VERSION" ) ;
|
||||
getPrints ( GL_EXTENSIONS , "GL_EXTENSIONS" ) ;
|
||||
|
||||
getPrinti ( GL_RED_BITS , "GL_RED_BITS" ) ;
|
||||
getPrinti ( GL_GREEN_BITS , "GL_GREEN_BITS" ) ;
|
||||
getPrinti ( GL_BLUE_BITS , "GL_BLUE_BITS" ) ;
|
||||
getPrinti ( GL_ALPHA_BITS , "GL_ALPHA_BITS" ) ;
|
||||
getPrinti ( GL_DEPTH_BITS , "GL_DEPTH_BITS" ) ;
|
||||
getPrinti ( GL_INDEX_BITS , "GL_INDEX_BITS" ) ;
|
||||
getPrinti ( GL_STENCIL_BITS, "GL_STENCIL_BITS" ) ;
|
||||
|
||||
getPrinti ( GL_ACCUM_RED_BITS , "GL_ACCUM_RED_BITS" ) ;
|
||||
getPrinti ( GL_ACCUM_GREEN_BITS, "GL_ACCUM_GREEN_BITS" ) ;
|
||||
getPrinti ( GL_ACCUM_BLUE_BITS , "GL_ACCUM_BLUE_BITS" ) ;
|
||||
getPrinti ( GL_ACCUM_ALPHA_BITS, "GL_ACCUM_ALPHA_BITS" ) ;
|
||||
|
||||
getPrinti ( GL_AUX_BUFFERS, "GL_AUX_BUFFERS" ) ;
|
||||
|
||||
getPrinti ( GL_MAX_ATTRIB_STACK_DEPTH , "GL_MAX_ATTRIB_STACK_DEPTH" ) ;
|
||||
getPrinti ( GL_MAX_NAME_STACK_DEPTH , "GL_MAX_NAME_STACK_DEPTH" ) ;
|
||||
getPrinti ( GL_MAX_TEXTURE_STACK_DEPTH , "GL_MAX_TEXTURE_STACK_DEPTH" ) ;
|
||||
getPrinti ( GL_MAX_PROJECTION_STACK_DEPTH, "GL_MAX_PROJECTION_STACK_DEPTH" ) ;
|
||||
getPrinti ( GL_MAX_MODELVIEW_STACK_DEPTH , "GL_MAX_MODELVIEW_STACK_DEPTH" ) ;
|
||||
|
||||
getPrinti ( GL_MAX_CLIP_PLANES , "GL_MAX_CLIP_PLANES" ) ;
|
||||
getPrinti ( GL_MAX_EVAL_ORDER , "GL_MAX_EVAL_ORDER" ) ;
|
||||
getPrinti ( GL_MAX_LIGHTS , "GL_MAX_LIGHTS" ) ;
|
||||
getPrinti ( GL_MAX_LIST_NESTING , "GL_MAX_LIST_NESTING" ) ;
|
||||
getPrinti ( GL_MAX_TEXTURE_SIZE , "GL_MAX_TEXTURE_SIZE" ) ;
|
||||
getPrint2i( GL_MAX_VIEWPORT_DIMS , "GL_MAX_VIEWPORT_DIMS" ) ;
|
||||
|
||||
getPrintf ( GL_POINT_SIZE_GRANULARITY, "GL_POINT_SIZE_GRANULARITY" ) ;
|
||||
getPrint2f( GL_POINT_SIZE_RANGE , "GL_POINT_SIZE_RANGE" ) ;
|
||||
|
||||
printf("Default values:\n\n");
|
||||
|
||||
getPrinti( GL_UNPACK_ALIGNMENT , "GL_UNPACK_ALIGNMENT" ) ;
|
||||
getPrinti( GL_UNPACK_ROW_LENGTH , "GL_UNPACK_ROW_LENGTH" ) ;
|
||||
getPrinti( GL_UNPACK_SKIP_PIXELS , "GL_UNPACK_SKIP_PIXELS" ) ;
|
||||
getPrinti( GL_UNPACK_SKIP_ROWS , "GL_UNPACK_SKIP_ROWS" ) ;
|
||||
getPrinti( GL_BLEND_SRC , "GL_BLEND_SRC" ) ;
|
||||
getPrinti( GL_BLEND_DST , "GL_BLEND_DST" ) ;
|
||||
#else
|
||||
|
||||
printf("GL Utility Toolkit (glut) was not found on this system.\n");
|
||||
#endif
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <osg/GL>
|
||||
#include <plib/pw.h>
|
||||
#include <plib/pu.h>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
|
||||
#include "layout.hxx"
|
||||
|
||||
// Takes a property file on the command line, lays it out, and writes
|
||||
// the resulting tree back to stdout. Requires that the
|
||||
// "Helvetica.txf" font file from the base package be in the current
|
||||
// directory.
|
||||
|
||||
// g++ -Wall -g -o layout layout.cxx layout-props.cxx layout-test.cxx
|
||||
// -I/fg/include -L/fg/lib -I.. -lsgprops -lsgdebug -lsgstructure
|
||||
// -lsgmisc -lsgxml -lplibpw -lplibpu -lplibfnt -lplibul -lGL
|
||||
|
||||
// We can't load a plib fntTexFont without a GL context, so we use the
|
||||
// PW library to initialize things. The callbacks are required, but
|
||||
// just stubs.
|
||||
void exitCB(){ pwCleanup(); exit(0); }
|
||||
void resizeCB(int w, int h){ }
|
||||
void mouseMotionCB(int x, int y){ puMouse(x, y); }
|
||||
void mouseButtonCB(int button, int updn, int x, int y){ puMouse(button, updn, x, y); }
|
||||
void keyboardCB(int key, int updn, int x, int y){ puKeyboard(key, updn, x, y); }
|
||||
|
||||
const char* FONT_FILE = "Helvetica.txf";
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
FILE* tmp;
|
||||
if(!(tmp = fopen(FONT_FILE, "r"))) {
|
||||
fprintf(stderr, "Could not open %s for reading.\n", FONT_FILE);
|
||||
exit(1);
|
||||
}
|
||||
fclose(tmp);
|
||||
|
||||
pwInit(0, 0, 600, 400, 0, const_cast<char*>("Layout Test"), true, 0);
|
||||
pwSetCallbacks(keyboardCB, mouseButtonCB, mouseMotionCB,
|
||||
resizeCB, exitCB);
|
||||
|
||||
fntTexFont helv;
|
||||
helv.load(FONT_FILE);
|
||||
puFont puhelv(&helv);
|
||||
|
||||
LayoutWidget::setDefaultFont(&puhelv, 15);
|
||||
SGPropertyNode props;
|
||||
readProperties(argv[1], &props);
|
||||
LayoutWidget w(&props);
|
||||
int pw=0, ph=0;
|
||||
w.calcPrefSize(&pw, &ph);
|
||||
w.layout(0, 0, pw, ph);
|
||||
writeProperties(std::cout, &props, true);
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#if defined( __APPLE__)
|
||||
# include <OpenGL/OpenGL.h>
|
||||
# include <GLUT/glut.h>
|
||||
#else
|
||||
# include <GL/gl.h>
|
||||
# ifdef HAVE_GLUT_H
|
||||
# include <GL/glut.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define TEXRES_X 256
|
||||
#define TEXRES_Y 256
|
||||
|
||||
#ifdef HAVE_GLUT_H
|
||||
unsigned char env_map[TEXRES_X][TEXRES_Y][4];
|
||||
GLuint texName;
|
||||
int window_x = 640, window_y = 480;
|
||||
float alpha = 0.0, beta = 0.0;
|
||||
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
void setColor(float x, float y, float z, float angular_size, float r, float g, float b, float a)
|
||||
{
|
||||
//normalize
|
||||
float inv_length = 1.0 / sqrt(x*x + y*y + z*z);
|
||||
x *= inv_length; y *= inv_length; z *= inv_length;
|
||||
printf("x = %f, y = %f, z = %f\n", x, y, z);
|
||||
|
||||
float cos_angular_size = cos(angular_size*3.1415/180.0);
|
||||
printf("cos_angular_size = %f\n", cos_angular_size);
|
||||
|
||||
for(float tz_sign = -1.0; tz_sign < 3.0; tz_sign += 2.0)
|
||||
{
|
||||
for(float tx = -1.0; tx <= 1.0; tx += 0.01)
|
||||
{
|
||||
for(float ty = -1.0; ty <= 1.0; ty += 0.01)
|
||||
{
|
||||
if ((1.0 - tx*tx - ty*ty)<0.0)
|
||||
continue;
|
||||
|
||||
float tz = tz_sign * sqrt(1.0 - tx*tx - ty*ty);
|
||||
|
||||
float cos_phi = x*tx + y*ty + z*tz;
|
||||
|
||||
if (cos_angular_size < cos_phi)
|
||||
{
|
||||
float rx = tx; //mirroring on the z=0 plane
|
||||
float ry = ty;
|
||||
float rz = -tz;
|
||||
|
||||
float inv_m = 1.0 / (2.0 * sqrt(rx*rx + ry*ry + (rz + 1)*(rz + 1)));
|
||||
int s = (int)(TEXRES_X * (rx * inv_m + 0.5));
|
||||
int t = (int)(TEXRES_Y * (ry * inv_m + 0.5));
|
||||
|
||||
//seg_fault protection:
|
||||
if (s<0) s=0;
|
||||
if (s>=TEXRES_X) s=TEXRES_X-1;
|
||||
|
||||
if (t<0) t=0;
|
||||
if (t>=TEXRES_Y) t=TEXRES_Y-1;
|
||||
|
||||
env_map[s][t][0] = (unsigned char)(r * 255);
|
||||
env_map[s][t][1] = (unsigned char)(g * 255);
|
||||
env_map[s][t][2] = (unsigned char)(b * 255);
|
||||
env_map[s][t][3] = (unsigned char)(a * 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
|
||||
void init(void)
|
||||
{
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glShadeModel(GL_FLAT);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
for(int x=0; x<TEXRES_X; x++)
|
||||
{
|
||||
for(int y=0; y<TEXRES_Y; y++)
|
||||
{
|
||||
env_map[x][y][0] = x; //a few colors
|
||||
env_map[x][y][1] = y;
|
||||
env_map[x][y][2] = 128;
|
||||
env_map[x][y][3] = 128;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
// x y z ang r g b a
|
||||
setColor(0.0, 0.0, -1.0 , 23.0, 1.0, 1.0, 1.0, 1.0);
|
||||
setColor(0.7071067, 0.0, -0.7071067, 23.0, 1.0, 0.0, 0.0, 1.0);
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glGenTextures(1, &texName);
|
||||
glBindTexture(GL_TEXTURE_2D, texName);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXRES_X, TEXRES_Y, 0, GL_RGBA, GL_UNSIGNED_BYTE, env_map);
|
||||
}
|
||||
|
||||
void reshape(int w, int h)
|
||||
{
|
||||
window_x = w; window_y = h;
|
||||
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective((GLdouble) 60.0, ((GLdouble)w)/((GLdouble)h), (GLdouble) 10.0, (GLdouble) 1000.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glTranslatef(0.0, 0.0, -20.0);
|
||||
}
|
||||
|
||||
void display()
|
||||
{
|
||||
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
|
||||
|
||||
//show light
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective((GLdouble) 60.0, (float)window_x/window_y, (GLdouble) 1.0, (GLdouble) 100.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glTranslatef(0.0, 0.0, -10.0);
|
||||
|
||||
glRotatef(alpha, 1.0, 0.0, 0.0);
|
||||
glRotatef(beta, 0.0, 1.0, 0.0);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
glVertex3f(0.0, 0.0, 0.0);
|
||||
glVertex3f(0.0, 0.0, 1.0);
|
||||
glEnd();
|
||||
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glBindTexture(GL_TEXTURE_2D, texName);
|
||||
|
||||
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
||||
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
||||
glEnable(GL_TEXTURE_GEN_S);
|
||||
glEnable(GL_TEXTURE_GEN_T);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glNormal3f(0.0, 0.0, 1.0);
|
||||
glVertex3f(1.0, 1.0, 0.0);
|
||||
glVertex3f(-1.0, 1.0, 0.0);
|
||||
glVertex3f(-1.0, -1.0, 0.0);
|
||||
glVertex3f(1.0, -1.0, 0.0);
|
||||
glEnd();
|
||||
|
||||
/*
|
||||
glPointSize(48.0);
|
||||
glBegin(GL_POINTS);
|
||||
glNormal3f(0.0, 0.0, 1.0);
|
||||
glVertex3f(0.0, 0.0, 0.0);
|
||||
glEnd();
|
||||
*/
|
||||
|
||||
glDisable(GL_TEXTURE_GEN_S);
|
||||
glDisable(GL_TEXTURE_GEN_T);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
/*****************************************************************/
|
||||
|
||||
//show how the map looks like
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
//gluOrtho2D(0.0 -10.0, 1.0 +10.0, -(float)window_x/window_y -10.0,0.0 +10.0);
|
||||
//glOrtho(0.0, 5.0, -5.0, 0.0, -10.0, 10.0);
|
||||
glOrtho(0.0, 5.0*((float)window_x/window_y), -5.0, 0.0, -10.0, 10.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glBindTexture(GL_TEXTURE_2D, texName);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
|
||||
glTexCoord2f(0.0, 1.0); glVertex3f(0.0, -1.0, 0.0);
|
||||
glTexCoord2f(1.0, 1.0); glVertex3f(1.0, -1.0, 0.0);
|
||||
glTexCoord2f(1.0, 0.0); glVertex3f(1.0, 0.0, 0.0);
|
||||
glEnd();
|
||||
glFlush();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glutPostRedisplay () ;
|
||||
glutSwapBuffers () ;
|
||||
}
|
||||
|
||||
void keyboard (unsigned char key, int x, int y)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
case 27:
|
||||
exit(0);
|
||||
|
||||
case '8':
|
||||
alpha += 1.0;
|
||||
if (alpha >= 360.0) alpha -= 360.0;
|
||||
break;
|
||||
|
||||
case '2':
|
||||
alpha -= 1.0;
|
||||
if (alpha < 0.0) alpha += 360.0;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
beta -= 1.0;
|
||||
if (beta <= -90.0) beta = -90.0;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
beta += 1.0;
|
||||
if (beta >= 90.0) beta = 90.0;
|
||||
break;
|
||||
|
||||
case '5':
|
||||
alpha = 0.0; beta = 0.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_GLUT_H */
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
#ifdef HAVE_GLUT_H
|
||||
glutInitWindowSize(window_x, window_y);
|
||||
glutInit(&argc, argv);
|
||||
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
|
||||
glutCreateWindow(argv[0]);
|
||||
init();
|
||||
glutDisplayFunc(display);
|
||||
glutReshapeFunc(reshape);
|
||||
glutKeyboardFunc(keyboard);
|
||||
|
||||
glutMainLoop();
|
||||
#else
|
||||
|
||||
printf("GL Utility Toolkit (glut) was not found on this system.\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#if defined( unix ) || defined( __CYGWIN__ )
|
||||
# include <unistd.h> // for gethostname()
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
#if defined( unix ) || defined( __CYGWIN__ )
|
||||
char name[256];
|
||||
gethostname( name, 256 );
|
||||
printf("hostname = %s\n", name);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// do some non-destructive read tests relating text files
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void readchars( FILE *fd ) {
|
||||
int c;
|
||||
while ( (c = fgetc(fd)) != EOF ) {
|
||||
printf("c = %d", c);
|
||||
if ( c == 10 ) {
|
||||
printf(" LF \\n");
|
||||
}
|
||||
if ( c == 13 ) {
|
||||
printf(" CR \\r");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void readlines( FILE *fd ) {
|
||||
char line[256];
|
||||
while ( fgets(line, 255, fd) != NULL ) {
|
||||
int len = strlen(line);
|
||||
printf("line = %s", line);
|
||||
if ( len >= 2 ) {
|
||||
printf(" char[n - 1] = %d char[n] = %d\n",
|
||||
line[len-2], line[len-1]);
|
||||
} else if ( len >= 1 ) {
|
||||
printf(" char[n] = %d\n",line[len-1]);
|
||||
} else {
|
||||
printf("empty string\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char **argv ) {
|
||||
// check usage
|
||||
if ( argc != 2 ) {
|
||||
printf("usage: %s file\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char file[256];
|
||||
strcpy( file, argv[1] );
|
||||
FILE *fd;
|
||||
|
||||
// open a file in (default) text mode
|
||||
printf("TEXT MODE (DEFAULT) by character\n\n");
|
||||
fd = fopen( file, "r" );
|
||||
if ( fd != NULL ) {
|
||||
readchars( fd );
|
||||
fclose(fd);
|
||||
} else {
|
||||
printf("Cannot open %s\n", file);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// open a file in (explicit) text mode
|
||||
printf("TEXT MODE (EXPLICIT) by character\n\n");
|
||||
fd = fopen( file, "rt" );
|
||||
if ( fd != NULL ) {
|
||||
readchars( fd );
|
||||
fclose(fd);
|
||||
} else {
|
||||
printf("Cannot open %s\n", file);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// open a file in (explicit) binary mode
|
||||
printf("BINARY MODE (EXPLICIT) by character\n\n");
|
||||
fd = fopen( file, "rb" );
|
||||
if ( fd != NULL ) {
|
||||
readchars( fd );
|
||||
fclose(fd);
|
||||
} else {
|
||||
printf("Cannot open %s\n", file);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// open a file in (default) text mode
|
||||
printf("TEXT MODE (DEFAULT) by line\n\n");
|
||||
fd = fopen( file, "r" );
|
||||
if ( fd != NULL ) {
|
||||
readlines( fd );
|
||||
fclose(fd);
|
||||
} else {
|
||||
printf("Cannot open %s\n", file);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// open a file in (explicit) text mode
|
||||
printf("TEXT MODE (EXPLICIT) by line\n\n");
|
||||
fd = fopen( file, "rt" );
|
||||
if ( fd != NULL ) {
|
||||
readlines( fd );
|
||||
fclose(fd);
|
||||
} else {
|
||||
printf("Cannot open %s\n", file);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// open a file in (explicit) binary mode
|
||||
printf("BINARY MODE (EXPLICIT) by line\n\n");
|
||||
fd = fopen( file, "rb" );
|
||||
if ( fd != NULL ) {
|
||||
readlines( fd );
|
||||
fclose(fd);
|
||||
} else {
|
||||
printf("Cannot open %s\n", file);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// bootstrap.cxx -- replacement bootstrap routines for the test suite.
|
||||
//
|
||||
// Written by Edward d'Auvergne, started May 2017.
|
||||
//
|
||||
// Copyright (C) 2017 Edward d'Auvergne
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int _bootstrap_OSInit;
|
||||
std::string hostname;
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2018 James Turner
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
|
||||
#include <Main/fg_init.hxx>
|
||||
|
||||
|
||||
#include "dataStore.hxx"
|
||||
|
||||
|
||||
// Sanity check.
|
||||
bool looksLikeFGData(const SGPath& path)
|
||||
{
|
||||
return (path / "defaults.xml").exists();
|
||||
}
|
||||
|
||||
|
||||
// Set up the path to FGData.
|
||||
int DataStore::findFGRoot(const std::string& fgRootCmdLineOpt, bool debug)
|
||||
{
|
||||
SGPath fgRoot;
|
||||
|
||||
// Command line supplied path.
|
||||
if (!fgRootCmdLineOpt.empty()) {
|
||||
fgRoot = SGPath::fromUtf8(fgRootCmdLineOpt);
|
||||
if (looksLikeFGData(fgRoot)) {
|
||||
if (debug)
|
||||
std::cerr << "FGdata from the command line: " << fgRoot << std::endl;
|
||||
_fgRootPath = fgRoot;
|
||||
return 0;
|
||||
|
||||
// Fail if an invalid path is supplied.
|
||||
} else {
|
||||
std::cerr << "The supplied path \"" << fgRootCmdLineOpt << "\" is not a valid FGData path." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// The FG_DATA_DIR CMake option.
|
||||
fgRoot = SGPath::fromUtf8(PKGLIBDIR);
|
||||
if (looksLikeFGData(fgRoot)) {
|
||||
if (debug)
|
||||
std::cerr << "FGdata found via $PKGLIBDIR: " << fgRoot << std::endl;
|
||||
_fgRootPath = fgRoot;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The FG_ROOT environmental variable.
|
||||
if (std::getenv("FG_ROOT")) {
|
||||
fgRoot = SGPath::fromEnv("FG_ROOT");
|
||||
if (looksLikeFGData(fgRoot)) {
|
||||
if (debug)
|
||||
std::cerr << "FGdata found via $FG_ROOT: " << fgRoot << std::endl;
|
||||
_fgRootPath = fgRoot;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Try in ../fgdata.
|
||||
fgRoot = SGPath::fromUtf8(FGSRCDIR) / ".." / "fgdata";
|
||||
if (looksLikeFGData(fgRoot)) {
|
||||
if (debug)
|
||||
std::cerr << "FGdata found at \"$FGSRCDIR/../fgdata\": " << fgRoot << std::endl;
|
||||
_fgRootPath = fgRoot;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Try in ../data.
|
||||
fgRoot = SGPath::fromUtf8(FGSRCDIR) / ".." / "data";
|
||||
if (looksLikeFGData(fgRoot)) {
|
||||
if (debug)
|
||||
std::cerr << "FGdata found at \"$FGSRCDIR/../data\": " << std::endl;
|
||||
_fgRootPath = fgRoot;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// No FGData.
|
||||
std::cerr << "FGData not found." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get the path to FGData.
|
||||
SGPath DataStore::getFGRoot()
|
||||
{
|
||||
return _fgRootPath;
|
||||
}
|
||||
|
||||
// Perform a version validation of FGData, returning zero if ok.
|
||||
int DataStore::validateFGRoot()
|
||||
{
|
||||
// The FGData version.
|
||||
SGPath root = getFGRoot();
|
||||
std::string base_version = fgBasePackageVersion(root);
|
||||
if (base_version.empty()) {
|
||||
std::cout << "Base package not found." << std::endl;
|
||||
std::cout << "Required FGData files not found, please check your configuration." << std::endl;
|
||||
std::cout << "Looking for FGData files in '" << root.str() << "'." << std::endl;
|
||||
std::cout.flush();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Comparison of only the major and minor version numbers.
|
||||
const int versionComp = simgear::strutils::compare_versions(FLIGHTGEAR_VERSION, base_version, 2);
|
||||
if (versionComp != 0) {
|
||||
std::cout << "Base package version mismatch." << std::endl;
|
||||
std::cout << "Version check failed, please check your configuration." << std::endl;
|
||||
std::cout << "The FGData version '" << base_version << "' in '" << root.str();
|
||||
std::cout << "does not match the FlightGear version '" << std::string(FLIGHTGEAR_VERSION);
|
||||
std::cout << "'." << std::endl;
|
||||
std::cout.flush();
|
||||
}
|
||||
return versionComp;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FG_TEST_SUITE_DATA_STORE_HXX
|
||||
#define _FG_TEST_SUITE_DATA_STORE_HXX
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
|
||||
// The data store singleton.
|
||||
class DataStore
|
||||
{
|
||||
public:
|
||||
// Return the singleton, instantiating it if required.
|
||||
static DataStore& get()
|
||||
{
|
||||
static DataStore instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Function deletion to allow the class to be a singleton.
|
||||
DataStore(DataStore const&) = delete;
|
||||
void operator=(DataStore const&) = delete;
|
||||
|
||||
// FGData path functions.
|
||||
int findFGRoot(const std::string& fgRootCmdLineOpt, bool debug = false);
|
||||
SGPath getFGRoot();
|
||||
int validateFGRoot();
|
||||
|
||||
private:
|
||||
DataStore() = default;
|
||||
|
||||
// The path to FGData.
|
||||
SGPath _fgRootPath;
|
||||
};
|
||||
|
||||
|
||||
#endif // _FG_TEST_SUITE_DATA_STORE_HXX
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
|
||||
#include <cppunit/SourceLine.h>
|
||||
#include <cppunit/TestResultCollector.h>
|
||||
|
||||
#include "fgCompilerOutputter.hxx"
|
||||
#include "formatting.hxx"
|
||||
#include "logging.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
// Create a new class instance.
|
||||
fgCompilerOutputter * fgCompilerOutputter::defaultOutputter(CppUnit::TestResultCollector *result, vector<TestIOCapt> *capt, const clock_t *clock, CppUnit::OStream &stream)
|
||||
{
|
||||
return new fgCompilerOutputter(result, capt, clock, stream);
|
||||
}
|
||||
|
||||
|
||||
// Printout for each failed test.
|
||||
void fgCompilerOutputter::printFailureDetail(CppUnit::TestFailure *failure)
|
||||
{
|
||||
// Declarations.
|
||||
TestIOCapt test_io;
|
||||
vector<TestIOCapt>::iterator test_iter;
|
||||
|
||||
// Initial separator.
|
||||
#ifdef _WIN32
|
||||
fg_stream << endl;
|
||||
#endif
|
||||
fg_stream << string(WIDTH_DIVIDER, '=') << endl;
|
||||
|
||||
// Test info.
|
||||
fg_stream << (failure->isError() ? "ERROR: " : "FAIL: ") << failure->failedTestName() << endl;
|
||||
fg_stream << string(WIDTH_DIVIDER, '-') << endl;
|
||||
fg_stream << (failure->isError() ? "Error" : "Assertion") << ": ";
|
||||
printFailureLocation(failure->sourceLine());
|
||||
printFailureMessage(failure);
|
||||
fg_stream.flush();
|
||||
|
||||
if (debug)
|
||||
return;
|
||||
|
||||
// The captured IO for this test.
|
||||
test_iter = find_if(io_capt->begin(), io_capt->end(), matchTestName(failure->failedTestName()));
|
||||
if (test_iter != io_capt->end())
|
||||
test_io = *test_iter;
|
||||
|
||||
// SG_LOG IO streams.
|
||||
if (!test_io.sg_interleaved.empty())
|
||||
fgCompilerOutputter::printIOStreamMessages("SG_LOG, "+test_io.log_class+" class, "+test_io.log_priority+" priority", test_io.sg_interleaved, true);
|
||||
if (!test_io.sg_bulk_only.empty())
|
||||
fgCompilerOutputter::printIOStreamMessages("SG_LOG, "+test_io.log_class+" class, SG_BULK only priority", test_io.sg_bulk_only);
|
||||
if (!test_io.sg_debug_only.empty())
|
||||
fgCompilerOutputter::printIOStreamMessages("SG_LOG, "+test_io.log_class+" class, SG_DEBUG only priority", test_io.sg_debug_only);
|
||||
if (!test_io.sg_info_only.empty())
|
||||
fgCompilerOutputter::printIOStreamMessages("SG_LOG, "+test_io.log_class+" class, SG_INFO only priority", test_io.sg_info_only);
|
||||
if (!test_io.sg_warn_only.empty())
|
||||
fgCompilerOutputter::printIOStreamMessages("SG_LOG, "+test_io.log_class+" class, SG_WARN only priority", test_io.sg_warn_only);
|
||||
if (!test_io.sg_alert_only.empty())
|
||||
fgCompilerOutputter::printIOStreamMessages("SG_LOG, "+test_io.log_class+" class, SG_ALERT only priority", test_io.sg_alert_only);
|
||||
|
||||
// Default IO streams.
|
||||
fgCompilerOutputter::printIOStreamMessages("STDOUT and STDERR", test_io.stdio);
|
||||
}
|
||||
|
||||
|
||||
// Detailed printout after a failed run of the test suite.
|
||||
void fgCompilerOutputter::printFailureReport()
|
||||
{
|
||||
// Custom printouts for each failed test.
|
||||
printFailuresList();
|
||||
|
||||
// CTest output (nothing).
|
||||
if (ctest_output)
|
||||
return;
|
||||
|
||||
// A summary with timing info.
|
||||
printSuiteStats();
|
||||
|
||||
// Final summary.
|
||||
fg_stream << endl << "[ FAILED ]" << endl << endl;
|
||||
fg_stream.flush();
|
||||
}
|
||||
|
||||
|
||||
void fgCompilerOutputter::printIOStreamMessages(string heading, string messages, bool empty)
|
||||
{
|
||||
// Silence.
|
||||
if (!empty && messages.size() == 0)
|
||||
return;
|
||||
|
||||
// Divider.
|
||||
fg_stream << string(WIDTH_DIVIDER, '-') << endl;
|
||||
|
||||
// Heading.
|
||||
fg_stream << "# " << heading << endl << endl;
|
||||
|
||||
// Nothing to do
|
||||
if (messages.size() == 0)
|
||||
fg_stream << "(empty)" << endl << endl;
|
||||
|
||||
// The IO stream contents.
|
||||
else
|
||||
fg_stream << messages << endl;
|
||||
}
|
||||
|
||||
|
||||
// Printout of the test suite stats.
|
||||
void fgCompilerOutputter::printSuiteStats()
|
||||
{
|
||||
// A divider.
|
||||
#ifdef _WIN32
|
||||
fg_stream << endl;
|
||||
#endif
|
||||
fg_stream << string(WIDTH_DIVIDER, '-') << endl;
|
||||
|
||||
// Timing and test count line.
|
||||
fg_stream << "Ran " << fg_result->runTests() << " tests";
|
||||
streamsize prec = fg_stream.precision();
|
||||
fg_stream << setprecision(3);
|
||||
fg_stream << " in " << ((double)*suite_timer)/CLOCKS_PER_SEC << " seconds." << endl;
|
||||
fg_stream << setprecision(prec);
|
||||
|
||||
// Failure line.
|
||||
if (!fg_result->wasSuccessful()) {
|
||||
fg_stream << endl << "Failures = " << fg_result->testFailures() << endl;
|
||||
fg_stream << "Errors = " << fg_result->testErrors() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Print a summary after a successful run of the test suite.
|
||||
void fgCompilerOutputter::printSuccess()
|
||||
{
|
||||
// CTest output (nothing).
|
||||
if (ctest_output)
|
||||
return;
|
||||
|
||||
// A summary with timing info.
|
||||
printSuiteStats();
|
||||
|
||||
// Final summary.
|
||||
fg_stream << endl << "[ OK ]" << endl << endl;
|
||||
fg_stream.flush();
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FG_COMPILER_OUTPUTTER_HXX
|
||||
#define _FG_COMPILER_OUTPUTTER_HXX
|
||||
|
||||
|
||||
#include <cppunit/CompilerOutputter.h>
|
||||
#include <cppunit/TestFailure.h>
|
||||
|
||||
#include "fgTestListener.hxx"
|
||||
|
||||
|
||||
// The custom outputter for the FlightGear test suite.
|
||||
class fgCompilerOutputter : public CppUnit::CompilerOutputter
|
||||
{
|
||||
public:
|
||||
// Constructor.
|
||||
fgCompilerOutputter(CppUnit::TestResultCollector *result,
|
||||
std::vector<TestIOCapt> *capt,
|
||||
const clock_t *clock,
|
||||
CppUnit::OStream &stream,
|
||||
bool ctest = false,
|
||||
bool debug = false,
|
||||
const std::string &locationFormat = CPPUNIT_COMPILER_LOCATION_FORMAT)
|
||||
: CppUnit::CompilerOutputter(result, stream, locationFormat)
|
||||
, io_capt(capt)
|
||||
, fg_result(result)
|
||||
, fg_stream(stream)
|
||||
, suite_timer(clock)
|
||||
, ctest_output(ctest)
|
||||
, debug(debug)
|
||||
{
|
||||
}
|
||||
|
||||
// Create a new class instance.
|
||||
static fgCompilerOutputter *defaultOutputter(CppUnit::TestResultCollector *result, std::vector<TestIOCapt> *capt, const clock_t *clock, CppUnit::OStream &stream);
|
||||
|
||||
// Print a summary after a successful run of the test suite.
|
||||
void printSuccess();
|
||||
|
||||
// Detailed printout after a failed run of the test suite.
|
||||
void printFailureReport();
|
||||
|
||||
// Printout for each failed test.
|
||||
void printFailureDetail(CppUnit::TestFailure *failure);
|
||||
|
||||
// Printout of the test suite stats.
|
||||
void printSuiteStats();
|
||||
|
||||
// The captured IO for each failed test.
|
||||
std::vector<TestIOCapt> *io_capt;
|
||||
|
||||
private:
|
||||
// Store copies of the base class objects.
|
||||
CppUnit::TestResultCollector *fg_result;
|
||||
CppUnit::OStream &fg_stream;
|
||||
|
||||
// The test suite time, in clock ticks.
|
||||
const clock_t *suite_timer;
|
||||
|
||||
// Output control.
|
||||
bool ctest_output;
|
||||
bool debug;
|
||||
|
||||
// Simgear logstream IO printout.
|
||||
void printIOStreamMessages(std::string heading, std::string messages, bool empty);
|
||||
void printIOStreamMessages(std::string heading, std::string messages) {printIOStreamMessages(heading, messages, false);}
|
||||
};
|
||||
|
||||
|
||||
#endif // _FG_COMPILER_OUTPUTTER_HXX
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <cppunit/Test.h>
|
||||
#include <cppunit/TestFailure.h>
|
||||
#include <cppunit/TestListener.h>
|
||||
|
||||
#include "fgTestListener.hxx"
|
||||
#include "logging.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
// Handle failures.
|
||||
void fgTestListener::addFailure(const CppUnit::TestFailure &failure)
|
||||
{
|
||||
m_failure = true;
|
||||
if (failure.isError())
|
||||
m_error = true;
|
||||
}
|
||||
|
||||
|
||||
// Override the base class function to restore IO streams.
|
||||
void fgTestListener::endTest(CppUnit::Test *test)
|
||||
{
|
||||
// Test timing.
|
||||
sum_time += clock() - m_time;
|
||||
|
||||
// Restore the IO streams.
|
||||
if (!debug) {
|
||||
cout.rdbuf(orig_cout);
|
||||
cerr.rdbuf(orig_cerr);
|
||||
}
|
||||
|
||||
// Debugging output.
|
||||
if (debug)
|
||||
cerr << string(WIDTH_DIVIDER, '-') << endl;
|
||||
|
||||
// Per-test single character status feedback.
|
||||
if (m_failure)
|
||||
cerr << (m_error ? "E" : "F");
|
||||
else
|
||||
cerr << '.';
|
||||
|
||||
// Timing output.
|
||||
if (timings || ctest_output || debug) {
|
||||
// Test timing.
|
||||
float time = ((float)(clock()-m_time))/CLOCKS_PER_SEC;
|
||||
char buffer[100];
|
||||
if (time > 60.0)
|
||||
snprintf(buffer, sizeof(buffer), "%10.3f %-3s", time/60, "min");
|
||||
else if (time > 1.0)
|
||||
snprintf(buffer, sizeof(buffer), "%10.3f %-3s", time, "s");
|
||||
else
|
||||
snprintf(buffer, sizeof(buffer), "%10.3f %-3s", time*1000, "ms");
|
||||
cerr << buffer;
|
||||
|
||||
// Test name.
|
||||
cerr << " for " << test->getName() << endl;
|
||||
}
|
||||
cerr.flush();
|
||||
|
||||
// Store the captured IO for any failed tests.
|
||||
if (m_failure && !debug) {
|
||||
// Set up the data structure.
|
||||
TestIOCapt test_io;
|
||||
test_io.name = test->getName();
|
||||
|
||||
// Standard IO.
|
||||
test_io.stdio = capt.str();
|
||||
|
||||
// The simgear logstreams.
|
||||
capturedIO &obj = getIOstreams();
|
||||
test_io.log_class = obj.log_class;
|
||||
test_io.log_priority = obj.log_priority;
|
||||
test_io.sg_interleaved = obj.sg_interleaved.str();
|
||||
test_io.sg_bulk_only = obj.sg_bulk_only.str();
|
||||
test_io.sg_debug_only = obj.sg_debug_only.str();
|
||||
test_io.sg_info_only = obj.sg_info_only.str();
|
||||
test_io.sg_warn_only = obj.sg_warn_only.str();
|
||||
test_io.sg_alert_only = obj.sg_alert_only.str();
|
||||
|
||||
// Add the test's IO to the list.
|
||||
io_capt.push_back(test_io);
|
||||
}
|
||||
}
|
||||
|
||||
// Override the base class function to capture IO streams.
|
||||
void fgTestListener::startTest(CppUnit::Test *test)
|
||||
{
|
||||
// IO capture.
|
||||
if (!debug) {
|
||||
// Clear the simgear logstream buffers.
|
||||
capturedIO &obj = getIOstreams();
|
||||
obj.sg_interleaved.str("");
|
||||
obj.sg_bulk_only.str("");
|
||||
obj.sg_debug_only.str("");
|
||||
obj.sg_info_only.str("");
|
||||
obj.sg_warn_only.str("");
|
||||
obj.sg_alert_only.str("");
|
||||
|
||||
// Store the original STDOUT and STDERR for restoring later on.
|
||||
orig_cout = cout.rdbuf();
|
||||
orig_cerr = cerr.rdbuf();
|
||||
|
||||
// Clear the captured stream and then catch stdout and stderr.
|
||||
capt.str(string());
|
||||
cout.rdbuf(capt.rdbuf());
|
||||
cerr.rdbuf(capt.rdbuf());
|
||||
|
||||
// Debugging output.
|
||||
} else {
|
||||
cerr << string(WIDTH_DIVIDER, '=') << endl;
|
||||
cerr << "Starting test: " << test->getName() << endl;
|
||||
cerr << string(WIDTH_DIVIDER, '-') << endl;
|
||||
}
|
||||
// Reset the test status.
|
||||
m_failure = false;
|
||||
m_error = false;
|
||||
m_time = clock();
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FG_TEST_LISTENER_HXX
|
||||
#define _FG_TEST_LISTENER_HXX
|
||||
|
||||
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
|
||||
#include "formatting.hxx"
|
||||
|
||||
|
||||
// Data structure for holding the captured IO for a failed test.
|
||||
struct TestIOCapt {
|
||||
std::string name;
|
||||
std::string log_class;
|
||||
std::string log_priority;
|
||||
std::string stdio;
|
||||
std::string sg_interleaved;
|
||||
std::string sg_bulk_only;
|
||||
std::string sg_debug_only;
|
||||
std::string sg_info_only;
|
||||
std::string sg_warn_only;
|
||||
std::string sg_alert_only;
|
||||
};
|
||||
|
||||
|
||||
// Match the test by name for std:find using a vector<TestIOCapt>.
|
||||
class matchTestName
|
||||
{
|
||||
std::string _name;
|
||||
|
||||
public:
|
||||
matchTestName(const std::string &name) : _name(name) {}
|
||||
|
||||
bool operator()(const TestIOCapt &item) const {
|
||||
return item.name == _name;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// The custom test runner for the FlightGear test suite.
|
||||
class fgTestListener : public CppUnit::TestListener
|
||||
{
|
||||
protected:
|
||||
// Failure state.
|
||||
bool m_failure, m_error;
|
||||
|
||||
public:
|
||||
// Constructor.
|
||||
fgTestListener(): m_failure(false), m_error(false), sum_time(0) { };
|
||||
|
||||
// Override the base class function to capture IO. streams
|
||||
void startTest(CppUnit::Test *test);
|
||||
|
||||
// Override the base class function to restore IO streams.
|
||||
void endTest(CppUnit::Test *test);
|
||||
|
||||
// Handle failures.
|
||||
void addFailure(const CppUnit::TestFailure &failure);
|
||||
|
||||
// Test suite timing.
|
||||
clock_t sum_time;
|
||||
|
||||
// IO capture for all failed tests.
|
||||
std::vector<TestIOCapt> io_capt;
|
||||
|
||||
// Output settings.
|
||||
bool timings;
|
||||
bool ctest_output;
|
||||
bool debug;
|
||||
|
||||
protected:
|
||||
// The original IO streams.
|
||||
std::streambuf *orig_cerr, *orig_cout;
|
||||
|
||||
// Captured IO streams.
|
||||
std::stringstream capt;
|
||||
|
||||
// Test timings.
|
||||
clock_t m_time;
|
||||
};
|
||||
|
||||
|
||||
#endif // _FG_TEST_LISTENER_HXX
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <cppunit/TestResult.h>
|
||||
#include <cppunit/TestResultCollector.h>
|
||||
#include <cppunit/TextTestRunner.h>
|
||||
#include <cppunit/extensions/TestFactoryRegistry.h>
|
||||
|
||||
#include "fgCompilerOutputter.hxx"
|
||||
#include "fgTestListener.hxx"
|
||||
#include "formatting.hxx"
|
||||
|
||||
|
||||
// Execute all test suites for the given test category.
|
||||
int testRunner(const std::string& type, const std::string& title, char *subset, bool timings, bool ctest_output, bool debug)
|
||||
{
|
||||
// Declarations.
|
||||
CppUnit::TextTestRunner runner;
|
||||
|
||||
// Print out a title.
|
||||
if (!ctest_output)
|
||||
printTitle(std::cerr, title);
|
||||
|
||||
// Get all tests.
|
||||
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry(type).makeTest());
|
||||
|
||||
// Set up the test listener.
|
||||
fgTestListener *testListener;
|
||||
testListener = new fgTestListener;
|
||||
runner.eventManager().addListener(testListener);
|
||||
testListener->timings = timings;
|
||||
testListener->ctest_output = ctest_output;
|
||||
testListener->debug = debug;
|
||||
|
||||
// Set the test suite output IO stream.
|
||||
runner.setOutputter(new fgCompilerOutputter(&runner.result(), &testListener->io_capt, &testListener->sum_time, std::cerr, ctest_output, debug));
|
||||
|
||||
// Execute the tests.
|
||||
if (subset == NULL)
|
||||
runner.run("", false, true, false);
|
||||
else {
|
||||
std::stringstream testStream(subset);
|
||||
std::string testName;
|
||||
while( testStream.good() ) {
|
||||
getline( testStream, testName, ',' );
|
||||
runner.run(testName, false, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up.
|
||||
delete testListener;
|
||||
|
||||
// Return the status of the tests.
|
||||
CppUnit::TestResultCollector &status = runner.result();
|
||||
return status.testFailuresTotal();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FG_TEST_RUNNER_HXX
|
||||
#define _FG_TEST_RUNNER_HXX
|
||||
|
||||
|
||||
// Execute all test suites for the given test category.
|
||||
int testRunner(const std::string&, const std::string&, char*, bool, bool, bool);
|
||||
|
||||
|
||||
#endif // _FG_TEST_RUNNER_HXX
|
||||
@@ -0,0 +1,19 @@
|
||||
# Add each simgear test category.
|
||||
foreach( simgear_test_category
|
||||
)
|
||||
|
||||
add_subdirectory(${simgear_test_category})
|
||||
|
||||
endforeach( simgear_test_category )
|
||||
|
||||
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "formatting.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
// Printout of a section label.
|
||||
void printSection(CppUnit::OStream &stream, const string &text)
|
||||
{
|
||||
// Declarations.
|
||||
string::size_type width = text.size();
|
||||
|
||||
// Format the text.
|
||||
stream << endl;
|
||||
stream << text << endl;
|
||||
stream << string(width, '=') << endl << endl;
|
||||
}
|
||||
|
||||
|
||||
// Print a summary line.
|
||||
void printSummaryLine(CppUnit::OStream &stream, const string &name, int passed)
|
||||
{
|
||||
// Declarations.
|
||||
int n;
|
||||
string dots, state;
|
||||
|
||||
// Passed.
|
||||
if (!passed)
|
||||
state = "OK";
|
||||
|
||||
// Skipped.
|
||||
else if (passed == -1)
|
||||
state = "Skipped";
|
||||
|
||||
// Failed.
|
||||
else
|
||||
state = "Failed";
|
||||
|
||||
// Dots.
|
||||
n = WIDTH_DIVIDER - name.size() - state.size() - 6;
|
||||
dots = string(n, '.');
|
||||
|
||||
// Write out the line.
|
||||
stream << name;
|
||||
stream << " " << dots << " ";
|
||||
stream << "[ " << state << " ]" << endl;
|
||||
}
|
||||
|
||||
|
||||
// Printout of a title label.
|
||||
void printTitle(CppUnit::OStream &stream, const string &text)
|
||||
{
|
||||
// Declarations.
|
||||
string::size_type width = text.size() + 4;
|
||||
|
||||
// Format the text.
|
||||
stream << endl << endl;
|
||||
stream << string(width, '=') << endl;
|
||||
stream << "= " << text << " =" << endl;
|
||||
stream << string(width, '=') << endl << endl;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FG_TEST_SUITE_FORMATTING_HXX
|
||||
#define _FG_TEST_SUITE_FORMATTING_HXX
|
||||
|
||||
#include <cppunit/portability/Stream.h>
|
||||
|
||||
|
||||
// Divider width.
|
||||
const int WIDTH_DIVIDER = 70;
|
||||
|
||||
// Printout of a section label.
|
||||
void printSection(CppUnit::OStream &stream, const std::string &text);
|
||||
|
||||
// Print a summary line.
|
||||
void printSummaryLine(CppUnit::OStream &stream, const std::string &name, int passed);
|
||||
|
||||
// Printout of a title label.
|
||||
void printTitle(CppUnit::OStream &stream, const std::string &text);
|
||||
|
||||
|
||||
#endif // _FG_TEST_SUITE_FORMATTING_HXX
|
||||
@@ -0,0 +1,19 @@
|
||||
# Add each GUI test category.
|
||||
foreach( gui_test_category
|
||||
)
|
||||
|
||||
add_subdirectory(${gui_test_category})
|
||||
|
||||
endforeach( gui_test_category )
|
||||
|
||||
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
#include "logging.hxx"
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/debug/OsgIoCapture.hxx>
|
||||
|
||||
|
||||
// The global stream capture data structure.
|
||||
static capturedIO *_iostreams = NULL;
|
||||
|
||||
|
||||
// capturedIO constructor.
|
||||
capturedIO::capturedIO(sgDebugClass c, sgDebugPriority p)
|
||||
{
|
||||
callback_interleaved = new StreamLogCallback(sg_interleaved, c, p, false);
|
||||
callback_bulk_only = new StreamLogCallback(sg_bulk_only, c, SG_BULK, true);
|
||||
callback_debug_only = new StreamLogCallback(sg_debug_only, c, SG_DEBUG, true);
|
||||
callback_info_only = new StreamLogCallback(sg_info_only, c, SG_INFO, true);
|
||||
callback_warn_only = new StreamLogCallback(sg_warn_only, c, SG_WARN, true);
|
||||
callback_alert_only = new StreamLogCallback(sg_alert_only, c, SG_ALERT, true);
|
||||
|
||||
// Store the class as a string.
|
||||
if (c == SG_ALL)
|
||||
log_class = "SG_ALL";
|
||||
else {
|
||||
std::stringstream stream;
|
||||
stream << "0x" << std::right << std::setfill('0') << std::setw(8) << std::hex << c;
|
||||
log_class = stream.str();
|
||||
}
|
||||
|
||||
// Store the priority as a string.
|
||||
if (p == SG_BULK)
|
||||
log_priority = "SG_BULK";
|
||||
else if (p == SG_DEBUG)
|
||||
log_priority = "SG_DEBUG";
|
||||
else if (p == SG_INFO)
|
||||
log_priority = "SG_INFO";
|
||||
else if (p == SG_WARN)
|
||||
log_priority = "SG_WARN";
|
||||
else if (p == SG_ALERT)
|
||||
log_priority = "SG_ALERT";
|
||||
else if (p == SG_POPUP)
|
||||
log_priority = "SG_POPUP";
|
||||
else if (p == SG_DEV_WARN)
|
||||
log_priority = "SG_DEV_WARN";
|
||||
else if (p == SG_DEV_ALERT)
|
||||
log_priority = "SG_DEV_ALERT";
|
||||
}
|
||||
|
||||
// capturedIO destructor.
|
||||
capturedIO::~capturedIO()
|
||||
{
|
||||
// Destroy the callback objects.
|
||||
delete callback_interleaved;
|
||||
delete callback_bulk_only;
|
||||
delete callback_debug_only;
|
||||
delete callback_info_only;
|
||||
delete callback_warn_only;
|
||||
delete callback_alert_only;
|
||||
}
|
||||
|
||||
|
||||
// Return the global stream capture data structure, creating it if needed.
|
||||
capturedIO & getIOstreams(sgDebugClass c, sgDebugPriority p)
|
||||
{
|
||||
// Initialise the global stream capture data structure, if needed.
|
||||
if (!_iostreams)
|
||||
_iostreams = new capturedIO(c, p);
|
||||
|
||||
// Return a pointer to the global object.
|
||||
return *_iostreams;
|
||||
}
|
||||
|
||||
|
||||
// Set up to capture all the simgear logging priorities as separate streams.
|
||||
void setupLogging(sgDebugClass c, sgDebugPriority p, bool split)
|
||||
{
|
||||
// Get the single logstream instance.
|
||||
logstream &log = sglog();
|
||||
|
||||
// Set up the logstream testing mode.
|
||||
log.setTestingMode(true);
|
||||
|
||||
// OSG IO capture.
|
||||
osg::setNotifyHandler(new NotifyLogger);
|
||||
|
||||
// IO capture.
|
||||
capturedIO &obj = getIOstreams(c, p);
|
||||
if (!split)
|
||||
log.addCallback(obj.callback_interleaved);
|
||||
else {
|
||||
if (p <= SG_BULK)
|
||||
log.addCallback(obj.callback_bulk_only);
|
||||
if (p <= SG_DEBUG)
|
||||
log.addCallback(obj.callback_debug_only);
|
||||
if (p <= SG_INFO)
|
||||
log.addCallback(obj.callback_info_only);
|
||||
if (p <= SG_WARN)
|
||||
log.addCallback(obj.callback_warn_only);
|
||||
if (p <= SG_ALERT)
|
||||
log.addCallback(obj.callback_alert_only);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Deactivate all the simgear logging priority IO captures.
|
||||
void stopLogging()
|
||||
{
|
||||
// Get the single logstream instance.
|
||||
logstream &log = sglog();
|
||||
|
||||
// IO decapture.
|
||||
capturedIO &obj = getIOstreams();
|
||||
log.removeCallback(obj.callback_interleaved);
|
||||
log.removeCallback(obj.callback_bulk_only);
|
||||
log.removeCallback(obj.callback_debug_only);
|
||||
log.removeCallback(obj.callback_info_only);
|
||||
log.removeCallback(obj.callback_warn_only);
|
||||
log.removeCallback(obj.callback_alert_only);
|
||||
|
||||
// Clean up the IO stream object.
|
||||
delete _iostreams;
|
||||
_iostreams = NULL;
|
||||
|
||||
// Stop the simgear logstream.
|
||||
simgear::shutdownLogging();
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FG_TEST_SUITE_LOGGING_HXX
|
||||
#define _FG_TEST_SUITE_LOGGING_HXX
|
||||
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <simgear/debug/LogCallback.hxx>
|
||||
|
||||
|
||||
// A logstream callback based on the simgear FileLogCallback class.
|
||||
class StreamLogCallback : public simgear::LogCallback
|
||||
{
|
||||
public:
|
||||
StreamLogCallback(std::ostringstream& stream, sgDebugClass c, sgDebugPriority p, bool priorityMatch):
|
||||
simgear::LogCallback(c, p),
|
||||
m_priority(p),
|
||||
m_stream(stream),
|
||||
m_priorityMatch(priorityMatch)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void operator()(sgDebugClass c, sgDebugPriority p, const char* file, int line, const std::string& message)
|
||||
{
|
||||
if (m_priorityMatch && p != m_priority) return;
|
||||
if (!shouldLog(c, p)) return;
|
||||
if (m_priorityMatch)
|
||||
m_stream << simgear::LogCallback::debugClassToString(c) << ":" << file << ":" << line << ": " << message << std::endl;
|
||||
else
|
||||
m_stream << simgear::LogCallback::debugClassToString(c) << ":" << (int) p << ":" << file << ":" << line << ": " << message << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
sgDebugPriority m_priority;
|
||||
std::ostringstream &m_stream;
|
||||
bool m_priorityMatch;
|
||||
};
|
||||
|
||||
|
||||
// All of the captured IO streams.
|
||||
class capturedIO
|
||||
{
|
||||
public:
|
||||
// Constructor and destructor.
|
||||
capturedIO(sgDebugClass, sgDebugPriority);
|
||||
~capturedIO();
|
||||
|
||||
// The IO streams.
|
||||
std::ostringstream sg_interleaved;
|
||||
std::ostringstream sg_bulk_only;
|
||||
std::ostringstream sg_debug_only;
|
||||
std::ostringstream sg_info_only;
|
||||
std::ostringstream sg_warn_only;
|
||||
std::ostringstream sg_alert_only;
|
||||
|
||||
// The callback objects.
|
||||
StreamLogCallback *callback_interleaved;
|
||||
StreamLogCallback *callback_bulk_only;
|
||||
StreamLogCallback *callback_debug_only;
|
||||
StreamLogCallback *callback_info_only;
|
||||
StreamLogCallback *callback_warn_only;
|
||||
StreamLogCallback *callback_alert_only;
|
||||
|
||||
// The logging class and priority text.
|
||||
std::string log_class;
|
||||
std::string log_priority;
|
||||
};
|
||||
|
||||
|
||||
// Return the global stream capture data structure, creating it if needed.
|
||||
capturedIO & getIOstreams(sgDebugClass c=SG_ALL, sgDebugPriority p=SG_BULK);
|
||||
|
||||
// Set up to capture all the simgear logging priorities as separate streams.
|
||||
void setupLogging(sgDebugClass, sgDebugPriority, bool);
|
||||
|
||||
// Deactivate all the simgear logging priority IO captures.
|
||||
void stopLogging();
|
||||
|
||||
|
||||
#endif // _FG_TEST_SUITE_LOGGING_HXX
|
||||
@@ -0,0 +1,23 @@
|
||||
# Add each simgear test category.
|
||||
foreach( simgear_test_category
|
||||
math
|
||||
props
|
||||
canvas
|
||||
structure
|
||||
)
|
||||
|
||||
add_subdirectory(${simgear_test_category})
|
||||
|
||||
endforeach( simgear_test_category )
|
||||
|
||||
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestSuite.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testCanvas.cxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testCanvas.hxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testCanvas.hxx"
|
||||
|
||||
|
||||
// Set up the tests.
|
||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CanvasTests, "Simgear unit tests");
|
||||
@@ -0,0 +1,123 @@
|
||||
#include "testCanvas.hxx"
|
||||
|
||||
#include <simgear/canvas/Canvas.hxx>
|
||||
#include <simgear/canvas/elements/CanvasImage.hxx>
|
||||
|
||||
#include "test_suite/FGTestApi/testGlobals.hxx"
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_commands.hxx>
|
||||
|
||||
#include <Canvas/canvas_mgr.hxx>
|
||||
#include <Canvas/FGCanvasSystemAdapter.hxx>
|
||||
extern bool global_nasalMinimalInit;
|
||||
|
||||
|
||||
void verifyPixel(osg::Image* img, int x, int y, const uint8_t* pixel)
|
||||
{
|
||||
auto rawPixel = img->data(x, y);
|
||||
CPPUNIT_ASSERT(memcmp(rawPixel, pixel, 4) == 0);
|
||||
}
|
||||
|
||||
void CanvasTests::setUp()
|
||||
{
|
||||
global_nasalMinimalInit = false;
|
||||
FGTestApi::setUp::initTestGlobals("canvas");
|
||||
|
||||
// Canvas needs loadxml command
|
||||
fgInitCommands();
|
||||
|
||||
simgear::canvas::Canvas::setSystemAdapter(
|
||||
simgear::canvas::SystemAdapterPtr(new canvas::FGCanvasSystemAdapter)
|
||||
);
|
||||
|
||||
globals->add_subsystem("Canvas", new CanvasMgr, SGSubsystemMgr::DISPLAY);
|
||||
|
||||
globals->get_subsystem_mgr()->bind();
|
||||
globals->get_subsystem_mgr()->init();
|
||||
|
||||
FGTestApi::setUp::initStandardNasal(true /* withCanvas */);
|
||||
globals->get_subsystem_mgr()->postinit();
|
||||
}
|
||||
|
||||
// Clean up after each test.
|
||||
void CanvasTests::tearDown()
|
||||
{
|
||||
FGTestApi::tearDown::shutdownTestGlobals();
|
||||
}
|
||||
|
||||
void CanvasTests::testCanvasBasic()
|
||||
{
|
||||
bool ok = FGTestApi::executeNasal(R"(
|
||||
var my_canvas = canvas.new({
|
||||
"name": "PFD-Test",
|
||||
"size": [512, 512],
|
||||
"view": [768, 1024],
|
||||
"mipmapping": 1
|
||||
});
|
||||
|
||||
globals.pfd = my_canvas;
|
||||
)");
|
||||
CPPUNIT_ASSERT(ok);
|
||||
|
||||
auto canvasPtr = globals->get_subsystem<CanvasMgr>()->getCanvas("PFD-Test");
|
||||
CPPUNIT_ASSERT(canvasPtr.valid());
|
||||
|
||||
ok = FGTestApi::executeNasal(R"(
|
||||
globals.pfd.createGroup("wibble");
|
||||
)");
|
||||
CPPUNIT_ASSERT(ok);
|
||||
|
||||
auto wibbleGroupPtr = canvasPtr->getGroup("wibble");
|
||||
CPPUNIT_ASSERT(wibbleGroupPtr.valid());
|
||||
}
|
||||
|
||||
void CanvasTests::testImagePixelOps()
|
||||
{
|
||||
bool ok = FGTestApi::executeNasal(R"(
|
||||
var my_canvas = canvas.new({
|
||||
"name": "ImagePixelOpsCanvas",
|
||||
"size": [512, 512],
|
||||
"view": [768, 1024],
|
||||
"mipmapping": 1
|
||||
});
|
||||
|
||||
var g = my_canvas.createGroup("root");
|
||||
var img = g.createChild('image', 'ops-image');
|
||||
|
||||
# deliberate non-power-of-two sizes here
|
||||
img.setSize(150, 170);
|
||||
|
||||
globals.pixelOps = my_canvas;
|
||||
)");
|
||||
CPPUNIT_ASSERT(ok);
|
||||
|
||||
auto canvasPtr = globals->get_subsystem<CanvasMgr>()->getCanvas("ImagePixelOpsCanvas");
|
||||
CPPUNIT_ASSERT(canvasPtr.valid());
|
||||
|
||||
auto imagePtr = canvasPtr->getRootGroup()->getElementById("ops-image");
|
||||
CPPUNIT_ASSERT(imagePtr.valid());
|
||||
|
||||
auto image = dynamic_cast<simgear::canvas::Image*>(imagePtr.get());
|
||||
image->setFill(osg::Vec4(1.0, 0.0, 0.5, 1.0));
|
||||
|
||||
image->fillRect(SGRecti(20, 40, 70, 55), "#7f3f1f");
|
||||
|
||||
ok = FGTestApi::executeNasal(R"(
|
||||
var canvas = globals.pixelOps;
|
||||
var img = canvas.getGroup('root').getElementById('ops-image');
|
||||
|
||||
print('Image is:', img);
|
||||
img.fillRect([5, 8, 180, 37], '#aabbcc');
|
||||
)");
|
||||
CPPUNIT_ASSERT(ok);
|
||||
|
||||
auto osgImage = image->getImage();
|
||||
const uint8_t testColor1[] = {0xff, 0xcc, 0xbb, 0xaa}; // little endian
|
||||
verifyPixel(osgImage.get(), 5, 8, testColor1);
|
||||
verifyPixel(osgImage.get(), 149, 44, testColor1);
|
||||
|
||||
// test pixles should not have been touched by the second fillRect
|
||||
const uint8_t testColor2[] = {0xff, 0x1f, 0x3f, 0x7f}; // little endian
|
||||
verifyPixel(osgImage.get(), 20, 45, testColor2);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <cppunit/TestFixture.h>
|
||||
|
||||
|
||||
// The unit tests.
|
||||
class CanvasTests : public CppUnit::TestFixture
|
||||
{
|
||||
// Set up the test suite.
|
||||
CPPUNIT_TEST_SUITE(CanvasTests);
|
||||
CPPUNIT_TEST(testCanvasBasic);
|
||||
CPPUNIT_TEST(testImagePixelOps);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
// Set up function for each test.
|
||||
void setUp();
|
||||
|
||||
// Clean up after each test.
|
||||
void tearDown();
|
||||
|
||||
// The tests.
|
||||
void testCanvasBasic();
|
||||
void testImagePixelOps();
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestSuite.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-up.cxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testSGGeodesy.hxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testSGGeodesy.hxx"
|
||||
|
||||
|
||||
// Set up the tests.
|
||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(MathGeodesyTests, "Simgear unit tests");
|
||||
@@ -0,0 +1,172 @@
|
||||
// do some test relating to the concept of "up"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
|
||||
#include "testSGGeodesy.hxx"
|
||||
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
|
||||
// The test-up unit test.
|
||||
void MathGeodesyTests::testUp()
|
||||
{
|
||||
// for each lat/lon given in goedetic coordinates, calculate
|
||||
// geocentric coordinates, cartesian coordinates, the local "up"
|
||||
// vector (based on original geodetic lat/lon), as well as the "Z"
|
||||
// intercept (for which 0 = center of earth)
|
||||
|
||||
|
||||
double lon = 0;
|
||||
double alt = 0;
|
||||
int i;
|
||||
const int n = 19;
|
||||
double lat[n] = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90};
|
||||
|
||||
// Hard coded expected results.
|
||||
double lat_geoc_expected[n] = {
|
||||
0,
|
||||
4.96669608700923,
|
||||
9.93439421027913,
|
||||
14.9040671396528,
|
||||
19.8766298623747,
|
||||
24.8529125604827,
|
||||
29.8336358098291,
|
||||
34.8193887023496,
|
||||
39.8106105519284,
|
||||
44.8075767840180,
|
||||
49.8103895262907,
|
||||
54.8189733092144,
|
||||
59.8330761504926,
|
||||
64.8522761370246,
|
||||
69.8759934364236,
|
||||
74.9035074740039,
|
||||
79.9339788099657,
|
||||
84.9664750566862,
|
||||
90
|
||||
};
|
||||
double cart_expected[n][3] = {
|
||||
{6378137, 0, 0},
|
||||
{6353866.26310279, 555891.26758132, 0},
|
||||
{6281238.76737403, 1107551.86696002, 0},
|
||||
{6160807.25190988, 1650783.32787306, 0},
|
||||
{5993488.27326157, 2181451.33089075, 0},
|
||||
{5780555.22988658, 2695517.17208404, 0},
|
||||
{5523628.67081747, 3189068.5, 0},
|
||||
{5224663.96230526, 3658349.09101875, 0},
|
||||
{4885936.40630155, 4099787.43648327, 0},
|
||||
{4510023.92403682, 4510023.92403682, 0},
|
||||
{4099787.43648328, 4885936.40630155, 0},
|
||||
{3658349.09101875, 5224663.96230526, 0},
|
||||
{3189068.5, 5523628.67081747, 0},
|
||||
{2695517.17208404, 5780555.22988658, 0},
|
||||
{2181451.33089075, 5993488.27326157, 0},
|
||||
{1650783.32787306, 6160807.25190988, 0},
|
||||
{1107551.86696002, 6281238.76737403, 0},
|
||||
{555891.26758132, 6353866.26310279, 0},
|
||||
{3.90548253078665e-10, 6378137, 0}
|
||||
};
|
||||
double up_expected[n][3] = {
|
||||
{6378137, 0, -0},
|
||||
{6354027.82056206, 0, -552183.96002777},
|
||||
{6281872.82960345, 0, -1100248.54773536},
|
||||
{6162189.08803834, 0, -1640100.14019589},
|
||||
{5995836.38389635, 0, -2167696.78782876},
|
||||
{5784014.11472572, 0, -2679074.46295779},
|
||||
{5528256.63929284, 0, -3170373.73538364},
|
||||
{5230426.84020036, 0, -3637866.9093781},
|
||||
{4892707.60007269, 0, -4077985.57220038},
|
||||
{4517590.87884893, 0, -4487348.40886592},
|
||||
{4107864.09120678, 0, -4862789.03770643},
|
||||
{3666593.52237417, 0, -5201383.52320227},
|
||||
{3197104.58692395, 0, -5500477.13393864},
|
||||
{2702958.82600294, 0, -5757709.84149597},
|
||||
{2187927.64927902, 0, -5971040.00711856},
|
||||
{1655962.9523645, 0, -6138765.68235824},
|
||||
{1111164.87081001, 0, -6259542.96102869},
|
||||
{557747.059253584, 0, -6332400.86398617},
|
||||
{3.91862092481447e-10, 0, -6356752.31424518}
|
||||
};
|
||||
double geod_intercept[n] = {
|
||||
0,
|
||||
552169.92020293,
|
||||
1100137.4939038,
|
||||
1639732.35699488,
|
||||
2166847.86675177,
|
||||
2677472.35586416,
|
||||
3167719.66364641,
|
||||
3633858.71206688,
|
||||
4072341.90150465,
|
||||
4479832.11012469,
|
||||
4853228.0913901,
|
||||
5189688.07642079,
|
||||
5486651.40157058,
|
||||
5741857.99662372,
|
||||
5953365.5852939,
|
||||
6119564.46711958,
|
||||
6239189.76825642,
|
||||
6311331.06793104,
|
||||
6335439.32729282
|
||||
};
|
||||
double geoc_intercept[n] = {
|
||||
0,
|
||||
552169.92020293,
|
||||
1100137.4939038,
|
||||
1639732.35699488,
|
||||
2166847.86675177,
|
||||
2677472.35586416,
|
||||
3167719.66364641,
|
||||
3633858.71206688,
|
||||
4072341.90150465,
|
||||
4479832.11012469,
|
||||
4853228.0913901,
|
||||
5189688.07642079,
|
||||
5486651.40157058,
|
||||
5741857.99662372,
|
||||
5953365.5852939,
|
||||
6119564.46711958,
|
||||
6239189.76825642,
|
||||
6311331.06793104,
|
||||
6378137 // Sole difference with geod, due to truncation artifacts.
|
||||
};
|
||||
|
||||
for (i=0; i < n; i++) {
|
||||
cout << "lon = " << lon << " geod lat = " << lat[i];
|
||||
|
||||
double sl_radius, lat_geoc;
|
||||
sgGeodToGeoc( lat[i] * SGD_DEGREES_TO_RADIANS, alt, &sl_radius, &lat_geoc );
|
||||
cout << " geoc lat = " << lat_geoc * SGD_RADIANS_TO_DEGREES << endl;
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(lat_geoc_expected[i], lat_geoc*SGD_RADIANS_TO_DEGREES, 1e-10);
|
||||
|
||||
double pc[3];
|
||||
sgGeodToCart( lon * SGD_DEGREES_TO_RADIANS, lat[i] * SGD_DEGREES_TO_RADIANS, 0.0, pc );
|
||||
cout << " cartesian = " << SGVec3d(pc[0], pc[1], pc[2]) << endl;
|
||||
for (int j=0; j < 3; j++)
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(cart_expected[i][j], pc[j], 1e-7);
|
||||
|
||||
SGGeod geod_up = SGGeod::fromDeg(lon, -lat[i]);
|
||||
SGVec3d geod_up_vect = SGVec3d::fromGeod(geod_up);
|
||||
cout << " geod up = " << geod_up_vect << endl;
|
||||
for (int j=0; j < 3; j++)
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(up_expected[i][j], geod_up_vect[j], 1e-7);
|
||||
|
||||
SGGeoc geoc_up = SGGeoc::fromGeod(geod_up);
|
||||
SGVec3d geoc_up_vect = SGVec3d::fromGeoc(geoc_up);
|
||||
cout << " geoc up = " << geoc_up_vect << endl;
|
||||
for (int j=0; j < 3; j++)
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(up_expected[i][j], geoc_up_vect[j], 1e-7);
|
||||
|
||||
double slope = geod_up_vect[2] / geod_up_vect[0];
|
||||
double intercept = pc[2] - slope * pc[0];
|
||||
cout << " Z intercept (based on geodetic up) = " << intercept << endl;
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(geod_intercept[i], intercept, 1e-7);
|
||||
|
||||
slope = geoc_up_vect[2] / geoc_up_vect[0];
|
||||
intercept = pc[2] - slope * pc[0];
|
||||
cout << " Z intercept (based on geocentric up) = " << intercept << endl;
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(geoc_intercept[i], intercept, 1e-7);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FG_MATH_GEODESY_SIMGEAR_UNIT_TESTS_HXX
|
||||
#define _FG_MATH_GEODESY_SIMGEAR_UNIT_TESTS_HXX
|
||||
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <cppunit/TestFixture.h>
|
||||
|
||||
|
||||
|
||||
// The unit tests.
|
||||
class MathGeodesyTests : public CppUnit::TestFixture
|
||||
{
|
||||
// Set up the test suite.
|
||||
CPPUNIT_TEST_SUITE(MathGeodesyTests);
|
||||
CPPUNIT_TEST(testUp);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
// Set up function for each test.
|
||||
void setUp() {}
|
||||
|
||||
// Clean up after each test.
|
||||
void tearDown() {}
|
||||
|
||||
// The tests.
|
||||
void testUp();
|
||||
};
|
||||
|
||||
|
||||
#endif // _FG_MATH_GEODESY_SIMGEAR_UNIT_TESTS_HXX
|
||||
@@ -0,0 +1,12 @@
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestSuite.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_props.cxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_props.hxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "test_props.hxx"
|
||||
|
||||
|
||||
// Set up the tests.
|
||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(SimgearPropsTests, "Simgear unit tests");
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "test_props.hxx"
|
||||
|
||||
#include <simgear/props/props_io.hxx>
|
||||
|
||||
// Set up function for each test.
|
||||
void SimgearPropsTests::setUp()
|
||||
{
|
||||
// Create a property tree.
|
||||
tree = new SGPropertyNode;
|
||||
}
|
||||
|
||||
|
||||
// Clean up after each test.
|
||||
void SimgearPropsTests::tearDown()
|
||||
{
|
||||
// Delete the tree (avoiding the memory leak).
|
||||
delete tree;
|
||||
}
|
||||
|
||||
|
||||
// Test property aliasing, to catch possible memory leaks.
|
||||
void SimgearPropsTests::testAliasLeak()
|
||||
{
|
||||
// Declarations.
|
||||
SGPropertyNode *alias;
|
||||
|
||||
// Create a new node.
|
||||
tree->getNode("test-node", true);
|
||||
|
||||
// Aliased node.
|
||||
alias = tree->getNode("test-alias", true);
|
||||
alias->alias("test-node");
|
||||
}
|
||||
|
||||
void SimgearPropsTests::testPropsCopyIf()
|
||||
{
|
||||
// dummy property tree structure
|
||||
tree->setIntValue("a/a/a", 42);
|
||||
tree->setStringValue("a/a/b", "foo");
|
||||
tree->setIntValue("a/a/c[2]", 99);
|
||||
tree->setIntValue("a/a/d", 1);
|
||||
tree->setIntValue("a/b/a[0]", 50);
|
||||
tree->setIntValue("a/b/a[1]", 100);
|
||||
tree->setStringValue("a/b/b", "foo");
|
||||
|
||||
SGPropertyNode_ptr destA(new SGPropertyNode);
|
||||
|
||||
copyPropertiesIf(tree, destA, [](const SGPropertyNode* src) {
|
||||
// always copy non-leaf nodes
|
||||
if (src->nChildren() > 0)
|
||||
return true;
|
||||
|
||||
return (src->getType() == simgear::props::INT) &&
|
||||
src->getIntValue() > 50;
|
||||
});
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1, destA->getNode("a/a")->nChildren()); // only 99
|
||||
CPPUNIT_ASSERT_EQUAL(99, destA->getIntValue("a/a/c[2]"));
|
||||
CPPUNIT_ASSERT_EQUAL(1, destA->getNode("a/b")->nChildren()); // only 100
|
||||
CPPUNIT_ASSERT_EQUAL(100, destA->getIntValue("a/b/a[1]"));
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FG_SIMGEAR_PROPS_SIMGEAR_UNIT_TESTS_HXX
|
||||
#define _FG_SIMGEAR_PROPS_SIMGEAR_UNIT_TESTS_HXX
|
||||
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <cppunit/TestFixture.h>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
|
||||
// The unit tests of the simgear property tree.
|
||||
class SimgearPropsTests : public CppUnit::TestFixture
|
||||
{
|
||||
// Set up the test suite.
|
||||
CPPUNIT_TEST_SUITE(SimgearPropsTests);
|
||||
CPPUNIT_TEST(testAliasLeak);
|
||||
CPPUNIT_TEST(testPropsCopyIf);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
// Set up function for each test.
|
||||
void setUp();
|
||||
|
||||
// Clean up after each test.
|
||||
void tearDown();
|
||||
|
||||
// The tests.
|
||||
void testAliasLeak();
|
||||
void testPropsCopyIf();
|
||||
private:
|
||||
// A property tree.
|
||||
SGPropertyNode *tree;
|
||||
};
|
||||
|
||||
#endif // _FG_SIMGEAR_PROPS_SIMGEAR_UNIT_TESTS_HXX
|
||||
@@ -0,0 +1,12 @@
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestSuite.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_event.cxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_event.hxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "test_event.hxx"
|
||||
|
||||
|
||||
// Set up the tests.
|
||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(SimgearEventTests, "Simgear unit tests");
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "test_event.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
SGEventMgr* global_eventManager = nullptr;
|
||||
double global_realTime = 0.0;
|
||||
|
||||
// class which behaves similarly to TimerObj in NasalSys
|
||||
class FakeNasalTimer
|
||||
{
|
||||
public:
|
||||
FakeNasalTimer(string n) : _name(n)
|
||||
{
|
||||
}
|
||||
|
||||
void invoke()
|
||||
{
|
||||
++_invokeCount;
|
||||
|
||||
if (_expectedTime > 0.0) {
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(_expectedTime, global_realTime, 0.1);
|
||||
}
|
||||
|
||||
// rescheudle base don the next time
|
||||
if (!_rescheduleTimes.empty()) {
|
||||
const auto t = _rescheduleTimes.front();
|
||||
_rescheduleTimes.pop_front();
|
||||
|
||||
// TimerObj does this, eugh
|
||||
if (global_eventManager) {
|
||||
global_eventManager->removeTask(_name);
|
||||
start(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void start(double interval)
|
||||
{
|
||||
if (!global_eventManager)
|
||||
return;
|
||||
|
||||
global_eventManager->addTask(_name, [this](){ this->invoke(); },
|
||||
interval, interval /* delay */, false);
|
||||
|
||||
_expectedTime = global_realTime + interval;
|
||||
}
|
||||
|
||||
string _name;
|
||||
deque<double> _rescheduleTimes;
|
||||
int _invokeCount = 0;
|
||||
double _expectedTime = 0.0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Set up function for each test.
|
||||
void SimgearEventTests::setUp()
|
||||
{
|
||||
_eventManager = new SGEventMgr;
|
||||
global_eventManager = _eventManager;
|
||||
_eventManager->init();
|
||||
|
||||
_realTimeProp = new SGPropertyNode{};
|
||||
_eventManager->setRealtimeProperty(_realTimeProp);
|
||||
}
|
||||
|
||||
// Clean up after each test.
|
||||
void SimgearEventTests::tearDown()
|
||||
{
|
||||
global_eventManager = nullptr;
|
||||
}
|
||||
|
||||
void SimgearEventTests::runForTestTime(double totalTime, double updateHz, double simTimeScaling)
|
||||
{
|
||||
const double dt = 1.0 / updateHz;
|
||||
const int updateCount = static_cast<int>(totalTime * updateHz);
|
||||
const double simDt = dt * simTimeScaling;
|
||||
_realTimeProp->setDoubleValue(dt);
|
||||
global_realTime = 0.0;
|
||||
|
||||
for (int c = 0; c < updateCount; ++c) {
|
||||
const double newRealTime = global_realTime + dt;
|
||||
global_realTime = newRealTime;
|
||||
_eventManager->update(simDt);
|
||||
}
|
||||
}
|
||||
|
||||
void SimgearEventTests::testTaskRescheduleDuringRun()
|
||||
{
|
||||
auto t1 = std::make_unique<FakeNasalTimer>("timer_aaa");
|
||||
t1->_rescheduleTimes.resize(10);
|
||||
fill(t1->_rescheduleTimes.begin(), t1->_rescheduleTimes.end(), 0.5);
|
||||
t1->_rescheduleTimes.push_back(30.0); // large final value
|
||||
|
||||
global_realTime = 0.0;
|
||||
t1->start(1.0);
|
||||
runForTestTime(8.0, 20);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(11, t1->_invokeCount);
|
||||
}
|
||||
|
||||
void SimgearEventTests::testTaskRescheduleDuringRun2()
|
||||
{
|
||||
auto t1 = std::make_unique<FakeNasalTimer>("timer_bbb");
|
||||
const std::initializer_list<double> times = {
|
||||
0.02, 0.05, 0.02, 0.1, 0.02, 0.125, 0.05, 0.02};
|
||||
t1->_rescheduleTimes = times;
|
||||
t1->_rescheduleTimes.push_back(30.0); // large final value
|
||||
|
||||
global_realTime = 0.0;
|
||||
t1->start(1.0);
|
||||
|
||||
// running at 60Hz, check we don't miss any
|
||||
runForTestTime(8.0, 60);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(9, t1->_invokeCount);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cppunit/TestFixture.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/structure/event_mgr.hxx>
|
||||
|
||||
// The unit tests of the simgear property tree.
|
||||
class SimgearEventTests : public CppUnit::TestFixture
|
||||
{
|
||||
// Set up the test suite.
|
||||
CPPUNIT_TEST_SUITE(SimgearEventTests);
|
||||
CPPUNIT_TEST(testTaskRescheduleDuringRun);
|
||||
CPPUNIT_TEST(testTaskRescheduleDuringRun2);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
// Set up function for each test.
|
||||
void setUp();
|
||||
|
||||
// Clean up after each test.
|
||||
void tearDown();
|
||||
|
||||
void runForTestTime(double totalTime, double updateHz, double simTimeScaling = 1.0);
|
||||
|
||||
// The tests.
|
||||
void testTaskRescheduleDuringRun();
|
||||
void testTaskRescheduleDuringRun2();
|
||||
|
||||
private:
|
||||
SGSharedPtr<SGEventMgr> _eventManager;
|
||||
SGPropertyNode_ptr _realTimeProp;
|
||||
SGPropertyNode_ptr _freezeProp;
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
# Add each system test category.
|
||||
foreach( system_test_category
|
||||
FDM
|
||||
Instrumentation
|
||||
Navaids
|
||||
Main
|
||||
)
|
||||
|
||||
add_subdirectory(${system_test_category})
|
||||
|
||||
endforeach( system_test_category )
|
||||
|
||||
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestSuite.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testAeroMesh.cxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testAeroMesh.hxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testAeroMesh.hxx"
|
||||
|
||||
|
||||
// Set up the unit tests.
|
||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(AeroMeshTests, "System tests");
|
||||
@@ -0,0 +1,222 @@
|
||||
#include "testAeroMesh.hxx"
|
||||
|
||||
#include "test_suite/FGTestApi/testGlobals.hxx"
|
||||
#include "test_suite/FGTestApi/PrivateAccessorFDM.hxx"
|
||||
#include "test_suite/FGTestApi/scene_graph.hxx"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/misc/test_macros.hxx>
|
||||
#include <simgear/math/SGVec3.hxx>
|
||||
#include <simgear/math/SGGeod.hxx>
|
||||
#include <simgear/math/SGQuat.hxx>
|
||||
#include <simgear/math/SGGeoc.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include <AIModel/AIAircraft.hxx>
|
||||
#include <AIModel/AIManager.hxx>
|
||||
#include <AIModel/performancedata.hxx>
|
||||
#include <AIModel/performancedb.hxx>
|
||||
#include "FDM/AIWake/AircraftMesh.hxx"
|
||||
#include "FDM/AIWake/AIWakeGroup.hxx"
|
||||
extern "C" {
|
||||
#include "src/FDM/LaRCsim/ls_matrix.h"
|
||||
}
|
||||
|
||||
#include "FDM/JSBSim/math/FGLocation.h"
|
||||
#include "FDM/JSBSim/math/FGQuaternion.h"
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace JSBSim;
|
||||
|
||||
double rho = 2.0E-3;
|
||||
|
||||
|
||||
// Set up function for each test.
|
||||
void AeroMeshTests::setUp()
|
||||
{
|
||||
FGTestApi::setUp::initTestGlobals("aeromesh");
|
||||
FGTestApi::setUp::initScenery();
|
||||
globals->get_props()->getNode("environment/density-slugft3", true)
|
||||
->setDoubleValue(rho);
|
||||
}
|
||||
|
||||
|
||||
// Clean up after each test.
|
||||
void AeroMeshTests::tearDown()
|
||||
{
|
||||
FGTestApi::tearDown::shutdownTestGlobals();
|
||||
}
|
||||
|
||||
|
||||
void AeroMeshTests::testLiftComputation()
|
||||
{
|
||||
double b = 10.0;
|
||||
double c = 2.0;
|
||||
AircraftMesh_ptr mesh = new AircraftMesh(b, c, "test");
|
||||
SGGeod geodPos = SGGeod::fromDeg(0.0, 0.0);
|
||||
SGVec3d pos;
|
||||
double vel = 100.;
|
||||
double weight = 50.;
|
||||
|
||||
SGGeodesy::SGGeodToCart(geodPos, pos);
|
||||
mesh->setPosition(pos, SGQuatd::unit());
|
||||
|
||||
SGPropertyNode* props = globals->get_props()->getNode("ai/models", true);
|
||||
props->setDoubleValue("acceleration-kts-hour", 0.0);
|
||||
props->setDoubleValue("deceleration-kts-hour", 0.0);
|
||||
props->setDoubleValue("climbrate-fpm", 0.0);
|
||||
props->setDoubleValue("decentrate-fpm", 0.0);
|
||||
props->setDoubleValue("rotate-speed-kts", 0.0);
|
||||
props->setDoubleValue("takeoff-speed-kts", 0.0);
|
||||
props->setDoubleValue("climb-speed-kts", 0.0);
|
||||
props->setDoubleValue("cruise-speed-kts", 0.0);
|
||||
props->setDoubleValue("decent-speed-kts", 0.0);
|
||||
props->setDoubleValue("approach-speed-kts", 0.0);
|
||||
props->setDoubleValue("touchdown-speed-kts", 0.0);
|
||||
props->setDoubleValue("taxi-speed-kts", 0.0);
|
||||
props->setDoubleValue("geometry/wing/span-ft", b);
|
||||
props->setDoubleValue("geometry/wing/chord-ft", c);
|
||||
props->setDoubleValue("geometry/weight-lbs", weight);
|
||||
|
||||
globals->add_new_subsystem<PerformanceDB>(SGSubsystemMgr::POST_FDM);
|
||||
globals->get_subsystem<PerformanceDB>()->bind();
|
||||
globals->get_subsystem<PerformanceDB>()->init();
|
||||
|
||||
FGAIManager *aiManager = new FGAIManager;
|
||||
FGAIAircraft *ai = new FGAIAircraft;
|
||||
ai->setGeodPos(geodPos);
|
||||
ai->setSpeed(vel * SG_FPS_TO_KT);
|
||||
ai->setPerformance("", "jet_transport");
|
||||
ai->getPerformance()->initFromProps(props);
|
||||
aiManager->attach(ai);
|
||||
|
||||
AIWakeGroup wg;
|
||||
wg.AddAI(ai);
|
||||
|
||||
SGVec3d force = mesh->GetForce(wg, SGVec3d(vel, 0., 0.), rho);
|
||||
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(force[1], 0.0, 1e-9);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(force[2], -weight, 1e-9);
|
||||
|
||||
SGVec3d moment = mesh->GetMoment();
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(moment[0], 0.0, 1e-9);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(moment[1], -0.5*weight, 1e-9);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(moment[2], 0.0, 1e-9);
|
||||
|
||||
auto accessor = FGTestApi::PrivateAccessor::FDM::Accessor();
|
||||
|
||||
for (int i=1; i<= accessor.read_FDM_AIWake_WakeMesh_nelm(mesh); ++i)
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(accessor.read_FDM_AIWake_WakeMesh_Gamma(accessor.read_FDM_AIWake_AIWakeGroup_aiWakeData(&wg, 1))[i][1],
|
||||
accessor.read_FDM_AIWake_WakeMesh_Gamma(mesh)[i][1], 1e-9);
|
||||
}
|
||||
|
||||
|
||||
void AeroMeshTests::testFourierLiftingLine()
|
||||
{
|
||||
double b = 10.0;
|
||||
double c = 2.0;
|
||||
double vel = 100.;
|
||||
double weight = 50.;
|
||||
|
||||
auto accessor = FGTestApi::PrivateAccessor::FDM::Accessor();
|
||||
|
||||
WakeMesh_ptr mesh = new WakeMesh(b, c, "testMesh");
|
||||
int N = accessor.read_FDM_AIWake_WakeMesh_nelm(mesh);
|
||||
double **mtx = nr_matrix(1, N, 1, N);
|
||||
double **coef = nr_matrix(1, N, 1, 1);
|
||||
|
||||
mesh->computeAoA(vel, rho, weight);
|
||||
|
||||
for (int m=1; m<=N; ++m) {
|
||||
double vm = M_PI*m/(N+1);
|
||||
double sm = sin(vm);
|
||||
coef[m][1] = c*M_PI/(2*b);
|
||||
for (int n=1; n<=N; ++n)
|
||||
mtx[m][n] = sin(n*vm)*(1.0+coef[m][1]*n/sm);
|
||||
}
|
||||
|
||||
nr_gaussj(mtx, N, coef, 1);
|
||||
|
||||
double S = b*c;
|
||||
double AR = b*b/S;
|
||||
double lift = 0.5*rho*S*vel*vel*coef[1][1]*M_PI*AR;
|
||||
double sinAlpha = weight / lift;
|
||||
lift *= sinAlpha;
|
||||
|
||||
cout << "y, Lift (Fourier), Lift (VLM), Corrected lift (VLM)" << endl;
|
||||
|
||||
for (int i=1; i<=N; ++i) {
|
||||
double y = accessor.read_FDM_AIWake_WakeMesh_elements(mesh)[i-1]->getBoundVortexMidPoint()[1];
|
||||
double theta = acos(2.0*y/b);
|
||||
double gamma = 0.0;
|
||||
for (int n=1; n<=N; ++n)
|
||||
gamma += coef[n][1]*sin(n*theta);
|
||||
|
||||
gamma *= 2.0*b*vel*sinAlpha;
|
||||
|
||||
cout << y << ", " << gamma << ", " << accessor.read_FDM_AIWake_WakeMesh_Gamma(mesh)[i][1] << ", "
|
||||
<< accessor.read_FDM_AIWake_WakeMesh_Gamma(mesh)[i][1] / gamma - 1.0 << endl;
|
||||
}
|
||||
|
||||
nr_free_matrix(mtx, 1, N, 1, N);
|
||||
nr_free_matrix(coef, 1, N, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
void AeroMeshTests::testFrameTransformations()
|
||||
{
|
||||
double b = 10.0;
|
||||
double c = 2.0;
|
||||
double yaw = 80. * SGD_DEGREES_TO_RADIANS;
|
||||
double pitch = 5. * SGD_DEGREES_TO_RADIANS;
|
||||
double roll = -10. * SGD_DEGREES_TO_RADIANS;
|
||||
SGQuatd orient = SGQuatd::fromYawPitchRoll(yaw, pitch, roll);
|
||||
SGGeod geodPos = SGGeod::fromDeg(45.0, 10.0);
|
||||
SGVec3d pos;
|
||||
|
||||
SGGeodesy::SGGeodToCart(geodPos, pos);
|
||||
SGGeoc geoc = SGGeoc::fromCart(pos);
|
||||
|
||||
FGLocation loc(geoc.getLongitudeRad(),
|
||||
geoc.getLatitudeRad(),
|
||||
geoc.getRadiusFt());
|
||||
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(pos[0] * SG_METER_TO_FEET, loc(1), 1e-7);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(pos[1] * SG_METER_TO_FEET, loc(2), 1e-7);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(pos[2] * SG_METER_TO_FEET, loc(3), 1e-7);
|
||||
|
||||
AircraftMesh_ptr mesh = new AircraftMesh(b, c, "test");
|
||||
mesh->setPosition(pos, orient);
|
||||
|
||||
FGQuaternion qJ(roll, pitch, yaw);
|
||||
FGMatrix33 Tb2l = qJ.GetTInv();
|
||||
FGColumnVector3 refPos = loc.GetTec2l() * loc;
|
||||
|
||||
for (int i=0; i < 4; ++i)
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(orient(i), qJ((i+1) % 4 + 1), 1e-9);
|
||||
|
||||
auto accessor = FGTestApi::PrivateAccessor::FDM::Accessor();
|
||||
|
||||
for (int i=0; i < accessor.read_FDM_AIWake_WakeMesh_nelm(mesh); ++i) {
|
||||
SGVec3d pt = accessor.read_FDM_AIWake_WakeMesh_elements(mesh)[i]->getBoundVortexMidPoint();
|
||||
FGColumnVector3 ptJ(pt[0], pt[1], pt[2]);
|
||||
FGColumnVector3 p = loc.GetTl2ec() * (refPos + Tb2l * ptJ);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(accessor.read_FDM_AIWake_AircraftMesh_midPt(mesh)[i][0], p(1), 1e-7);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(accessor.read_FDM_AIWake_AircraftMesh_midPt(mesh)[i][1], p(2), 1e-7);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(accessor.read_FDM_AIWake_AircraftMesh_midPt(mesh)[i][2], p(3), 1e-7);
|
||||
|
||||
pt = accessor.read_FDM_AIWake_WakeMesh_elements(mesh)[i]->getCollocationPoint();
|
||||
ptJ.InitMatrix(pt[0], pt[1], pt[2]);
|
||||
p = loc.GetTl2ec() * (refPos + Tb2l * ptJ);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(accessor.read_FDM_AIWake_AircraftMesh_collPt(mesh)[i][0], p(1), 1e-7);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(accessor.read_FDM_AIWake_AircraftMesh_collPt(mesh)[i][1], p(2), 1e-7);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(accessor.read_FDM_AIWake_AircraftMesh_collPt(mesh)[i][2], p(3), 1e-7);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FG_AERO_MESH_SYSTEM_TESTS_HXX
|
||||
#define _FG_AERO_MESH_SYSTEM_TESTS_HXX
|
||||
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <cppunit/TestFixture.h>
|
||||
|
||||
|
||||
// The system tests.
|
||||
class AeroMeshTests : public CppUnit::TestFixture
|
||||
{
|
||||
// Set up the test suite.
|
||||
CPPUNIT_TEST_SUITE(AeroMeshTests);
|
||||
CPPUNIT_TEST(testFourierLiftingLine);
|
||||
CPPUNIT_TEST(testFrameTransformations);
|
||||
CPPUNIT_TEST(testLiftComputation);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
// Set up function for each test.
|
||||
void setUp();
|
||||
|
||||
// Clean up after each test.
|
||||
void tearDown();
|
||||
|
||||
// The tests.
|
||||
void testFourierLiftingLine();
|
||||
void testFrameTransformations();
|
||||
void testLiftComputation();
|
||||
};
|
||||
|
||||
#endif // _FG_AERO_MESH_SYSTEM_TESTS_HXX
|
||||
@@ -0,0 +1,12 @@
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestSuite.cxx
|
||||
#${CMAKE_CURRENT_SOURCE_DIR}/testgps.cxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
#${CMAKE_CURRENT_SOURCE_DIR}/testgps.hxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testgps.hxx"
|
||||
|
||||
|
||||
// Set up the unit tests.
|
||||
//CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(GPSTests, "System tests");
|
||||
@@ -0,0 +1,351 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/io/iostreams/sgstream.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
#include <Main/fg_init.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include <Instrumentation/gps.hxx>
|
||||
#include <Autopilot/route_mgr.hxx>
|
||||
#include <Environment/environment_mgr.hxx>
|
||||
#include <Navaids/airways.hxx>
|
||||
#include <Navaids/waypoint.hxx>
|
||||
#include <Navaids/procedure.hxx>
|
||||
|
||||
#include "test_suite/helpers/globals.hxx"
|
||||
#include "test_suite/helpers/NavDataCache.hxx"
|
||||
|
||||
#include "testgps.hxx"
|
||||
|
||||
|
||||
using std::string;
|
||||
using namespace flightgear;
|
||||
|
||||
char *homedir = ::getenv( "HOME" );
|
||||
char *hostname = ::getenv( "HOSTNAME" );
|
||||
bool free_hostname = false;
|
||||
|
||||
void testSetPosition(const SGGeod& aPos)
|
||||
{
|
||||
fgSetDouble("/position/longitude-deg", aPos.getLongitudeDeg());
|
||||
fgSetDouble("/position/latitude-deg", aPos.getLatitudeDeg());
|
||||
fgSetDouble("/position/altitude-ft", aPos.getElevationFt());
|
||||
}
|
||||
|
||||
void printScratch(SGPropertyNode* scratch)
|
||||
{
|
||||
if (!scratch->getBoolValue("valid", false)) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Scratch is invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Scratch:" <<
|
||||
scratch->getStringValue("ident") << "/" << scratch->getStringValue("name"));
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "\t" << scratch->getDoubleValue("longitude-deg")
|
||||
<< " " << scratch->getDoubleValue("latitude-deg") << " @ " << scratch->getDoubleValue("altitude-ft"));
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "\t" << scratch->getDoubleValue("true-bearing-deg") <<
|
||||
" (" << scratch->getDoubleValue("mag-bearing-deg") << " magnetic) " << scratch->getDoubleValue("distance-nm"));
|
||||
|
||||
if (scratch->hasChild("result-index")) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "\tresult-index:" << scratch->getIntValue("result-index"));
|
||||
}
|
||||
|
||||
if (scratch->hasChild("route-index")) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "\troute-index:" << scratch->getIntValue("route-index"));
|
||||
}
|
||||
}
|
||||
|
||||
void printRoute(const WayptVec& aRoute)
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "route size=" << aRoute.size());
|
||||
for (unsigned int r=0; r<aRoute.size();++r) {
|
||||
Waypt* w = aRoute[r];
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "\t" << r << ": " << w->ident() << " "
|
||||
<< w->owner()->ident());
|
||||
}
|
||||
}
|
||||
|
||||
void createDummyRoute(FGRouteMgr* rm)
|
||||
{
|
||||
SGPropertyNode* rmInput = fgGetNode("/autopilot/route-manager/input", true);
|
||||
rmInput->setStringValue("UW");
|
||||
rmInput->setStringValue("TLA/347/13");
|
||||
rmInput->setStringValue("TLA");
|
||||
rmInput->setStringValue("HAVEN");
|
||||
rmInput->setStringValue("NEW/305/29");
|
||||
rmInput->setStringValue("NEW");
|
||||
rmInput->setStringValue("OTR");
|
||||
}
|
||||
|
||||
|
||||
void GPSTests::setUp()
|
||||
{
|
||||
fgtest::initTestGlobals("GPS");
|
||||
fgtest::initNavDataCache();
|
||||
}
|
||||
|
||||
|
||||
void GPSTests::tearDown()
|
||||
{
|
||||
fgtest::shutdownTestGlobals();
|
||||
}
|
||||
|
||||
|
||||
void GPSTests::testGPS()
|
||||
{
|
||||
fgSetDouble("/environment/magnetic-variation-deg", 0.0);
|
||||
|
||||
Airway::load();
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "hello world!");
|
||||
|
||||
const FGAirport* egph = fgFindAirportID("EGPH");
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "egph: cart location:" << egph->cart());
|
||||
|
||||
FGAirport::AirportFilter af;
|
||||
FGPositionedList l = FGPositioned::findClosestN(egph->geod(), 20, 2000.0, &af);
|
||||
for (unsigned int i=0; i<l.size(); ++i) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "\t" << l[i]->ident() << "/" << l[i]->name());
|
||||
}
|
||||
|
||||
//l = FGPositioned::findWithinRange(egph->geod(), 500.0, &af);
|
||||
//for (unsigned int i=0; i<l.size(); ++i) {
|
||||
// SG_LOG(SG_GENERAL, SG_ALERT, "\t" << l[i]->ident() << "/" << l[i]->name());
|
||||
//}
|
||||
|
||||
|
||||
FGRouteMgr* rm = new FGRouteMgr;
|
||||
globals->add_subsystem( "route-manager", rm );
|
||||
|
||||
// FGEnvironmentMgr* envMgr = new FGEnvironmentMgr;
|
||||
// globals->add_subsystem("environment", envMgr);
|
||||
// envMgr->init();
|
||||
|
||||
fgSetBool("/sim/realism/simple-gps", true);
|
||||
|
||||
// _realismSimpleGps
|
||||
|
||||
SGPropertyNode* nd = fgGetNode("/instrumentation/gps", true);
|
||||
GPS* gps = new GPS(nd);
|
||||
globals->add_subsystem("gps", gps);
|
||||
|
||||
const FGAirport* egph = fgFindAirportID("EGPH");
|
||||
testSetPosition(egph->geod());
|
||||
|
||||
// startup the route manager
|
||||
rm->init();
|
||||
|
||||
nd->setBoolValue("serviceable", true);
|
||||
fgSetBool("/systems/electrical/outputs/gps", true);
|
||||
|
||||
gps->init();
|
||||
SGPropertyNode* scratch = nd->getChild("scratch", 0, true);
|
||||
SGPropertyNode* wp = nd->getChild("wp", 0, true);
|
||||
SGPropertyNode* wp1 = wp->getChild("wp", 1, true);
|
||||
|
||||
// update a few times
|
||||
gps->update(0.05);
|
||||
gps->update(0.05);
|
||||
gps->update(0.05);
|
||||
|
||||
scratch->setStringValue("query", "TL");
|
||||
scratch->setStringValue("type", "Vor");
|
||||
scratch->setBoolValue("exact", false);
|
||||
nd->setStringValue("command", "search");
|
||||
printScratch(scratch);
|
||||
|
||||
nd->setStringValue("command", "next");
|
||||
printScratch(scratch);
|
||||
|
||||
nd->setStringValue("command", "next");
|
||||
printScratch(scratch);
|
||||
|
||||
// alphanumeric sort, partial matching
|
||||
nd->setDoubleValue("config/min-runway-length-ft", 5000.0);
|
||||
scratch->setBoolValue("exact", false);
|
||||
scratch->setBoolValue("order-by-distance", false);
|
||||
scratch->setStringValue("query", "KS");
|
||||
scratch->setStringValue("type", "apt");
|
||||
|
||||
nd->setStringValue("command", "search");
|
||||
printScratch(scratch);
|
||||
|
||||
nd->setStringValue("command", "next");
|
||||
printScratch(scratch);
|
||||
|
||||
nd->setStringValue("command", "next");
|
||||
printScratch(scratch);
|
||||
|
||||
// alphanumeric sort, explicit matching
|
||||
scratch->setBoolValue("exact", true);
|
||||
scratch->setBoolValue("order-by-distance", true);
|
||||
scratch->setStringValue("type", "vor");
|
||||
scratch->setStringValue("query", "DCS");
|
||||
|
||||
nd->setStringValue("command", "search");
|
||||
printScratch(scratch);
|
||||
|
||||
nd->setStringValue("command", "next");
|
||||
printScratch(scratch);
|
||||
|
||||
// search on totally missing
|
||||
scratch->setBoolValue("exact", true);
|
||||
scratch->setBoolValue("order-by-distance", true);
|
||||
scratch->setStringValue("query", "FOFOFOFOF");
|
||||
nd->setStringValue("command", "search");
|
||||
printScratch(scratch);
|
||||
|
||||
// nearest
|
||||
scratch->setStringValue("type", "apt");
|
||||
scratch->setIntValue("max-results", 10);
|
||||
nd->setStringValue("command", "nearest");
|
||||
printScratch(scratch);
|
||||
|
||||
nd->setStringValue("command", "next");
|
||||
printScratch(scratch);
|
||||
|
||||
nd->setStringValue("command", "next");
|
||||
printScratch(scratch);
|
||||
|
||||
// direct to
|
||||
nd->setStringValue("command", "direct");
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "mode:" << nd->getStringValue("mode") << "\n\t"
|
||||
<< wp1->getStringValue("ID") << " " << wp1->getDoubleValue("longitude-deg")
|
||||
<< " " << wp1->getDoubleValue("latitude-deg"));
|
||||
|
||||
// OBS mode
|
||||
scratch->setStringValue("query", "UW");
|
||||
scratch->setBoolValue("order-by-distance", true);
|
||||
nd->setStringValue("command", "search");
|
||||
printScratch(scratch);
|
||||
|
||||
nd->setStringValue("command", "obs");
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "mode:" << nd->getStringValue("mode") << "\n\t"
|
||||
<< wp1->getStringValue("ID") << " " << wp1->getDoubleValue("longitude-deg")
|
||||
<< " " << wp1->getDoubleValue("latitude-deg"));
|
||||
|
||||
// load route waypoints
|
||||
createDummyRoute(rm);
|
||||
|
||||
scratch->setIntValue("route-index", 5);
|
||||
nd->setStringValue("command", "load-route-wpt");
|
||||
printScratch(scratch);
|
||||
|
||||
nd->setStringValue("command", "next");
|
||||
printScratch(scratch);
|
||||
|
||||
nd->setStringValue("command", "next");
|
||||
printScratch(scratch);
|
||||
|
||||
scratch->setIntValue("route-index", 2);
|
||||
nd->setStringValue("command", "load-route-wpt");
|
||||
nd->setStringValue("command", "direct");
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "mode:" << nd->getStringValue("mode") << "\n\t"
|
||||
<< wp1->getStringValue("ID") << " " << wp1->getDoubleValue("longitude-deg")
|
||||
<< " " << wp1->getDoubleValue("latitude-deg"));
|
||||
|
||||
// route editing
|
||||
SGGeod pos = egph->geod();
|
||||
scratch->setStringValue("ident", "FOOBAR");
|
||||
scratch->setDoubleValue("longitude-deg", pos.getLongitudeDeg());
|
||||
scratch->setDoubleValue("latitude-deg", pos.getLatitudeDeg());
|
||||
nd->setStringValue("command", "define-user-wpt");
|
||||
printScratch(scratch);
|
||||
|
||||
// airways
|
||||
FGPositioned::TypeFilter vorFilt(FGPositioned::VOR);
|
||||
FGPositionedRef tla = FGPositioned::findClosestWithIdent("TLA", pos, &vorFilt);
|
||||
FGPositionedRef big = FGPositioned::findClosestWithIdent("BIG", pos, &vorFilt);
|
||||
FGPositionedRef pol = FGPositioned::findClosestWithIdent("POL", pos, &vorFilt);
|
||||
|
||||
const FGAirport* eddm = fgFindAirportID("EDDM");
|
||||
FGPositionedRef mun = FGPositioned::findClosestWithIdent("MUN",
|
||||
eddm->geod(), &vorFilt);
|
||||
|
||||
const FGAirport* ksfo = fgFindAirportID("KSFO");
|
||||
FGPositionedRef sfo = FGPositioned::findClosestWithIdent("SFO",
|
||||
ksfo->geod(), &vorFilt);
|
||||
|
||||
|
||||
WayptRef awy1 = new NavaidWaypoint(tla, NULL);
|
||||
WayptRef awy2 = new NavaidWaypoint(big, NULL);
|
||||
WayptRef awy3 = new NavaidWaypoint(pol, NULL);
|
||||
WayptRef awy4 = new NavaidWaypoint(mun, NULL);
|
||||
WayptRef awy5 = new NavaidWaypoint(sfo, NULL);
|
||||
|
||||
WayptRef awy6 = new NavaidWaypoint(
|
||||
(FGPositioned*) fgFindAirportID("KJFK"), NULL);
|
||||
|
||||
SGPath p("/Users/jmt/Desktop/airways.kml");
|
||||
sg_ofstream f;
|
||||
f.open(p, fstream::out | fstream::trunc);
|
||||
|
||||
// pre-amble
|
||||
f << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
|
||||
"<Document>\n";
|
||||
|
||||
WayptVec route;
|
||||
Airway::highLevel()->route(awy1, awy3, route);
|
||||
Route::dumpRouteToLineString("egph-egcc", route, f);
|
||||
|
||||
Airway::lowLevel()->route(awy1, awy2, route);
|
||||
Route::dumpRouteToLineString("egph-big", route, f);
|
||||
|
||||
Airway::lowLevel()->route(awy2, awy4, route);
|
||||
Route::dumpRouteToLineString("big-mun", route, f);
|
||||
|
||||
Airway::highLevel()->route(awy4, awy5, route);
|
||||
Route::dumpRouteToLineString("mun-sfo", route, f);
|
||||
|
||||
Airway::lowLevel()->route(awy5, awy6, route);
|
||||
Route::dumpRouteToLineString("sfo-jfk", route, f);
|
||||
|
||||
// post-amble
|
||||
f << "</Document>\n"
|
||||
"</kml>" << endl;
|
||||
f.close();
|
||||
|
||||
// procedures
|
||||
SGPath op("/Users/jmt/Desktop/procedures.kml");
|
||||
f.open(op, fstream::out | fstream::trunc);
|
||||
|
||||
FGAirport* eham = (FGAirport*) fgFindAirportID("EHAM");
|
||||
FGPositioned::TypeFilter fixFilt(FGPositioned::FIX);
|
||||
|
||||
WayptVec approach;
|
||||
FGPositionedRef redfa = FGPositioned::findClosestWithIdent("REDFA",
|
||||
eham->geod(), &fixFilt);
|
||||
bool ok = eham->buildApproach(new NavaidWaypoint(redfa, NULL),
|
||||
eham->getRunwayByIdent("18R"), approach);
|
||||
if (!ok ) {
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "failed to build approach");
|
||||
}
|
||||
|
||||
|
||||
FGAirport* egll = (FGAirport*) fgFindAirportID("EGLL");
|
||||
WayptVec approach2;
|
||||
ok = egll->buildApproach(new NavaidWaypoint(big, NULL),
|
||||
egll->getRunwayByIdent("27R"), approach2);
|
||||
if (!ok ) {
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "failed to build approach");
|
||||
}
|
||||
|
||||
// pre-amble
|
||||
f << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n"
|
||||
"<Document>\n";
|
||||
|
||||
Route::dumpRouteToLineString("REDFA 18R", approach, f);
|
||||
Route::dumpRouteToLineString("EGLL 27R", approach2, f);
|
||||
|
||||
// post-amble
|
||||
f << "</Document>\n"
|
||||
"</kml>" << endl;
|
||||
f.close();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FG_GPS_SYSTEM_TESTS_HXX
|
||||
#define _FG_GPS_SYSTEM_TESTS_HXX
|
||||
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <cppunit/TestFixture.h>
|
||||
|
||||
|
||||
// The system tests.
|
||||
class GPSTests : public CppUnit::TestFixture
|
||||
{
|
||||
// Set up the test suite.
|
||||
CPPUNIT_TEST_SUITE(GPSTests);
|
||||
CPPUNIT_TEST(testGPS);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
// Set up function for each test.
|
||||
void setUp();
|
||||
|
||||
// Clean up after each test.
|
||||
void tearDown();
|
||||
|
||||
// The tests.
|
||||
void testGPS();
|
||||
};
|
||||
|
||||
#endif // _FG_GPS_SYSTEM_TESTS_HXX
|
||||
@@ -0,0 +1,12 @@
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestSuite.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testOptions.cxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testOptions.hxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testOptions.hxx"
|
||||
|
||||
|
||||
// Set up the unit tests.
|
||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(OptionsTests, "System tests");
|
||||
@@ -0,0 +1,171 @@
|
||||
// Written by James Turner, started 2017.
|
||||
//
|
||||
// Copyright (C) 2017 James Turner
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include "testOptions.hxx"
|
||||
#include "config.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "test_suite/FGTestApi/NavDataCache.hxx"
|
||||
#include "test_suite/FGTestApi/scene_graph.hxx"
|
||||
#include "test_suite/FGTestApi/testGlobals.hxx"
|
||||
|
||||
#include <simgear/package/Root.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
|
||||
#include "Main/fg_props.hxx"
|
||||
#include "Main/globals.hxx"
|
||||
#include "Main/options.hxx"
|
||||
#include <Main/fg_init.hxx>
|
||||
|
||||
using namespace std::string_literals;
|
||||
using namespace flightgear;
|
||||
using namespace simgear::pkg;
|
||||
|
||||
void OptionsTests::setUp()
|
||||
{
|
||||
FGTestApi::setUp::initTestGlobals("options");
|
||||
FGTestApi::setUp::initNavDataCache();
|
||||
Options::reset();
|
||||
fgLoadProps("defaults.xml", globals->get_props());
|
||||
}
|
||||
|
||||
|
||||
void OptionsTests::tearDown()
|
||||
{
|
||||
FGTestApi::tearDown::shutdownTestGlobals();
|
||||
}
|
||||
|
||||
void OptionsTests::testLoadDefaultAircraft()
|
||||
{
|
||||
const auto customFGAircraftPath = SGPath::fromUtf8(FG_TEST_SUITE_DATA) / "customAircraftDir";
|
||||
|
||||
{
|
||||
Options* opts = Options::sharedInstance();
|
||||
opts->setShouldLoadDefaultConfig(false);
|
||||
|
||||
const string fgAircraftArg = "--fg-aircraft=" + customFGAircraftPath.utf8Str();
|
||||
const char* args[] = {"dummypath", fgAircraftArg.c_str()};
|
||||
opts->init(2, (char**)args, SGPath());
|
||||
opts->processOptions();
|
||||
}
|
||||
|
||||
fgInitAircraftPaths(false);
|
||||
fgInitAircraft(false, false);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL("c172p"s, string{fgGetString("/sim/aircraft")});
|
||||
CPPUNIT_ASSERT_EQUAL("c172p"s, string{fgGetString("/sim/aircraft-id")});
|
||||
//CPPUNIT_ASSERT_EQUAL(adPath.utf8Str(), string{fgGetString("/sim/aircraft-dir")});
|
||||
}
|
||||
|
||||
void OptionsTests::testOptionAircraftWithAircraftDir()
|
||||
{
|
||||
const auto adPath = SGPath::fromUtf8(FG_TEST_SUITE_DATA) / "customAircraftDir" / "overrideUfo";
|
||||
|
||||
{
|
||||
Options* opts = Options::sharedInstance();
|
||||
opts->setShouldLoadDefaultConfig(false);
|
||||
|
||||
const string aircraftDirArg = "--aircraft-dir=" + adPath.utf8Str();
|
||||
const char* args[] = {"dummypath", "--aircraft=ufo", aircraftDirArg.c_str()};
|
||||
opts->init(3, (char**)args, SGPath());
|
||||
opts->processOptions();
|
||||
}
|
||||
|
||||
fgInitAircraftPaths(false);
|
||||
fgInitAircraft(false, false);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL("ufo"s, string{fgGetString("/sim/aircraft")});
|
||||
CPPUNIT_ASSERT_EQUAL("ufo"s, string{fgGetString("/sim/aircraft-id")});
|
||||
CPPUNIT_ASSERT_EQUAL(adPath.utf8Str(), string{fgGetString("/sim/aircraft-dir")});
|
||||
}
|
||||
|
||||
void OptionsTests::testOptionAircraftWithFGAircraft()
|
||||
{
|
||||
const auto customFGAircraftPath = SGPath::fromUtf8(FG_TEST_SUITE_DATA) / "customAircraftDir";
|
||||
|
||||
{
|
||||
Options* opts = Options::sharedInstance();
|
||||
opts->setShouldLoadDefaultConfig(false);
|
||||
|
||||
const string fgAircraftArg = "--fg-aircraft=" + customFGAircraftPath.utf8Str();
|
||||
const char* args[] = {"dummypath", "--aircraft=ufo", fgAircraftArg.c_str()};
|
||||
opts->init(3, (char**)args, SGPath());
|
||||
opts->processOptions();
|
||||
}
|
||||
|
||||
fgInitAircraftPaths(false);
|
||||
fgInitAircraft(false, false);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL("ufo"s, string{fgGetString("/sim/aircraft")});
|
||||
CPPUNIT_ASSERT_EQUAL("ufo"s, string{fgGetString("/sim/aircraft-id")});
|
||||
|
||||
const auto correctDir = (customFGAircraftPath / "overrideUfo").utf8Str();
|
||||
CPPUNIT_ASSERT_EQUAL(correctDir, string{fgGetString("/sim/aircraft-dir")});
|
||||
}
|
||||
|
||||
void OptionsTests::testOptionAircraftUnqualified()
|
||||
{
|
||||
const auto packageAircraftDir = SGPath::fromUtf8(FG_TEST_SUITE_DATA) / "dummy_package_root";
|
||||
SGSharedPtr<Root> pkgRoot(new Root(packageAircraftDir, FLIGHTGEAR_VERSION));
|
||||
globals->setPackageRoot(pkgRoot);
|
||||
|
||||
{
|
||||
Options* opts = Options::sharedInstance();
|
||||
opts->setShouldLoadDefaultConfig(false);
|
||||
|
||||
const char* args[] = {"dummypath", "--aircraft=bob"};
|
||||
opts->init(2, (char**)args, SGPath());
|
||||
opts->processOptions();
|
||||
}
|
||||
|
||||
fgInitAircraftPaths(false);
|
||||
fgInitAircraft(false, false);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL("bob"s, string{fgGetString("/sim/aircraft")});
|
||||
CPPUNIT_ASSERT_EQUAL("org.fg.test.catalog1.bob"s, string{fgGetString("/sim/aircraft-id")});
|
||||
|
||||
const auto correctDir = (packageAircraftDir / "org.fg.test.catalog1" / "Aircraft" / "bobCraft").utf8Str();
|
||||
CPPUNIT_ASSERT_EQUAL(correctDir, string{fgGetString("/sim/aircraft-dir")});
|
||||
}
|
||||
|
||||
void OptionsTests::testOptionAircraftFullyQualified()
|
||||
{
|
||||
const auto packageAircraftDir = SGPath::fromUtf8(FG_TEST_SUITE_DATA) / "dummy_package_root";
|
||||
SGSharedPtr<Root> pkgRoot(new Root(packageAircraftDir, FLIGHTGEAR_VERSION));
|
||||
globals->setPackageRoot(pkgRoot);
|
||||
|
||||
{
|
||||
Options* opts = Options::sharedInstance();
|
||||
opts->setShouldLoadDefaultConfig(false);
|
||||
|
||||
const char* args[] = {"dummypath", "--aircraft=org.fg.test.catalog1.bob"};
|
||||
opts->init(2, (char**)args, SGPath());
|
||||
opts->processOptions();
|
||||
}
|
||||
|
||||
fgInitAircraftPaths(false);
|
||||
fgInitAircraft(false, false);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL("bob"s, string{fgGetString("/sim/aircraft")});
|
||||
CPPUNIT_ASSERT_EQUAL("org.fg.test.catalog1.bob"s, string{fgGetString("/sim/aircraft-id")});
|
||||
|
||||
const auto correctDir = (packageAircraftDir / "org.fg.test.catalog1" / "Aircraft" / "bobCraft").utf8Str();
|
||||
CPPUNIT_ASSERT_EQUAL(correctDir, string{fgGetString("/sim/aircraft-dir")});
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cppunit/TestFixture.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
|
||||
// The system tests.
|
||||
class OptionsTests : public CppUnit::TestFixture
|
||||
{
|
||||
// Set up the test suite.
|
||||
CPPUNIT_TEST_SUITE(OptionsTests);
|
||||
CPPUNIT_TEST(testLoadDefaultAircraft);
|
||||
CPPUNIT_TEST(testOptionAircraftWithAircraftDir);
|
||||
CPPUNIT_TEST(testOptionAircraftUnqualified);
|
||||
CPPUNIT_TEST(testOptionAircraftFullyQualified);
|
||||
CPPUNIT_TEST(testOptionAircraftWithFGAircraft);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
// Set up function for each test.
|
||||
void setUp();
|
||||
|
||||
// Clean up after each test.
|
||||
void tearDown();
|
||||
|
||||
// The tests.
|
||||
void testOptionAircraftWithAircraftDir();
|
||||
void testOptionAircraftUnqualified();
|
||||
void testOptionAircraftFullyQualified();
|
||||
void testOptionAircraftWithFGAircraft();
|
||||
void testLoadDefaultAircraft();
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestSuite.cxx
|
||||
#${CMAKE_CURRENT_SOURCE_DIR}/testnavs.cxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
#${CMAKE_CURRENT_SOURCE_DIR}/testnavs.hxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testnavs.hxx"
|
||||
|
||||
|
||||
// Set up the unit tests.
|
||||
//CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(NavaidsTests, "System tests");
|
||||
@@ -0,0 +1,107 @@
|
||||
// Written by James Turner, started 2009.
|
||||
//
|
||||
// Copyright (C) 2009 Curtis L. Olson
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include <Navaids/fixlist.hxx>
|
||||
//#include "ilslist.hxx"
|
||||
#include <Navaids/navlist.hxx>
|
||||
//#include "mkrbeacons.hxx"
|
||||
|
||||
#include "test_suite/dataStore.hxx"
|
||||
|
||||
#include "testnavs.hxx"
|
||||
|
||||
|
||||
void NavaidsTests::testNavs()
|
||||
{
|
||||
double heading, dist;
|
||||
|
||||
DataStore &data = DataStore::get();
|
||||
|
||||
FGNavList *current_navlist = new FGNavList;
|
||||
SGPath p_nav = data.getFGRoot() / "/Navaids/default.nav";
|
||||
|
||||
current_navlist->init( p_nav );
|
||||
|
||||
FGNavRecord *n;
|
||||
if ( (n = current_navlist->findByFreq( -93.2 * SG_DEGREES_TO_RADIANS,
|
||||
45.14 * SG_DEGREES_TO_RADIANS,
|
||||
3000, 117.30)) != NULL )
|
||||
{
|
||||
std::cout << "Found a vor station in range" << std::endl;
|
||||
std::cout << " id = " << n->get_ident() << std::endl;
|
||||
} else {
|
||||
std::cout << "not picking up vor. :-(" << std::endl;
|
||||
}
|
||||
|
||||
FGNavRecord *dcs;
|
||||
if ( (dcs = current_navlist->findByIdent( "DCS",
|
||||
-3.3 * SG_DEGREES_TO_RADIANS,
|
||||
55.9 * SG_DEGREES_TO_RADIANS))
|
||||
!= NULL ) {
|
||||
|
||||
std::cout << "Found DCS by ident" << std::endl;
|
||||
if (dcs->get_freq() != 11520)
|
||||
std::cout << "Frequency for DCS VOR is wrong (should be 115.20), it's "
|
||||
<< dcs->get_freq() << std::endl;
|
||||
} else {
|
||||
std::cout << "couldn't locate DCS (Dean-Cross) VOR" << std::endl;
|
||||
}
|
||||
|
||||
// we have to init the marker beacon storage before we parse the ILS file
|
||||
FGMarkerBeacons *current_beacons = new FGMarkerBeacons;
|
||||
current_beacons->init();
|
||||
|
||||
FGILSList *current_ilslist = new FGILSList;
|
||||
SGPath p_ils = data.getFGRoot() / "/Navaids/default.ils";
|
||||
current_ilslist->init( p_ils );
|
||||
FGILS *i = current_ilslist->findByFreq( -93.1 * SG_DEGREES_TO_RADIANS,
|
||||
45.24 * SG_DEGREES_TO_RADIANS,
|
||||
3000, 110.30);
|
||||
if ( i != NULL ) {
|
||||
std::cout << "Found an ils station in range" << std::endl;
|
||||
std::cout << " apt = " << i->get_aptcode() << std::endl;
|
||||
std::cout << " rwy = " << i->get_rwyno() << std::endl;
|
||||
} else {
|
||||
std::cout << "not picking up ils. :-(" << std::endl;
|
||||
}
|
||||
|
||||
FGFixList *current_fixlist = new FGFixList;
|
||||
SGPath p_fix = data.getFGRoot() / "/Navaids/default.fix";
|
||||
current_fixlist->init( p_fix );
|
||||
FGFix fix;
|
||||
|
||||
// attempting to get the position relative to the OTR VOR; heading
|
||||
// should be 108 degrees, distance 74nm (according to my SimCharts
|
||||
// v1.5)
|
||||
if ( current_fixlist->query_and_offset( "DOGGA",
|
||||
-0.103 * SG_DEGREES_TO_RADIANS,
|
||||
53.698 * SG_DEGREES_TO_RADIANS,
|
||||
3000, &fix, &heading, &dist) )
|
||||
{
|
||||
std::cout << "Found a matching fix" << std::endl;
|
||||
std::cout << " id = " << fix.get_ident() << std::endl;
|
||||
std::cout << " heading = " << heading << " dist = " << dist * SG_METER_TO_NM
|
||||
<< std::endl;
|
||||
} else {
|
||||
CPPUNIT_FAIL("did not find fix. :-(");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FG_NAVAIDS_SYSTEM_TESTS_HXX
|
||||
#define _FG_NAVAIDS_SYSTEM_TESTS_HXX
|
||||
|
||||
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <cppunit/TestFixture.h>
|
||||
|
||||
|
||||
// The system tests.
|
||||
class NavaidsTests : public CppUnit::TestFixture
|
||||
{
|
||||
// Set up the test suite.
|
||||
CPPUNIT_TEST_SUITE(NavaidsTests);
|
||||
CPPUNIT_TEST(testNavs);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
// Set up function for each test.
|
||||
void setUp() {}
|
||||
|
||||
// Clean up after each test.
|
||||
void tearDown() {}
|
||||
|
||||
// The tests.
|
||||
void testNavs();
|
||||
};
|
||||
|
||||
#endif // _FG_NAVAIDS_SYSTEM_TESTS_HXX
|
||||
@@ -0,0 +1,457 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Edward d'Auvergne
|
||||
*
|
||||
* This file is part of the program FlightGear.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "dataStore.hxx"
|
||||
#include "fgTestRunner.hxx"
|
||||
#include "formatting.hxx"
|
||||
#include "logging.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
// The help message.
|
||||
void helpPrintout(std::ostream &stream) {
|
||||
stream << "Usage: run_test_suite [options]" << std::endl << std::endl;
|
||||
stream << "Options:" << std::endl;
|
||||
stream << " -h, --help show this help message and exit." << std::endl;
|
||||
stream << std::endl;
|
||||
stream << " Test selection options:" << std::endl;
|
||||
stream << " -s, --system-tests execute the system/functional tests." << std::endl;
|
||||
stream << " -u, --unit-tests execute the unit tests." << std::endl;
|
||||
stream << " -g, --gui-tests execute the GUI tests." << std::endl;
|
||||
stream << " -m, --simgear-tests execute the simgear tests." << std::endl;
|
||||
stream << " -f, --fgdata-tests execute the FGData tests." << std::endl;
|
||||
stream << std::endl;
|
||||
stream << " The -s, -u, -g, and -m options accept an optional argument to perform a" << std::endl;
|
||||
stream << " subset of all tests. This argument should either be the name of a test" << std::endl;
|
||||
stream << " suite, the full name of an individual test, or a comma separated list." << std::endl;
|
||||
stream << " E.g. -u DigitalFilterTests\n";
|
||||
stream << std::endl;
|
||||
stream << " Full test names consist of the test suite name, the separator '::' and then" << std::endl;
|
||||
stream << " the individual test name. The test names can revealed with the verbose" << std::endl;
|
||||
stream << " option." << std::endl;
|
||||
stream << std::endl;
|
||||
stream << " Logging options:" << std::endl;
|
||||
stream << " --log-level={bulk,debug,info,warn,alert,popup,dev_warn,dev_alert}" << std::endl;
|
||||
stream << " specify the minimum logging level to output" << std::endl;
|
||||
stream << " --log-class=[none, terrain, astro, flight, input, gl, view, cockpit," << std::endl;
|
||||
stream << " general, math, event, aircraft, autopilot, io, clipper," << std::endl;
|
||||
stream << " network, atc, nasal, instrumentation, systems, ai, environment," << std::endl;
|
||||
stream << " sound, navaid, gui, terrasync, particles, headless, osg," << std::endl;
|
||||
stream << " undefined, all]" << std::endl;
|
||||
stream << " select the logging class(es) to output." << std::endl;
|
||||
stream << " --log-split output the different non-interleaved log streams" << std::endl;
|
||||
stream << " sequentially." << std::endl;
|
||||
stream << std::endl;
|
||||
stream << " Verbosity options:" << std::endl;
|
||||
stream << " -t, --timings verbose output including names and timings for all" << std::endl;
|
||||
stream << " tests." << std::endl;
|
||||
stream << " -c, --ctest simplified output suitable for running via CTest." << std::endl;
|
||||
stream << " -d, --debug disable IO capture for debugging (super verbose output)." << std::endl;
|
||||
stream << " --no-summary disable the final summary printout." << std::endl;
|
||||
stream << std::endl;
|
||||
stream << " FG options:" << std::endl;
|
||||
stream << " --fg-root the path to FGData." << std::endl;
|
||||
stream << std::endl;
|
||||
stream << "Environmental variables:" << std::endl;
|
||||
stream << " FG_TEST_LOG_LEVEL equivalent to the --log-level option." << std::endl;
|
||||
stream << " FG_TEST_LOG_CLASS equivalent to the --log-class option." << std::endl;
|
||||
stream << " FG_TEST_LOG_SPLIT equivalent to the --log-split option." << std::endl;
|
||||
stream << " FG_TEST_TIMINGS equivalent to the -t or --timings option." << std::endl;
|
||||
stream << " FG_TEST_DEBUG equivalent to the -d or --debug option." << std::endl;
|
||||
stream << " FG_ROOT the path to FGData. The order of precedence is" << std::endl;
|
||||
stream << " --fg-root, the FG_DATA_DIR CMake option, FG_ROOT," << std::endl;
|
||||
stream << " '../fgdata/', and '../data/'." << std::endl;
|
||||
stream.flush();
|
||||
}
|
||||
|
||||
|
||||
// Convert the log class comma separated string list into a simgear debug class value.
|
||||
sgDebugClass processLogClass(std::string classList, bool &failure) {
|
||||
// Declarations.
|
||||
std::string logClassItem, val;
|
||||
unsigned int logClass=0;
|
||||
|
||||
// Convert the command line value into a string array.
|
||||
std::replace(classList.begin(), classList.end(), ',', ' ');
|
||||
std::vector<std::string> logClasses;
|
||||
stringstream temp(classList);
|
||||
while (temp >> val)
|
||||
logClasses.push_back(val);
|
||||
|
||||
// Build up the value.
|
||||
for (auto const& logClassItem: logClasses)
|
||||
if (logClassItem == "none")
|
||||
logClass |= SG_NONE;
|
||||
else if (logClassItem == "terrain")
|
||||
logClass |= SG_TERRAIN;
|
||||
else if (logClassItem == "astro")
|
||||
logClass |= SG_ASTRO;
|
||||
else if (logClassItem == "flight")
|
||||
logClass |= SG_FLIGHT;
|
||||
else if (logClassItem == "input")
|
||||
logClass |= SG_INPUT;
|
||||
else if (logClassItem == "gl")
|
||||
logClass |= SG_GL;
|
||||
else if (logClassItem == "view")
|
||||
logClass |= SG_VIEW;
|
||||
else if (logClassItem == "cockpit")
|
||||
logClass |= SG_COCKPIT;
|
||||
else if (logClassItem == "general")
|
||||
logClass |= SG_GENERAL;
|
||||
else if (logClassItem == "math")
|
||||
logClass |= SG_MATH;
|
||||
else if (logClassItem == "event")
|
||||
logClass |= SG_EVENT;
|
||||
else if (logClassItem == "aircraft")
|
||||
logClass |= SG_AIRCRAFT;
|
||||
else if (logClassItem == "autopilot")
|
||||
logClass |= SG_AUTOPILOT;
|
||||
else if (logClassItem == "io")
|
||||
logClass |= SG_IO;
|
||||
else if (logClassItem == "clipper")
|
||||
logClass |= SG_CLIPPER;
|
||||
else if (logClassItem == "network")
|
||||
logClass |= SG_NETWORK;
|
||||
else if (logClassItem == "atc")
|
||||
logClass |= SG_ATC;
|
||||
else if (logClassItem == "nasal")
|
||||
logClass |= SG_NASAL;
|
||||
else if (logClassItem == "instrumentation")
|
||||
logClass |= SG_INSTR;
|
||||
else if (logClassItem == "systems")
|
||||
logClass |= SG_SYSTEMS;
|
||||
else if (logClassItem == "ai")
|
||||
logClass |= SG_AI;
|
||||
else if (logClassItem == "environment")
|
||||
logClass |= SG_ENVIRONMENT;
|
||||
else if (logClassItem == "sound")
|
||||
logClass |= SG_SOUND;
|
||||
else if (logClassItem == "navaid")
|
||||
logClass |= SG_NAVAID;
|
||||
else if (logClassItem == "gui")
|
||||
logClass |= SG_GUI;
|
||||
else if (logClassItem == "terrasync")
|
||||
logClass |= SG_TERRASYNC;
|
||||
else if (logClassItem == "particles")
|
||||
logClass |= SG_PARTICLES;
|
||||
else if (logClassItem == "headless")
|
||||
logClass |= SG_HEADLESS;
|
||||
else if (logClassItem == "osg")
|
||||
logClass |= SG_OSG;
|
||||
else if (logClassItem == "undefined")
|
||||
logClass |= SG_UNDEFD;
|
||||
else if (logClassItem == "all")
|
||||
logClass |= SG_ALL;
|
||||
else {
|
||||
std::cout << "The log class \"" << logClassItem << "\" must be one of:" << std::endl;
|
||||
std::cout << " {none, terrain, astro, flight, input, gl, view, cockpit, general, math," << std::endl;
|
||||
std::cout << " event, aircraft, autopilot, io, clipper, network, atc, nasal," << std::endl;
|
||||
std::cout << " instrumentation, systems, ai, environment, sound, navaid, gui, terrasync," << std::endl;
|
||||
std::cout << " particles, headless, osg, undefined, all}" << std::endl << std::endl;
|
||||
std::cout.flush();
|
||||
failure = true;
|
||||
}
|
||||
|
||||
// Return a simgear debug class.
|
||||
return sgDebugClass(logClass);
|
||||
}
|
||||
|
||||
|
||||
// Convert the log priority string into a simgear debug priority value.
|
||||
sgDebugPriority processLogPriority(std::string logLevel, bool &failure) {
|
||||
// Declarations.
|
||||
sgDebugPriority logPriority=SG_INFO;
|
||||
|
||||
// Conversion.
|
||||
if (logLevel == "bulk")
|
||||
logPriority = SG_BULK;
|
||||
else if (logLevel == "debug")
|
||||
logPriority = SG_DEBUG;
|
||||
else if (logLevel == "info")
|
||||
logPriority = SG_INFO;
|
||||
else if (logLevel == "warn")
|
||||
logPriority = SG_WARN;
|
||||
else if (logLevel == "alert")
|
||||
logPriority = SG_ALERT;
|
||||
else if (logLevel == "popup")
|
||||
logPriority = SG_POPUP;
|
||||
else if (logLevel == "dev_warn")
|
||||
logPriority = SG_DEV_WARN;
|
||||
else if (logLevel == "dev_alert")
|
||||
logPriority = SG_DEV_ALERT;
|
||||
else {
|
||||
std::cout << "The log level setting of \"" << logLevel << "\" must be one of {bulk,debug,info,warn,alert,popup,dev_warn,dev_alert}.\n\n";
|
||||
std::cout.flush();
|
||||
failure = true;
|
||||
}
|
||||
|
||||
// Return the simgear debug priority.
|
||||
return logPriority;
|
||||
}
|
||||
|
||||
|
||||
// Print out a summary of the relax test suite.
|
||||
void summary(CppUnit::OStream &stream, int system_result, int unit_result, int gui_result, int simgear_result, int fgdata_result)
|
||||
{
|
||||
int synopsis = 0;
|
||||
|
||||
// Title.
|
||||
string text = "Summary of the FlightGear test suite";
|
||||
printTitle(stream, text);
|
||||
|
||||
// Subtitle.
|
||||
text = "Synopsis";
|
||||
printSection(stream, text);
|
||||
|
||||
// System/functional test summary.
|
||||
if (system_result != -1) {
|
||||
text = "System/functional tests";
|
||||
printSummaryLine(stream, text, system_result);
|
||||
synopsis += system_result;
|
||||
}
|
||||
|
||||
// Unit test summary.
|
||||
if (unit_result != -1) {
|
||||
text = "Unit tests";
|
||||
printSummaryLine(stream, text, unit_result);
|
||||
synopsis += unit_result;
|
||||
}
|
||||
|
||||
// GUI test summary.
|
||||
if (gui_result != -1) {
|
||||
text = "GUI tests";
|
||||
printSummaryLine(stream, text, gui_result);
|
||||
synopsis += gui_result;
|
||||
}
|
||||
|
||||
// Simgear unit test summary.
|
||||
if (simgear_result != -1) {
|
||||
text = "Simgear unit tests";
|
||||
printSummaryLine(stream, text, simgear_result);
|
||||
synopsis += simgear_result;
|
||||
}
|
||||
|
||||
// FGData test summary.
|
||||
if (fgdata_result != -1) {
|
||||
text = "FGData tests";
|
||||
printSummaryLine(stream, text, fgdata_result);
|
||||
synopsis += fgdata_result;
|
||||
}
|
||||
|
||||
// Synopsis.
|
||||
text ="Synopsis";
|
||||
printSummaryLine(stream, text, synopsis);
|
||||
|
||||
// End.
|
||||
stream << endl << endl;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// Declarations.
|
||||
int status_gui=-1, status_simgear=-1, status_system=-1, status_unit=-1, status_fgdata=-1;
|
||||
bool run_system=false, run_unit=false, run_gui=false, run_simgear=false, run_fgdata=false;
|
||||
bool logSplit=false;
|
||||
bool timings=false, ctest_output=false, debug=false, printSummary=true, help=false;
|
||||
char *subset_system=NULL, *subset_unit=NULL, *subset_gui=NULL, *subset_simgear=NULL, *subset_fgdata=NULL;
|
||||
bool failure=false;
|
||||
char firstchar;
|
||||
std::string arg, delim, fgRoot, logClassVal, logLevel;
|
||||
size_t delimPos;
|
||||
|
||||
// The default logging class and priority to show.
|
||||
sgDebugClass logClass=SG_ALL;
|
||||
sgDebugPriority logPriority=SG_INFO;
|
||||
|
||||
// Process environmental variables before the command line options.
|
||||
if (getenv("FG_TEST_LOG_LEVEL"))
|
||||
logPriority = processLogPriority(getenv("FG_TEST_LOG_LEVEL"), failure);
|
||||
if (getenv("FG_TEST_LOG_CLASS"))
|
||||
logClass = processLogClass(getenv("FG_TEST_LOG_CLASS"), failure);
|
||||
if (getenv("FG_TEST_LOG_SPLIT"))
|
||||
logSplit = true;
|
||||
if (getenv("FG_TEST_TIMINGS"))
|
||||
timings = true;
|
||||
if (getenv("FG_TEST_DEBUG"))
|
||||
debug = true;
|
||||
if (failure)
|
||||
return 1;
|
||||
|
||||
// Argument parsing.
|
||||
for (int i = 1; i < argc; i++) {
|
||||
firstchar = '\0';
|
||||
arg = argv[i];
|
||||
|
||||
if (i < argc-1)
|
||||
firstchar = argv[i+1][0];
|
||||
|
||||
// System test.
|
||||
if (arg == "-s" || arg == "--system-tests") {
|
||||
run_system = true;
|
||||
if (firstchar != '-')
|
||||
subset_system = argv[i+1];
|
||||
|
||||
// Unit test.
|
||||
} else if (arg == "-u" || arg == "--unit-tests") {
|
||||
run_unit = true;
|
||||
if (firstchar != '-')
|
||||
subset_unit = argv[i+1];
|
||||
|
||||
// GUI test.
|
||||
} else if (arg == "-g" || arg == "--gui-tests") {
|
||||
run_gui = true;
|
||||
if (firstchar != '-')
|
||||
subset_gui = argv[i+1];
|
||||
|
||||
// Simgear test.
|
||||
} else if (arg == "-m" || arg == "--simgear-tests") {
|
||||
run_simgear = true;
|
||||
if (firstchar != '-')
|
||||
subset_simgear = argv[i+1];
|
||||
|
||||
// FGData test.
|
||||
} else if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--fgdata-tests") == 0) {
|
||||
run_fgdata = true;
|
||||
if (firstchar != '-')
|
||||
subset_fgdata = argv[i+1];
|
||||
|
||||
// Log class.
|
||||
} else if (arg.find( "--log-class" ) == 0) {
|
||||
// Process the command line.
|
||||
logClass = SG_NONE;
|
||||
delimPos = arg.find('=');
|
||||
logClassVal = arg.substr(delimPos + 1);
|
||||
logClass = processLogClass(logClassVal, failure);
|
||||
if (failure)
|
||||
return 1;
|
||||
|
||||
// Log level.
|
||||
} else if (arg.find( "--log-level" ) == 0) {
|
||||
// Process the command line level.
|
||||
delimPos = arg.find('=');
|
||||
logLevel = arg.substr(delimPos + 1);
|
||||
logPriority = processLogPriority(logLevel, failure);
|
||||
if (failure)
|
||||
return 1;
|
||||
|
||||
// Log splitting.
|
||||
} else if (arg == "--log-split") {
|
||||
logSplit = true;
|
||||
|
||||
// Timing output.
|
||||
} else if (arg == "-t" || arg == "--timings") {
|
||||
timings = true;
|
||||
|
||||
// CTest suitable output.
|
||||
} else if (arg == "-c" || arg == "--ctest") {
|
||||
ctest_output = true;
|
||||
|
||||
// Debug output.
|
||||
} else if (arg == "-d" || arg == "--debug") {
|
||||
debug = true;
|
||||
|
||||
// No summary output.
|
||||
} else if (arg == "--no-summary") {
|
||||
printSummary = false;
|
||||
|
||||
// Help.
|
||||
} else if (arg == "-h" || arg == "--help") {
|
||||
help = true;
|
||||
|
||||
// FGData path.
|
||||
} else if (arg == "--fg-root") {
|
||||
if (firstchar != '-')
|
||||
fgRoot = argv[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
// Help.
|
||||
if (help) {
|
||||
helpPrintout(std::cout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Turn on all tests if no subset was specified.
|
||||
if (!run_system && !run_unit && !run_gui && !run_simgear && !run_fgdata) {
|
||||
run_system = true;
|
||||
run_unit = true;
|
||||
run_gui = true;
|
||||
run_simgear = true;
|
||||
run_fgdata = true;
|
||||
}
|
||||
|
||||
// Set up the data store singleton and FGData path.
|
||||
DataStore& data = DataStore::get();
|
||||
if (data.findFGRoot(fgRoot, debug) != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (data.validateFGRoot() != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set up logging.
|
||||
sglog().setDeveloperMode(true);
|
||||
if (debug)
|
||||
sglog().setLogLevels(sgDebugClass(logClass), logPriority);
|
||||
else
|
||||
setupLogging(sgDebugClass(logClass), logPriority, logSplit);
|
||||
|
||||
// Execute each of the test suite categories.
|
||||
if (run_system)
|
||||
status_system = testRunner("System tests", "System / functional tests", subset_system, timings, ctest_output, debug);
|
||||
if (run_unit)
|
||||
status_unit = testRunner("Unit tests", "Unit tests", subset_unit, timings, ctest_output, debug);
|
||||
if (run_gui && 0) // Disabled as there are no GUI tests yet.
|
||||
status_gui = testRunner("GUI tests", "GUI tests", subset_gui, timings, ctest_output, debug);
|
||||
if (run_simgear)
|
||||
status_simgear = testRunner("Simgear unit tests", "Simgear unit tests", subset_simgear, timings, ctest_output, debug);
|
||||
if (run_fgdata)
|
||||
status_fgdata = testRunner("FGData tests", "FGData tests", subset_fgdata, timings, ctest_output, debug);
|
||||
|
||||
// Summary printout.
|
||||
if (printSummary && !ctest_output)
|
||||
summary(cerr, status_system, status_unit, status_gui, status_simgear, status_fgdata);
|
||||
|
||||
// Deactivate the logging.
|
||||
if (!debug)
|
||||
stopLogging();
|
||||
|
||||
// Failure.
|
||||
if (status_system > 0)
|
||||
return 1;
|
||||
if (status_unit > 0)
|
||||
return 1;
|
||||
if (status_gui > 0)
|
||||
return 1;
|
||||
if (status_simgear > 0)
|
||||
return 1;
|
||||
if (status_fgdata > 0)
|
||||
return 1;
|
||||
|
||||
// Success.
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<PropertyList include="BN-2-main.xml">
|
||||
<texture-path>Textures/Directflight</texture-path>
|
||||
</PropertyList>
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<PropertyList include="BN-2-main.xml">
|
||||
<texture-path>Textures/Hebridean</texture-path>
|
||||
</PropertyList>
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<PropertyList include="BN-2-main.xml">
|
||||
<texture-path>Textures/Loganair</texture-path>
|
||||
</PropertyList>
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0"?>
|
||||
<PropertyList>
|
||||
<description>Britten-Norman BN-2 Islander</description>
|
||||
<author>Paul RICHTER, Syd Adams, Keith Paterson</author>
|
||||
<path>Models/bn2.ac</path>
|
||||
<animation>
|
||||
<type>select</type>
|
||||
<object-name>prop-blur-left</object-name>
|
||||
<condition>
|
||||
<greater-than>
|
||||
<property>velocities/true-airspeed-kt</property>
|
||||
<value>10</value>
|
||||
</greater-than>
|
||||
</condition>
|
||||
</animation>
|
||||
|
||||
<animation>
|
||||
<type>select</type>
|
||||
<object-name>landinglight.L</object-name>
|
||||
<condition>
|
||||
<less-than>
|
||||
<property>velocities/true-airspeed-kt</property>
|
||||
<value>10</value>
|
||||
</less-than>
|
||||
</condition>
|
||||
</animation>
|
||||
<animation>
|
||||
<type>select</type>
|
||||
<object-name>landinglight.R</object-name>
|
||||
<condition>
|
||||
<less-than>
|
||||
<property>velocities/true-airspeed-kt</property>
|
||||
<value>10</value>
|
||||
</less-than>
|
||||
</condition>
|
||||
</animation>
|
||||
<animation>
|
||||
<type>select</type>
|
||||
<object-name>prop-left</object-name>
|
||||
<condition>
|
||||
<less-than>
|
||||
<property>velocities/true-airspeed-kt</property>
|
||||
<value>10</value>
|
||||
</less-than>
|
||||
</condition>
|
||||
</animation>
|
||||
<animation>
|
||||
<type>select</type>
|
||||
<object-name>prop-disc-left</object-name>
|
||||
<condition>
|
||||
<greater-than>
|
||||
<property>velocities/true-airspeed-kt</property>
|
||||
<value>20</value>
|
||||
</greater-than>
|
||||
</condition>
|
||||
</animation>
|
||||
<animation>
|
||||
<type>select</type>
|
||||
<object-name>prop-blur-right</object-name>
|
||||
<condition>
|
||||
<greater-than>
|
||||
<property>velocities/true-airspeed-kt</property>
|
||||
<value>10</value>
|
||||
</greater-than>
|
||||
</condition>
|
||||
</animation>
|
||||
<animation>
|
||||
<type>select</type>
|
||||
<object-name>prop-disc-right</object-name>
|
||||
<condition>
|
||||
<greater-than>
|
||||
<property>velocities/true-airspeed-kt</property>
|
||||
<value>20</value>
|
||||
</greater-than>
|
||||
</condition>
|
||||
</animation>
|
||||
<animation>
|
||||
<type>select</type>
|
||||
<object-name>prop-right</object-name>
|
||||
<condition>
|
||||
<less-than>
|
||||
<property>velocities/true-airspeed-kt</property>
|
||||
<value>10</value>
|
||||
</less-than>
|
||||
</condition>
|
||||
</animation>
|
||||
</PropertyList>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
[LocalizedFileNames]
|
||||
bn2.ac=@bn2.ac,0
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
+57
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<PropertyList>
|
||||
<flightplan>
|
||||
<wp>
|
||||
<name>on1</name>
|
||||
<lat>59.534235</lat>
|
||||
<lon>-1.629072</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on2</name>
|
||||
<lat>59.534315</lat>
|
||||
<lon>-1.629182</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on5</name>
|
||||
<lat>59.534364</lat>
|
||||
<lon>-1.629345</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on4</name>
|
||||
<lat>59.534372</lat>
|
||||
<lon>-1.629544</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on10</name>
|
||||
<lat>59.534363</lat>
|
||||
<lon>-1.629681</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on3</name>
|
||||
<lat>59.5343438</lat>
|
||||
<lon>-1.6298094</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on11</name>
|
||||
<lat>59.5341711</lat>
|
||||
<lon>-1.63037</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>END</name>
|
||||
</wp>
|
||||
</flightplan>
|
||||
</PropertyList>
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<PropertyList>
|
||||
<flightplan>
|
||||
<wp>
|
||||
<name>on1</name>
|
||||
<lat>59.534235</lat>
|
||||
<lon>-1.629072</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on2</name>
|
||||
<lat>59.534315</lat>
|
||||
<lon>-1.629182</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on6</name>
|
||||
<lat>59.5343928</lat>
|
||||
<lon>-1.6292113</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on7</name>
|
||||
<lat>59.5344594</lat>
|
||||
<lon>-1.6292113</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on8</name>
|
||||
<lat>59.5345519</lat>
|
||||
<lon>-1.6291362</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on9</name>
|
||||
<lat>59.5346335</lat>
|
||||
<lon>-1.6288868</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>on12</name>
|
||||
<lat>59.5347749</lat>
|
||||
<lon>-1.6284227</lon>
|
||||
<ktas>10</ktas>
|
||||
<on-ground>1</on-ground>
|
||||
</wp>
|
||||
<wp>
|
||||
<name>END</name>
|
||||
</wp>
|
||||
</flightplan>
|
||||
</PropertyList>
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Updated 29NOV20 to remove EGEL flights as no runway defined in FG -->
|
||||
<trafficlist>
|
||||
<aircraft>
|
||||
<model>Aircraft/BN-2/BN-2-Hebridean.xml</model>
|
||||
<livery>HBR</livery>
|
||||
<airline>HBR</airline>
|
||||
<home-port>EGEO</home-port>
|
||||
<required-aircraft>HBR_BN_2</required-aircraft>
|
||||
<actype>BN2</actype>
|
||||
<offset>0</offset>
|
||||
<radius>8</radius>
|
||||
<flighttype>gate</flighttype>
|
||||
<performance-class>turboprop_transport</performance-class>
|
||||
<registration>G-HEBO</registration>
|
||||
<heavy>false</heavy>
|
||||
</aircraft>
|
||||
<aircraft>
|
||||
<model>Aircraft/BN-2/BN-2-Hebridean.xml</model>
|
||||
<livery>HBR</livery>
|
||||
<airline>HBR</airline>
|
||||
<home-port>EGEO</home-port>
|
||||
<required-aircraft>HBR_BN_2</required-aircraft>
|
||||
<actype>BN2</actype>
|
||||
<offset>0</offset>
|
||||
<radius>8</radius>
|
||||
<flighttype>gate</flighttype>
|
||||
<performance-class>turboprop_transport</performance-class>
|
||||
<registration>G-HEBS</registration>
|
||||
<heavy>false</heavy>
|
||||
</aircraft>
|
||||
<flight>
|
||||
<callsign>Hebridean_1000</callsign>
|
||||
<required-aircraft>HBR_BN_2</required-aircraft>
|
||||
<fltrules>VFR</fltrules>
|
||||
<departure>
|
||||
<port>EGEO</port>
|
||||
<time>2/08:25:00</time>
|
||||
</departure>
|
||||
<cruise-alt>50</cruise-alt>
|
||||
<arrival>
|
||||
<port>EGEY</port>
|
||||
<time>2/08:50:00</time>
|
||||
</arrival>
|
||||
<repeat>WEEK</repeat>
|
||||
</flight>
|
||||
<flight>
|
||||
<callsign>Hebridean_1001</callsign>
|
||||
<required-aircraft>HBR_BN_2</required-aircraft>
|
||||
<fltrules>VFR</fltrules>
|
||||
<departure>
|
||||
<port>EGEO</port>
|
||||
<time>2/14:10:00</time>
|
||||
</departure>
|
||||
<cruise-alt>50</cruise-alt>
|
||||
<arrival>
|
||||
<port>EGEY</port>
|
||||
<time>2/15:20:00</time>
|
||||
</arrival>
|
||||
<repeat>WEEK</repeat>
|
||||
</flight>
|
||||
</trafficlist>
|
||||
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Updated 29NOV20 to remove EGEL flights as no runway defined in FG -->
|
||||
<trafficlist>
|
||||
<aircraft>
|
||||
<model>Aircraft/BN-2/BN-2-Hebridean.xml</model>
|
||||
<livery>TST</livery>
|
||||
<airline>TST</airline>
|
||||
<home-port>YSSY</home-port>
|
||||
<required-aircraft>TST_BN_1</required-aircraft>
|
||||
<actype>BN2</actype>
|
||||
<offset>0</offset>
|
||||
<radius>8</radius>
|
||||
<performance-class>turboprop_transport</performance-class>
|
||||
<registration>G-HEBO</registration>
|
||||
<heavy>false</heavy>
|
||||
</aircraft>
|
||||
<aircraft>
|
||||
<model>Aircraft/BN-2/BN-2-Hebridean.xml</model>
|
||||
<livery>TST</livery>
|
||||
<airline>TST</airline>
|
||||
<home-port>YBBN</home-port>
|
||||
<required-aircraft>TST_BN_2</required-aircraft>
|
||||
<actype>BN2</actype>
|
||||
<offset>0</offset>
|
||||
<radius>8</radius>
|
||||
<performance-class>turboprop_transport</performance-class>
|
||||
<registration>G-HEBY</registration>
|
||||
<heavy>false</heavy>
|
||||
</aircraft>
|
||||
<flight>
|
||||
<callsign>gaParkYSSY1</callsign>
|
||||
<required-aircraft>TST_BN_1</required-aircraft>
|
||||
<fltrules>VFR</fltrules>
|
||||
<departure>
|
||||
<port>YSSY</port>
|
||||
<time>00:40:00</time>
|
||||
</departure>
|
||||
<cruise-alt>50</cruise-alt>
|
||||
<arrival>
|
||||
<port>YBBN</port>
|
||||
<time>00:52:00</time>
|
||||
</arrival>
|
||||
<repeat>03Hr</repeat>
|
||||
</flight>
|
||||
<flight>
|
||||
<callsign>gaParkYSSY2</callsign>
|
||||
<required-aircraft>TST_BN_1</required-aircraft>
|
||||
<fltrules>VFR</fltrules>
|
||||
<departure>
|
||||
<port>YBBN</port>
|
||||
<time>01:20:00</time>
|
||||
</departure>
|
||||
<cruise-alt>50</cruise-alt>
|
||||
<arrival>
|
||||
<port>YSSY</port>
|
||||
<time>01:50:00</time>
|
||||
</arrival>
|
||||
<repeat>03Hr</repeat>
|
||||
</flight>
|
||||
<flight>
|
||||
<callsign>Test_YSSY_1002</callsign>
|
||||
<required-aircraft>TST_BN_2</required-aircraft>
|
||||
<fltrules>VFR</fltrules>
|
||||
<departure>
|
||||
<port>YSSY</port>
|
||||
<time>00:48:00</time>
|
||||
</departure>
|
||||
<cruise-alt>50</cruise-alt>
|
||||
<arrival>
|
||||
<port>YBBN</port>
|
||||
<time>00:49:00</time>
|
||||
</arrival>
|
||||
<repeat>03Hr</repeat>
|
||||
</flight>
|
||||
</trafficlist>
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<PropertyList>
|
||||
<submodel n="0">
|
||||
<name>testLoadXML</name>
|
||||
<model>Models/Geometry/null.ac</model>
|
||||
<trigger>ai/submodels/submodel[0]/trigger</trigger>
|
||||
<speed>100</speed>
|
||||
<speed-prop>ai/submodels/submodel[0]/speed</speed-prop>
|
||||
<count>42</count>
|
||||
<repeat>true</repeat>
|
||||
<delay>0.5</delay>
|
||||
<offsets>
|
||||
<x-m>2</x-m>
|
||||
<y-m>0</y-m>
|
||||
<z-m>0</z-m>
|
||||
<heading-deg>90</heading-deg>
|
||||
<pitch-deg>45</pitch-deg>
|
||||
</offsets>
|
||||
<life>1</life>
|
||||
<buoyancy>10</buoyancy>
|
||||
<wind>true</wind>
|
||||
<weight>3</weight>
|
||||
<contents>ai/submodels/submodel[0]/content</contents>
|
||||
<cd>0.2</cd>
|
||||
<eda>0.1</eda>
|
||||
<aero-stabilized>false</aero-stabilized>
|
||||
<external-force>true</external-force>
|
||||
<force-path>ai/submodels/submodel[0]/force</force-path>
|
||||
<force-stabilized>true</force-stabilized>
|
||||
<no-roll>true</no-roll>
|
||||
<random>true</random>
|
||||
<randomness>
|
||||
<azimuth>5</azimuth>
|
||||
<elevation>5</elevation>
|
||||
<cd>0.1</cd>
|
||||
<life>0.2</life>
|
||||
</randomness>
|
||||
<collision>true</collision>
|
||||
<fuze-range>1</fuze-range>
|
||||
<impact>true</impact>
|
||||
<expiry>true</expiry>
|
||||
<impact-reports>ai/submodels/submodel[0]/report</impact-reports>
|
||||
<slaved>true</slaved>
|
||||
</submodel>
|
||||
|
||||
<submodel n="1">
|
||||
<name>testRelease</name>
|
||||
<model>Models/Geometry/null.ac</model>
|
||||
<trigger>ai/submodels/submodel[1]/trigger</trigger>
|
||||
<count>-1</count>
|
||||
<repeat>false</repeat>
|
||||
<delay>1</delay>
|
||||
<life>10</life>
|
||||
</submodel>
|
||||
|
||||
<submodel n="2">
|
||||
<name>testInitialState</name>
|
||||
<model>Models/Geometry/null.ac</model>
|
||||
<trigger>ai/submodels/submodel[2]/trigger</trigger>
|
||||
<speed>100</speed>
|
||||
<repeat>false</repeat>
|
||||
<delay>-1</delay>
|
||||
<count>-1</count>
|
||||
<aero-stabilised>false</aero-stabilised>
|
||||
<wind>true</wind>
|
||||
<offsets>
|
||||
<x-m>10</x-m>
|
||||
<y-m>6</y-m>
|
||||
<z-m>1</z-m>
|
||||
<heading-deg>30</heading-deg>
|
||||
<pitch-deg>50</pitch-deg>
|
||||
</offsets>
|
||||
<life>10</life>
|
||||
</submodel>
|
||||
</PropertyList>
|
||||
@@ -0,0 +1,813 @@
|
||||
<?xml version="1.0"?>
|
||||
<groundnet>
|
||||
<version>1</version>
|
||||
<parkingList>
|
||||
<Parking index="0" type="gate" name="V109" lat="N50 2.999935" lon="E8 35.484849" heading="160.6" radius="44" pushBackRoute="92" airlineCodes="" />
|
||||
<Parking index="1" type="gate" name="V115" lat="N50 2.956904" lon="E8 35.314977" heading="160.6" radius="44" pushBackRoute="96" airlineCodes="" />
|
||||
<Parking index="2" type="gate" name="V118" lat="N50 2.888276" lon="E8 35.303240" heading="341.45" radius="44" pushBackRoute="95" airlineCodes="" />
|
||||
<Parking index="3" type="gate" name="V110" lat="N50 2.932207" lon="E8 35.467774" heading="341.45" radius="44" pushBackRoute="91" airlineCodes="" />
|
||||
<Parking index="4" type="gate" name="V100" lat="N50 2.934293" lon="E8 35.797018" heading="341.45" radius="44" pushBackRoute="167" airlineCodes="" />
|
||||
<Parking index="5" type="gate" name="V95" lat="N50 2.967058" lon="E8 35.940585" heading="341.45" radius="44" pushBackRoute="166" airlineCodes="" />
|
||||
<Parking index="6" type="gate" name="V92" lat="N50 2.987622" lon="E8 36.025770" heading="341.45" radius="44" pushBackRoute="165" airlineCodes="" />
|
||||
<Parking index="7" type="gate" name="C16" lat="N50 2.970491" lon="E8 34.976214" heading="-20.5" radius="44" pushBackRoute="97" airlineCodes="" />
|
||||
<Parking index="8" type="gate" name="D4" lat="N50 3.020838" lon="E8 35.186507" heading="342.71" radius="44" pushBackRoute="177" airlineCodes="" />
|
||||
<Parking index="9" type="gate" name="E5" lat="N50 3.064577" lon="E8 35.388765" heading="342.71" radius="44" pushBackRoute="94" airlineCodes="" />
|
||||
<Parking index="10" type="gate" name="E9" lat="N50 3.093001" lon="E8 35.514331" heading="342.71" radius="44" pushBackRoute="93" airlineCodes="" />
|
||||
<Parking index="11" type="gate" name="V268" lat="N50 2.217246" lon="E8 31.436516" heading="339.3" radius="44" pushBackRoute="81" airlineCodes="" />
|
||||
<Parking index="12" type="gate" name="C4" lat="N50 3.002208" lon="E8 34.510773" heading="21.75" radius="44" pushBackRoute="102" airlineCodes="" />
|
||||
<Parking index="13" type="gate" name="B28" lat="N50 2.784223" lon="E8 34.361486" heading="298.11" radius="44" pushBackRoute="105" airlineCodes="" />
|
||||
<Parking index="14" type="gate" name="B48" lat="N50 2.829055" lon="E8 34.522248" heading="28.08" radius="44" pushBackRoute="104" airlineCodes="" />
|
||||
<Parking index="15" type="gate" name="B44" lat="N50 2.901543" lon="E8 34.574913" heading="205.71" radius="44" pushBackRoute="101" airlineCodes="" />
|
||||
<Parking index="16" type="gate" name="C8" lat="N50 2.959101" lon="E8 34.669919" heading="21.75" radius="44" pushBackRoute="100" airlineCodes="" />
|
||||
<Parking index="17" type="gate" name="C14" lat="N50 2.934648" lon="E8 34.840979" heading="340.18" radius="44" pushBackRoute="98" airlineCodes="" />
|
||||
<Parking index="18" type="gate" name="C2" lat="N50 3.000238" lon="E8 34.441947" heading="79.63" radius="44" pushBackRoute="102" airlineCodes="" />
|
||||
<Parking index="19" type="gate" name="B22" lat="N50 2.854101" lon="E8 34.270133" heading="119.89" radius="44" pushBackRoute="109" airlineCodes="" />
|
||||
<Parking index="20" type="gate" name="B23" lat="N50 2.825169" lon="E8 34.377412" heading="-84.06" radius="44" pushBackRoute="105" airlineCodes="" />
|
||||
<Parking index="21" type="gate" name="B10" lat="N50 2.940697" lon="E8 34.286900" heading="159.59" radius="44" pushBackRoute="110" airlineCodes="" />
|
||||
<Parking index="22" type="gate" name="A66" lat="N50 2.792857" lon="E8 33.631193" heading="340.34" radius="44" pushBackRoute="116" airlineCodes="" />
|
||||
<Parking index="23" type="gate" name="A54" lat="N50 2.841211" lon="E8 33.838648" heading="340.34" radius="44" pushBackRoute="117" airlineCodes="" />
|
||||
<Parking index="24" type="gate" name="A16" lat="N50 2.846693" lon="E8 34.029215" heading="113.9" radius="44" pushBackRoute="123" airlineCodes="" />
|
||||
<Parking index="25" type="gate" name="A28" lat="N50 2.695002" lon="E8 33.884392" heading="157.98" radius="44" pushBackRoute="122" airlineCodes="" />
|
||||
<Parking index="26" type="gate" name="F224" lat="N50 2.365898" lon="E8 32.469863" heading="250.54" radius="44" pushBackRoute="83" airlineCodes="" />
|
||||
<Parking index="27" type="gate" name="F211" lat="N50 2.375008" lon="E8 32.623026" heading="70.16" radius="44" pushBackRoute="83" airlineCodes="" />
|
||||
<Parking index="28" type="gate" name="F219" lat="N50 2.498238" lon="E8 32.981234" heading="70.16" radius="44" pushBackRoute="190" airlineCodes="" />
|
||||
<Parking index="29" type="gate" name="V266" lat="N50 2.237159" lon="E8 31.501546" heading="339.44" radius="44" pushBackRoute="82" airlineCodes="" />
|
||||
<Parking index="30" type="gate" name="F235" lat="N50 2.204985" lon="E8 31.785992" heading="339.44" radius="44" pushBackRoute="70" airlineCodes="" />
|
||||
<Parking index="31" type="gate" name="F231" lat="N50 2.280024" lon="E8 32.101077" heading="339.44" radius="44" pushBackRoute="69" airlineCodes="" />
|
||||
<Parking index="32" type="gate" name="V178" lat="N50 2.159443" lon="E8 32.191372" heading="159.54" radius="44" pushBackRoute="194" airlineCodes="" />
|
||||
<Parking index="33" type="gate" name="V174" lat="N50 2.199657" lon="E8 32.361192" heading="159.54" radius="44" pushBackRoute="85" airlineCodes="" />
|
||||
<Parking index="34" type="gate" name="V169" lat="N50 2.300216" lon="E8 32.746177" heading="159.54" radius="44" pushBackRoute="86" airlineCodes="" />
|
||||
<Parking index="35" type="gate" name="V164" lat="N50 2.373806" lon="E8 33.066649" heading="159.54" radius="44" pushBackRoute="190" airlineCodes="" />
|
||||
<Parking index="36" type="gate" name="V159" lat="N50 2.462450" lon="E8 33.442180" heading="159.09" radius="44" pushBackRoute="88" airlineCodes="" />
|
||||
<Parking index="37" type="gate" name="A40" lat="N50 2.646960" lon="E8 33.694767" heading="155.92" radius="44" pushBackRoute="121" airlineCodes="" />
|
||||
<Parking index="38" type="gate" name="A17" lat="N50 2.846756" lon="E8 34.142889" heading="292.36" radius="44" pushBackRoute="108" airlineCodes="" />
|
||||
<Parking index="39" type="gate" name="A1" lat="N50 2.952545" lon="E8 34.235065" heading="99.04" radius="44" pushBackRoute="110" airlineCodes="" />
|
||||
</parkingList>
|
||||
<TaxiNodes>
|
||||
<node index="40" lat="N50 2.768508" lon="E8 35.248439" isOnRunway="0" holdPointType="none" />
|
||||
<node index="41" lat="N50 2.723872" lon="E8 35.194098" isOnRunway="0" holdPointType="none" />
|
||||
<node index="42" lat="N50 2.002157" lon="E8 32.028565" isOnRunway="0" holdPointType="none" />
|
||||
<node index="43" lat="N50 1.598113" lon="E8 32.515177" isOnRunway="0" holdPointType="none" />
|
||||
<node index="44" lat="N50 1.688136" lon="E8 32.918501" isOnRunway="0" holdPointType="none" />
|
||||
<node index="45" lat="N50 1.738117" lon="E8 32.892184" isOnRunway="0" holdPointType="none" />
|
||||
<node index="46" lat="N50 2.366208" lon="E8 35.519847" isOnRunway="0" holdPointType="none" />
|
||||
<node index="47" lat="N50 2.387651" lon="E8 35.577599" isOnRunway="0" holdPointType="none" />
|
||||
<node index="48" lat="N50 2.418646" lon="E8 35.623960" isOnRunway="0" holdPointType="none" />
|
||||
<node index="49" lat="N50 2.456653" lon="E8 35.656871" isOnRunway="0" holdPointType="none" />
|
||||
<node index="50" lat="N50 2.490318" lon="E8 35.675517" isOnRunway="0" holdPointType="none" />
|
||||
<node index="51" lat="N50 2.533802" lon="E8 35.692053" isOnRunway="0" holdPointType="none" />
|
||||
<node index="52" lat="N50 2.626921" lon="E8 35.687006" isOnRunway="0" holdPointType="none" />
|
||||
<node index="53" lat="N50 2.772243" lon="E8 35.679001" isOnRunway="0" holdPointType="none" />
|
||||
<node index="54" lat="N50 2.813156" lon="E8 35.668730" isOnRunway="0" holdPointType="none" />
|
||||
<node index="55" lat="N50 2.872962" lon="E8 35.634612" isOnRunway="0" holdPointType="none" />
|
||||
<node index="56" lat="N50 2.019011" lon="E8 34.065677" isOnRunway="0" holdPointType="none" />
|
||||
<node index="57" lat="N50 1.968782" lon="E8 34.092582" isOnRunway="0" holdPointType="none" />
|
||||
<node index="58" lat="N50 2.284498" lon="E8 35.411532" isOnRunway="0" holdPointType="none" />
|
||||
<node index="59" lat="N50 2.318854" lon="E8 35.558524" isOnRunway="0" holdPointType="none" />
|
||||
<node index="60" lat="N50 2.347394" lon="E8 35.629704" isOnRunway="0" holdPointType="none" />
|
||||
<node index="61" lat="N50 2.382562" lon="E8 35.685301" isOnRunway="0" holdPointType="none" />
|
||||
<node index="62" lat="N50 2.431933" lon="E8 35.729527" isOnRunway="0" holdPointType="none" />
|
||||
<node index="63" lat="N50 2.493341" lon="E8 35.765540" isOnRunway="0" holdPointType="none" />
|
||||
<node index="64" lat="N50 2.531756" lon="E8 35.780072" isOnRunway="0" holdPointType="none" />
|
||||
<node index="65" lat="N50 2.576257" lon="E8 35.783231" isOnRunway="0" holdPointType="none" />
|
||||
<node index="66" lat="N50 2.785100" lon="E8 35.770384" isOnRunway="0" holdPointType="none" />
|
||||
<node index="67" lat="N50 2.816616" lon="E8 35.768067" isOnRunway="0" holdPointType="none" />
|
||||
<node index="68" lat="N50 2.855165" lon="E8 35.749532" isOnRunway="0" holdPointType="none" />
|
||||
<node index="69" lat="N50 2.230702" lon="E8 32.119703" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="70" lat="N50 2.156528" lon="E8 31.809707" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="71" lat="N50 2.111141" lon="E8 31.022815" isOnRunway="0" holdPointType="none" />
|
||||
<node index="72" lat="N50 2.104445" lon="E8 31.053390" isOnRunway="0" holdPointType="none" />
|
||||
<node index="73" lat="N50 2.118431" lon="E8 31.248425" isOnRunway="0" holdPointType="none" />
|
||||
<node index="74" lat="N50 2.134649" lon="E8 31.407790" isOnRunway="0" holdPointType="none" />
|
||||
<node index="75" lat="N50 2.153669" lon="E8 31.493328" isOnRunway="0" holdPointType="none" />
|
||||
<node index="76" lat="N50 2.158680" lon="E8 31.590320" isOnRunway="0" holdPointType="none" />
|
||||
<node index="77" lat="N50 2.184821" lon="E8 31.711053" isOnRunway="0" holdPointType="none" />
|
||||
<node index="78" lat="N50 2.138639" lon="E8 31.736488" isOnRunway="0" holdPointType="none" />
|
||||
<node index="79" lat="N50 2.146045" lon="E8 31.459077" isOnRunway="0" holdPointType="none" />
|
||||
<node index="80" lat="N50 2.187217" lon="E8 31.435337" isOnRunway="0" holdPointType="none" />
|
||||
<node index="81" lat="N50 2.201594" lon="E8 31.451616" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="82" lat="N50 2.218150" lon="E8 31.521140" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="83" lat="N50 2.378574" lon="E8 32.544269" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="84" lat="N50 2.119540" lon="E8 32.211832" isOnRunway="0" holdPointType="none" />
|
||||
<node index="85" lat="N50 2.161474" lon="E8 32.381569" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="86" lat="N50 2.261876" lon="E8 32.767313" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="87" lat="N50 2.334242" lon="E8 33.085543" isOnRunway="0" holdPointType="none" />
|
||||
<node index="88" lat="N50 2.422424" lon="E8 33.464592" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="89" lat="N50 2.962635" lon="E8 35.943877" isOnRunway="0" holdPointType="none" />
|
||||
<node index="90" lat="N50 2.930355" lon="E8 35.801090" isOnRunway="0" holdPointType="none" />
|
||||
<node index="91" lat="N50 2.918671" lon="E8 35.477894" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="92" lat="N50 3.013926" lon="E8 35.475427" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="93" lat="N50 3.084823" lon="E8 35.519220" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="94" lat="N50 3.043830" lon="E8 35.401102" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="95" lat="N50 2.873717" lon="E8 35.315062" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="96" lat="N50 2.973329" lon="E8 35.304268" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="97" lat="N50 2.951846" lon="E8 34.988089" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="98" lat="N50 2.915488" lon="E8 34.855981" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="99" lat="N50 2.897627" lon="E8 34.729840" isOnRunway="0" holdPointType="none" />
|
||||
<node index="100" lat="N50 2.920271" lon="E8 34.656833" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="101" lat="N50 2.939089" lon="E8 34.593759" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="102" lat="N50 2.976405" lon="E8 34.465127" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="103" lat="N50 2.747990" lon="E8 34.502624" isOnRunway="0" holdPointType="none" />
|
||||
<node index="104" lat="N50 2.792754" lon="E8 34.460763" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="105" lat="N50 2.819903" lon="E8 34.431622" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="106" lat="N50 2.645840" lon="E8 34.108153" isOnRunway="0" holdPointType="none" />
|
||||
<node index="107" lat="N50 2.714132" lon="E8 34.107406" isOnRunway="0" holdPointType="none" />
|
||||
<node index="108" lat="N50 2.831943" lon="E8 34.188566" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="109" lat="N50 2.863974" lon="E8 34.212603" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="110" lat="N50 2.923791" lon="E8 34.254066" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="111" lat="N50 2.546371" lon="E8 33.617272" isOnRunway="0" holdPointType="none" />
|
||||
<node index="112" lat="N50 2.562927" lon="E8 33.583692" isOnRunway="0" holdPointType="none" />
|
||||
<node index="113" lat="N50 2.610634" lon="E8 33.552826" isOnRunway="0" holdPointType="none" />
|
||||
<node index="114" lat="N50 2.646578" lon="E8 33.542650" isOnRunway="0" holdPointType="none" />
|
||||
<node index="115" lat="N50 2.729139" lon="E8 33.578944" isOnRunway="0" holdPointType="none" />
|
||||
<node index="116" lat="N50 2.748527" lon="E8 33.646785" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="117" lat="N50 2.801023" lon="E8 33.865967" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="118" lat="N50 2.568248" lon="E8 33.730581" isOnRunway="0" holdPointType="none" />
|
||||
<node index="119" lat="N50 2.580447" lon="E8 33.648159" isOnRunway="0" holdPointType="none" />
|
||||
<node index="120" lat="N50 2.654077" lon="E8 33.611525" isOnRunway="0" holdPointType="none" />
|
||||
<node index="121" lat="N50 2.672812" lon="E8 33.681738" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="122" lat="N50 2.714636" lon="E8 33.853373" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="123" lat="N50 2.814625" lon="E8 33.924607" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="124" lat="N50 2.580757" lon="E8 32.866928" isOnRunway="0" holdPointType="none" />
|
||||
<node index="125" lat="N50 2.607402" lon="E8 32.844502" isOnRunway="0" holdPointType="none" />
|
||||
<node index="126" lat="N50 2.642508" lon="E8 32.791240" isOnRunway="0" holdPointType="none" />
|
||||
<node index="127" lat="N50 2.666092" lon="E8 32.719475" isOnRunway="0" holdPointType="none" />
|
||||
<node index="128" lat="N50 2.671133" lon="E8 32.633694" isOnRunway="0" holdPointType="none" />
|
||||
<node index="129" lat="N50 2.638547" lon="E8 32.136389" isOnRunway="0" holdPointType="none" />
|
||||
<node index="130" lat="N50 2.633326" lon="E8 32.074997" isOnRunway="0" holdPointType="none" />
|
||||
<node index="131" lat="N50 2.573375" lon="E8 31.831956" isOnRunway="0" holdPointType="none" />
|
||||
<node index="132" lat="N50 2.134276" lon="E8 29.995441" isOnRunway="0" holdPointType="none" />
|
||||
<node index="133" lat="N50 2.263648" lon="E8 30.537065" isOnRunway="0" holdPointType="none" />
|
||||
<node index="134" lat="N50 2.129774" lon="E8 29.971337" isOnRunway="0" holdPointType="none" />
|
||||
<node index="135" lat="N50 2.133015" lon="E8 29.925371" isOnRunway="0" holdPointType="none" />
|
||||
<node index="136" lat="N50 2.146517" lon="E8 29.888655" isOnRunway="0" holdPointType="none" />
|
||||
<node index="137" lat="N50 2.696267" lon="E8 32.037025" isOnRunway="0" holdPointType="none" />
|
||||
<node index="138" lat="N50 2.171461" lon="E8 29.867013" isOnRunway="0" holdPointType="none" />
|
||||
<node index="139" lat="N50 2.081473" lon="E8 32.118503" isOnRunway="0" holdPointType="none" />
|
||||
<node index="140" lat="N50 2.047358" lon="E8 31.976352" isOnRunway="0" holdPointType="none" />
|
||||
<node index="141" lat="N50 2.323862" lon="E8 33.132875" isOnRunway="0" holdPointType="none" />
|
||||
<node index="142" lat="N50 2.315552" lon="E8 33.097108" isOnRunway="0" holdPointType="none" />
|
||||
<node index="143" lat="N50 2.298799" lon="E8 33.028902" isOnRunway="0" holdPointType="none" />
|
||||
<node index="144" lat="N50 2.240071" lon="E8 32.781490" isOnRunway="0" holdPointType="none" />
|
||||
<node index="145" lat="N50 2.146617" lon="E8 32.390895" isOnRunway="0" holdPointType="none" />
|
||||
<node index="146" lat="N50 2.105162" lon="E8 32.218547" isOnRunway="0" holdPointType="none" />
|
||||
<node index="147" lat="N50 2.507168" lon="E8 33.900910" isOnRunway="0" holdPointType="none" />
|
||||
<node index="148" lat="N50 2.478498" lon="E8 33.780101" isOnRunway="0" holdPointType="none" />
|
||||
<node index="149" lat="N50 2.452265" lon="E8 33.670862" isOnRunway="0" holdPointType="none" />
|
||||
<node index="150" lat="N50 2.404931" lon="E8 33.472427" isOnRunway="0" holdPointType="none" />
|
||||
<node index="151" lat="N50 2.716334" lon="E8 34.775263" isOnRunway="0" holdPointType="none" />
|
||||
<node index="152" lat="N50 2.664357" lon="E8 34.558436" isOnRunway="0" holdPointType="none" />
|
||||
<node index="153" lat="N50 2.549294" lon="E8 34.077749" isOnRunway="0" holdPointType="none" />
|
||||
<node index="154" lat="N50 2.813551" lon="E8 35.181499" isOnRunway="0" holdPointType="none" />
|
||||
<node index="155" lat="N50 2.730184" lon="E8 34.832643" isOnRunway="0" holdPointType="none" />
|
||||
<node index="156" lat="N50 2.840393" lon="E8 35.279110" isOnRunway="0" holdPointType="none" />
|
||||
<node index="157" lat="N50 2.835443" lon="E8 35.260718" isOnRunway="0" holdPointType="none" />
|
||||
<node index="158" lat="N50 2.832217" lon="E8 35.250756" isOnRunway="0" holdPointType="none" />
|
||||
<node index="159" lat="N50 2.903896" lon="E8 35.546206" isOnRunway="0" holdPointType="none" />
|
||||
<node index="160" lat="N50 2.890550" lon="E8 35.490847" isOnRunway="0" holdPointType="none" />
|
||||
<node index="161" lat="N50 2.851735" lon="E8 35.326780" isOnRunway="0" holdPointType="none" />
|
||||
<node index="162" lat="N50 2.924845" lon="E8 35.644838" isOnRunway="0" holdPointType="none" />
|
||||
<node index="163" lat="N50 2.915776" lon="E8 35.602059" isOnRunway="0" holdPointType="none" />
|
||||
<node index="164" lat="N50 2.895221" lon="E8 35.694028" isOnRunway="0" holdPointType="none" />
|
||||
<node index="165" lat="N50 2.976072" lon="E8 36.037339" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="166" lat="N50 2.955110" lon="E8 35.948503" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="167" lat="N50 2.921839" lon="E8 35.806025" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="168" lat="N50 2.896288" lon="E8 35.698426" isOnRunway="0" holdPointType="none" />
|
||||
<node index="169" lat="N50 2.924681" lon="E8 35.645347" isOnRunway="0" holdPointType="none" />
|
||||
<node index="170" lat="N50 3.027955" lon="E8 35.585198" isOnRunway="0" holdPointType="none" />
|
||||
<node index="171" lat="N50 3.045139" lon="E8 35.565827" isOnRunway="0" holdPointType="none" />
|
||||
<node index="172" lat="N50 3.044321" lon="E8 35.519185" isOnRunway="0" holdPointType="none" />
|
||||
<node index="173" lat="N50 3.044424" lon="E8 35.535257" isOnRunway="0" holdPointType="none" />
|
||||
<node index="174" lat="N50 2.875253" lon="E8 34.810636" isOnRunway="0" holdPointType="none" />
|
||||
<node index="175" lat="N50 2.888696" lon="E8 34.869391" isOnRunway="0" holdPointType="none" />
|
||||
<node index="176" lat="N50 2.922823" lon="E8 35.008451" isOnRunway="0" holdPointType="none" />
|
||||
<node index="177" lat="N50 2.966518" lon="E8 35.190721" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="178" lat="N50 2.990360" lon="E8 35.291932" isOnRunway="0" holdPointType="none" />
|
||||
<node index="179" lat="N50 3.019669" lon="E8 35.414054" isOnRunway="0" holdPointType="none" />
|
||||
<node index="180" lat="N50 3.030958" lon="E8 35.463399" isOnRunway="0" holdPointType="none" />
|
||||
<node index="181" lat="N50 2.819771" lon="E8 34.722454" isOnRunway="0" holdPointType="none" />
|
||||
<node index="182" lat="N50 2.844818" lon="E8 34.762262" isOnRunway="0" holdPointType="none" />
|
||||
<node index="183" lat="N50 2.691620" lon="E8 34.186239" isOnRunway="0" holdPointType="none" />
|
||||
<node index="184" lat="N50 2.763718" lon="E8 34.487916" isOnRunway="0" holdPointType="none" />
|
||||
<node index="185" lat="N50 2.538592" lon="E8 33.545312" isOnRunway="0" holdPointType="none" />
|
||||
<node index="186" lat="N50 2.552705" lon="E8 33.604424" isOnRunway="0" holdPointType="none" />
|
||||
<node index="187" lat="N50 2.573827" lon="E8 33.692887" isOnRunway="0" holdPointType="none" />
|
||||
<node index="188" lat="N50 2.672906" lon="E8 34.107857" isOnRunway="0" holdPointType="none" />
|
||||
<node index="189" lat="N50 2.321243" lon="E8 32.636606" isOnRunway="0" holdPointType="none" />
|
||||
<node index="190" lat="N50 2.401028" lon="E8 32.970175" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="191" lat="N50 2.280818" lon="E8 32.538248" isOnRunway="0" holdPointType="none" />
|
||||
<node index="192" lat="N50 2.300655" lon="E8 32.588034" isOnRunway="0" holdPointType="none" />
|
||||
<node index="193" lat="N50 2.133100" lon="E8 31.931101" isOnRunway="0" holdPointType="none" />
|
||||
<node index="194" lat="N50 2.188574" lon="E8 32.159503" isOnRunway="0" holdPointType="PushBack" />
|
||||
<node index="195" lat="N50 2.090723" lon="E8 31.753430" isOnRunway="0" holdPointType="none" />
|
||||
<node index="196" lat="N50 2.058914" lon="E8 31.636988" isOnRunway="0" holdPointType="none" />
|
||||
<node index="197" lat="N50 2.072246" lon="E8 31.689653" isOnRunway="0" holdPointType="none" />
|
||||
<node index="198" lat="N50 1.959143" lon="E8 31.691518" isOnRunway="0" holdPointType="none" />
|
||||
<node index="199" lat="N50 1.979281" lon="E8 31.691186" isOnRunway="0" holdPointType="none" />
|
||||
<node index="200" lat="N50 1.641881" lon="E8 31.694873" isOnRunway="0" holdPointType="none" />
|
||||
<node index="201" lat="N49 59.998617" lon="E8 31.711146" isOnRunway="0" holdPointType="none" />
|
||||
<node index="202" lat="N50 1.402856" lon="E8 31.697371" isOnRunway="0" holdPointType="none" />
|
||||
<node index="203" lat="N49 59.974172" lon="E8 31.709017" isOnRunway="0" holdPointType="none" />
|
||||
<node index="204" lat="N49 59.943965" lon="E8 31.668430" isOnRunway="0" holdPointType="none" />
|
||||
<node index="205" lat="N49 59.928482" lon="E8 31.646584" isOnRunway="0" holdPointType="none" />
|
||||
<node index="206" lat="N49 59.922001" lon="E8 31.625299" isOnRunway="0" holdPointType="none" />
|
||||
<node index="207" lat="N50 1.966928" lon="E8 31.639534" isOnRunway="0" holdPointType="none" />
|
||||
<node index="208" lat="N50 2.056045" lon="E8 31.623504" isOnRunway="0" holdPointType="none" />
|
||||
<node index="209" lat="N50 2.037712" lon="E8 31.555410" isOnRunway="1" holdPointType="none" />
|
||||
<node index="210" lat="N49 59.925487" lon="E8 31.577437" isOnRunway="1" holdPointType="none" />
|
||||
<node index="211" lat="N50 1.947323" lon="E8 31.556298" isOnRunway="1" holdPointType="none" />
|
||||
<node index="212" lat="N50 2.393382" lon="E8 35.154155" isOnRunway="1" holdPointType="none" />
|
||||
<node index="213" lat="N50 1.657742" lon="E8 32.074192" isOnRunway="1" holdPointType="none" />
|
||||
<node index="214" lat="N50 2.698705" lon="E8 35.184926" isOnRunway="1" holdPointType="none" />
|
||||
<node index="215" lat="N50 1.965053" lon="E8 32.114816" isOnRunway="1" holdPointType="none" />
|
||||
<node index="216" lat="N50 2.745050" lon="E8 31.999783" isOnRunway="1" holdPointType="none" />
|
||||
<node index="217" lat="N50 2.228933" lon="E8 29.842340" isOnRunway="1" holdPointType="none" />
|
||||
<node index="218" lat="N50 2.297290" lon="E8 35.231582" isOnRunway="0" holdPointType="none" />
|
||||
<node index="219" lat="N50 2.383706" lon="E8 35.179090" isOnRunway="0" holdPointType="none" />
|
||||
<node index="220" lat="N50 2.393526" lon="E8 35.154118" isOnRunway="0" holdPointType="none" />
|
||||
<node index="221" lat="N50 1.511581" lon="E8 32.153321" isOnRunway="0" holdPointType="none" />
|
||||
<node index="222" lat="N50 1.657691" lon="E8 32.073653" isOnRunway="0" holdPointType="none" />
|
||||
<node index="223" lat="N50 3.025520" lon="E8 35.475840" isOnRunway="0" holdPointType="none" />
|
||||
<node index="224" lat="N50 2.982489" lon="E8 35.305968" isOnRunway="0" holdPointType="none" />
|
||||
<node index="225" lat="N50 2.862561" lon="E8 35.311869" isOnRunway="0" holdPointType="none" />
|
||||
<node index="226" lat="N50 2.906491" lon="E8 35.476404" isOnRunway="0" holdPointType="none" />
|
||||
<node index="227" lat="N50 2.908578" lon="E8 35.805647" isOnRunway="0" holdPointType="none" />
|
||||
<node index="228" lat="N50 2.941343" lon="E8 35.949214" isOnRunway="0" holdPointType="none" />
|
||||
<node index="229" lat="N50 2.961906" lon="E8 36.034399" isOnRunway="0" holdPointType="none" />
|
||||
<node index="230" lat="N50 2.945084" lon="E8 34.985713" isOnRunway="0" holdPointType="none" />
|
||||
<node index="231" lat="N50 2.994939" lon="E8 35.194569" isOnRunway="0" holdPointType="none" />
|
||||
<node index="232" lat="N50 3.038678" lon="E8 35.396827" isOnRunway="0" holdPointType="none" />
|
||||
<node index="233" lat="N50 3.067102" lon="E8 35.522393" isOnRunway="0" holdPointType="none" />
|
||||
<node index="234" lat="N50 2.191873" lon="E8 31.446103" isOnRunway="0" holdPointType="none" />
|
||||
<node index="235" lat="N50 2.977014" lon="E8 34.500721" isOnRunway="0" holdPointType="none" />
|
||||
<node index="236" lat="N50 2.771443" lon="E8 34.385411" isOnRunway="0" holdPointType="none" />
|
||||
<node index="237" lat="N50 2.805123" lon="E8 34.509480" isOnRunway="0" holdPointType="none" />
|
||||
<node index="238" lat="N50 2.925982" lon="E8 34.586681" isOnRunway="0" holdPointType="none" />
|
||||
<node index="239" lat="N50 2.933907" lon="E8 34.659868" isOnRunway="0" holdPointType="none" />
|
||||
<node index="240" lat="N50 2.909130" lon="E8 34.850176" isOnRunway="0" holdPointType="none" />
|
||||
<node index="241" lat="N50 2.995356" lon="E8 34.415266" isOnRunway="0" holdPointType="none" />
|
||||
<node index="242" lat="N50 2.867618" lon="E8 34.246616" isOnRunway="0" holdPointType="none" />
|
||||
<node index="243" lat="N50 2.822362" lon="E8 34.404391" isOnRunway="0" holdPointType="none" />
|
||||
<node index="244" lat="N50 2.966119" lon="E8 34.277440" isOnRunway="0" holdPointType="none" />
|
||||
<node index="245" lat="N50 2.767314" lon="E8 33.640319" isOnRunway="0" holdPointType="none" />
|
||||
<node index="246" lat="N50 2.815668" lon="E8 33.847773" isOnRunway="0" holdPointType="none" />
|
||||
<node index="247" lat="N50 2.857682" lon="E8 34.004416" isOnRunway="0" holdPointType="none" />
|
||||
<node index="248" lat="N50 2.720148" lon="E8 33.874222" isOnRunway="0" holdPointType="none" />
|
||||
<node index="249" lat="N50 2.374934" lon="E8 32.495439" isOnRunway="0" holdPointType="none" />
|
||||
<node index="250" lat="N50 2.365802" lon="E8 32.597511" isOnRunway="0" holdPointType="none" />
|
||||
<node index="251" lat="N50 2.489032" lon="E8 32.955720" isOnRunway="0" holdPointType="none" />
|
||||
<node index="252" lat="N50 2.211762" lon="E8 31.511072" isOnRunway="0" holdPointType="none" />
|
||||
<node index="253" lat="N50 2.179588" lon="E8 31.795518" isOnRunway="0" holdPointType="none" />
|
||||
<node index="254" lat="N50 2.254627" lon="E8 32.110603" isOnRunway="0" holdPointType="none" />
|
||||
<node index="255" lat="N50 2.184857" lon="E8 32.181891" isOnRunway="0" holdPointType="none" />
|
||||
<node index="256" lat="N50 2.225071" lon="E8 32.351710" isOnRunway="0" holdPointType="none" />
|
||||
<node index="257" lat="N50 2.325630" lon="E8 32.736696" isOnRunway="0" holdPointType="none" />
|
||||
<node index="258" lat="N50 2.399219" lon="E8 33.057168" isOnRunway="0" holdPointType="none" />
|
||||
<node index="259" lat="N50 2.487788" lon="E8 33.432499" isOnRunway="0" holdPointType="none" />
|
||||
<node index="260" lat="N50 2.671725" lon="E8 33.683700" isOnRunway="0" holdPointType="none" />
|
||||
<node index="261" lat="N50 2.836437" lon="E8 34.167974" isOnRunway="0" holdPointType="none" />
|
||||
<node index="262" lat="N50 2.956807" lon="E8 34.208277" isOnRunway="0" holdPointType="none" />
|
||||
</TaxiNodes>
|
||||
<TaxiWaySegments>
|
||||
<arc begin="40" end="158" isPushBackRoute="0" name="L1" />
|
||||
<arc begin="158" end="40" isPushBackRoute="0" name="L1" />
|
||||
<arc begin="41" end="40" isPushBackRoute="0" name="L1" />
|
||||
<arc begin="40" end="41" isPushBackRoute="0" name="L1" />
|
||||
<arc begin="214" end="41" isPushBackRoute="0" name="L1" />
|
||||
<arc begin="41" end="214" isPushBackRoute="0" name="L1" />
|
||||
<arc begin="42" end="140" isPushBackRoute="0" name="L21" />
|
||||
<arc begin="140" end="42" isPushBackRoute="0" name="L21" />
|
||||
<arc begin="215" end="42" isPushBackRoute="0" name="L21" />
|
||||
<arc begin="42" end="215" isPushBackRoute="0" name="L21" />
|
||||
<arc begin="43" end="202" isPushBackRoute="0" name="S" />
|
||||
<arc begin="202" end="43" isPushBackRoute="0" name="S" />
|
||||
<arc begin="44" end="43" isPushBackRoute="0" name="S" />
|
||||
<arc begin="43" end="44" isPushBackRoute="0" name="S" />
|
||||
<arc begin="45" end="44" isPushBackRoute="0" name="S" />
|
||||
<arc begin="44" end="45" isPushBackRoute="0" name="S" />
|
||||
<arc begin="56" end="45" isPushBackRoute="0" name="R" />
|
||||
<arc begin="45" end="56" isPushBackRoute="0" name="R" />
|
||||
<arc begin="46" end="56" isPushBackRoute="0" name="R" />
|
||||
<arc begin="56" end="46" isPushBackRoute="0" name="R" />
|
||||
<arc begin="47" end="46" isPushBackRoute="0" name="R" />
|
||||
<arc begin="46" end="47" isPushBackRoute="0" name="R" />
|
||||
<arc begin="48" end="47" isPushBackRoute="0" name="R" />
|
||||
<arc begin="47" end="48" isPushBackRoute="0" name="R" />
|
||||
<arc begin="49" end="48" isPushBackRoute="0" name="R" />
|
||||
<arc begin="48" end="49" isPushBackRoute="0" name="R" />
|
||||
<arc begin="50" end="49" isPushBackRoute="0" name="R" />
|
||||
<arc begin="49" end="50" isPushBackRoute="0" name="R" />
|
||||
<arc begin="51" end="50" isPushBackRoute="0" name="R" />
|
||||
<arc begin="50" end="51" isPushBackRoute="0" name="R" />
|
||||
<arc begin="52" end="51" isPushBackRoute="0" name="R" />
|
||||
<arc begin="51" end="52" isPushBackRoute="0" name="R" />
|
||||
<arc begin="53" end="52" isPushBackRoute="0" name="R" />
|
||||
<arc begin="52" end="53" isPushBackRoute="0" name="R" />
|
||||
<arc begin="54" end="53" isPushBackRoute="0" name="R" />
|
||||
<arc begin="53" end="54" isPushBackRoute="0" name="R" />
|
||||
<arc begin="55" end="54" isPushBackRoute="0" name="R" />
|
||||
<arc begin="54" end="55" isPushBackRoute="0" name="R" />
|
||||
<arc begin="163" end="55" isPushBackRoute="0" name="R" />
|
||||
<arc begin="55" end="163" isPushBackRoute="0" name="R" />
|
||||
<arc begin="57" end="56" isPushBackRoute="0" name="S" />
|
||||
<arc begin="56" end="57" isPushBackRoute="0" name="S" />
|
||||
<arc begin="58" end="57" isPushBackRoute="0" name="S" />
|
||||
<arc begin="57" end="58" isPushBackRoute="0" name="S" />
|
||||
<arc begin="59" end="58" isPushBackRoute="0" name="S" />
|
||||
<arc begin="58" end="59" isPushBackRoute="0" name="S" />
|
||||
<arc begin="60" end="59" isPushBackRoute="0" name="S" />
|
||||
<arc begin="59" end="60" isPushBackRoute="0" name="S" />
|
||||
<arc begin="61" end="60" isPushBackRoute="0" name="S" />
|
||||
<arc begin="60" end="61" isPushBackRoute="0" name="S" />
|
||||
<arc begin="62" end="61" isPushBackRoute="0" name="S" />
|
||||
<arc begin="61" end="62" isPushBackRoute="0" name="S" />
|
||||
<arc begin="63" end="62" isPushBackRoute="0" name="S" />
|
||||
<arc begin="62" end="63" isPushBackRoute="0" name="S" />
|
||||
<arc begin="64" end="63" isPushBackRoute="0" name="S" />
|
||||
<arc begin="63" end="64" isPushBackRoute="0" name="S" />
|
||||
<arc begin="65" end="64" isPushBackRoute="0" name="S" />
|
||||
<arc begin="64" end="65" isPushBackRoute="0" name="S" />
|
||||
<arc begin="66" end="65" isPushBackRoute="0" name="S" />
|
||||
<arc begin="65" end="66" isPushBackRoute="0" name="S" />
|
||||
<arc begin="67" end="66" isPushBackRoute="0" name="S" />
|
||||
<arc begin="66" end="67" isPushBackRoute="0" name="S" />
|
||||
<arc begin="68" end="67" isPushBackRoute="0" name="S" />
|
||||
<arc begin="67" end="68" isPushBackRoute="0" name="S" />
|
||||
<arc begin="168" end="68" isPushBackRoute="0" name="S" />
|
||||
<arc begin="68" end="168" isPushBackRoute="0" name="S" />
|
||||
<arc begin="69" end="194" isPushBackRoute="0" name="NN" />
|
||||
<arc begin="194" end="69" isPushBackRoute="0" name="NN" />
|
||||
<arc begin="70" end="69" isPushBackRoute="0" name="NN" />
|
||||
<arc begin="69" end="70" isPushBackRoute="0" name="NN" />
|
||||
<arc begin="78" end="70" isPushBackRoute="0" name="NN" />
|
||||
<arc begin="70" end="78" isPushBackRoute="0" name="NN" />
|
||||
<arc begin="71" end="133" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="133" end="71" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="72" end="71" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="71" end="72" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="73" end="72" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="72" end="73" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="74" end="73" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="73" end="74" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="79" end="74" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="74" end="79" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="75" end="79" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="79" end="75" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="76" end="75" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="75" end="76" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="77" end="76" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="76" end="77" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="78" end="77" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="77" end="78" isPushBackRoute="0" name="P1" />
|
||||
<arc begin="80" end="79" isPushBackRoute="0" name="N19" />
|
||||
<arc begin="79" end="80" isPushBackRoute="0" name="N19" />
|
||||
<arc begin="81" end="80" isPushBackRoute="0" name="N19" />
|
||||
<arc begin="80" end="81" isPushBackRoute="0" name="N19" />
|
||||
<arc begin="82" end="81" isPushBackRoute="0" name="N19" />
|
||||
<arc begin="81" end="82" isPushBackRoute="0" name="N19" />
|
||||
<arc begin="83" end="192" isPushBackRoute="0" name="N14" />
|
||||
<arc begin="192" end="83" isPushBackRoute="0" name="N14" />
|
||||
<arc begin="84" end="146" isPushBackRoute="0" name="" />
|
||||
<arc begin="146" end="84" isPushBackRoute="0" name="" />
|
||||
<arc begin="85" end="145" isPushBackRoute="0" name="" />
|
||||
<arc begin="145" end="85" isPushBackRoute="0" name="" />
|
||||
<arc begin="86" end="144" isPushBackRoute="0" name="" />
|
||||
<arc begin="144" end="86" isPushBackRoute="0" name="" />
|
||||
<arc begin="87" end="142" isPushBackRoute="0" name="" />
|
||||
<arc begin="142" end="87" isPushBackRoute="0" name="" />
|
||||
<arc begin="88" end="150" isPushBackRoute="0" name="" />
|
||||
<arc begin="150" end="88" isPushBackRoute="0" name="" />
|
||||
<arc begin="89" end="166" isPushBackRoute="0" name="" />
|
||||
<arc begin="166" end="89" isPushBackRoute="0" name="" />
|
||||
<arc begin="90" end="167" isPushBackRoute="0" name="" />
|
||||
<arc begin="167" end="90" isPushBackRoute="0" name="" />
|
||||
<arc begin="91" end="160" isPushBackRoute="0" name="" />
|
||||
<arc begin="160" end="91" isPushBackRoute="0" name="" />
|
||||
<arc begin="92" end="180" isPushBackRoute="0" name="" />
|
||||
<arc begin="180" end="92" isPushBackRoute="0" name="" />
|
||||
<arc begin="93" end="173" isPushBackRoute="0" name="" />
|
||||
<arc begin="173" end="93" isPushBackRoute="0" name="" />
|
||||
<arc begin="94" end="179" isPushBackRoute="0" name="" />
|
||||
<arc begin="179" end="94" isPushBackRoute="0" name="" />
|
||||
<arc begin="95" end="161" isPushBackRoute="0" name="" />
|
||||
<arc begin="161" end="95" isPushBackRoute="0" name="" />
|
||||
<arc begin="96" end="178" isPushBackRoute="0" name="" />
|
||||
<arc begin="178" end="96" isPushBackRoute="0" name="" />
|
||||
<arc begin="177" end="157" isPushBackRoute="0" name="N1" />
|
||||
<arc begin="157" end="177" isPushBackRoute="0" name="N1" />
|
||||
<arc begin="97" end="176" isPushBackRoute="0" name="" />
|
||||
<arc begin="176" end="97" isPushBackRoute="0" name="" />
|
||||
<arc begin="98" end="175" isPushBackRoute="0" name="" />
|
||||
<arc begin="175" end="98" isPushBackRoute="0" name="" />
|
||||
<arc begin="182" end="155" isPushBackRoute="0" name="N3" />
|
||||
<arc begin="155" end="182" isPushBackRoute="0" name="N3" />
|
||||
<arc begin="99" end="182" isPushBackRoute="0" name="N3" />
|
||||
<arc begin="182" end="99" isPushBackRoute="0" name="N3" />
|
||||
<arc begin="100" end="99" isPushBackRoute="0" name="N3" />
|
||||
<arc begin="99" end="100" isPushBackRoute="0" name="N3" />
|
||||
<arc begin="101" end="100" isPushBackRoute="0" name="N3" />
|
||||
<arc begin="100" end="101" isPushBackRoute="0" name="N3" />
|
||||
<arc begin="102" end="101" isPushBackRoute="0" name="N3" />
|
||||
<arc begin="101" end="102" isPushBackRoute="0" name="N3" />
|
||||
<arc begin="103" end="152" isPushBackRoute="0" name="N4" />
|
||||
<arc begin="152" end="103" isPushBackRoute="0" name="N4" />
|
||||
<arc begin="184" end="103" isPushBackRoute="0" name="N4" />
|
||||
<arc begin="103" end="184" isPushBackRoute="0" name="N4" />
|
||||
<arc begin="104" end="184" isPushBackRoute="0" name="N4" />
|
||||
<arc begin="184" end="104" isPushBackRoute="0" name="N4" />
|
||||
<arc begin="105" end="104" isPushBackRoute="0" name="N4" />
|
||||
<arc begin="104" end="105" isPushBackRoute="0" name="N4" />
|
||||
<arc begin="106" end="153" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="153" end="106" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="188" end="106" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="106" end="188" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="107" end="188" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="188" end="107" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="108" end="107" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="107" end="108" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="109" end="108" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="108" end="109" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="110" end="109" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="109" end="110" isPushBackRoute="0" name="N5" />
|
||||
<arc begin="111" end="149" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="149" end="111" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="186" end="111" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="111" end="186" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="112" end="186" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="186" end="112" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="113" end="112" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="112" end="113" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="114" end="113" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="113" end="114" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="115" end="114" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="114" end="115" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="116" end="115" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="115" end="116" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="117" end="116" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="116" end="117" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="123" end="117" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="117" end="123" isPushBackRoute="0" name="N8" />
|
||||
<arc begin="118" end="148" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="148" end="118" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="187" end="118" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="118" end="187" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="119" end="187" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="187" end="119" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="120" end="119" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="119" end="120" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="121" end="120" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="120" end="121" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="122" end="121" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="121" end="122" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="123" end="122" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="122" end="123" isPushBackRoute="0" name="N7" />
|
||||
<arc begin="137" end="130" isPushBackRoute="0" name="P4" />
|
||||
<arc begin="130" end="137" isPushBackRoute="0" name="P4" />
|
||||
<arc begin="190" end="143" isPushBackRoute="0" name="N11" />
|
||||
<arc begin="143" end="190" isPushBackRoute="0" name="N11" />
|
||||
<arc begin="124" end="190" isPushBackRoute="0" name="N11" />
|
||||
<arc begin="190" end="124" isPushBackRoute="0" name="N11" />
|
||||
<arc begin="125" end="124" isPushBackRoute="0" name="P" />
|
||||
<arc begin="124" end="125" isPushBackRoute="0" name="P" />
|
||||
<arc begin="126" end="125" isPushBackRoute="0" name="P" />
|
||||
<arc begin="125" end="126" isPushBackRoute="0" name="P" />
|
||||
<arc begin="127" end="126" isPushBackRoute="0" name="P" />
|
||||
<arc begin="126" end="127" isPushBackRoute="0" name="P" />
|
||||
<arc begin="128" end="127" isPushBackRoute="0" name="P" />
|
||||
<arc begin="127" end="128" isPushBackRoute="0" name="P" />
|
||||
<arc begin="129" end="128" isPushBackRoute="0" name="P" />
|
||||
<arc begin="128" end="129" isPushBackRoute="0" name="P" />
|
||||
<arc begin="130" end="129" isPushBackRoute="0" name="P" />
|
||||
<arc begin="129" end="130" isPushBackRoute="0" name="P" />
|
||||
<arc begin="131" end="130" isPushBackRoute="0" name="P" />
|
||||
<arc begin="130" end="131" isPushBackRoute="0" name="P" />
|
||||
<arc begin="132" end="133" isPushBackRoute="0" name="P" />
|
||||
<arc begin="133" end="132" isPushBackRoute="0" name="P" />
|
||||
<arc begin="133" end="131" isPushBackRoute="0" name="P" />
|
||||
<arc begin="131" end="133" isPushBackRoute="0" name="P" />
|
||||
<arc begin="134" end="132" isPushBackRoute="0" name="P" />
|
||||
<arc begin="132" end="134" isPushBackRoute="0" name="P" />
|
||||
<arc begin="135" end="134" isPushBackRoute="0" name="P" />
|
||||
<arc begin="134" end="135" isPushBackRoute="0" name="P" />
|
||||
<arc begin="136" end="135" isPushBackRoute="0" name="P" />
|
||||
<arc begin="135" end="136" isPushBackRoute="0" name="P" />
|
||||
<arc begin="138" end="136" isPushBackRoute="0" name="P" />
|
||||
<arc begin="136" end="138" isPushBackRoute="0" name="P" />
|
||||
<arc begin="216" end="137" isPushBackRoute="0" name="P" />
|
||||
<arc begin="137" end="216" isPushBackRoute="0" name="P" />
|
||||
<arc begin="217" end="138" isPushBackRoute="0" name="P" />
|
||||
<arc begin="138" end="217" isPushBackRoute="0" name="P" />
|
||||
<arc begin="199" end="207" isPushBackRoute="0" name="L" />
|
||||
<arc begin="207" end="199" isPushBackRoute="0" name="L" />
|
||||
<arc begin="139" end="140" isPushBackRoute="0" name="L" />
|
||||
<arc begin="140" end="139" isPushBackRoute="0" name="L" />
|
||||
<arc begin="140" end="199" isPushBackRoute="0" name="L" />
|
||||
<arc begin="199" end="140" isPushBackRoute="0" name="L" />
|
||||
<arc begin="141" end="142" isPushBackRoute="0" name="L" />
|
||||
<arc begin="142" end="141" isPushBackRoute="0" name="L" />
|
||||
<arc begin="142" end="143" isPushBackRoute="0" name="L" />
|
||||
<arc begin="143" end="142" isPushBackRoute="0" name="L" />
|
||||
<arc begin="143" end="144" isPushBackRoute="0" name="L" />
|
||||
<arc begin="144" end="143" isPushBackRoute="0" name="L" />
|
||||
<arc begin="144" end="145" isPushBackRoute="0" name="L" />
|
||||
<arc begin="145" end="144" isPushBackRoute="0" name="L" />
|
||||
<arc begin="145" end="146" isPushBackRoute="0" name="L" />
|
||||
<arc begin="146" end="145" isPushBackRoute="0" name="L" />
|
||||
<arc begin="146" end="139" isPushBackRoute="0" name="L" />
|
||||
<arc begin="139" end="146" isPushBackRoute="0" name="L" />
|
||||
<arc begin="147" end="148" isPushBackRoute="0" name="L" />
|
||||
<arc begin="148" end="147" isPushBackRoute="0" name="L" />
|
||||
<arc begin="148" end="149" isPushBackRoute="0" name="L" />
|
||||
<arc begin="149" end="148" isPushBackRoute="0" name="L" />
|
||||
<arc begin="149" end="150" isPushBackRoute="0" name="L" />
|
||||
<arc begin="150" end="149" isPushBackRoute="0" name="L" />
|
||||
<arc begin="150" end="141" isPushBackRoute="0" name="L" />
|
||||
<arc begin="141" end="150" isPushBackRoute="0" name="L" />
|
||||
<arc begin="151" end="152" isPushBackRoute="0" name="L" />
|
||||
<arc begin="152" end="151" isPushBackRoute="0" name="L" />
|
||||
<arc begin="152" end="153" isPushBackRoute="0" name="L" />
|
||||
<arc begin="153" end="152" isPushBackRoute="0" name="L" />
|
||||
<arc begin="153" end="147" isPushBackRoute="0" name="L" />
|
||||
<arc begin="147" end="153" isPushBackRoute="0" name="L" />
|
||||
<arc begin="154" end="155" isPushBackRoute="0" name="L" />
|
||||
<arc begin="155" end="154" isPushBackRoute="0" name="L" />
|
||||
<arc begin="155" end="151" isPushBackRoute="0" name="L" />
|
||||
<arc begin="151" end="155" isPushBackRoute="0" name="L" />
|
||||
<arc begin="156" end="157" isPushBackRoute="0" name="L" />
|
||||
<arc begin="157" end="156" isPushBackRoute="0" name="L" />
|
||||
<arc begin="157" end="158" isPushBackRoute="0" name="L" />
|
||||
<arc begin="158" end="157" isPushBackRoute="0" name="L" />
|
||||
<arc begin="158" end="154" isPushBackRoute="0" name="L" />
|
||||
<arc begin="154" end="158" isPushBackRoute="0" name="L" />
|
||||
<arc begin="159" end="160" isPushBackRoute="0" name="L" />
|
||||
<arc begin="160" end="159" isPushBackRoute="0" name="L" />
|
||||
<arc begin="160" end="161" isPushBackRoute="0" name="L" />
|
||||
<arc begin="161" end="160" isPushBackRoute="0" name="L" />
|
||||
<arc begin="161" end="156" isPushBackRoute="0" name="L" />
|
||||
<arc begin="156" end="161" isPushBackRoute="0" name="L" />
|
||||
<arc begin="162" end="163" isPushBackRoute="0" name="L" />
|
||||
<arc begin="163" end="162" isPushBackRoute="0" name="L" />
|
||||
<arc begin="163" end="159" isPushBackRoute="0" name="L" />
|
||||
<arc begin="159" end="163" isPushBackRoute="0" name="L" />
|
||||
<arc begin="169" end="162" isPushBackRoute="0" name="L" />
|
||||
<arc begin="162" end="169" isPushBackRoute="0" name="L" />
|
||||
<arc begin="164" end="169" isPushBackRoute="0" name="L" />
|
||||
<arc begin="169" end="164" isPushBackRoute="0" name="L" />
|
||||
<arc begin="165" end="166" isPushBackRoute="0" name="L" />
|
||||
<arc begin="166" end="165" isPushBackRoute="0" name="L" />
|
||||
<arc begin="166" end="167" isPushBackRoute="0" name="L" />
|
||||
<arc begin="167" end="166" isPushBackRoute="0" name="L" />
|
||||
<arc begin="167" end="168" isPushBackRoute="0" name="L" />
|
||||
<arc begin="168" end="167" isPushBackRoute="0" name="L" />
|
||||
<arc begin="168" end="164" isPushBackRoute="0" name="L" />
|
||||
<arc begin="164" end="168" isPushBackRoute="0" name="L" />
|
||||
<arc begin="170" end="169" isPushBackRoute="0" name="N" />
|
||||
<arc begin="169" end="170" isPushBackRoute="0" name="N" />
|
||||
<arc begin="171" end="170" isPushBackRoute="0" name="N" />
|
||||
<arc begin="170" end="171" isPushBackRoute="0" name="N" />
|
||||
<arc begin="172" end="173" isPushBackRoute="0" name="N" />
|
||||
<arc begin="173" end="172" isPushBackRoute="0" name="N" />
|
||||
<arc begin="173" end="171" isPushBackRoute="0" name="N" />
|
||||
<arc begin="171" end="173" isPushBackRoute="0" name="N" />
|
||||
<arc begin="174" end="175" isPushBackRoute="0" name="N" />
|
||||
<arc begin="175" end="174" isPushBackRoute="0" name="N" />
|
||||
<arc begin="175" end="176" isPushBackRoute="0" name="N" />
|
||||
<arc begin="176" end="175" isPushBackRoute="0" name="N" />
|
||||
<arc begin="176" end="177" isPushBackRoute="0" name="N" />
|
||||
<arc begin="177" end="176" isPushBackRoute="0" name="N" />
|
||||
<arc begin="177" end="178" isPushBackRoute="0" name="N" />
|
||||
<arc begin="178" end="177" isPushBackRoute="0" name="N" />
|
||||
<arc begin="178" end="179" isPushBackRoute="0" name="N" />
|
||||
<arc begin="179" end="178" isPushBackRoute="0" name="N" />
|
||||
<arc begin="179" end="180" isPushBackRoute="0" name="N" />
|
||||
<arc begin="180" end="179" isPushBackRoute="0" name="N" />
|
||||
<arc begin="180" end="172" isPushBackRoute="0" name="N" />
|
||||
<arc begin="172" end="180" isPushBackRoute="0" name="N" />
|
||||
<arc begin="181" end="182" isPushBackRoute="0" name="N" />
|
||||
<arc begin="182" end="181" isPushBackRoute="0" name="N" />
|
||||
<arc begin="182" end="174" isPushBackRoute="0" name="N" />
|
||||
<arc begin="174" end="182" isPushBackRoute="0" name="N" />
|
||||
<arc begin="183" end="184" isPushBackRoute="0" name="N" />
|
||||
<arc begin="184" end="183" isPushBackRoute="0" name="N" />
|
||||
<arc begin="184" end="181" isPushBackRoute="0" name="N" />
|
||||
<arc begin="181" end="184" isPushBackRoute="0" name="N" />
|
||||
<arc begin="185" end="186" isPushBackRoute="0" name="N" />
|
||||
<arc begin="186" end="185" isPushBackRoute="0" name="N" />
|
||||
<arc begin="186" end="187" isPushBackRoute="0" name="N" />
|
||||
<arc begin="187" end="186" isPushBackRoute="0" name="N" />
|
||||
<arc begin="187" end="188" isPushBackRoute="0" name="N" />
|
||||
<arc begin="188" end="187" isPushBackRoute="0" name="N" />
|
||||
<arc begin="188" end="183" isPushBackRoute="0" name="N" />
|
||||
<arc begin="183" end="188" isPushBackRoute="0" name="N" />
|
||||
<arc begin="189" end="190" isPushBackRoute="0" name="N" />
|
||||
<arc begin="190" end="189" isPushBackRoute="0" name="N" />
|
||||
<arc begin="190" end="185" isPushBackRoute="0" name="N" />
|
||||
<arc begin="185" end="190" isPushBackRoute="0" name="N" />
|
||||
<arc begin="191" end="192" isPushBackRoute="0" name="N" />
|
||||
<arc begin="192" end="191" isPushBackRoute="0" name="N" />
|
||||
<arc begin="192" end="189" isPushBackRoute="0" name="N" />
|
||||
<arc begin="189" end="192" isPushBackRoute="0" name="N" />
|
||||
<arc begin="193" end="194" isPushBackRoute="0" name="N" />
|
||||
<arc begin="194" end="193" isPushBackRoute="0" name="N" />
|
||||
<arc begin="194" end="191" isPushBackRoute="0" name="N" />
|
||||
<arc begin="191" end="194" isPushBackRoute="0" name="N" />
|
||||
<arc begin="195" end="193" isPushBackRoute="0" name="N" />
|
||||
<arc begin="193" end="195" isPushBackRoute="0" name="N" />
|
||||
<arc begin="197" end="195" isPushBackRoute="0" name="N" />
|
||||
<arc begin="195" end="197" isPushBackRoute="0" name="N" />
|
||||
<arc begin="196" end="197" isPushBackRoute="0" name="N" />
|
||||
<arc begin="197" end="196" isPushBackRoute="0" name="N" />
|
||||
<arc begin="198" end="199" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="199" end="198" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="199" end="197" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="197" end="199" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="200" end="198" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="198" end="200" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="201" end="202" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="202" end="201" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="202" end="200" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="200" end="202" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="203" end="201" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="201" end="203" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="204" end="203" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="203" end="204" isPushBackRoute="0" name="Y" />
|
||||
<arc begin="205" end="204" isPushBackRoute="0" name="" />
|
||||
<arc begin="204" end="205" isPushBackRoute="0" name="" />
|
||||
<arc begin="206" end="205" isPushBackRoute="0" name="" />
|
||||
<arc begin="205" end="206" isPushBackRoute="0" name="" />
|
||||
<arc begin="210" end="206" isPushBackRoute="0" name="" />
|
||||
<arc begin="206" end="210" isPushBackRoute="0" name="" />
|
||||
<arc begin="211" end="207" isPushBackRoute="0" name="L" />
|
||||
<arc begin="207" end="211" isPushBackRoute="0" name="L" />
|
||||
<arc begin="209" end="208" isPushBackRoute="0" name="N" />
|
||||
<arc begin="208" end="209" isPushBackRoute="0" name="N" />
|
||||
<arc begin="219" end="218" isPushBackRoute="0" name="R3" />
|
||||
<arc begin="218" end="219" isPushBackRoute="0" name="R3" />
|
||||
<arc begin="220" end="219" isPushBackRoute="0" name="R3" />
|
||||
<arc begin="219" end="220" isPushBackRoute="0" name="R3" />
|
||||
<arc begin="222" end="221" isPushBackRoute="0" name="R17" />
|
||||
<arc begin="221" end="222" isPushBackRoute="0" name="R17" />
|
||||
<arc begin="0" end="223" isPushBackRoute="1" name="V109" />
|
||||
<arc begin="223" end="0" isPushBackRoute="1" name="V109" />
|
||||
<arc begin="223" end="92" isPushBackRoute="1" name="V109" />
|
||||
<arc begin="92" end="223" isPushBackRoute="1" name="V109" />
|
||||
<arc begin="1" end="224" isPushBackRoute="1" name="V115" />
|
||||
<arc begin="224" end="1" isPushBackRoute="1" name="V115" />
|
||||
<arc begin="224" end="96" isPushBackRoute="1" name="V115" />
|
||||
<arc begin="96" end="224" isPushBackRoute="1" name="V115" />
|
||||
<arc begin="2" end="225" isPushBackRoute="1" name="V118" />
|
||||
<arc begin="225" end="2" isPushBackRoute="1" name="V118" />
|
||||
<arc begin="225" end="95" isPushBackRoute="1" name="V118" />
|
||||
<arc begin="95" end="225" isPushBackRoute="1" name="V118" />
|
||||
<arc begin="3" end="226" isPushBackRoute="1" name="V110" />
|
||||
<arc begin="226" end="3" isPushBackRoute="1" name="V110" />
|
||||
<arc begin="226" end="91" isPushBackRoute="1" name="V110" />
|
||||
<arc begin="91" end="226" isPushBackRoute="1" name="V110" />
|
||||
<arc begin="4" end="227" isPushBackRoute="1" name="V100" />
|
||||
<arc begin="227" end="4" isPushBackRoute="1" name="V100" />
|
||||
<arc begin="227" end="167" isPushBackRoute="1" name="V100" />
|
||||
<arc begin="167" end="227" isPushBackRoute="1" name="V100" />
|
||||
<arc begin="5" end="228" isPushBackRoute="1" name="V95" />
|
||||
<arc begin="228" end="5" isPushBackRoute="1" name="V95" />
|
||||
<arc begin="228" end="166" isPushBackRoute="1" name="V95" />
|
||||
<arc begin="166" end="228" isPushBackRoute="1" name="V95" />
|
||||
<arc begin="6" end="229" isPushBackRoute="1" name="V92" />
|
||||
<arc begin="229" end="6" isPushBackRoute="1" name="V92" />
|
||||
<arc begin="229" end="165" isPushBackRoute="1" name="V92" />
|
||||
<arc begin="165" end="229" isPushBackRoute="1" name="V92" />
|
||||
<arc begin="7" end="230" isPushBackRoute="1" name="C16" />
|
||||
<arc begin="230" end="7" isPushBackRoute="1" name="C16" />
|
||||
<arc begin="230" end="97" isPushBackRoute="1" name="C16" />
|
||||
<arc begin="97" end="230" isPushBackRoute="1" name="C16" />
|
||||
<arc begin="8" end="231" isPushBackRoute="1" name="D4" />
|
||||
<arc begin="231" end="8" isPushBackRoute="1" name="D4" />
|
||||
<arc begin="231" end="177" isPushBackRoute="1" name="D4" />
|
||||
<arc begin="177" end="231" isPushBackRoute="1" name="D4" />
|
||||
<arc begin="9" end="232" isPushBackRoute="1" name="E5" />
|
||||
<arc begin="232" end="9" isPushBackRoute="1" name="E5" />
|
||||
<arc begin="232" end="94" isPushBackRoute="1" name="E5" />
|
||||
<arc begin="94" end="232" isPushBackRoute="1" name="E5" />
|
||||
<arc begin="10" end="233" isPushBackRoute="1" name="E9" />
|
||||
<arc begin="233" end="10" isPushBackRoute="1" name="E9" />
|
||||
<arc begin="233" end="93" isPushBackRoute="1" name="E9" />
|
||||
<arc begin="93" end="233" isPushBackRoute="1" name="E9" />
|
||||
<arc begin="11" end="234" isPushBackRoute="1" name="V268" />
|
||||
<arc begin="234" end="11" isPushBackRoute="1" name="V268" />
|
||||
<arc begin="234" end="81" isPushBackRoute="1" name="V268" />
|
||||
<arc begin="81" end="234" isPushBackRoute="1" name="V268" />
|
||||
<arc begin="12" end="235" isPushBackRoute="1" name="C4" />
|
||||
<arc begin="235" end="12" isPushBackRoute="1" name="C4" />
|
||||
<arc begin="235" end="102" isPushBackRoute="1" name="C4" />
|
||||
<arc begin="102" end="235" isPushBackRoute="1" name="C4" />
|
||||
<arc begin="13" end="236" isPushBackRoute="1" name="B28" />
|
||||
<arc begin="236" end="13" isPushBackRoute="1" name="B28" />
|
||||
<arc begin="236" end="105" isPushBackRoute="1" name="B28" />
|
||||
<arc begin="105" end="236" isPushBackRoute="1" name="B28" />
|
||||
<arc begin="14" end="237" isPushBackRoute="1" name="B48" />
|
||||
<arc begin="237" end="14" isPushBackRoute="1" name="B48" />
|
||||
<arc begin="237" end="104" isPushBackRoute="1" name="B48" />
|
||||
<arc begin="104" end="237" isPushBackRoute="1" name="B48" />
|
||||
<arc begin="15" end="238" isPushBackRoute="1" name="B44" />
|
||||
<arc begin="238" end="15" isPushBackRoute="1" name="B44" />
|
||||
<arc begin="238" end="101" isPushBackRoute="1" name="B44" />
|
||||
<arc begin="101" end="238" isPushBackRoute="1" name="B44" />
|
||||
<arc begin="16" end="239" isPushBackRoute="1" name="C8" />
|
||||
<arc begin="239" end="16" isPushBackRoute="1" name="C8" />
|
||||
<arc begin="239" end="100" isPushBackRoute="1" name="C8" />
|
||||
<arc begin="100" end="239" isPushBackRoute="1" name="C8" />
|
||||
<arc begin="17" end="240" isPushBackRoute="1" name="C14" />
|
||||
<arc begin="240" end="17" isPushBackRoute="1" name="C14" />
|
||||
<arc begin="240" end="98" isPushBackRoute="1" name="C14" />
|
||||
<arc begin="98" end="240" isPushBackRoute="1" name="C14" />
|
||||
<arc begin="18" end="241" isPushBackRoute="1" name="C2" />
|
||||
<arc begin="241" end="18" isPushBackRoute="1" name="C2" />
|
||||
<arc begin="241" end="102" isPushBackRoute="1" name="C2" />
|
||||
<arc begin="102" end="241" isPushBackRoute="1" name="C2" />
|
||||
<arc begin="19" end="242" isPushBackRoute="1" name="B22" />
|
||||
<arc begin="242" end="19" isPushBackRoute="1" name="B22" />
|
||||
<arc begin="242" end="109" isPushBackRoute="1" name="B22" />
|
||||
<arc begin="109" end="242" isPushBackRoute="1" name="B22" />
|
||||
<arc begin="20" end="243" isPushBackRoute="1" name="B23" />
|
||||
<arc begin="243" end="20" isPushBackRoute="1" name="B23" />
|
||||
<arc begin="243" end="105" isPushBackRoute="1" name="B23" />
|
||||
<arc begin="105" end="243" isPushBackRoute="1" name="B23" />
|
||||
<arc begin="21" end="244" isPushBackRoute="1" name="B10" />
|
||||
<arc begin="244" end="21" isPushBackRoute="1" name="B10" />
|
||||
<arc begin="244" end="110" isPushBackRoute="1" name="B10" />
|
||||
<arc begin="110" end="244" isPushBackRoute="1" name="B10" />
|
||||
<arc begin="22" end="245" isPushBackRoute="1" name="A66" />
|
||||
<arc begin="245" end="22" isPushBackRoute="1" name="A66" />
|
||||
<arc begin="245" end="116" isPushBackRoute="1" name="A66" />
|
||||
<arc begin="116" end="245" isPushBackRoute="1" name="A66" />
|
||||
<arc begin="23" end="246" isPushBackRoute="1" name="A54" />
|
||||
<arc begin="246" end="23" isPushBackRoute="1" name="A54" />
|
||||
<arc begin="246" end="117" isPushBackRoute="1" name="A54" />
|
||||
<arc begin="117" end="246" isPushBackRoute="1" name="A54" />
|
||||
<arc begin="24" end="247" isPushBackRoute="1" name="A16" />
|
||||
<arc begin="247" end="24" isPushBackRoute="1" name="A16" />
|
||||
<arc begin="247" end="123" isPushBackRoute="1" name="A16" />
|
||||
<arc begin="123" end="247" isPushBackRoute="1" name="A16" />
|
||||
<arc begin="25" end="248" isPushBackRoute="1" name="A28" />
|
||||
<arc begin="248" end="25" isPushBackRoute="1" name="A28" />
|
||||
<arc begin="248" end="122" isPushBackRoute="1" name="A28" />
|
||||
<arc begin="122" end="248" isPushBackRoute="1" name="A28" />
|
||||
<arc begin="26" end="249" isPushBackRoute="1" name="F224" />
|
||||
<arc begin="249" end="26" isPushBackRoute="1" name="F224" />
|
||||
<arc begin="249" end="83" isPushBackRoute="1" name="F224" />
|
||||
<arc begin="83" end="249" isPushBackRoute="1" name="F224" />
|
||||
<arc begin="27" end="250" isPushBackRoute="1" name="F211" />
|
||||
<arc begin="250" end="27" isPushBackRoute="1" name="F211" />
|
||||
<arc begin="250" end="83" isPushBackRoute="1" name="F211" />
|
||||
<arc begin="83" end="250" isPushBackRoute="1" name="F211" />
|
||||
<arc begin="28" end="251" isPushBackRoute="1" name="F219" />
|
||||
<arc begin="251" end="28" isPushBackRoute="1" name="F219" />
|
||||
<arc begin="251" end="190" isPushBackRoute="1" name="F219" />
|
||||
<arc begin="190" end="251" isPushBackRoute="1" name="F219" />
|
||||
<arc begin="29" end="252" isPushBackRoute="1" name="V266" />
|
||||
<arc begin="252" end="29" isPushBackRoute="1" name="V266" />
|
||||
<arc begin="252" end="82" isPushBackRoute="1" name="V266" />
|
||||
<arc begin="82" end="252" isPushBackRoute="1" name="V266" />
|
||||
<arc begin="30" end="253" isPushBackRoute="1" name="F235" />
|
||||
<arc begin="253" end="30" isPushBackRoute="1" name="F235" />
|
||||
<arc begin="253" end="70" isPushBackRoute="1" name="F235" />
|
||||
<arc begin="70" end="253" isPushBackRoute="1" name="F235" />
|
||||
<arc begin="31" end="254" isPushBackRoute="1" name="F231" />
|
||||
<arc begin="254" end="31" isPushBackRoute="1" name="F231" />
|
||||
<arc begin="254" end="69" isPushBackRoute="1" name="F231" />
|
||||
<arc begin="69" end="254" isPushBackRoute="1" name="F231" />
|
||||
<arc begin="32" end="255" isPushBackRoute="1" name="V178" />
|
||||
<arc begin="255" end="32" isPushBackRoute="1" name="V178" />
|
||||
<arc begin="255" end="194" isPushBackRoute="1" name="V178" />
|
||||
<arc begin="194" end="255" isPushBackRoute="1" name="V178" />
|
||||
<arc begin="33" end="256" isPushBackRoute="1" name="V174" />
|
||||
<arc begin="256" end="33" isPushBackRoute="1" name="V174" />
|
||||
<arc begin="256" end="85" isPushBackRoute="1" name="V174" />
|
||||
<arc begin="85" end="256" isPushBackRoute="1" name="V174" />
|
||||
<arc begin="34" end="257" isPushBackRoute="1" name="V169" />
|
||||
<arc begin="257" end="34" isPushBackRoute="1" name="V169" />
|
||||
<arc begin="257" end="86" isPushBackRoute="1" name="V169" />
|
||||
<arc begin="86" end="257" isPushBackRoute="1" name="V169" />
|
||||
<arc begin="35" end="258" isPushBackRoute="1" name="V164" />
|
||||
<arc begin="258" end="35" isPushBackRoute="1" name="V164" />
|
||||
<arc begin="258" end="190" isPushBackRoute="1" name="V164" />
|
||||
<arc begin="190" end="258" isPushBackRoute="1" name="V164" />
|
||||
<arc begin="36" end="259" isPushBackRoute="1" name="V159" />
|
||||
<arc begin="259" end="36" isPushBackRoute="1" name="V159" />
|
||||
<arc begin="259" end="88" isPushBackRoute="1" name="V159" />
|
||||
<arc begin="88" end="259" isPushBackRoute="1" name="V159" />
|
||||
<arc begin="37" end="260" isPushBackRoute="1" name="A40" />
|
||||
<arc begin="260" end="37" isPushBackRoute="1" name="A40" />
|
||||
<arc begin="260" end="121" isPushBackRoute="1" name="A40" />
|
||||
<arc begin="121" end="260" isPushBackRoute="1" name="A40" />
|
||||
<arc begin="38" end="261" isPushBackRoute="1" name="A17" />
|
||||
<arc begin="261" end="38" isPushBackRoute="1" name="A17" />
|
||||
<arc begin="261" end="108" isPushBackRoute="1" name="A17" />
|
||||
<arc begin="108" end="261" isPushBackRoute="1" name="A17" />
|
||||
<arc begin="39" end="262" isPushBackRoute="1" name="A1" />
|
||||
<arc begin="262" end="39" isPushBackRoute="1" name="A1" />
|
||||
<arc begin="262" end="110" isPushBackRoute="1" name="A1" />
|
||||
<arc begin="110" end="262" isPushBackRoute="1" name="A1" />
|
||||
</TaxiWaySegments>
|
||||
</groundnet>
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
<Approach Name="ILS28">
|
||||
<App_Waypoint ID="1">
|
||||
<Name>CF28</Name>
|
||||
<Type>Normal</Type>
|
||||
<Latitude>49.085211</Latitude>
|
||||
<Longitude>10.104772</Longitude>
|
||||
<Speed>0</Speed>
|
||||
<Altitude>5000</Altitude>
|
||||
<AltitudeCons>0</AltitudeCons>
|
||||
<AltitudeRestriction>above</AltitudeRestriction>
|
||||
<Flytype>Fly-by</Flytype>
|
||||
<BankLimit>25</BankLimit>
|
||||
<Sp_Turn>Auto</Sp_Turn>
|
||||
</App_Waypoint>
|
||||
<App_Waypoint ID="2">
|
||||
<Name>ESUVA</Name>
|
||||
<Type>Normal</Type>
|
||||
<Latitude>49.087931</Latitude>
|
||||
<Longitude>10.079558</Longitude>
|
||||
<Speed>0</Speed>
|
||||
<Altitude>5000</Altitude>
|
||||
<AltitudeCons>0</AltitudeCons>
|
||||
<AltitudeRestriction>at</AltitudeRestriction>
|
||||
<Flytype>Fly-by</Flytype>
|
||||
<BankLimit>25</BankLimit>
|
||||
<Sp_Turn>Auto</Sp_Turn>
|
||||
</App_Waypoint>
|
||||
<App_Waypoint ID="3">
|
||||
<Name>RW28</Name>
|
||||
<Type>Runway</Type>
|
||||
<Latitude>49.117467</Latitude>
|
||||
<Longitude>9.792336</Longitude>
|
||||
<Speed>0</Speed>
|
||||
<Altitude>1363</Altitude>
|
||||
<AltitudeCons>0</AltitudeCons>
|
||||
<AltitudeRestriction>at</AltitudeRestriction>
|
||||
<Flytype>Fly-by</Flytype>
|
||||
<BankLimit>25</BankLimit>
|
||||
<Sp_Turn>Auto</Sp_Turn>
|
||||
</App_Waypoint>
|
||||
<App_Waypoint ID="4">
|
||||
<Name>TY021</Name>
|
||||
<Type>Normal</Type>
|
||||
<Latitude>49.131786</Latitude>
|
||||
<Longitude>9.650253</Longitude>
|
||||
<Speed>0</Speed>
|
||||
<Altitude>4000</Altitude>
|
||||
<AltitudeCons>0</AltitudeCons>
|
||||
<AltitudeRestriction>above</AltitudeRestriction>
|
||||
<Flytype>Fly-over</Flytype>
|
||||
<BankLimit>25</BankLimit>
|
||||
<Sp_Turn>Auto</Sp_Turn>
|
||||
</App_Waypoint>
|
||||
<App_Waypoint ID="5">
|
||||
<Name>DKB</Name>
|
||||
<Type>Normal</Type>
|
||||
<Latitude>49.142753</Latitude>
|
||||
<Longitude>10.238306</Longitude>
|
||||
<Speed>0</Speed>
|
||||
<Altitude>5000</Altitude>
|
||||
<AltitudeCons>0</AltitudeCons>
|
||||
<AltitudeRestriction>at</AltitudeRestriction>
|
||||
<Flytype>Fly-by</Flytype>
|
||||
<BankLimit>25</BankLimit>
|
||||
<Sp_Turn>Right</Sp_Turn>
|
||||
</App_Waypoint>
|
||||
<App_Transition Name="DKB">
|
||||
<AppTr_Waypoint ID="1">
|
||||
<Name>DKB</Name>
|
||||
<Type>Normal</Type>
|
||||
<Latitude>49.142753</Latitude>
|
||||
<Longitude>10.238306</Longitude>
|
||||
<Speed>0</Speed>
|
||||
<Altitude>0</Altitude>
|
||||
<AltitudeCons>0</AltitudeCons>
|
||||
<AltitudeRestriction>at</AltitudeRestriction>
|
||||
<Flytype>Fly-by</Flytype>
|
||||
<BankLimit>25</BankLimit>
|
||||
<Sp_Turn>Auto</Sp_Turn>
|
||||
</AppTr_Waypoint>
|
||||
<AppTr_Waypoint ID="2">
|
||||
<Name>DKB</Name>
|
||||
<Type>DmeIntc</Type>
|
||||
<Latitude>49.142753</Latitude>
|
||||
<Longitude>10.238306</Longitude>
|
||||
<Speed>0</Speed>
|
||||
<Altitude>5000</Altitude>
|
||||
<AltitudeCons>0</AltitudeCons>
|
||||
<AltitudeRestriction>above</AltitudeRestriction>
|
||||
<Hdg_Crs>0</Hdg_Crs>
|
||||
<Hdg_Crs_value>214</Hdg_Crs_value>
|
||||
<Flytype>Fly-by</Flytype>
|
||||
<BankLimit>25</BankLimit>
|
||||
<DMEtoIntercept>4.0</DMEtoIntercept>
|
||||
<Sp_Turn>Auto</Sp_Turn>
|
||||
</AppTr_Waypoint>
|
||||
</App_Transition>
|
||||
</Approach>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
This is a simulation of a user-provided custom aircraft dir.
|
||||
|
||||
It contains a fake UFO which intentinoally is different to the one in FGData,
|
||||
for checking precedence of paths and options.
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
|
||||
<PropertyList>
|
||||
<sim>
|
||||
<description>Better UFO than FG data</description>
|
||||
</sim>
|
||||
<zot>42</zot>
|
||||
</PropertyList>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<PropertyList>
|
||||
<id>org.fg.test.catalog1</id>
|
||||
<description>First test catalog</description>
|
||||
<url>http://localhost:2000/catalogTest1/catalog.xml</url>
|
||||
<catalog-version>4</catalog-version>
|
||||
|
||||
<version>*</version>
|
||||
|
||||
|
||||
<package>
|
||||
<id>bob</id>
|
||||
<name>The Bob Craft</name>
|
||||
<revision type="int">8</revision>
|
||||
<file-size-bytes type="int">593</file-size-bytes>
|
||||
|
||||
<md5>a469c4b837f0521db48616cfe65ac1ea</md5>
|
||||
<url>http://localhost:2000/catalogTest1/alpha.zip</url>
|
||||
|
||||
<dir>bobCraft</dir>
|
||||
|
||||
</package>
|
||||
|
||||
</PropertyList>
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
set(TESTSUITE_SOURCES
|
||||
${TESTSUITE_SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TestSuite.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_AIFlightPlan.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_AIManager.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_traffic.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_TrafficMgr.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_groundnet.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_submodels.cxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_VectorMath.cxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
set(TESTSUITE_HEADERS
|
||||
${TESTSUITE_HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_AIFlightPlan.hxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_AIManager.hxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_traffic.hxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_TrafficMgr.hxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_groundnet.hxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_submodels.hxx
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_VectorMath.hxx
|
||||
PARENT_SCOPE
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user