Namespaces

Better File handling
This commit is contained in:
Kilian Hofmann 2022-09-06 00:29:19 +02:00
parent 9dcca746ed
commit b22a60c85e
24 changed files with 1106 additions and 781 deletions

View File

@ -17,7 +17,7 @@ add_subdirectory(
ixwebsocket ixwebsocket
) )
add_subdirectory( add_subdirectory(
makerwysxp simdata
) )
add_subdirectory( add_subdirectory(
xplugin xplugin

View File

@ -1,8 +1,6 @@
#ifndef GERMANAIRLINESVA_GACONNECTOR_CONFIG_H #ifndef GERMANAIRLINESVA_GACONNECTOR_CONFIG_H
#define GERMANAIRLINESVA_GACONNECTOR_CONFIG_H #define GERMANAIRLINESVA_GACONNECTOR_CONFIG_H
#include "stringExtensions.hpp"
#include <map> #include <map>
#include <fstream> #include <fstream>
@ -10,7 +8,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace config #include "util.hpp"
namespace germanairlinesva_config
{ {
static inline std::map<std::string, std::string> static inline std::map<std::string, std::string>
readConfig(const std::string &file) readConfig(const std::string &file)
@ -20,10 +20,10 @@ namespace config
std::string line; std::string line;
while (std::getline(config, line)) { while (std::getline(config, line)) {
std::vector<std::string> fields = split(line, '='); std::vector<std::string> fields = germanairlinesva_util::split(line, '=');
if (fields.size() >= 2) { if (fields.size() >= 2) {
trim(fields[0]); germanairlinesva_util::trim(fields[0]);
trim(fields[1]); germanairlinesva_util::trim(fields[1]);
settings[fields[0]] = fields[1]; settings[fields[0]] = fields[1];
} }
} }
@ -32,7 +32,6 @@ namespace config
return settings; return settings;
} }
static inline void static inline void
writeConfig(const std::map<std::string, std::string> &config, writeConfig(const std::map<std::string, std::string> &config,
const std::string &file) const std::string &file)
@ -43,5 +42,5 @@ namespace config
} }
cfg.close(); cfg.close();
} }
} // namespace config } // namespace germanairlinesva_config
#endif #endif

View File

@ -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()

View File

@ -1,56 +0,0 @@
#ifndef GERMANAIRLINESVA_GACONNECTOR_GATE_H
#define GERMANAIRLINESVA_GACONNECTOR_GATE_H
#include <cstdint>
#include <cstring>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
/*
* 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<std::uint8_t> file;
public:
Gate(const std::string &designator, double latitude, double longitude)
{
this->designator = designator;
this->latitude = latitude;
this->longitude = longitude;
file = std::vector<std::uint8_t>(18 + this->designator.length(), 0);
std::uint8_t *bufPtr = file.data();
memset(bufPtr,
static_cast<std::uint8_t>(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

View File

@ -1,30 +0,0 @@
#ifndef GERMANAIRLINESVA_GACONNECTOR_XPLUGIN_MAKERWYSXP_H
#define GERMANAIRLINESVA_GACONNECTOR_XPLUGIN_MAKERWYSXP_H
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#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::string,
std::pair<std::vector<Gate>, std::vector<Runway>>> &airports);
void makeAirport(
const std::string &kind,
std::ifstream *infile,
std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>>
*airports,
std::ofstream *logfile);
void makeGate15(std::vector<Gate> *gates, std::vector<std::string> fields);
void makeRunway(std::vector<Runway> *runways, std::vector<std::string> fields);
void makeGate1300(std::vector<Gate> *gates, std::vector<std::string> fields);
#endif

View File

@ -1,114 +0,0 @@
#ifndef GERMANAIRLINESVA_GACONNECTOR_RUNWAY_H
#define GERMANAIRLINESVA_GACONNECTOR_RUNWAY_H
#include <iomanip>
#include <regex>
#include <sstream>
#include <string>
#include <utility>
#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<std::uint8_t> 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<std::uint8_t>(23 + this->designator.length(), 0);
std::uint8_t *bufPtr = file.data();
memset(bufPtr,
static_cast<std::uint8_t>(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<std::uint8_t>(23 + this->designator.length(), 0);
std::uint8_t *bufPtr = file.data();
memset(bufPtr,
static_cast<std::uint8_t>(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

View File

@ -1,174 +0,0 @@
#include "include/makeRwysXP.h"
int scan(const char *defaultFile,
const char *sceneryPack,
const char *logFile,
std::map<std::string,
std::pair<std::vector<Gate>, std::vector<Runway>>> &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 << "<FILE> " << defaultFile << std::endl;
makeAirport("DEFAULT", &base, &airports, &logfile);
base.close();
std::string line;
size_t pos;
std::vector<std::string> 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 << "<FILE> " << path << std::endl;
makeAirport("CUSTOM", &pack, &airports, &logfile);
pack.close();
} else {
pack.close();
logfile << "<STATUS>"
<< "Could not find " << path << std::endl;
}
}
logfile << std::endl
<< "<STATUS> Total airports: " << airports.size() << std::endl;
custom.close();
logfile.close();
return 0;
}
void makeAirport(
const std::string &kind,
std::ifstream *infile,
std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>>
*airports,
std::ofstream *logfile)
{
std::string line;
std::string *currentIcao = nullptr;
std::vector<Gate> tmpGates;
std::vector<Runway> tmpRunways;
int apCount = 0;
int validCount = 0;
while (std::getline(*infile, line)) {
std::vector<std::string> fields = split(line, ' ');
fields = util::select_T<std::string>(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<STATUS> " << *currentIcao << " committed" << std::endl;
} else if (currentIcao != nullptr) {
*logfile << "\t<STATUS> " << *currentIcao << " had no gates or runways"
<< std::endl;
}
tmpGates = std::vector<Gate>();
tmpRunways = std::vector<Runway>();
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<GATE OLD> " << 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<STATUS> " << *currentIcao << " committed" << std::endl;
} else if (currentIcao != nullptr) {
*logfile << "\t<STATUS> " << *currentIcao << " had no gates or runways"
<< std::endl;
}
tmpGates = std::vector<Gate>();
tmpRunways = std::vector<Runway>();
currentIcao = nullptr;
*logfile << "\t<" << kind << " SKIPPED> " << line << std::endl;
} else if (currentIcao != nullptr && fields[0] == "100") {
makeRunway(&tmpRunways, fields);
*logfile << "\t\t<RUNWAY> " << line << std::endl;
} else if (currentIcao != nullptr && fields[0] == "1300") {
makeGate1300(&tmpGates, fields);
*logfile << "\t\t<GATE> " << line << std::endl;
}
}
if (currentIcao != nullptr && !tmpRunways.empty() && !tmpGates.empty()) {
(*airports)[*currentIcao] = {tmpGates, tmpRunways};
validCount += 1;
*logfile << "\t<STATUS> " << *currentIcao << " committed" << std::endl;
}
*logfile << "<STATUS> " << apCount << " airports found, of which "
<< validCount << " are valid" << std::endl;
}
void makeGate15(std::vector<Gate> *gates, std::vector<std::string> 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<Runway> *runways, std::vector<std::string> 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<Gate> *gates, std::vector<std::string> 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])});
}

92
simdata/CMakeLists.txt Normal file
View File

@ -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()

52
simdata/gate.cpp Normal file
View File

@ -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<std::uint8_t>(1 + this->designator.length() + 1 +
sizeof(center) + sizeof(radius),
0);
std::uint8_t *bufPtr = file.data();
memset(bufPtr,
static_cast<std::uint8_t>(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<std::uint8_t>(1 + this->designator.length() + 1 +
sizeof(center) + sizeof(radius),
0);
std::uint8_t *bufPtr = file.data();
memset(bufPtr,
static_cast<std::uint8_t>(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

68
simdata/include/gate.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef GERMANAIRLINESVA_GACONNECTOR_GATE_H
#define GERMANAIRLINESVA_GACONNECTOR_GATE_H
#include <cstdint>
#include <cstring>
#include <iostream>
#include <sstream>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#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<std::uint8_t> 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

208
simdata/include/geodata.h Normal file
View File

@ -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 <cmath>
#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

81
simdata/include/runway.h Normal file
View File

@ -0,0 +1,81 @@
#ifndef GERMANAIRLINESVA_GACONNECTOR_RUNWAY_H
#define GERMANAIRLINESVA_GACONNECTOR_RUNWAY_H
#include <iomanip>
#include <iostream>
#include <regex>
#include <sstream>
#include <string>
#include <utility>
#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<std::uint8_t> 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

35
simdata/include/simdata.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef GERMANAIRLINESVA_GACONNECTOR_SIMDATA_H
#define GERMANAIRLINESVA_GACONNECTOR_SIMDATA_H
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#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::string, std::pair<std::vector<Gate>, std::vector<Runway>>>
&airports);
void makeAirport(
const std::string &kind,
std::ifstream *infile,
std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>>
*airports,
std::ofstream *logfile);
void makeGate15(std::vector<Gate> *gates, std::vector<std::string> fields);
void makeRunway(std::vector<Runway> *runways,
std::vector<std::string> fields);
void makeGate1300(std::vector<Gate> *gates, std::vector<std::string> fields);
} // namespace germanairlinesva_simdata
#endif

View File

@ -1,9 +1,8 @@
#ifndef GERMANAIRLINESVA_GACONNECTOR_SIMULATORDATABASE_H #ifndef GERMANAIRLINESVA_GACONNECTOR_SIMULATORDATABASE_H
#define GERMANAIRLINESVA_GACONNECTOR_SIMULATORDATABASE_H #define GERMANAIRLINESVA_GACONNECTOR_SIMULATORDATABASE_H
#include "gate.hpp" #include "gate.h"
#include "runway.hpp" #include "runway.h"
#include "stringExtensions.hpp"
#define CURRENT_VERSION 1 #define CURRENT_VERSION 1
@ -25,17 +24,19 @@
/* /*
* Airport * 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( static inline void
std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>> toFile(std::map<std::string,
&airports, std::pair<std::vector<germanairlinesva_simdata::Gate>,
const std::string &file) std::vector<germanairlinesva_simdata::Runway>>>
&airports,
const std::string &file)
{ {
std::uint8_t null = 0; std::uint8_t null = 0;
std::ofstream out(file, std::fstream::binary); std::ofstream out(file, std::fstream::binary);
@ -48,12 +49,15 @@ namespace simulatorDatabase
out.write(reinterpret_cast<const char *>(&numAirports), out.write(reinterpret_cast<const char *>(&numAirports),
sizeof(numAirports)); sizeof(numAirports));
// Airport // Airport
for (const std::pair<const std::string, for (const std::pair<
std::pair<std::vector<Gate>, std::vector<Runway>>> const std::string,
std::pair<std::vector<germanairlinesva_simdata::Gate>,
std::vector<germanairlinesva_simdata::Runway>>>
&airport : airports) { &airport : airports) {
std::string icao = airport.first; std::string icao = airport.first;
std::vector<Gate> gates = airport.second.first; std::vector<germanairlinesva_simdata::Gate> gates = airport.second.first;
std::vector<Runway> runways = airport.second.second; std::vector<germanairlinesva_simdata::Runway> runways =
airport.second.second;
// ICAO // ICAO
std::uint8_t icaoLength = icao.length(); std::uint8_t icaoLength = icao.length();
out.write(reinterpret_cast<const char *>(&icaoLength), out.write(reinterpret_cast<const char *>(&icaoLength),
@ -63,7 +67,7 @@ namespace simulatorDatabase
// Gates // Gates
std::uint16_t numGates = gates.size(); std::uint16_t numGates = gates.size();
out.write(reinterpret_cast<const char *>(&numGates), sizeof(numGates)); out.write(reinterpret_cast<const char *>(&numGates), sizeof(numGates));
for (Gate &gate : gates) { for (germanairlinesva_simdata::Gate &gate : gates) {
out.write(reinterpret_cast<const char *>(gate.getBinaryData()), out.write(reinterpret_cast<const char *>(gate.getBinaryData()),
(std::streamsize)gate.getBinaryLength()); (std::streamsize)gate.getBinaryLength());
} }
@ -71,7 +75,7 @@ namespace simulatorDatabase
std::uint8_t numRunways = runways.size(); std::uint8_t numRunways = runways.size();
out.write(reinterpret_cast<const char *>(&numRunways), out.write(reinterpret_cast<const char *>(&numRunways),
sizeof(numRunways)); sizeof(numRunways));
for (Runway &runway : runways) { for (germanairlinesva_simdata::Runway &runway : runways) {
out.write(reinterpret_cast<const char *>(runway.getBinaryData()), out.write(reinterpret_cast<const char *>(runway.getBinaryData()),
(std::streamsize)runway.getBinaryLength()); (std::streamsize)runway.getBinaryLength());
} }
@ -79,11 +83,15 @@ namespace simulatorDatabase
out.close(); out.close();
} }
static inline std::map<std::string, static inline std::map<
std::pair<std::vector<Gate>, std::vector<Runway>>> std::string,
std::pair<std::vector<germanairlinesva_simdata::Gate>,
std::vector<germanairlinesva_simdata::Runway>>>
readVersion1(std::ifstream &in) readVersion1(std::ifstream &in)
{ {
std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>> std::map<std::string,
std::pair<std::vector<germanairlinesva_simdata::Gate>,
std::vector<germanairlinesva_simdata::Runway>>>
airports; airports;
std::uint16_t numAirports; std::uint16_t numAirports;
@ -106,14 +114,14 @@ namespace simulatorDatabase
char *designator = char *designator =
static_cast<char *>(calloc(designatorLength + 1, sizeof(char))); static_cast<char *>(calloc(designatorLength + 1, sizeof(char)));
in.read(designator, designatorLength + 1); in.read(designator, designatorLength + 1);
// Latitude // Center
double latitude; germanairlinesva_geodata::point center;
in.read(reinterpret_cast<char *>(&latitude), sizeof(latitude)); in.read(reinterpret_cast<char *>(&center), sizeof(center));
// Latitude // Radius
double longitude; std::uint8_t radius;
in.read(reinterpret_cast<char *>(&longitude), sizeof(longitude)); in.read(reinterpret_cast<char *>(&radius), sizeof(radius));
airports[icao].first.emplace_back(designator, latitude, longitude); airports[icao].first.emplace_back(designator, center, radius);
} }
// Runways // Runways
std::uint8_t numRunways; std::uint8_t numRunways;
@ -126,12 +134,9 @@ namespace simulatorDatabase
char *designator = char *designator =
static_cast<char *>(calloc(designatorLength + 1, sizeof(char))); static_cast<char *>(calloc(designatorLength + 1, sizeof(char)));
in.read(designator, designatorLength + 1); in.read(designator, designatorLength + 1);
// Latitude // Bounds
double latitude; germanairlinesva_geodata::box bounds;
in.read(reinterpret_cast<char *>(&latitude), sizeof(latitude)); in.read(reinterpret_cast<char *>(&bounds), sizeof(bounds));
// Latitude
double longitude;
in.read(reinterpret_cast<char *>(&longitude), sizeof(longitude));
// Width // Width
std::uint8_t width; std::uint8_t width;
in.read(reinterpret_cast<char *>(&width), sizeof(width)); in.read(reinterpret_cast<char *>(&width), sizeof(width));
@ -143,8 +148,7 @@ namespace simulatorDatabase
in.read(reinterpret_cast<char *>(&trueHeading), sizeof(trueHeading)); in.read(reinterpret_cast<char *>(&trueHeading), sizeof(trueHeading));
airports[icao].second.emplace_back(designator, airports[icao].second.emplace_back(designator,
latitude, bounds,
longitude,
width, width,
length, length,
trueHeading); trueHeading);
@ -156,13 +160,17 @@ namespace simulatorDatabase
return airports; return airports;
} }
static inline std::map<std::string, static inline std::map<
std::pair<std::vector<Gate>, std::vector<Runway>>> std::string,
std::pair<std::vector<germanairlinesva_simdata::Gate>,
std::vector<germanairlinesva_simdata::Runway>>>
fromFile(const std::string &file) fromFile(const std::string &file)
{ {
std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>> std::map<std::string,
std::pair<std::vector<germanairlinesva_simdata::Gate>,
std::vector<germanairlinesva_simdata::Runway>>>
airports; airports;
std::ifstream in(file); std::ifstream in(file, std::ifstream::binary);
// File Header // File Header
char ident[5]; char ident[5];
@ -178,6 +186,6 @@ namespace simulatorDatabase
} }
return airports; return airports;
} }
} // namespace simulatorDatabase } // namespace germanairlinesva_simdata
#endif #endif

81
simdata/runway.cpp Normal file
View File

@ -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<std::uint8_t>(
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<std::uint8_t>(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<std::uint8_t>(
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<std::uint8_t>(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

184
simdata/simdata.cpp Normal file
View File

@ -0,0 +1,184 @@
#include "simdata.h"
namespace germanairlinesva_simdata
{
int scan(
const char *defaultFile,
const char *sceneryPack,
const char *logFile,
std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>>
&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 << "<FILE> " << defaultFile << std::endl;
makeAirport("DEFAULT", &base, &airports, &logfile);
base.close();
std::string line;
size_t pos;
std::vector<std::string> 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 << "<FILE> " << path << std::endl;
makeAirport("CUSTOM", &pack, &airports, &logfile);
pack.close();
} else {
pack.close();
logfile << "<STATUS>"
<< "Could not find " << path << std::endl;
}
}
logfile << std::endl
<< "<STATUS> Total airports: " << airports.size() << std::endl;
custom.close();
logfile.close();
return 0;
}
void makeAirport(
const std::string &kind,
std::ifstream *infile,
std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>>
*airports,
std::ofstream *logfile)
{
std::string line;
std::string *currentIcao = nullptr;
std::vector<Gate> tmpGates;
std::vector<Runway> tmpRunways;
int apCount = 0;
int validCount = 0;
while (std::getline(*infile, line)) {
std::vector<std::string> fields = germanairlinesva_util::split(line, ' ');
fields = germanairlinesva_util::select_T<std::string>(
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<STATUS> " << *currentIcao << " committed"
<< std::endl;
} else if (currentIcao != nullptr) {
*logfile << "\t<STATUS> " << *currentIcao
<< " had no gates or runways" << std::endl;
}
tmpGates = std::vector<Gate>();
tmpRunways = std::vector<Runway>();
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<GATE OLD> " << 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<STATUS> " << *currentIcao << " committed"
<< std::endl;
} else if (currentIcao != nullptr) {
*logfile << "\t<STATUS> " << *currentIcao
<< " had no gates or runways" << std::endl;
}
tmpGates = std::vector<Gate>();
tmpRunways = std::vector<Runway>();
currentIcao = nullptr;
*logfile << "\t<" << kind << " SKIPPED> " << line << std::endl;
} else if (currentIcao != nullptr && fields[0] == "100") {
makeRunway(&tmpRunways, fields);
*logfile << "\t\t<RUNWAY> " << line << std::endl;
} else if (currentIcao != nullptr && fields[0] == "1300") {
makeGate1300(&tmpGates, fields);
*logfile << "\t\t<GATE> " << line << std::endl;
}
}
if (currentIcao != nullptr && !tmpRunways.empty() && !tmpGates.empty()) {
(*airports)[*currentIcao] = {tmpGates, tmpRunways};
validCount += 1;
*logfile << "\t<STATUS> " << *currentIcao << " committed" << std::endl;
}
*logfile << "<STATUS> " << apCount << " airports found, of which "
<< validCount << " are valid" << std::endl;
}
void makeGate15(std::vector<Gate> *gates, std::vector<std::string> 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<Runway> *runways, std::vector<std::string> 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<Gate> *gates, std::vector<std::string> 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

View File

@ -1,53 +0,0 @@
#ifndef GERMANAIRLINESVA_GACONNECTOR_STRINGEXTENSIONS_H
#define GERMANAIRLINESVA_GACONNECTOR_STRINGEXTENSIONS_H
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
// 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<std::string> split(const std::string &s, char delim)
{
std::vector<std::string> result;
std::stringstream ss(s);
std::string item;
while (getline(ss, item, delim)) {
result.push_back(item);
}
return result;
}
#endif

View File

@ -31,54 +31,15 @@
#endif #endif
#include <cmath> #include <cmath>
#include <fstream>
#include <functional> #include <functional>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
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 <typename T> template <typename T>
static inline std::vector<T> static inline std::vector<T>
select_T(const std::vector<T> &inVec, select_T(const std::vector<T> &inVec,
@ -90,7 +51,7 @@ namespace util
} }
#if defined APL || defined LIN #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 { struct stat buf {
}; };
@ -100,7 +61,7 @@ namespace util
} }
#endif #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++) { for (int i = 0; i < MD5LEN; i++) {
if (buffer != nullptr) { if (buffer != nullptr) {
@ -109,6 +70,11 @@ namespace util
} }
} }
static inline bool fileExists(const char *path)
{
return static_cast<bool>(std::ifstream(path));
}
#ifdef IBM #ifdef IBM
static inline int static inline int
generateMD5(const char *filepath, generateMD5(const char *filepath,
@ -293,6 +259,50 @@ namespace util
} }
#pragma clang diagnostic pop #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<std::string> split(const std::string &s, char delim)
{
std::vector<std::string> result;
std::stringstream ss(s);
std::string item;
while (getline(ss, item, delim)) {
result.push_back(item);
}
return result;
}
} // namespace germanairlinesva_util
#endif #endif

View File

@ -3,53 +3,56 @@
#include <cstdint> #include <cstdint>
/* 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(push) /* push current alignment to stack */
#pragma pack(1) /* set alignment to 1 byte boundary */ #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 { typedef enum commands {
double latitude; PROCESS,
double longitude; SAVE,
float trueHeading; LOAD,
} command_port; 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 */ #pragma pack(pop) /* restore original alignment from stack */
} // namespace germanairlinesva_websocket
#endif #endif

View File

@ -19,23 +19,26 @@
#include <string> #include <string>
#include <utility> #include <utility>
class Websocket namespace germanairlinesva_websocket
{ {
private: class Websocket
char lastPath[513] = ""; {
char lastHash[2 * MD5LEN + 1] = ""; private:
ix::WebSocket *webSocket = nullptr; char lastPath[513] = "";
std::string host; char lastHash[2 * MD5LEN + 1] = "";
std::string user; ix::WebSocket *webSocket = nullptr;
std::function<void(std::string)> toLog; std::string host;
std::string user;
std::function<void(std::string)> toLog;
public: public:
explicit Websocket(std::string host, explicit Websocket(std::string host,
std::string user, std::string user,
std::function<void(const std::string)> toLog); std::function<void(const std::string)> toLog);
~Websocket(); ~Websocket();
void onClientMessageCallback(const ix::WebSocketMessagePtr &msg); void onClientMessageCallback(const ix::WebSocketMessagePtr &msg);
void sendData(data &d); void sendData(data &d);
}; };
} // namespace germanairlinesva_websocket
#endif #endif

View File

@ -1,107 +1,110 @@
#include "include/websocket.h" #include "include/websocket.h"
Websocket::Websocket(std::string host, namespace germanairlinesva_websocket
std::string user,
std::function<void(const std::string)> toLog)
: host(host), user(user), toLog(std::move(toLog))
{ {
Websocket::Websocket(std::string host,
std::string user,
std::function<void(const std::string)> toLog)
: host(host), user(user), toLog(std::move(toLog))
{
#ifdef IBM #ifdef IBM
// Required on Windows // Required on Windows
ix::initNetSystem(); ix::initNetSystem();
#endif #endif
webSocket = new ix::WebSocket(); webSocket = new ix::WebSocket();
webSocket->enableAutomaticReconnection(); webSocket->enableAutomaticReconnection();
webSocket->setUrl(host); webSocket->setUrl(host);
webSocket->setOnMessageCallback([this](const ix::WebSocketMessagePtr &msg) { webSocket->setOnMessageCallback([this](const ix::WebSocketMessagePtr &msg) {
this->onClientMessageCallback(msg); this->onClientMessageCallback(msg);
}); });
webSocket->start(); webSocket->start();
} }
Websocket::~Websocket() Websocket::~Websocket()
{ {
webSocket->stop(); webSocket->stop();
toLog("WebSocket stopped"); toLog("WebSocket stopped");
#ifdef IBM #ifdef IBM
// Required on Windows // Required on Windows
ix::uninitNetSystem(); ix::uninitNetSystem();
#endif #endif
} }
void Websocket::onClientMessageCallback(const ix::WebSocketMessagePtr &msg) void Websocket::onClientMessageCallback(const ix::WebSocketMessagePtr &msg)
{ {
if (msg->type == ix::WebSocketMessageType::Open) { 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 {
std::stringstream debug_msg; std::stringstream debug_msg;
debug_msg << "Connection closed" << std::endl; debug_msg << "New connection" << std::endl;
debug_msg << "Code: " << msg->closeInfo.code << std::endl; debug_msg << "Uri: " << msg->openInfo.uri << std::endl;
debug_msg << "Reason: " << msg->closeInfo.reason << std::endl; debug_msg << "Headers:" << std::endl;
debug_msg << "Remote: " << msg->closeInfo.remote << std::endl; for (const auto &it : msg->openInfo.headers) {
debug_msg << it.first << ": " << it.second << std::endl;
}
toLog(debug_msg.str()); toLog(debug_msg.str());
}
} else if (msg->type == ix::WebSocketMessageType::Error) {
std::stringstream debug_msg;
debug_msg << "Connection error" << std::endl; webSocket->send("MASTER:" + user);
debug_msg << "Decompression: " << msg->errorInfo.decompressionError toLog("Connecting as " + user);
<< std::endl; } else if (msg->type == ix::WebSocketMessageType::Close) {
debug_msg << "HTTP status: " << msg->errorInfo.http_status << std::endl; if (msg->closeInfo.reason.compare("DUPLICATE")) {
debug_msg << "Reason: " << msg->errorInfo.reason << std::endl; webSocket->disableAutomaticReconnection();
debug_msg << "Retries: " << msg->errorInfo.retries << std::endl;
debug_msg << "Wait time: " << msg->errorInfo.wait_time << std::endl;
toLog(debug_msg.str()); toLog("Disconnected due to beeing a duplicate simualtor");
} else if (msg->type == ix::WebSocketMessageType::Message) { } else {
if (!msg->str.empty()) { std::stringstream debug_msg;
toLog(msg->str);
}
}
}
void Websocket::sendData(data &d) debug_msg << "Connection closed" << std::endl;
{ debug_msg << "Code: " << msg->closeInfo.code << std::endl;
if (strcmp(d.path, lastPath) != 0) { debug_msg << "Reason: " << msg->closeInfo.reason << std::endl;
strcpy(lastPath, d.path); debug_msg << "Remote: " << msg->closeInfo.remote << std::endl;
if (util::generateMD5(d.path, lastHash, toLog)) {
strcpy(lastHash, "NOT SET"); 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 = { void Websocket::sendData(data &d)
{"altitude", d.alt}, {
{"vs", d.vs}, if (strcmp(d.path, lastPath) != 0) {
{"ias", d.ias}, strcpy(lastPath, d.path);
{"magHdg", d.magHeading}, if (germanairlinesva_util::generateMD5(d.path, lastHash, toLog)) {
{"truHdg", d.truHdg}, strcpy(lastHash, "NOT SET");
{"totFuel", d.totFuelKg}, }
{"fuelFlow", d.ff}, }
{"hash", lastHash},
};
if (webSocket != nullptr) { nlohmann::json json = {
std::ostringstream msg; {"altitude", d.alt},
msg << "SEND:" << user << ":" << json.dump(); {"vs", d.vs},
webSocket->send(msg.str(), false); {"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);
}
} }
} } // namespace germanairlinesva_websocket

View File

@ -9,7 +9,7 @@ add_library(germanairlinesva_xplugin SHARED
target_include_directories(germanairlinesva_xplugin PRIVATE target_include_directories(germanairlinesva_xplugin PRIVATE
${CMAKE_SOURCE_DIR}/ixwebsocket/include ${CMAKE_SOURCE_DIR}/ixwebsocket/include
${CMAKE_SOURCE_DIR}/makerwysxp/include ${CMAKE_SOURCE_DIR}/simdata/include
${CMAKE_SOURCE_DIR}/websocket/include ${CMAKE_SOURCE_DIR}/websocket/include
${CMAKE_SOURCE_DIR}/utilities/include ${CMAKE_SOURCE_DIR}/utilities/include
${CMAKE_SOURCE_DIR}/nlohmann/include ${CMAKE_SOURCE_DIR}/nlohmann/include
@ -134,6 +134,6 @@ elseif(WIN32)
endif() endif()
target_link_libraries(germanairlinesva_xplugin PRIVATE target_link_libraries(germanairlinesva_xplugin PRIVATE
makerwysxp simdata
ixwebsocket ixwebsocket
) )

View File

@ -2,8 +2,8 @@
#define GERMANAIRLINESVA_GACONNECTOR_XPLUGIN_MAIN_H #define GERMANAIRLINESVA_GACONNECTOR_XPLUGIN_MAIN_H
#include "config.hpp" #include "config.hpp"
#include "makeRwysXP.h"
#include "recordingPath.hpp" #include "recordingPath.hpp"
#include "simdata.h"
#include "simulatorDatabase.hpp" #include "simulatorDatabase.hpp"
#include "websocket.h" #include "websocket.h"

View File

@ -12,7 +12,7 @@ std::atomic<bool> wantsExit;
std::map<std::string, std::string> configuration; std::map<std::string, std::string> configuration;
Websocket *connector; germanairlinesva_websocket::Websocket *connector;
/* Datarefs */ /* Datarefs */
XPLMDataRef pauseIndicator; XPLMDataRef pauseIndicator;
@ -42,7 +42,7 @@ XPLMDataRef pitch;
XPLMDataRef roll; XPLMDataRef roll;
XPLMDataRef quaternion; XPLMDataRef quaternion;
data toSend; germanairlinesva_websocket::data toSend;
Path p; Path p;
/* /*
@ -107,14 +107,15 @@ PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc)
roll = XPLMFindDataRef("sim/flightmodel/position/phi"); // FLOAT roll = XPLMFindDataRef("sim/flightmodel/position/phi"); // FLOAT
quaternion = XPLMFindDataRef("sim/flightmodel/position/q"); // FLOAT[4] quaternion = XPLMFindDataRef("sim/flightmodel/position/q"); // FLOAT[4]
configuration = configuration = germanairlinesva_config::readConfig(
config::readConfig("Resources/plugins/GAConnector/config.cfg"); "Resources/plugins/GAConnector/config.cfg");
toLog("Config loaded"); toLog("Config loaded");
try { try {
connector = new Websocket("wss://ws.hofmannnet.myhome-server.de:8000", connector = new germanairlinesva_websocket::Websocket(
configuration["user"], "wss://ws.hofmannnet.myhome-server.de:8000",
toLog); configuration["user"],
toLog);
} catch (const std::invalid_argument &e) { } catch (const std::invalid_argument &e) {
toLog(e.what()); toLog(e.what());
return 0; return 0;
@ -122,28 +123,44 @@ PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc)
toLog("WebSocket started"); toLog("WebSocket started");
char hash[2 * MD5LEN + 1] = ""; char hash[2 * MD5LEN + 1] = "";
if (util::generateMD5("Custom Scenery/scenery_packs.ini", hash, toLog) == 0) { if (germanairlinesva_util::generateMD5("Custom Scenery/scenery_packs.ini",
std::map<std::string, std::pair<std::vector<Gate>, std::vector<Runway>>> hash,
toLog) == 0) {
std::map<std::string,
std::pair<std::vector<germanairlinesva_simdata::Gate>,
std::vector<germanairlinesva_simdata::Runway>>>
airports; 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 " scan("Resources/default scenery/default apt dat/Earth nav "
"data/apt.dat", "data/apt.dat",
"Custom Scenery/scenery_packs.ini", "Custom Scenery/scenery_packs.ini",
"Resources/plugins/GAConnector/log.txt", "Resources/plugins/GAConnector/log.txt",
airports); airports);
simulatorDatabase::toFile(airports, germanairlinesva_simdata::toFile(airports,
"Resources/plugins/GAConnector/sim.bin"); "Resources/plugins/GAConnector/sim.bin");
configuration["scenery"] = hash; configuration["scenery"] = hash;
config::writeConfig(configuration, germanairlinesva_config::writeConfig(
"Resources/plugins/GAConnector/config.cfg"); configuration,
"Resources/plugins/GAConnector/config.cfg");
toLog("Sim Database updated"); toLog("Sim Database updated");
} else { } else {
airports = airports = germanairlinesva_simdata::fromFile(
simulatorDatabase::fromFile("Resources/plugins/GAConnector/sim.bin"); "Resources/plugins/GAConnector/sim.bin");
toLog("Sim Database loaded"); 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 // 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<std::mutex> lock(mutex); const std::lock_guard<std::mutex> lock(mutex);
memset(&toSend, 0, sizeof(data)); memset(&toSend, 0, sizeof(germanairlinesva_websocket::data));
toSend.pause = XPLMGetDatai(pauseIndicator); toSend.pause = XPLMGetDatai(pauseIndicator);
toSend.pBrake = XPLMGetDataf(parkingBrake); toSend.pBrake = XPLMGetDataf(parkingBrake);
@ -226,14 +243,14 @@ float flightLoop(float elapsedMe, float elapsedSim, int counter, void *refcon)
void serverWorker() void serverWorker()
{ {
util::setThreadName("GAServerWorker"); germanairlinesva_util::setThreadName("GAServerWorker");
while (!wantsExit) { while (!wantsExit) {
data copy; germanairlinesva_websocket::data copy;
{ {
const std::lock_guard<std::mutex> lock(mutex); const std::lock_guard<std::mutex> lock(mutex);
memcpy(&copy, &toSend, sizeof(data)); memcpy(&copy, &toSend, sizeof(germanairlinesva_websocket::data));
} }
connector->sendData(copy); connector->sendData(copy);
@ -244,16 +261,16 @@ void serverWorker()
void recordingWorker() void recordingWorker()
{ {
util::setThreadName("GARecordingWorker"); germanairlinesva_util::setThreadName("GARecordingWorker");
PathSegment lastPath; PathSegment lastPath;
while (!wantsExit) { while (!wantsExit) {
data copy; germanairlinesva_websocket::data copy;
{ {
const std::lock_guard<std::mutex> lock(mutex); const std::lock_guard<std::mutex> lock(mutex);
memcpy(&copy, &toSend, sizeof(data)); memcpy(&copy, &toSend, sizeof(germanairlinesva_websocket::data));
} }
PathSegment currentPath(static_cast<std::uint16_t>(copy.alt), PathSegment currentPath(static_cast<std::uint16_t>(copy.alt),