Ref T417, parse SimBrief XML format

This commit is contained in:
Klaus Basan
2019-06-28 16:37:51 +02:00
committed by Mat Sutcliffe
parent 3f66adfb94
commit 88373744f8
3 changed files with 13345 additions and 13 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,7 @@
#include <QFile>
#include <QDateTime>
#include <QTimeZone>
#include <QStringBuilder>
#include <QRegularExpression>
#include <QDomDocument>
@@ -125,6 +126,31 @@ namespace BlackMisc
}
}
void CFlightPlanRemarks::setIcaoEquipmentCodes(const QString &eq)
{
// https://en.wikipedia.org/wiki/Equipment_codes
const QString r = eq.toUpper().trimmed();
QStringList remarks;
if (r.isEmpty()) { return; }
if (r.contains('W'))
{
if (r.contains('G')) { remarks << "/L"; }
else if (r.contains('D') || r.contains('L') || r.contains('O')) { remarks << "/Z"; }
else if (r.contains('A')) { remarks << "/W"; }
}
else
{
if (r.contains('G')) { remarks << "/G"; }
else if (r.contains('D') || r.contains('L') || r.contains('O')) { remarks << "/I"; }
}
if (r.contains('G')) { remarks << "NAV/GPSRNAV"; }
else if (r.contains('D') || r.contains('L') || r.contains('O')) { remarks << "NAV/VORNDB"; }
m_remarks = remarks.join(" ");
this->parseFlightPlanRemarks(true);
}
QString CFlightPlanRemarks::cut(const QString &remarks, const QString &marker)
{
const int maxIndex = remarks.size() - 1;
@@ -186,6 +212,16 @@ namespace BlackMisc
m_equipmentSuffix = parts[2];
}
void CFlightPlan::setTakeoffTimePlanned(const QDateTime &takeoffTimePlanned)
{
m_takeoffTimePlanned = takeoffTimePlanned.toUTC();
}
void CFlightPlan::setTakeoffTimeActual(const QDateTime &takeoffTimeActual)
{
m_takeoffTimeActual = takeoffTimeActual.toUTC();
}
void CFlightPlan::setFlightRule(const QString &flightRule)
{
const CFlightPlan::FlightRules r = CFlightPlan::stringToFlightRules(flightRule);
@@ -210,6 +246,16 @@ namespace BlackMisc
m_remarks.setVoiceCapabilities(vc);
}
QString CFlightPlan::getTakeoffTimePlannedHourMin() const
{
return m_takeoffTimePlanned.toString("hh:mm");
}
QString CFlightPlan::getTakeoffTimeActualHourMin() const
{
return m_takeoffTimeActual.toString("hh:mm");
}
CFlightPlan::FlightRules CFlightPlan::getFlightRulesAsVFRorIFR() const
{
switch (this->getFlightRules())
@@ -404,20 +450,112 @@ namespace BlackMisc
return fp;
}
CFlightPlan CFlightPlan::fromMultipleFormats(const QString &data)
CFlightPlan CFlightPlan::fromSimBriefFormat(const QString &simBrief)
{
if (simBrief.isEmpty()) { return CFlightPlan(); }
CFlightPlan fp;
QDomDocument doc;
doc.setContent(simBrief);
const QDomNodeList originList = doc.elementsByTagName("origin");
if (!originList.isEmpty())
{
const QDomNode origin = originList.at(0);
const QString icao = origin.firstChildElement("icao_code").text();
fp.setOriginAirportIcao(icao);
}
const QDomNodeList destList = doc.elementsByTagName("destination");
if (!destList.isEmpty())
{
const QDomNode dest = destList.at(0);
const QString icao = dest.firstChildElement("icao_code").text();
fp.setDestinationAirportIcao(icao);
}
const QDomNodeList altList = doc.elementsByTagName("alternate");
if (!altList.isEmpty())
{
const QDomNode alternate = altList.at(0);
const QString icao = alternate.firstChildElement("icao_code").text();
fp.setAlternateAirportIcao(icao);
}
const QDomNodeList generalList = doc.elementsByTagName("general");
if (!generalList.isEmpty())
{
bool ok;
const QDomNode general = generalList.at(0);
QString route = general.firstChildElement("route").text();
fp.setRoute(route.remove("DCT").simplified().trimmed());
const QString airline = general.firstChildElement("icao_airline").text();
const QString flightNumber = general.firstChildElement("flight_number").text();
fp.setCallsign(CCallsign(airline + flightNumber, CCallsign::Aircraft));
const QString cruiseAlt = general.firstChildElement("initial_altitude").text();
fp.setCruiseAltitudeString(cruiseAlt);
const QString tas = general.firstChildElement("cruise_tas").text();
const int tasKts = tas.toInt(&ok);
if (ok) { fp.setCruiseTrueAirspeed(CSpeed(tasKts, CSpeedUnit::kts())); }
}
const QDomNodeList timeList = doc.elementsByTagName("times");
if (!timeList.isEmpty())
{
bool ok;
const QDomNode times = timeList.at(0);
const QString enroute = times.firstChildElement("est_time_enroute").text();
const int enrouteSecs = enroute.toInt(&ok);
if (ok) { fp.setEnrouteTime(CTime(enrouteSecs, CTimeUnit::s())); }
const QString endurance = times.firstChildElement("endurance").text();
const int enduranceSecs = endurance.toInt(&ok);
if (ok) { fp.setFuelTime(CTime(enduranceSecs, CTimeUnit::s())); }
const QString depTime = times.firstChildElement("sched_out").text();
const int depTimeUnixTs = depTime.toInt(&ok);
if (ok)
{
QDateTime depTs = QDateTime::fromSecsSinceEpoch(depTimeUnixTs, QTimeZone::utc());
depTs.setTimeZone(QTimeZone::utc());
fp.setTakeoffTimePlanned(depTs);
}
}
const QDomNodeList aircraftList = doc.elementsByTagName("aircraft");
if (!aircraftList.isEmpty())
{
const QDomNode aircraft = aircraftList.at(0);
const QString equipment = aircraft.firstChildElement("equip").text();
// H-SDE2E3GHIJ1J3J4J5LM1ORWXY/LB1D1
const int b = equipment.indexOf('-');
const int e = equipment.indexOf('/');
if (e > b && e >= 0 && b >= 0 && equipment.size() > e)
{
CFlightPlanRemarks r = fp.getFlightPlanRemarks();
const QString icao = equipment.mid(b + 1, e - b - 1);
r.setIcaoEquipmentCodes(icao);
fp.setFlightPlanRemarks(r);
}
}
// read FP
return fp;
}
CFlightPlan CFlightPlan::fromMultipleFormats(const QString &data, const QString &fileSuffix)
{
if (data.isEmpty()) { return CFlightPlan(); }
if (fileSuffix.contains("xml", Qt::CaseInsensitive))
{
if (data.contains("<OFP>", Qt::CaseInsensitive) && data.contains("<general>", Qt::CaseInsensitive)) { return CFlightPlan::fromSimBriefFormat(data); }
}
if (data.contains("[SBFlightPlan]", Qt::CaseInsensitive)) { return CFlightPlan::fromSB4Format(data); }
if (data.contains("<FlightPlan", Qt::CaseInsensitive) && data.contains("<?xml", Qt::CaseInsensitive)) { return CFlightPlan::fromVPilotFormat(data); }
return CFlightPlan::fromJson(data);
}
CFlightPlan CFlightPlan::fromMultipleFormatsNoThrow(const QString &data)
CFlightPlan CFlightPlan::fromMultipleFormatsNoThrow(const QString &data, const QString &fileSuffix)
{
CFlightPlan fp;
try
{
fp = CFlightPlan::fromMultipleFormats(data);
fp = CFlightPlan::fromMultipleFormats(data, fileSuffix);
}
catch (const CJsonException &ex)
{
@@ -431,6 +569,7 @@ namespace BlackMisc
{
try
{
QFileInfo fi(fileName);
if (fileName.isEmpty())
{
if (msgs) { msgs->push_back(CStatusMessage(getLogCategories()).validationError(u"No file name")); }
@@ -438,8 +577,7 @@ namespace BlackMisc
}
else
{
QFile f(fileName);
if (!f.exists())
if (!fi.exists())
{
if (msgs) { msgs->push_back(CStatusMessage(getLogCategories()).validationError(u"File '%1' does not exist") << fileName); }
return CFlightPlan();
@@ -502,7 +640,7 @@ namespace BlackMisc
while (false);
}
return CFlightPlan::fromMultipleFormats(data);
return CFlightPlan::fromMultipleFormats(data, fi.suffix());
}
catch (const CJsonException &ex)
{

View File

@@ -99,6 +99,9 @@ namespace BlackMisc
//! Empty remarks?
bool isEmpty() const { return m_remarks.isEmpty(); }
//! Equipment codes (ICAO)
void setIcaoEquipmentCodes(const QString &eq);
//! Already parsed?
bool isParsed() const { return m_isParsed; }
@@ -211,13 +214,13 @@ namespace BlackMisc
void setAlternateAirportIcao(const CAirportIcaoCode &alternateAirportIcao) { m_alternateAirportIcao = alternateAirportIcao; }
//! Set planned takeoff time
void setTakeoffTimePlanned(const QDateTime &takeoffTimePlanned) { m_takeoffTimePlanned = takeoffTimePlanned; }
void setTakeoffTimePlanned(const QDateTime &takeoffTimePlanned);
//! Set planned takeoff time hh:mm
void setTakeoffTimePlanned(const QString &time) { m_takeoffTimePlanned = QDateTime::currentDateTimeUtc(); m_takeoffTimePlanned.setTime(QTime::fromString(time, "hh:mm"));}
//! Set actual takeoff time (reserved for ATC use)
void setTakeoffTimeActual(const QDateTime &takeoffTimeActual) { m_takeoffTimeActual = takeoffTimeActual; }
void setTakeoffTimeActual(const QDateTime &takeoffTimeActual);
//! Set actual takeoff time hh:mm
void setTakeoffTimeActual(const QString &time) { m_takeoffTimeActual = QDateTime::currentDateTimeUtc(); m_takeoffTimeActual.setTime(QTime::fromString(time, "hh:mm"));}
@@ -277,13 +280,13 @@ namespace BlackMisc
const QDateTime &getTakeoffTimePlanned() const { return m_takeoffTimePlanned; }
//! Get planned takeoff time (planned)
QString getTakeoffTimePlannedHourMin() const { return m_takeoffTimePlanned.toString("hh:mm"); }
QString getTakeoffTimePlannedHourMin() const;
//! Get actual takeoff time (actual)
const QDateTime &getTakeoffTimeActual() const { return m_takeoffTimeActual; }
//! Get actual takeoff time (actual)
QString getTakeoffTimeActualHourMin() const { return m_takeoffTimeActual.toString("hh:mm"); }
QString getTakeoffTimeActualHourMin() const;
//! Get planned enroute flight time
const PhysicalQuantities::CTime &getEnrouteTime() const { return m_enrouteTime; }
@@ -333,6 +336,9 @@ namespace BlackMisc
//! Get the parsable remarks
const CFlightPlanRemarks &getFlightPlanRemarks() const { return m_remarks; }
//! Set FP remarks
void setFlightPlanRemarks(const CFlightPlanRemarks &remarks) { m_remarks = remarks; }
//! Get ICAO aircraft equipment prefix H/B737/F "H"
const QString &getPrefix() const { return m_prefix; }
@@ -378,11 +384,14 @@ namespace BlackMisc
//! From SB4 data
static CFlightPlan fromSB4Format(const QString &sbData);
//! From multiple formats
static CFlightPlan fromMultipleFormats(const QString &data);
//! From SimBrief format (XML)
static CFlightPlan fromSimBriefFormat(const QString &simBrief);
//! From multiple formats
static CFlightPlan fromMultipleFormatsNoThrow(const QString &data);
static CFlightPlan fromMultipleFormats(const QString &data, const QString &fileSuffix);
//! From multiple formats
static CFlightPlan fromMultipleFormatsNoThrow(const QString &data, const QString &fileSuffix);
//! Load from multiple formats
static CFlightPlan loadFromMultipleFormats(const QString &fileName, CStatusMessageList *msgs = nullptr);