From b22a60c85eeace10ad59a66dc1ae791459c37565 Mon Sep 17 00:00:00 2001 From: Kilian Hofmann Date: Tue, 6 Sep 2022 00:29:19 +0200 Subject: [PATCH] Namespaces Better File handling --- CMakeLists.txt | 2 +- file/config.hpp | 15 +- makerwysxp/CMakeLists.txt | 92 -------- makerwysxp/include/gate.hpp | 56 ----- makerwysxp/include/makeRwysXP.h | 30 --- makerwysxp/include/runway.hpp | 114 ---------- makerwysxp/makeRwysXP.cpp | 174 --------------- simdata/CMakeLists.txt | 92 ++++++++ simdata/gate.cpp | 52 +++++ simdata/include/gate.h | 68 ++++++ simdata/include/geodata.h | 208 ++++++++++++++++++ simdata/include/runway.h | 81 +++++++ simdata/include/simdata.h | 35 +++ .../include}/simulatorDatabase.hpp | 86 ++++---- simdata/runway.cpp | 81 +++++++ simdata/simdata.cpp | 184 ++++++++++++++++ utilities/include/stringExtensions.hpp | 53 ----- utilities/include/util.hpp | 98 +++++---- websocket/include/types.h | 89 ++++---- websocket/include/websocket.h | 35 +-- websocket/websocket.cpp | 173 ++++++++------- xplugin/CMakeLists.txt | 4 +- xplugin/include/main.h | 2 +- xplugin/main.cpp | 63 ++++-- 24 files changed, 1106 insertions(+), 781 deletions(-) delete mode 100644 makerwysxp/CMakeLists.txt delete mode 100644 makerwysxp/include/gate.hpp delete mode 100644 makerwysxp/include/makeRwysXP.h delete mode 100644 makerwysxp/include/runway.hpp delete mode 100644 makerwysxp/makeRwysXP.cpp create mode 100644 simdata/CMakeLists.txt create mode 100644 simdata/gate.cpp create mode 100644 simdata/include/gate.h create mode 100644 simdata/include/geodata.h create mode 100644 simdata/include/runway.h create mode 100644 simdata/include/simdata.h rename {file => simdata/include}/simulatorDatabase.hpp (65%) create mode 100644 simdata/runway.cpp create mode 100644 simdata/simdata.cpp delete mode 100644 utilities/include/stringExtensions.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a6373d..5d25527 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ add_subdirectory( ixwebsocket ) add_subdirectory( - makerwysxp + simdata ) add_subdirectory( xplugin diff --git a/file/config.hpp b/file/config.hpp index a8cd004..40740dc 100644 --- a/file/config.hpp +++ b/file/config.hpp @@ -1,8 +1,6 @@ #ifndef GERMANAIRLINESVA_GACONNECTOR_CONFIG_H #define GERMANAIRLINESVA_GACONNECTOR_CONFIG_H -#include "stringExtensions.hpp" - #include #include @@ -10,7 +8,9 @@ #include #include -namespace config +#include "util.hpp" + +namespace germanairlinesva_config { static inline std::map readConfig(const std::string &file) @@ -20,10 +20,10 @@ namespace config std::string line; while (std::getline(config, line)) { - std::vector fields = split(line, '='); + std::vector fields = germanairlinesva_util::split(line, '='); if (fields.size() >= 2) { - trim(fields[0]); - trim(fields[1]); + germanairlinesva_util::trim(fields[0]); + germanairlinesva_util::trim(fields[1]); settings[fields[0]] = fields[1]; } } @@ -32,7 +32,6 @@ namespace config return settings; } - static inline void writeConfig(const std::map &config, const std::string &file) @@ -43,5 +42,5 @@ namespace config } cfg.close(); } -} // namespace config +} // namespace germanairlinesva_config #endif diff --git a/makerwysxp/CMakeLists.txt b/makerwysxp/CMakeLists.txt deleted file mode 100644 index 3cad92c..0000000 --- a/makerwysxp/CMakeLists.txt +++ /dev/null @@ -1,92 +0,0 @@ -file(GLOB makerwysxp CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/makerwysxp/*.cpp) - -add_library(makerwysxp SHARED - ${makerwysxp} -) - -target_include_directories(makerwysxp PRIVATE - ${CMAKE_SOURCE_DIR}/makerwysxp/include - ${CMAKE_SOURCE_DIR}/utilities/include -) - -set_target_properties(makerwysxp PROPERTIES - PUBLIC_HEADER ${CMAKE_SOURCE_DIR}/makerwysxp/include -) -target_compile_definitions(makerwysxp PRIVATE - _USE_MATH_DEFINES -) -target_compile_options(makerwysxp PRIVATE - -Wall - -Wextra - -pedantic -) -if(DEBUG) - target_compile_options(makerwysxp PRIVATE - -g - ) - target_link_options(makerwysxp PRIVATE - -g - ) -else() - target_compile_options(makerwysxp PRIVATE - -O2 - ) -endif() - -if(APPLE) - message("Building makerwysxp for MacOSX Universal into ${PROJECT_BINARY_DIR}/${PLUGIN_NAME}") - - set_target_properties(makerwysxp PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Plugin/${PLUGIN_NAME}" - BUILD_WITH_INSTALL_NAME_DIR TRUE - ) - - target_compile_options(makerwysxp PRIVATE - "SHELL:-arch i386" - "SHELL:-arch x86_64" - ) - target_link_options(makerwysxp PRIVATE - "SHELL:-arch i386" - "SHELL:-arch x86_64" - ) - target_link_libraries(makerwysxp PRIVATE - "-framework Security" - ) -elseif(UNIX) - message("Building makerwysxp for Linux ${BIT} into ${PROJECT_BINARY_DIR}/Plugin/${PLUGIN_NAME}/${BIT}") - - set_target_properties(makerwysxp PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Plugin/${PLUGIN_NAME}/${BIT}" - ) - - target_compile_options(makerwysxp PRIVATE - -nodefaultlibs - ) - if(BIT STREQUAL "32") - target_compile_options(makerwysxp PRIVATE - -m32 - ) - target_link_options(makerwysxp PRIVATE - -m32 - ) - endif() -elseif(WIN32) - message("Building makerwysxp for Windows ${BIT} into ${PROJECT_BINARY_DIR}/Plugin/${PLUGIN_NAME}/${BIT}") - - set_target_properties(makerwysxp PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Plugin/${PLUGIN_NAME}/${BIT}" - ) - - if(DEBUG) - target_compile_options(makerwysxp PRIVATE - -gcodeview - ) - target_link_options(makerwysxp PRIVATE - -Wl,-pdb= - ) - endif() - target_link_options(makerwysxp PRIVATE - -static-libgcc - -static-libstdc++ - ) -endif() diff --git a/makerwysxp/include/gate.hpp b/makerwysxp/include/gate.hpp deleted file mode 100644 index 54f5386..0000000 --- a/makerwysxp/include/gate.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef GERMANAIRLINESVA_GACONNECTOR_GATE_H -#define GERMANAIRLINESVA_GACONNECTOR_GATE_H - -#include -#include -#include -#include -#include -#include - -/* - * Representation of X-Plane gate - * Heading in degrees (0...360) - * - * Length in bytes: 18 + length of designator - * Designator must be null terminated - * - * UINT8 | CHAR[] | DOUBLE | DOUBLE | UINT8 - * ------+------------+--------+--------+------ - * LEN | DESIGNATOR | LAT | LON | WIDTH - */ -class Gate -{ - private: - std::string designator; - double latitude; - double longitude; - std::vector file; - - public: - Gate(const std::string &designator, double latitude, double longitude) - { - - this->designator = designator; - this->latitude = latitude; - this->longitude = longitude; - - file = std::vector(18 + this->designator.length(), 0); - std::uint8_t *bufPtr = file.data(); - memset(bufPtr, - static_cast(this->designator.length()), - sizeof(std::uint8_t)); - bufPtr++; // Designator length - memcpy(bufPtr, this->designator.c_str(), this->designator.length()); - bufPtr += - this->designator.length() + 1; // Designator plus null termination - memcpy(bufPtr, &this->latitude, sizeof(this->latitude)); - bufPtr += 8; // Latitude - memcpy(bufPtr, &this->longitude, sizeof(this->longitude)); - } - - std::uint8_t *getBinaryData() { return file.data(); } - std::size_t getBinaryLength() { return file.size(); } -}; - -#endif \ No newline at end of file diff --git a/makerwysxp/include/makeRwysXP.h b/makerwysxp/include/makeRwysXP.h deleted file mode 100644 index 1b35b82..0000000 --- a/makerwysxp/include/makeRwysXP.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef GERMANAIRLINESVA_GACONNECTOR_XPLUGIN_MAKERWYSXP_H -#define GERMANAIRLINESVA_GACONNECTOR_XPLUGIN_MAKERWYSXP_H - -#include -#include -#include -#include - -#include "gate.hpp" -#include "runway.hpp" -#include "stringExtensions.hpp" -#include "util.hpp" - -int scan(const char *defaultFile, - const char *sceneryPack, - const char *logFile, - std::map, std::vector>> &airports); - -void makeAirport( - const std::string &kind, - std::ifstream *infile, - std::map, std::vector>> - *airports, - std::ofstream *logfile); -void makeGate15(std::vector *gates, std::vector fields); -void makeRunway(std::vector *runways, std::vector fields); -void makeGate1300(std::vector *gates, std::vector fields); - -#endif \ No newline at end of file diff --git a/makerwysxp/include/runway.hpp b/makerwysxp/include/runway.hpp deleted file mode 100644 index ec6a310..0000000 --- a/makerwysxp/include/runway.hpp +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef GERMANAIRLINESVA_GACONNECTOR_RUNWAY_H -#define GERMANAIRLINESVA_GACONNECTOR_RUNWAY_H - -#include -#include -#include -#include -#include - -#include "util.hpp" - -/* - * Representation of one X-Plane runway with supplementary information - * Heading in degrees (0...360) - * Width and length in feet - * - * Length in bytes: 23 + length of designator - * Designator must be null terminated - * - * UINT8 | CHAR[] | DOUBLE | DOUBLE | UINT8 | UINT16 | UINT16 - * ------+------------+--------+--------+-------+--------+------- - * LEN | DESIGNATOR | LAT | LON | WIDTH | LENGTH | TRUHDG - */ -class Runway -{ - private: - std::string designator; - double latitudeStart; - double longitudeStart; - std::uint8_t width; - std::uint16_t length; - std::uint16_t trueHeading; - std::vector file; - - public: - Runway(std::string designator, - double latitudeStart, - double longitudeStart, - double latitudeEnd, - double longitudeEnd, - double width) - { - this->designator = std::move(designator); - this->latitudeStart = latitudeStart; - this->longitudeStart = longitudeStart; - this->width = (std::uint8_t)std::round(util::to_feet(width)); - double dist = util::distanceEarth(latitudeStart, - longitudeStart, - latitudeEnd, - longitudeEnd); - this->length = (std::uint16_t)std::round(util::to_feet(dist)); - this->trueHeading = - (std::uint16_t)std::round(util::bearing(latitudeStart, - longitudeStart, - latitudeEnd, - longitudeEnd)); - - file = std::vector(23 + this->designator.length(), 0); - std::uint8_t *bufPtr = file.data(); - memset(bufPtr, - static_cast(this->designator.length()), - sizeof(std::uint8_t)); - bufPtr++; - memcpy(bufPtr, this->designator.c_str(), this->designator.length()); - bufPtr += this->designator.length() + 1; - memcpy(bufPtr, &this->latitudeStart, sizeof(this->latitudeStart)); - bufPtr += sizeof(this->latitudeStart); - memcpy(bufPtr, &this->longitudeStart, sizeof(this->longitudeStart)); - bufPtr += sizeof(this->longitudeStart); - memcpy(bufPtr, &this->width, sizeof(this->width)); - bufPtr += sizeof(this->width); - memcpy(bufPtr, &this->length, sizeof(this->length)); - bufPtr += sizeof(this->length); - memcpy(bufPtr, &this->trueHeading, sizeof(this->trueHeading)); - } - - Runway(std::string designator, - double latitudeStart, - double longitudeStart, - std::uint8_t width, - std::uint16_t length, - std::uint16_t trueHeading) - { - this->designator = std::move(designator); - this->latitudeStart = latitudeStart; - this->longitudeStart = longitudeStart; - this->width = width; - this->length = length; - this->trueHeading = trueHeading; - - file = std::vector(23 + this->designator.length(), 0); - std::uint8_t *bufPtr = file.data(); - memset(bufPtr, - static_cast(this->designator.length()), - sizeof(std::uint8_t)); - bufPtr++; - memcpy(bufPtr, this->designator.c_str(), this->designator.length()); - bufPtr += this->designator.length() + 1; - memcpy(bufPtr, &this->latitudeStart, sizeof(this->latitudeStart)); - bufPtr += sizeof(this->latitudeStart); - memcpy(bufPtr, &this->longitudeStart, sizeof(this->longitudeStart)); - bufPtr += sizeof(this->longitudeStart); - memcpy(bufPtr, &this->width, sizeof(this->width)); - bufPtr += sizeof(this->width); - memcpy(bufPtr, &this->length, sizeof(this->length)); - bufPtr += sizeof(this->length); - memcpy(bufPtr, &this->trueHeading, sizeof(this->trueHeading)); - } - - std::uint8_t *getBinaryData() { return file.data(); } - std::size_t getBinaryLength() { return file.size(); } -}; - -#endif \ No newline at end of file diff --git a/makerwysxp/makeRwysXP.cpp b/makerwysxp/makeRwysXP.cpp deleted file mode 100644 index 9b0c013..0000000 --- a/makerwysxp/makeRwysXP.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include "include/makeRwysXP.h" - -int scan(const char *defaultFile, - const char *sceneryPack, - const char *logFile, - std::map, std::vector>> &airports) -{ - std::ifstream base(defaultFile); - if (!base.good()) { - return 1; - } - std::ifstream custom(sceneryPack); - if (!custom.good()) { - base.close(); - return 2; - } - std::ofstream logfile(logFile, std::ios::out | std::ios::trunc); - if (!logfile.good()) { - base.close(); - custom.close(); - return 3; - } - - // Default - logfile << " " << defaultFile << std::endl; - makeAirport("DEFAULT", &base, &airports, &logfile); - base.close(); - - std::string line; - size_t pos; - std::vector packs; - while (std::getline(custom, line)) { - if ((pos = line.find("SCENERY_PACK")) != std::string::npos) { - std::string path = - rtrim_copy(line.substr(pos + 13)) + "Earth nav data/apt.dat"; - packs.push_back(path); - } - } - std::reverse(packs.begin(), packs.end()); - - for (std::string const &path : packs) { - std::ifstream pack(path); - if (pack.good()) { - logfile << " " << path << std::endl; - makeAirport("CUSTOM", &pack, &airports, &logfile); - pack.close(); - } else { - pack.close(); - logfile << "" - << "Could not find " << path << std::endl; - } - } - - logfile << std::endl - << " Total airports: " << airports.size() << std::endl; - - custom.close(); - logfile.close(); - return 0; -} - -void makeAirport( - const std::string &kind, - std::ifstream *infile, - std::map, std::vector>> - *airports, - std::ofstream *logfile) -{ - std::string line; - std::string *currentIcao = nullptr; - std::vector tmpGates; - std::vector tmpRunways; - - int apCount = 0; - int validCount = 0; - - while (std::getline(*infile, line)) { - std::vector fields = split(line, ' '); - fields = util::select_T(fields, [](const std::string &s) { - return s.length() > 0; - }); - - if (fields.empty()) - continue; - if (fields[0] == "1") { - // Write to file if ICAO is valid, and we have gates and runways - if (currentIcao != nullptr && !tmpRunways.empty() && !tmpGates.empty()) { - (*airports)[*currentIcao] = {tmpGates, tmpRunways}; - validCount += 1; - *logfile << "\t " << *currentIcao << " committed" << std::endl; - } else if (currentIcao != nullptr) { - *logfile << "\t " << *currentIcao << " had no gates or runways" - << std::endl; - } - tmpGates = std::vector(); - tmpRunways = std::vector(); - currentIcao = new std::string(fields[4]); - apCount += 1; - *logfile << "\t<" << kind << "> " << line << std::endl; - } else if (currentIcao != nullptr && fields[0] == "15") { - makeGate15(&tmpGates, fields); - *logfile << "\t\t " << line << std::endl; - } else if (fields[0] == "16" || fields[0] == "17") { - // Write to file if ICAO is valid, and we have gates and runways - if (currentIcao != nullptr && !tmpRunways.empty() && !tmpGates.empty()) { - (*airports)[*currentIcao] = {tmpGates, tmpRunways}; - validCount += 1; - *logfile << "\t " << *currentIcao << " committed" << std::endl; - } else if (currentIcao != nullptr) { - *logfile << "\t " << *currentIcao << " had no gates or runways" - << std::endl; - } - tmpGates = std::vector(); - tmpRunways = std::vector(); - currentIcao = nullptr; - *logfile << "\t<" << kind << " SKIPPED> " << line << std::endl; - } else if (currentIcao != nullptr && fields[0] == "100") { - makeRunway(&tmpRunways, fields); - *logfile << "\t\t " << line << std::endl; - } else if (currentIcao != nullptr && fields[0] == "1300") { - makeGate1300(&tmpGates, fields); - *logfile << "\t\t " << line << std::endl; - } - } - - if (currentIcao != nullptr && !tmpRunways.empty() && !tmpGates.empty()) { - (*airports)[*currentIcao] = {tmpGates, tmpRunways}; - validCount += 1; - *logfile << "\t " << *currentIcao << " committed" << std::endl; - } - *logfile << " " << apCount << " airports found, of which " - << validCount << " are valid" << std::endl; -} - -void makeGate15(std::vector *gates, std::vector fields) -{ - std::string gateName; - for (size_t j = 4; j < fields.size() - 1; j++) { - gateName += fields[j] + " "; - } - gateName += fields.back(); - gateName = std::regex_replace(gateName, std::regex{","}, "0"); - - gates->push_back(Gate{gateName, std::stod(fields[1]), std::stod(fields[2])}); -} - -void makeRunway(std::vector *runways, std::vector fields) -{ - runways->push_back(Runway{fields[8], - std::stod(fields[9]), - std::stod(fields[10]), - std::stod(fields[18]), - std::stod(fields[19]), - std::stod(fields[1])}); - runways->push_back(Runway{fields[17], - std::stod(fields[18]), - std::stod(fields[19]), - std::stod(fields[9]), - std::stod(fields[10]), - std::stod(fields[1])}); -} - -void makeGate1300(std::vector *gates, std::vector fields) -{ - std::string gateName; - for (size_t j = 6; j < fields.size() - 1; j++) { - gateName += fields[j] + " "; - } - gateName += fields.back(); - gateName = std::regex_replace(gateName, std::regex{","}, "0"); - - gates->push_back(Gate{gateName, std::stod(fields[1]), std::stod(fields[2])}); -} \ No newline at end of file diff --git a/simdata/CMakeLists.txt b/simdata/CMakeLists.txt new file mode 100644 index 0000000..79ebe7e --- /dev/null +++ b/simdata/CMakeLists.txt @@ -0,0 +1,92 @@ +file(GLOB simdata CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/simdata/*.cpp) + +add_library(simdata SHARED + ${simdata} +) + +target_include_directories(simdata PRIVATE + ${CMAKE_SOURCE_DIR}/simdata/include + ${CMAKE_SOURCE_DIR}/utilities/include +) + +set_target_properties(simdata PROPERTIES + PUBLIC_HEADER ${CMAKE_SOURCE_DIR}/simdata/include +) +target_compile_definitions(simdata PRIVATE + _USE_MATH_DEFINES +) +target_compile_options(simdata PRIVATE + -Wall + -Wextra + -pedantic +) +if(DEBUG) + target_compile_options(simdata PRIVATE + -g + ) + target_link_options(simdata PRIVATE + -g + ) +else() + target_compile_options(simdata PRIVATE + -O2 + ) +endif() + +if(APPLE) + message("Building simdata for MacOSX Universal into ${PROJECT_BINARY_DIR}/${PLUGIN_NAME}") + + set_target_properties(simdata PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Plugin/${PLUGIN_NAME}" + BUILD_WITH_INSTALL_NAME_DIR TRUE + ) + + target_compile_options(simdata PRIVATE + "SHELL:-arch i386" + "SHELL:-arch x86_64" + ) + target_link_options(simdata PRIVATE + "SHELL:-arch i386" + "SHELL:-arch x86_64" + ) + target_link_libraries(simdata PRIVATE + "-framework Security" + ) +elseif(UNIX) + message("Building simdata for Linux ${BIT} into ${PROJECT_BINARY_DIR}/Plugin/${PLUGIN_NAME}/${BIT}") + + set_target_properties(simdata PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Plugin/${PLUGIN_NAME}/${BIT}" + ) + + target_compile_options(simdata PRIVATE + -nodefaultlibs + ) + if(BIT STREQUAL "32") + target_compile_options(simdata PRIVATE + -m32 + ) + target_link_options(simdata PRIVATE + -m32 + ) + endif() +elseif(WIN32) + message("Building simdata for Windows ${BIT} into ${PROJECT_BINARY_DIR}/Plugin/${PLUGIN_NAME}/${BIT}") + + set_target_properties(simdata PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Plugin/${PLUGIN_NAME}/${BIT}" + ) + + if(DEBUG) + target_compile_options(simdata PRIVATE + -gcodeview + ) + target_link_options(simdata PRIVATE + -Wl,-pdb= + ) + endif() + target_link_options(simdata PRIVATE + -static-libgcc + -static-libstdc++ + ) +endif() diff --git a/simdata/gate.cpp b/simdata/gate.cpp new file mode 100644 index 0000000..fdfbc0b --- /dev/null +++ b/simdata/gate.cpp @@ -0,0 +1,52 @@ +#include "gate.h" + +namespace germanairlinesva_simdata +{ + Gate::Gate(const std::string &designator, + double latitude, + double longitude, + std::uint8_t radius) + { + this->designator = designator; + this->center = {latitude, longitude}; + this->radius = radius; + + file = std::vector(1 + this->designator.length() + 1 + + sizeof(center) + sizeof(radius), + 0); + std::uint8_t *bufPtr = file.data(); + memset(bufPtr, + static_cast(this->designator.length()), + sizeof(std::uint8_t)); + bufPtr++; + memcpy(bufPtr, this->designator.c_str(), this->designator.length()); + bufPtr += this->designator.length() + 1; + memcpy(bufPtr, &this->center, sizeof(this->center)); + bufPtr += sizeof(this->center); + memcpy(bufPtr, &this->radius, sizeof(this->radius)); + } + + // From database + Gate::Gate(const std::string &designator, + germanairlinesva_geodata::point center, + std::uint8_t radius) + { + this->designator = designator; + this->center = center; + this->radius = radius; + + file = std::vector(1 + this->designator.length() + 1 + + sizeof(center) + sizeof(radius), + 0); + std::uint8_t *bufPtr = file.data(); + memset(bufPtr, + static_cast(this->designator.length()), + sizeof(std::uint8_t)); + bufPtr++; + memcpy(bufPtr, this->designator.c_str(), this->designator.length()); + bufPtr += this->designator.length() + 1; + memcpy(bufPtr, &this->center, sizeof(this->center)); + bufPtr += sizeof(this->center); + memcpy(bufPtr, &this->radius, sizeof(this->radius)); + } +} // namespace germanairlinesva_simdata \ No newline at end of file diff --git a/simdata/include/gate.h b/simdata/include/gate.h new file mode 100644 index 0000000..a7535a4 --- /dev/null +++ b/simdata/include/gate.h @@ -0,0 +1,68 @@ +#ifndef GERMANAIRLINESVA_GACONNECTOR_GATE_H +#define GERMANAIRLINESVA_GACONNECTOR_GATE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "geodata.h" + +namespace germanairlinesva_simdata +{ + /* + * Representation of gate + * Heading in degrees (0...360) + * Radius in metres + * + * Designator must be null terminated + * + * UINT8 | CHAR[] | POINT | UINT8 + * -------+------------+--------+------- + * STRLEN | DESIGNATOR | CENTER | RADIUS + */ + class Gate + { + private: + std::string designator; + germanairlinesva_geodata::point center; + std::uint8_t radius; + std::vector file; + + public: + // From X-Plane or MakeRwys + Gate(const std::string &designator, + double latitude, + double longitude, + std::uint8_t radius); + // From database + Gate(const std::string &designator, + germanairlinesva_geodata::point center, + std::uint8_t radius); + + std::uint8_t *getBinaryData() { return file.data(); } + std::size_t getBinaryLength() { return file.size(); } + + std::string to_string() const + { + std::ostringstream str; + str << "Gate " << this->designator << " at " << this->center.latitude + << "N " << this->center.longitude << "E, Radius " + << (int)this->radius; + return str.str(); + } + + friend std::ostream &operator<<(std::ostream &os, const Gate &gate); + }; + + inline std::ostream &operator<<(std::ostream &os, const Gate &gate) + { + return os << gate.to_string(); + } +} // namespace germanairlinesva_simdata + +#endif \ No newline at end of file diff --git a/simdata/include/geodata.h b/simdata/include/geodata.h new file mode 100644 index 0000000..37c2395 --- /dev/null +++ b/simdata/include/geodata.h @@ -0,0 +1,208 @@ +#ifndef GERMANAIRLINESVA_GACONNECTOR_GEODATA_H +#define GERMANAIRLINESVA_GACONNECTOR_GEODATA_H + +#ifdef IBM +#define WIN32_LEAN_AND_MEAN +#endif + +#define BUFSIZE 1024 +#define MD5LEN 16 +#define EARTH_M 6371000 + +#include + +#pragma pack(push) +#pragma pack(1) + +namespace germanairlinesva_geodata +{ + struct point { + double latitude; + double longitude; + }; + + struct box { + struct point topLeft; + struct point topRight; + struct point bottomRight; + struct point bottomLeft; + }; + + static inline double toFeet(double value) { return value * 3.280839895; } + + static inline double toDegrees(double value) { return value * 180 / M_PI; } + + static inline double toRadians(double value) { return value * M_PI / 180; } + + static inline double normalize(double value) + { + return fmod(value + 360, 360); + } + + // Input and Output in degrees + static inline double bearingDD(double fromLatitude, + double fromLongitude, + double toLatitude, + double toLongitude) + { + double y = sin(toRadians(toLongitude) - toRadians(fromLongitude)) * + cos(toRadians(toLatitude)); + double x = cos(toRadians(fromLatitude)) * sin(toRadians(toLatitude)) - + sin(toRadians(fromLatitude)) * cos(toRadians(toLatitude)) * + cos(toRadians(toLongitude) - toRadians(fromLongitude)); + + return normalize(toDegrees(atan2(y, x))); + } + + // Input in degrees, Output in metres + static inline double distanceEarthD(double fromLatitude, + double fromLongitude, + double toLatitude, + double toLongitude) + { + double lat1r, lon1r, lat2r, lon2r, u, v; + lat1r = toRadians(fromLatitude); + lon1r = toRadians(fromLongitude); + lat2r = toRadians(toLatitude); + lon2r = toRadians(toLongitude); + u = sin((lat2r - lat1r) / 2); + v = sin((lon2r - lon1r) / 2); + return 2.0 * EARTH_M * asin(sqrt(u * u + cos(lat1r) * cos(lat2r) * v * v)); + } + + // Input and Output in degrees + static inline struct point calculatePointDD(struct point coordinates, + double bearing, + double distance) + { + double r_latitude = toRadians(coordinates.latitude); + double r_longitude = toRadians(coordinates.longitude); + double r_bearing = toRadians(bearing); + + double newLatitude = + std::asin(std::sin(r_latitude) * std::cos(distance / EARTH_M) + + std::cos(r_latitude) * std::sin(distance / EARTH_M) * + std::cos(r_bearing)); + double newLongitude = + r_longitude + + std::atan2(std::sin(r_bearing) * std::sin(distance / EARTH_M) * + std::cos(r_latitude), + std::cos(distance / EARTH_M) - + std::sin(r_latitude) * std::sin(newLatitude)); + + return {toDegrees(newLatitude), toDegrees(newLongitude)}; + } + + // Input in degrees, Output in radians + static inline struct point calculatePointDR(struct point coordinates, + double bearing, + double distance) + { + double r_latitude = toRadians(coordinates.latitude); + double r_longitude = toRadians(coordinates.longitude); + double r_bearing = toRadians(bearing); + + double newLatitude = + std::asin(std::sin(r_latitude) * std::cos(distance / EARTH_M) + + std::cos(r_latitude) * std::sin(distance / EARTH_M) * + std::cos(r_bearing)); + double newLongitude = + r_longitude + + std::atan2(std::sin(r_bearing) * std::sin(distance / EARTH_M) * + std::cos(r_latitude), + std::cos(distance / EARTH_M) - + std::sin(r_latitude) * std::sin(newLatitude)); + + return {newLatitude, newLongitude}; + } + + // LAT/LON in radians, BEARING/Output in degrees + static inline struct point calculatePointRD(struct point coordinates, + double bearing, + double distance) + { + double r_bearing = toRadians(bearing); + + double newLatitude = std::asin( + std::sin(coordinates.latitude) * std::cos(distance / EARTH_M) + + std::cos(coordinates.latitude) * std::sin(distance / EARTH_M) * + std::cos(r_bearing)); + double newLongitude = + coordinates.longitude + + std::atan2(std::sin(r_bearing) * std::sin(distance / EARTH_M) * + std::cos(coordinates.latitude), + std::cos(distance / EARTH_M) - + std::sin(coordinates.latitude) * std::sin(newLatitude)); + + return {toDegrees(newLatitude), toDegrees(newLongitude)}; + } + + // LAT/LON/Output in radians, BEARING in degrees + static inline struct point calculatePointRR(struct point coordinates, + double bearing, + double distance) + { + double r_bearing = toRadians(bearing); + + double newLatitude = std::asin( + std::sin(coordinates.latitude) * std::cos(distance / EARTH_M) + + std::cos(coordinates.latitude) * std::sin(distance / EARTH_M) * + std::cos(r_bearing)); + double newLongitude = + coordinates.longitude + + std::atan2(std::sin(r_bearing) * std::sin(distance / EARTH_M) * + std::cos(coordinates.latitude), + std::cos(distance / EARTH_M) - + std::sin(coordinates.latitude) * std::sin(newLatitude)); + + return {newLatitude, newLongitude}; + } + + // Input in degrees, calculate from center + static inline box calculateBoxDD(struct point center, + double bearing, + double length, + double width) + { + struct point primaryCenter = calculatePointDR(center, bearing, -length / 2); + struct point secondaryCenter = + calculatePointDR(center, bearing, length / 2); + double offsetHeadingNorth = + bearing - 90 > 0 ? bearing - 90 : bearing - 90 + 360; + struct point primaryTop = + calculatePointRD(primaryCenter, offsetHeadingNorth, width / 2); + struct point primaryBottom = + calculatePointRD(primaryCenter, offsetHeadingNorth, -width / 2); + struct point secondaryTop = + calculatePointRD(secondaryCenter, offsetHeadingNorth, width / 2); + struct point secondaryBottom = + calculatePointRD(secondaryCenter, offsetHeadingNorth, -width / 2); + + return {primaryTop, secondaryTop, secondaryBottom, primaryBottom}; + } + + // Input in degrees, calculate from start end + static inline box calculateBoxDD(struct point start, + struct point end, + double bearing, + double width) + { + double offsetHeadingNorth = + bearing - 90 > 0 ? bearing - 90 : bearing - 90 + 360; + struct point primaryTop = + calculatePointDD(start, offsetHeadingNorth, width / 2); + struct point primaryBottom = + calculatePointDD(start, offsetHeadingNorth, -width / 2); + struct point secondaryTop = + calculatePointDD(end, offsetHeadingNorth, width / 2); + struct point secondaryBottom = + calculatePointDD(end, offsetHeadingNorth, -width / 2); + + return {primaryTop, secondaryTop, secondaryBottom, primaryBottom}; + } + +} // namespace germanairlinesva_geodata + +#pragma pack(pop) + +#endif \ No newline at end of file diff --git a/simdata/include/runway.h b/simdata/include/runway.h new file mode 100644 index 0000000..91f32f5 --- /dev/null +++ b/simdata/include/runway.h @@ -0,0 +1,81 @@ +#ifndef GERMANAIRLINESVA_GACONNECTOR_RUNWAY_H +#define GERMANAIRLINESVA_GACONNECTOR_RUNWAY_H + +#include +#include +#include +#include +#include +#include + +#include "geodata.h" +#include "util.hpp" + +namespace germanairlinesva_simdata +{ + /* + * Representation of one runway with supplementary information + * Heading in degrees (0...360) true + * Width and length in meters + * + * Designator must be null terminated + * + * UINT8 | CHAR[] | BOX | UINT8 | UINT16 | UINT16 + * -------+------------+--------+-------+--------+------- + * STRLEN | DESIGNATOR | BOUNDS | WIDTH | LENGTH | TRUHDG + */ + class Runway + { + private: + std::string designator; + struct germanairlinesva_geodata::box bounds; + std::uint8_t width; + std::uint16_t length; + std::uint16_t trueHeading; + std::vector file; + + public: + // From X-Plane or MakeRwys + Runway(std::string designator, + double latitudeStart, + double longitudeStart, + double latitudeEnd, + double longitudeEnd, + double width); + // From database + Runway(std::string designator, + struct germanairlinesva_geodata::box bounds, + std::uint8_t width, + std::uint16_t length, + std::uint16_t trueHeading); + + std::uint8_t *getBinaryData() { return file.data(); } + std::size_t getBinaryLength() { return file.size(); } + + std::string to_string() const + { + std::ostringstream str; + str << "Runway " << this->designator << " with bounds " + << this->bounds.topLeft.latitude << "N " + << this->bounds.topLeft.longitude << "E, " + << this->bounds.topRight.latitude << "N " + << this->bounds.topRight.longitude << "E, " + << this->bounds.bottomRight.latitude << "N " + << this->bounds.bottomRight.longitude << "E, " + << this->bounds.bottomLeft.latitude << "N " + << this->bounds.bottomLeft.longitude << "E, " + << "Width " << (int)this->width << "m, Length " << this->length + << "m, True Heading " << this->trueHeading << "°"; + return str.str(); + } + + friend std::ostream &operator<<(std::ostream &os, const Runway &runway); + }; + + inline std::ostream &operator<<(std::ostream &os, const Runway &runway) + { + return os << runway.to_string(); + } +} // namespace germanairlinesva_simdata + +#endif \ No newline at end of file diff --git a/simdata/include/simdata.h b/simdata/include/simdata.h new file mode 100644 index 0000000..bee1487 --- /dev/null +++ b/simdata/include/simdata.h @@ -0,0 +1,35 @@ +#ifndef GERMANAIRLINESVA_GACONNECTOR_SIMDATA_H +#define GERMANAIRLINESVA_GACONNECTOR_SIMDATA_H + +#include +#include +#include +#include + +#include "gate.h" +#include "runway.h" +#include "util.hpp" + +namespace germanairlinesva_simdata +{ + int scan( + const char *defaultFile, + const char *sceneryPack, + const char *logFile, + std::map, std::vector>> + &airports); + + void makeAirport( + const std::string &kind, + std::ifstream *infile, + std::map, std::vector>> + *airports, + std::ofstream *logfile); + void makeGate15(std::vector *gates, std::vector fields); + void makeRunway(std::vector *runways, + std::vector fields); + void makeGate1300(std::vector *gates, std::vector fields); + +} // namespace germanairlinesva_simdata + +#endif \ No newline at end of file diff --git a/file/simulatorDatabase.hpp b/simdata/include/simulatorDatabase.hpp similarity index 65% rename from file/simulatorDatabase.hpp rename to simdata/include/simulatorDatabase.hpp index 9a951fc..fe90bff 100644 --- a/file/simulatorDatabase.hpp +++ b/simdata/include/simulatorDatabase.hpp @@ -1,9 +1,8 @@ #ifndef GERMANAIRLINESVA_GACONNECTOR_SIMULATORDATABASE_H #define GERMANAIRLINESVA_GACONNECTOR_SIMULATORDATABASE_H -#include "gate.hpp" -#include "runway.hpp" -#include "stringExtensions.hpp" +#include "gate.h" +#include "runway.h" #define CURRENT_VERSION 1 @@ -25,17 +24,19 @@ /* * Airport * - * UINT8 | CHAR[] | UINT16 | GATE[] | UINT8 | RUNWAY[] + * UINT8 | CHAR[] | UINT16 | GATE[] | UINT8 | RUNWAY[] * --------+--------+----------+--------+---------+--------- - * STRLEN | ICAO | NUMGATES | GATES | NUMRWYS | RUNWAYS + * STRLEN | ICAO | NUMGATES | GATES | NUMRWYS | RUNWAYS */ -namespace simulatorDatabase +namespace germanairlinesva_simdata { - static inline void toFile( - std::map, std::vector>> - &airports, - const std::string &file) + static inline void + toFile(std::map, + std::vector>> + &airports, + const std::string &file) { std::uint8_t null = 0; std::ofstream out(file, std::fstream::binary); @@ -48,12 +49,15 @@ namespace simulatorDatabase out.write(reinterpret_cast(&numAirports), sizeof(numAirports)); // Airport - for (const std::pair, std::vector>> + for (const std::pair< + const std::string, + std::pair, + std::vector>> &airport : airports) { std::string icao = airport.first; - std::vector gates = airport.second.first; - std::vector runways = airport.second.second; + std::vector gates = airport.second.first; + std::vector runways = + airport.second.second; // ICAO std::uint8_t icaoLength = icao.length(); out.write(reinterpret_cast(&icaoLength), @@ -63,7 +67,7 @@ namespace simulatorDatabase // Gates std::uint16_t numGates = gates.size(); out.write(reinterpret_cast(&numGates), sizeof(numGates)); - for (Gate &gate : gates) { + for (germanairlinesva_simdata::Gate &gate : gates) { out.write(reinterpret_cast(gate.getBinaryData()), (std::streamsize)gate.getBinaryLength()); } @@ -71,7 +75,7 @@ namespace simulatorDatabase std::uint8_t numRunways = runways.size(); out.write(reinterpret_cast(&numRunways), sizeof(numRunways)); - for (Runway &runway : runways) { + for (germanairlinesva_simdata::Runway &runway : runways) { out.write(reinterpret_cast(runway.getBinaryData()), (std::streamsize)runway.getBinaryLength()); } @@ -79,11 +83,15 @@ namespace simulatorDatabase out.close(); } - static inline std::map, std::vector>> + static inline std::map< + std::string, + std::pair, + std::vector>> readVersion1(std::ifstream &in) { - std::map, std::vector>> + std::map, + std::vector>> airports; std::uint16_t numAirports; @@ -106,14 +114,14 @@ namespace simulatorDatabase char *designator = static_cast(calloc(designatorLength + 1, sizeof(char))); in.read(designator, designatorLength + 1); - // Latitude - double latitude; - in.read(reinterpret_cast(&latitude), sizeof(latitude)); - // Latitude - double longitude; - in.read(reinterpret_cast(&longitude), sizeof(longitude)); + // Center + germanairlinesva_geodata::point center; + in.read(reinterpret_cast(¢er), sizeof(center)); + // Radius + std::uint8_t radius; + in.read(reinterpret_cast(&radius), sizeof(radius)); - airports[icao].first.emplace_back(designator, latitude, longitude); + airports[icao].first.emplace_back(designator, center, radius); } // Runways std::uint8_t numRunways; @@ -126,12 +134,9 @@ namespace simulatorDatabase char *designator = static_cast(calloc(designatorLength + 1, sizeof(char))); in.read(designator, designatorLength + 1); - // Latitude - double latitude; - in.read(reinterpret_cast(&latitude), sizeof(latitude)); - // Latitude - double longitude; - in.read(reinterpret_cast(&longitude), sizeof(longitude)); + // Bounds + germanairlinesva_geodata::box bounds; + in.read(reinterpret_cast(&bounds), sizeof(bounds)); // Width std::uint8_t width; in.read(reinterpret_cast(&width), sizeof(width)); @@ -143,8 +148,7 @@ namespace simulatorDatabase in.read(reinterpret_cast(&trueHeading), sizeof(trueHeading)); airports[icao].second.emplace_back(designator, - latitude, - longitude, + bounds, width, length, trueHeading); @@ -156,13 +160,17 @@ namespace simulatorDatabase return airports; } - static inline std::map, std::vector>> + static inline std::map< + std::string, + std::pair, + std::vector>> fromFile(const std::string &file) { - std::map, std::vector>> + std::map, + std::vector>> airports; - std::ifstream in(file); + std::ifstream in(file, std::ifstream::binary); // File Header char ident[5]; @@ -178,6 +186,6 @@ namespace simulatorDatabase } return airports; } -} // namespace simulatorDatabase +} // namespace germanairlinesva_simdata #endif diff --git a/simdata/runway.cpp b/simdata/runway.cpp new file mode 100644 index 0000000..aad8055 --- /dev/null +++ b/simdata/runway.cpp @@ -0,0 +1,81 @@ +#include "runway.h" +namespace germanairlinesva_simdata +{ + Runway::Runway(std::string designator, + double latitudeStart, + double longitudeStart, + double latitudeEnd, + double longitudeEnd, + double width) + { + this->designator = std::move(designator); + this->width = width; + this->length = germanairlinesva_geodata::distanceEarthD(latitudeStart, + longitudeStart, + latitudeEnd, + longitudeEnd); + this->trueHeading = (std::uint16_t)std::round( + germanairlinesva_geodata::bearingDD(latitudeStart, + longitudeStart, + latitudeEnd, + longitudeEnd)); + this->bounds = germanairlinesva_geodata::calculateBoxDD( + {latitudeStart, longitudeStart}, + {latitudeEnd, longitudeEnd}, + this->trueHeading, + this->width); + + file = std::vector( + 1 + this->designator.length() + 1 + sizeof(this->bounds) + + sizeof(this->width) + sizeof(this->length) + + sizeof(this->trueHeading), + 0); + std::uint8_t *bufPtr = file.data(); + memset(bufPtr, + static_cast(this->designator.length()), + sizeof(std::uint8_t)); + bufPtr++; + memcpy(bufPtr, this->designator.c_str(), this->designator.length()); + bufPtr += this->designator.length() + 1; + memcpy(bufPtr, &this->bounds, sizeof(this->bounds)); + bufPtr += sizeof(this->bounds); + memcpy(bufPtr, &this->width, sizeof(this->width)); + bufPtr += sizeof(this->width); + memcpy(bufPtr, &this->length, sizeof(this->length)); + bufPtr += sizeof(this->length); + memcpy(bufPtr, &this->trueHeading, sizeof(this->trueHeading)); + } + + Runway::Runway(std::string designator, + germanairlinesva_geodata::box bounds, + std::uint8_t width, + std::uint16_t length, + std::uint16_t trueHeading) + { + this->designator = std::move(designator); + this->bounds = bounds; + this->width = width; + this->length = length; + this->trueHeading = trueHeading; + + file = std::vector( + 1 + this->designator.length() + 1 + sizeof(this->bounds) + + sizeof(this->width) + sizeof(this->length) + + sizeof(this->trueHeading), + 0); + std::uint8_t *bufPtr = file.data(); + memset(bufPtr, + static_cast(this->designator.length()), + sizeof(std::uint8_t)); + bufPtr++; + memcpy(bufPtr, this->designator.c_str(), this->designator.length()); + bufPtr += this->designator.length() + 1; + memcpy(bufPtr, &this->bounds, sizeof(this->bounds)); + bufPtr += sizeof(this->bounds); + memcpy(bufPtr, &this->width, sizeof(this->width)); + bufPtr += sizeof(this->width); + memcpy(bufPtr, &this->length, sizeof(this->length)); + bufPtr += sizeof(this->length); + memcpy(bufPtr, &this->trueHeading, sizeof(this->trueHeading)); + } +} // namespace germanairlinesva_simdata \ No newline at end of file diff --git a/simdata/simdata.cpp b/simdata/simdata.cpp new file mode 100644 index 0000000..47c19bc --- /dev/null +++ b/simdata/simdata.cpp @@ -0,0 +1,184 @@ +#include "simdata.h" +namespace germanairlinesva_simdata +{ + int scan( + const char *defaultFile, + const char *sceneryPack, + const char *logFile, + std::map, std::vector>> + &airports) + { + std::ifstream base(defaultFile); + if (!base.good()) { + return 1; + } + std::ifstream custom(sceneryPack); + if (!custom.good()) { + base.close(); + return 2; + } + std::ofstream logfile(logFile, std::ios::out | std::ios::trunc); + if (!logfile.good()) { + base.close(); + custom.close(); + return 3; + } + + // Default + logfile << " " << defaultFile << std::endl; + makeAirport("DEFAULT", &base, &airports, &logfile); + base.close(); + + std::string line; + size_t pos; + std::vector packs; + while (std::getline(custom, line)) { + if ((pos = line.find("SCENERY_PACK")) != std::string::npos) { + std::string path = + germanairlinesva_util::rtrim_copy(line.substr(pos + 13)) + + "Earth nav data/apt.dat"; + packs.push_back(path); + } + } + std::reverse(packs.begin(), packs.end()); + + for (std::string const &path : packs) { + std::ifstream pack(path); + if (pack.good()) { + logfile << " " << path << std::endl; + makeAirport("CUSTOM", &pack, &airports, &logfile); + pack.close(); + } else { + pack.close(); + logfile << "" + << "Could not find " << path << std::endl; + } + } + + logfile << std::endl + << " Total airports: " << airports.size() << std::endl; + + custom.close(); + logfile.close(); + return 0; + } + + void makeAirport( + const std::string &kind, + std::ifstream *infile, + std::map, std::vector>> + *airports, + std::ofstream *logfile) + { + std::string line; + std::string *currentIcao = nullptr; + std::vector tmpGates; + std::vector tmpRunways; + + int apCount = 0; + int validCount = 0; + + while (std::getline(*infile, line)) { + std::vector fields = germanairlinesva_util::split(line, ' '); + fields = germanairlinesva_util::select_T( + fields, + [](const std::string &s) { return s.length() > 0; }); + + if (fields.empty()) + continue; + if (fields[0] == "1") { + // Write to file if ICAO is valid, and we have gates and runways + if (currentIcao != nullptr && !tmpRunways.empty() && + !tmpGates.empty()) { + (*airports)[*currentIcao] = {tmpGates, tmpRunways}; + validCount += 1; + *logfile << "\t " << *currentIcao << " committed" + << std::endl; + } else if (currentIcao != nullptr) { + *logfile << "\t " << *currentIcao + << " had no gates or runways" << std::endl; + } + tmpGates = std::vector(); + tmpRunways = std::vector(); + currentIcao = new std::string(fields[4]); + apCount += 1; + *logfile << "\t<" << kind << "> " << line << std::endl; + } else if (currentIcao != nullptr && fields[0] == "15") { + makeGate15(&tmpGates, fields); + *logfile << "\t\t " << line << std::endl; + } else if (fields[0] == "16" || fields[0] == "17") { + // Write to file if ICAO is valid, and we have gates and runways + if (currentIcao != nullptr && !tmpRunways.empty() && + !tmpGates.empty()) { + (*airports)[*currentIcao] = {tmpGates, tmpRunways}; + validCount += 1; + *logfile << "\t " << *currentIcao << " committed" + << std::endl; + } else if (currentIcao != nullptr) { + *logfile << "\t " << *currentIcao + << " had no gates or runways" << std::endl; + } + tmpGates = std::vector(); + tmpRunways = std::vector(); + currentIcao = nullptr; + *logfile << "\t<" << kind << " SKIPPED> " << line << std::endl; + } else if (currentIcao != nullptr && fields[0] == "100") { + makeRunway(&tmpRunways, fields); + *logfile << "\t\t " << line << std::endl; + } else if (currentIcao != nullptr && fields[0] == "1300") { + makeGate1300(&tmpGates, fields); + *logfile << "\t\t " << line << std::endl; + } + } + + if (currentIcao != nullptr && !tmpRunways.empty() && !tmpGates.empty()) { + (*airports)[*currentIcao] = {tmpGates, tmpRunways}; + validCount += 1; + *logfile << "\t " << *currentIcao << " committed" << std::endl; + } + *logfile << " " << apCount << " airports found, of which " + << validCount << " are valid" << std::endl; + } + + void makeGate15(std::vector *gates, std::vector fields) + { + std::string gateName; + for (size_t j = 4; j < fields.size() - 1; j++) { + gateName += fields[j] + " "; + } + gateName += fields.back(); + gateName = std::regex_replace(gateName, std::regex{","}, "0"); + + gates->push_back( + Gate{gateName, std::stod(fields[1]), std::stod(fields[2]), 40}); + } + + void makeRunway(std::vector *runways, std::vector fields) + { + runways->push_back(Runway{fields[8], + std::stod(fields[9]), + std::stod(fields[10]), + std::stod(fields[18]), + std::stod(fields[19]), + std::stod(fields[1])}); + runways->push_back(Runway{fields[17], + std::stod(fields[18]), + std::stod(fields[19]), + std::stod(fields[9]), + std::stod(fields[10]), + std::stod(fields[1])}); + } + + void makeGate1300(std::vector *gates, std::vector fields) + { + std::string gateName; + for (size_t j = 6; j < fields.size() - 1; j++) { + gateName += fields[j] + " "; + } + gateName += fields.back(); + gateName = std::regex_replace(gateName, std::regex{","}, "0"); + + gates->push_back( + Gate{gateName, std::stod(fields[1]), std::stod(fields[2]), 40}); + } +} // namespace germanairlinesva_simdata \ No newline at end of file diff --git a/utilities/include/stringExtensions.hpp b/utilities/include/stringExtensions.hpp deleted file mode 100644 index ceea395..0000000 --- a/utilities/include/stringExtensions.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef GERMANAIRLINESVA_GACONNECTOR_STRINGEXTENSIONS_H -#define GERMANAIRLINESVA_GACONNECTOR_STRINGEXTENSIONS_H - -#include -#include -#include -#include - -// trim from start (in place) -static inline void ltrim(std::string &s) -{ - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { - return !std::isspace(ch); - })); -} - -// trim from end (in place) -static inline void rtrim(std::string &s) -{ - s.erase(std::find_if(s.rbegin(), - s.rend(), - [](unsigned char ch) { return !std::isspace(ch); }) - .base(), - s.end()); -} - -static inline std::string rtrim_copy(std::string s) -{ - rtrim(s); - return s; -} - -// trim from both ends (in place) -static inline void trim(std::string &s) -{ - ltrim(s); - rtrim(s); -} - -static inline std::vector split(const std::string &s, char delim) -{ - std::vector result; - std::stringstream ss(s); - std::string item; - - while (getline(ss, item, delim)) { - result.push_back(item); - } - - return result; -} - -#endif \ No newline at end of file diff --git a/utilities/include/util.hpp b/utilities/include/util.hpp index 592cec0..03b628e 100644 --- a/utilities/include/util.hpp +++ b/utilities/include/util.hpp @@ -31,54 +31,15 @@ #endif #include +#include #include #include #include #include #include -namespace util +namespace germanairlinesva_util { - static inline double to_feet(double value) { return value * 3.280839895; } - - static inline double to_degrees(double value) { return value * 180 / M_PI; } - - static inline double to_radians(double value) { return value * M_PI / 180; } - - static inline double normalize(double value) - { - return fmod(value + 360, 360); - } - - static inline double bearing(double fromLatitude, - double fromLongitude, - double toLatitude, - double toLongitude) - { - double y = sin(to_radians(toLongitude) - to_radians(fromLongitude)) * - cos(to_radians(toLatitude)); - double x = cos(to_radians(fromLatitude)) * sin(to_radians(toLatitude)) - - sin(to_radians(fromLatitude)) * cos(to_radians(toLatitude)) * - cos(to_radians(toLongitude) - to_radians(fromLongitude)); - - return normalize(to_degrees(atan2(y, x))); - } - - static inline double distanceEarth(double fromLatitude, - double fromLongitude, - double toLatitude, - double toLongitude) - { - double lat1r, lon1r, lat2r, lon2r, u, v; - lat1r = to_radians(fromLatitude); - lon1r = to_radians(fromLongitude); - lat2r = to_radians(toLatitude); - lon2r = to_radians(toLongitude); - u = sin((lat2r - lat1r) / 2); - v = sin((lon2r - lon1r) / 2); - return 2.0 * EARTH_M * asin(sqrt(u * u + cos(lat1r) * cos(lat2r) * v * v)); - } - template static inline std::vector select_T(const std::vector &inVec, @@ -90,7 +51,7 @@ namespace util } #if defined APL || defined LIN - static unsigned long get_size_by_fd(int fd) + static inline unsigned long get_size_by_fd(int fd) { struct stat buf { }; @@ -100,7 +61,7 @@ namespace util } #endif - static void to_hex(const char *hash, char *buffer) + static inline void to_hex(const char *hash, char *buffer) { for (int i = 0; i < MD5LEN; i++) { if (buffer != nullptr) { @@ -109,6 +70,11 @@ namespace util } } + static inline bool fileExists(const char *path) + { + return static_cast(std::ifstream(path)); + } + #ifdef IBM static inline int generateMD5(const char *filepath, @@ -293,6 +259,50 @@ namespace util } #pragma clang diagnostic pop -} // namespace util + // trim from start (in place) + static inline void ltrim(std::string &s) + { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { + return !std::isspace(ch); + })); + } + + // trim from end (in place) + static inline void rtrim(std::string &s) + { + s.erase(std::find_if(s.rbegin(), + s.rend(), + [](unsigned char ch) { return !std::isspace(ch); }) + .base(), + s.end()); + } + + static inline std::string rtrim_copy(std::string s) + { + rtrim(s); + return s; + } + + // trim from both ends (in place) + static inline void trim(std::string &s) + { + ltrim(s); + rtrim(s); + } + + static inline std::vector split(const std::string &s, char delim) + { + std::vector result; + std::stringstream ss(s); + std::string item; + + while (getline(ss, item, delim)) { + result.push_back(item); + } + + return result; + } + +} // namespace germanairlinesva_util #endif diff --git a/websocket/include/types.h b/websocket/include/types.h index 6316166..7665eb5 100644 --- a/websocket/include/types.h +++ b/websocket/include/types.h @@ -3,53 +3,56 @@ #include -/* Structures and enums */ -typedef struct data { - std::int32_t pause = 0; - float pBrake = 0; - std::int32_t onGrnd = 0; - float totFuelKg = 0; - float truHdg = 0; - double alt = 0; - float gs = 0; - float ias = 0; - float vs = 0; - double lat = 0; - double lon = 0; - float ff[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - float maxSpd = 0; - char path[513] = ""; - float uptime = 0; - float magHeading = 0; - float payloadKg = 0; - float totalWeightKg = 0; -} data; - -typedef enum commands { - PROCESS, - SAVE, - LOAD, - TEXT, - TIME, - UNPAUSE, - PAUSE, - PORT, - END -} commands; - -typedef struct command_base { - commands type; -} command_base; - #pragma pack(push) /* push current alignment to stack */ #pragma pack(1) /* set alignment to 1 byte boundary */ +namespace germanairlinesva_websocket +{ + /* Structures and enums */ + typedef struct data { + std::int32_t pause = 0; + float pBrake = 0; + std::int32_t onGrnd = 0; + float totFuelKg = 0; + float truHdg = 0; + double alt = 0; + float gs = 0; + float ias = 0; + float vs = 0; + double lat = 0; + double lon = 0; + float ff[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + float maxSpd = 0; + char path[513] = ""; + float uptime = 0; + float magHeading = 0; + float payloadKg = 0; + float totalWeightKg = 0; + } data; -typedef struct command_port { - double latitude; - double longitude; - float trueHeading; -} command_port; + typedef enum commands { + PROCESS, + SAVE, + LOAD, + TEXT, + TIME, + UNPAUSE, + PAUSE, + PORT, + END + } commands; + + typedef struct command_base { + commands type; + } command_base; + + + typedef struct command_port { + double latitude; + double longitude; + float trueHeading; + } command_port; #pragma pack(pop) /* restore original alignment from stack */ +} // namespace germanairlinesva_websocket #endif diff --git a/websocket/include/websocket.h b/websocket/include/websocket.h index 73e0599..3497365 100644 --- a/websocket/include/websocket.h +++ b/websocket/include/websocket.h @@ -19,23 +19,26 @@ #include #include -class Websocket +namespace germanairlinesva_websocket { - private: - char lastPath[513] = ""; - char lastHash[2 * MD5LEN + 1] = ""; - ix::WebSocket *webSocket = nullptr; - std::string host; - std::string user; - std::function toLog; + class Websocket + { + private: + char lastPath[513] = ""; + char lastHash[2 * MD5LEN + 1] = ""; + ix::WebSocket *webSocket = nullptr; + std::string host; + std::string user; + std::function toLog; - public: - explicit Websocket(std::string host, - std::string user, - std::function toLog); - ~Websocket(); - void onClientMessageCallback(const ix::WebSocketMessagePtr &msg); - void sendData(data &d); -}; + public: + explicit Websocket(std::string host, + std::string user, + std::function toLog); + ~Websocket(); + void onClientMessageCallback(const ix::WebSocketMessagePtr &msg); + void sendData(data &d); + }; +} // namespace germanairlinesva_websocket #endif \ No newline at end of file diff --git a/websocket/websocket.cpp b/websocket/websocket.cpp index ec35cd7..473c04a 100644 --- a/websocket/websocket.cpp +++ b/websocket/websocket.cpp @@ -1,107 +1,110 @@ #include "include/websocket.h" -Websocket::Websocket(std::string host, - std::string user, - std::function toLog) - : host(host), user(user), toLog(std::move(toLog)) +namespace germanairlinesva_websocket { + Websocket::Websocket(std::string host, + std::string user, + std::function toLog) + : host(host), user(user), toLog(std::move(toLog)) + { #ifdef IBM - // Required on Windows - ix::initNetSystem(); + // Required on Windows + ix::initNetSystem(); #endif - webSocket = new ix::WebSocket(); - webSocket->enableAutomaticReconnection(); - webSocket->setUrl(host); - webSocket->setOnMessageCallback([this](const ix::WebSocketMessagePtr &msg) { - this->onClientMessageCallback(msg); - }); - webSocket->start(); -} + webSocket = new ix::WebSocket(); + webSocket->enableAutomaticReconnection(); + webSocket->setUrl(host); + webSocket->setOnMessageCallback([this](const ix::WebSocketMessagePtr &msg) { + this->onClientMessageCallback(msg); + }); + webSocket->start(); + } -Websocket::~Websocket() -{ - webSocket->stop(); - toLog("WebSocket stopped"); + Websocket::~Websocket() + { + webSocket->stop(); + toLog("WebSocket stopped"); #ifdef IBM - // Required on Windows - ix::uninitNetSystem(); + // Required on Windows + ix::uninitNetSystem(); #endif -} + } -void Websocket::onClientMessageCallback(const ix::WebSocketMessagePtr &msg) -{ - if (msg->type == ix::WebSocketMessageType::Open) { - std::stringstream debug_msg; - - debug_msg << "New connection" << std::endl; - debug_msg << "Uri: " << msg->openInfo.uri << std::endl; - debug_msg << "Headers:" << std::endl; - for (const auto &it : msg->openInfo.headers) { - debug_msg << it.first << ": " << it.second << std::endl; - } - - toLog(debug_msg.str()); - - webSocket->send("MASTER:" + user); - toLog("Connecting as " + user); - } else if (msg->type == ix::WebSocketMessageType::Close) { - if (msg->closeInfo.reason.compare("DUPLICATE")) { - webSocket->disableAutomaticReconnection(); - - toLog("Disconnected due to beeing a duplicate simualtor"); - } else { + void Websocket::onClientMessageCallback(const ix::WebSocketMessagePtr &msg) + { + if (msg->type == ix::WebSocketMessageType::Open) { std::stringstream debug_msg; - debug_msg << "Connection closed" << std::endl; - debug_msg << "Code: " << msg->closeInfo.code << std::endl; - debug_msg << "Reason: " << msg->closeInfo.reason << std::endl; - debug_msg << "Remote: " << msg->closeInfo.remote << std::endl; + debug_msg << "New connection" << std::endl; + debug_msg << "Uri: " << msg->openInfo.uri << std::endl; + debug_msg << "Headers:" << std::endl; + for (const auto &it : msg->openInfo.headers) { + debug_msg << it.first << ": " << it.second << std::endl; + } toLog(debug_msg.str()); - } - } else if (msg->type == ix::WebSocketMessageType::Error) { - std::stringstream debug_msg; - debug_msg << "Connection error" << std::endl; - debug_msg << "Decompression: " << msg->errorInfo.decompressionError - << std::endl; - debug_msg << "HTTP status: " << msg->errorInfo.http_status << std::endl; - debug_msg << "Reason: " << msg->errorInfo.reason << std::endl; - debug_msg << "Retries: " << msg->errorInfo.retries << std::endl; - debug_msg << "Wait time: " << msg->errorInfo.wait_time << std::endl; + webSocket->send("MASTER:" + user); + toLog("Connecting as " + user); + } else if (msg->type == ix::WebSocketMessageType::Close) { + if (msg->closeInfo.reason.compare("DUPLICATE")) { + webSocket->disableAutomaticReconnection(); - toLog(debug_msg.str()); - } else if (msg->type == ix::WebSocketMessageType::Message) { - if (!msg->str.empty()) { - toLog(msg->str); - } - } -} + toLog("Disconnected due to beeing a duplicate simualtor"); + } else { + std::stringstream debug_msg; -void Websocket::sendData(data &d) -{ - if (strcmp(d.path, lastPath) != 0) { - strcpy(lastPath, d.path); - if (util::generateMD5(d.path, lastHash, toLog)) { - strcpy(lastHash, "NOT SET"); + debug_msg << "Connection closed" << std::endl; + debug_msg << "Code: " << msg->closeInfo.code << std::endl; + debug_msg << "Reason: " << msg->closeInfo.reason << std::endl; + debug_msg << "Remote: " << msg->closeInfo.remote << std::endl; + + toLog(debug_msg.str()); + } + } else if (msg->type == ix::WebSocketMessageType::Error) { + std::stringstream debug_msg; + + debug_msg << "Connection error" << std::endl; + debug_msg << "Decompression: " << msg->errorInfo.decompressionError + << std::endl; + debug_msg << "HTTP status: " << msg->errorInfo.http_status << std::endl; + debug_msg << "Reason: " << msg->errorInfo.reason << std::endl; + debug_msg << "Retries: " << msg->errorInfo.retries << std::endl; + debug_msg << "Wait time: " << msg->errorInfo.wait_time << std::endl; + + toLog(debug_msg.str()); + } else if (msg->type == ix::WebSocketMessageType::Message) { + if (!msg->str.empty()) { + toLog(msg->str); + } } } - nlohmann::json json = { - {"altitude", d.alt}, - {"vs", d.vs}, - {"ias", d.ias}, - {"magHdg", d.magHeading}, - {"truHdg", d.truHdg}, - {"totFuel", d.totFuelKg}, - {"fuelFlow", d.ff}, - {"hash", lastHash}, - }; + void Websocket::sendData(data &d) + { + if (strcmp(d.path, lastPath) != 0) { + strcpy(lastPath, d.path); + if (germanairlinesva_util::generateMD5(d.path, lastHash, toLog)) { + strcpy(lastHash, "NOT SET"); + } + } - if (webSocket != nullptr) { - std::ostringstream msg; - msg << "SEND:" << user << ":" << json.dump(); - webSocket->send(msg.str(), false); + nlohmann::json json = { + {"altitude", d.alt}, + {"vs", d.vs}, + {"ias", d.ias}, + {"magHdg", d.magHeading}, + {"truHdg", d.truHdg}, + {"totFuel", d.totFuelKg}, + {"fuelFlow", d.ff}, + {"hash", lastHash}, + }; + + if (webSocket != nullptr) { + std::ostringstream msg; + msg << "SEND:" << user << ":" << json.dump(); + webSocket->send(msg.str(), false); + } } -} \ No newline at end of file +} // namespace germanairlinesva_websocket \ No newline at end of file diff --git a/xplugin/CMakeLists.txt b/xplugin/CMakeLists.txt index 4b461e1..b6fa6e9 100644 --- a/xplugin/CMakeLists.txt +++ b/xplugin/CMakeLists.txt @@ -9,7 +9,7 @@ add_library(germanairlinesva_xplugin SHARED target_include_directories(germanairlinesva_xplugin PRIVATE ${CMAKE_SOURCE_DIR}/ixwebsocket/include - ${CMAKE_SOURCE_DIR}/makerwysxp/include + ${CMAKE_SOURCE_DIR}/simdata/include ${CMAKE_SOURCE_DIR}/websocket/include ${CMAKE_SOURCE_DIR}/utilities/include ${CMAKE_SOURCE_DIR}/nlohmann/include @@ -134,6 +134,6 @@ elseif(WIN32) endif() target_link_libraries(germanairlinesva_xplugin PRIVATE - makerwysxp + simdata ixwebsocket ) diff --git a/xplugin/include/main.h b/xplugin/include/main.h index 820e824..857825b 100644 --- a/xplugin/include/main.h +++ b/xplugin/include/main.h @@ -2,8 +2,8 @@ #define GERMANAIRLINESVA_GACONNECTOR_XPLUGIN_MAIN_H #include "config.hpp" -#include "makeRwysXP.h" #include "recordingPath.hpp" +#include "simdata.h" #include "simulatorDatabase.hpp" #include "websocket.h" diff --git a/xplugin/main.cpp b/xplugin/main.cpp index f47652a..ac777e5 100644 --- a/xplugin/main.cpp +++ b/xplugin/main.cpp @@ -12,7 +12,7 @@ std::atomic wantsExit; std::map configuration; -Websocket *connector; +germanairlinesva_websocket::Websocket *connector; /* Datarefs */ XPLMDataRef pauseIndicator; @@ -42,7 +42,7 @@ XPLMDataRef pitch; XPLMDataRef roll; XPLMDataRef quaternion; -data toSend; +germanairlinesva_websocket::data toSend; Path p; /* @@ -107,14 +107,15 @@ PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc) roll = XPLMFindDataRef("sim/flightmodel/position/phi"); // FLOAT quaternion = XPLMFindDataRef("sim/flightmodel/position/q"); // FLOAT[4] - configuration = - config::readConfig("Resources/plugins/GAConnector/config.cfg"); + configuration = germanairlinesva_config::readConfig( + "Resources/plugins/GAConnector/config.cfg"); toLog("Config loaded"); try { - connector = new Websocket("wss://ws.hofmannnet.myhome-server.de:8000", - configuration["user"], - toLog); + connector = new germanairlinesva_websocket::Websocket( + "wss://ws.hofmannnet.myhome-server.de:8000", + configuration["user"], + toLog); } catch (const std::invalid_argument &e) { toLog(e.what()); return 0; @@ -122,28 +123,44 @@ PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc) toLog("WebSocket started"); char hash[2 * MD5LEN + 1] = ""; - if (util::generateMD5("Custom Scenery/scenery_packs.ini", hash, toLog) == 0) { - std::map, std::vector>> + if (germanairlinesva_util::generateMD5("Custom Scenery/scenery_packs.ini", + hash, + toLog) == 0) { + std::map, + std::vector>> airports; - if (strcmp(configuration["scenery"].c_str(), hash) != 0) { + if (strcmp(configuration["scenery"].c_str(), hash) != 0 || + !germanairlinesva_util::fileExists( + "Resources/plugins/GAConnector/sim.bin")) { scan("Resources/default scenery/default apt dat/Earth nav " "data/apt.dat", "Custom Scenery/scenery_packs.ini", "Resources/plugins/GAConnector/log.txt", airports); - simulatorDatabase::toFile(airports, - "Resources/plugins/GAConnector/sim.bin"); + germanairlinesva_simdata::toFile(airports, + "Resources/plugins/GAConnector/sim.bin"); configuration["scenery"] = hash; - config::writeConfig(configuration, - "Resources/plugins/GAConnector/config.cfg"); + germanairlinesva_config::writeConfig( + configuration, + "Resources/plugins/GAConnector/config.cfg"); toLog("Sim Database updated"); } else { - airports = - simulatorDatabase::fromFile("Resources/plugins/GAConnector/sim.bin"); + airports = germanairlinesva_simdata::fromFile( + "Resources/plugins/GAConnector/sim.bin"); toLog("Sim Database loaded"); } + + toLog("Readback test of sim database using EDDF"); + auto ap = airports["EDDF"]; + for (const auto &it : ap.first) { + toLog(" " + it.to_string()); + } + for (const auto &it : ap.second) { + toLog(" " + it.to_string()); + } } // Thread for sending data to web socket @@ -188,7 +205,7 @@ float flightLoop(float elapsedMe, float elapsedSim, int counter, void *refcon) { const std::lock_guard lock(mutex); - memset(&toSend, 0, sizeof(data)); + memset(&toSend, 0, sizeof(germanairlinesva_websocket::data)); toSend.pause = XPLMGetDatai(pauseIndicator); toSend.pBrake = XPLMGetDataf(parkingBrake); @@ -226,14 +243,14 @@ float flightLoop(float elapsedMe, float elapsedSim, int counter, void *refcon) void serverWorker() { - util::setThreadName("GAServerWorker"); + germanairlinesva_util::setThreadName("GAServerWorker"); while (!wantsExit) { - data copy; + germanairlinesva_websocket::data copy; { const std::lock_guard lock(mutex); - memcpy(©, &toSend, sizeof(data)); + memcpy(©, &toSend, sizeof(germanairlinesva_websocket::data)); } connector->sendData(copy); @@ -244,16 +261,16 @@ void serverWorker() void recordingWorker() { - util::setThreadName("GARecordingWorker"); + germanairlinesva_util::setThreadName("GARecordingWorker"); PathSegment lastPath; while (!wantsExit) { - data copy; + germanairlinesva_websocket::data copy; { const std::lock_guard lock(mutex); - memcpy(©, &toSend, sizeof(data)); + memcpy(©, &toSend, sizeof(germanairlinesva_websocket::data)); } PathSegment currentPath(static_cast(copy.alt),