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 <QFile>
#include <QDateTime> #include <QDateTime>
#include <QTimeZone>
#include <QStringBuilder> #include <QStringBuilder>
#include <QRegularExpression> #include <QRegularExpression>
#include <QDomDocument> #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) QString CFlightPlanRemarks::cut(const QString &remarks, const QString &marker)
{ {
const int maxIndex = remarks.size() - 1; const int maxIndex = remarks.size() - 1;
@@ -186,6 +212,16 @@ namespace BlackMisc
m_equipmentSuffix = parts[2]; 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) void CFlightPlan::setFlightRule(const QString &flightRule)
{ {
const CFlightPlan::FlightRules r = CFlightPlan::stringToFlightRules(flightRule); const CFlightPlan::FlightRules r = CFlightPlan::stringToFlightRules(flightRule);
@@ -210,6 +246,16 @@ namespace BlackMisc
m_remarks.setVoiceCapabilities(vc); 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 CFlightPlan::FlightRules CFlightPlan::getFlightRulesAsVFRorIFR() const
{ {
switch (this->getFlightRules()) switch (this->getFlightRules())
@@ -404,20 +450,112 @@ namespace BlackMisc
return fp; 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 (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("[SBFlightPlan]", Qt::CaseInsensitive)) { return CFlightPlan::fromSB4Format(data); }
if (data.contains("<FlightPlan", Qt::CaseInsensitive) && data.contains("<?xml", Qt::CaseInsensitive)) { return CFlightPlan::fromVPilotFormat(data); } if (data.contains("<FlightPlan", Qt::CaseInsensitive) && data.contains("<?xml", Qt::CaseInsensitive)) { return CFlightPlan::fromVPilotFormat(data); }
return CFlightPlan::fromJson(data); return CFlightPlan::fromJson(data);
} }
CFlightPlan CFlightPlan::fromMultipleFormatsNoThrow(const QString &data) CFlightPlan CFlightPlan::fromMultipleFormatsNoThrow(const QString &data, const QString &fileSuffix)
{ {
CFlightPlan fp; CFlightPlan fp;
try try
{ {
fp = CFlightPlan::fromMultipleFormats(data); fp = CFlightPlan::fromMultipleFormats(data, fileSuffix);
} }
catch (const CJsonException &ex) catch (const CJsonException &ex)
{ {
@@ -431,6 +569,7 @@ namespace BlackMisc
{ {
try try
{ {
QFileInfo fi(fileName);
if (fileName.isEmpty()) if (fileName.isEmpty())
{ {
if (msgs) { msgs->push_back(CStatusMessage(getLogCategories()).validationError(u"No file name")); } if (msgs) { msgs->push_back(CStatusMessage(getLogCategories()).validationError(u"No file name")); }
@@ -438,8 +577,7 @@ namespace BlackMisc
} }
else else
{ {
QFile f(fileName); if (!fi.exists())
if (!f.exists())
{ {
if (msgs) { msgs->push_back(CStatusMessage(getLogCategories()).validationError(u"File '%1' does not exist") << fileName); } if (msgs) { msgs->push_back(CStatusMessage(getLogCategories()).validationError(u"File '%1' does not exist") << fileName); }
return CFlightPlan(); return CFlightPlan();
@@ -502,7 +640,7 @@ namespace BlackMisc
while (false); while (false);
} }
return CFlightPlan::fromMultipleFormats(data); return CFlightPlan::fromMultipleFormats(data, fi.suffix());
} }
catch (const CJsonException &ex) catch (const CJsonException &ex)
{ {

View File

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