Skip to content

Commit

Permalink
Now also showing ILS frequency for final approach in flight plan tabl…
Browse files Browse the repository at this point in the history
…e for circling as well as IGS, LDA, LOC and SDF approaches if navaid is present.
  • Loading branch information
albar965 committed Aug 13, 2021
1 parent add8f9e commit d1a70e7
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 59 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ This version fixes flight plan issues with X-Plane as well as flight plan export
labels on the map.
* More tolerance for finding airports when loading flight plans. Trying all available internal and
official ids (ICAO, FAA, IATA and local) now.
* Now also showing ILS frequency for final approach in flight plan table for circling as well as
IGS, LDA, LOC and SDF approaches if navaid is present.

### Web interface

Expand Down
4 changes: 3 additions & 1 deletion src/common/maptypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,9 @@ struct MapIls
{
}

QString ident, name, region;
QString ident, /* IRHF */
name, /* ILS-CAT-I */
region;
float magvar, slope, heading, width;
int frequency /* MHz * 1000 */, range /* nm */;

Expand Down
15 changes: 3 additions & 12 deletions src/common/proctypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,8 @@ struct MapProcedureLegs
MapProcedureRef ref;
atools::geo::Rect bounding;

QString approachType, approachSuffix, approachFixIdent /* Approach fix or SID/STAR name */,
QString approachType, /* GPS ILS LDA LOC LOCB NDB NDBDME RNAV SDF VOR VORDME */
approachSuffix, approachFixIdent /* Approach fix or SID/STAR name */,
approachArincName, transitionType, transitionFixIdent,
procedureRunway; /* Runway from the procedure does not have to match the airport runway but is saved */

Expand All @@ -466,17 +467,7 @@ struct MapProcedureLegs
bool hasIlsGuidance() const
{
return approachType == "ILS" || approachType == "LOC" || approachType == "LOCB" || approachType == "LDA" ||
approachType == "IGS";
}

bool isTypeIls() const
{
return approachType == "ILS";
}

bool isTypeLoc() const
{
return approachType == "LOC";
approachType == "IGS" || approachType == "SDF";
}

bool isCustom() const
Expand Down
42 changes: 32 additions & 10 deletions src/query/mapquery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,16 +511,31 @@ QVector<map::MapIls> MapQuery::getIlsByAirportAndRunway(const QString& airportId
return ils;
}

QVector<MapIls> MapQuery::getIlsByAirportAndIdent(const QString& airportIdent, const QString& ilsIdent)
{
QVector<map::MapIls> ilsList;
ilsQuerySimByAirportAndIdent->bindValue(":apt", airportIdent);
ilsQuerySimByAirportAndIdent->bindValue(":ident", ilsIdent);
ilsQuerySimByAirportAndIdent->exec();
while(ilsQuerySimByAirportAndIdent->next())
{
map::MapIls ils;
mapTypesFactory->fillIls(ilsQuerySimByAirportAndIdent->record(), ils);
ilsList.append(ils);
}
return ilsList;
}

QVector<map::MapIls> MapQuery::ilsByAirportAndRunway(const QString& airportIdent, const QString& runway)
{
QVector<map::MapIls> ilsList;
ilsQuerySimByName->bindValue(":apt", airportIdent);
ilsQuerySimByName->bindValue(":rwy", runway);
ilsQuerySimByName->exec();
while(ilsQuerySimByName->next())
ilsQuerySimByAirportAndRw->bindValue(":apt", airportIdent);
ilsQuerySimByAirportAndRw->bindValue(":rwy", runway);
ilsQuerySimByAirportAndRw->exec();
while(ilsQuerySimByAirportAndRw->next())
{
map::MapIls ils;
mapTypesFactory->fillIls(ilsQuerySimByName->record(), ils);
mapTypesFactory->fillIls(ilsQuerySimByAirportAndRw->record(), ils);
ilsList.append(ils);
}
return ilsList;
Expand Down Expand Up @@ -1116,9 +1131,13 @@ void MapQuery::initQueries()
ilsByIdQuery = new SqlQuery(dbSim);
ilsByIdQuery->prepare("select " + ilsQueryBase + " from ils where ils_id = :id");

ilsQuerySimByName = new SqlQuery(dbSim);
ilsQuerySimByName->prepare("select " + ilsQueryBase + " from ils "
"where loc_airport_ident = :apt and loc_runway_name = :rwy");
ilsQuerySimByAirportAndRw = new SqlQuery(dbSim);
ilsQuerySimByAirportAndRw->prepare("select " + ilsQueryBase +
" from ils where loc_airport_ident = :apt and loc_runway_name = :rwy");

ilsQuerySimByAirportAndIdent = new SqlQuery(dbSim);
ilsQuerySimByAirportAndIdent->prepare("select " + ilsQueryBase +
" from ils where loc_airport_ident = :apt and ident = :ident");

airportByRectQuery = new SqlQuery(dbSim);
airportByRectQuery->prepare(
Expand Down Expand Up @@ -1223,6 +1242,9 @@ void MapQuery::deInitQueries()
delete ilsByIdQuery;
ilsByIdQuery = nullptr;

delete ilsQuerySimByName;
ilsQuerySimByName = nullptr;
delete ilsQuerySimByAirportAndRw;
ilsQuerySimByAirportAndRw = nullptr;

delete ilsQuerySimByAirportAndIdent;
ilsQuerySimByAirportAndIdent = nullptr;
}
9 changes: 7 additions & 2 deletions src/query/mapquery.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,13 @@ class MapQuery
/* Always from sim db */
map::MapIls getIlsById(int id);

/* Get ILS from sim database based on airport ident and runway name.
* Runway name can be zero prefixed or prefixed with "RW". */
QVector<map::MapIls> getIlsByAirportAndRunway(const QString& airportIdent, const QString& runway);

/* Get ILS from sim database based on airport ident and ILS ident. Uses exact match. */
QVector<map::MapIls> getIlsByAirportAndIdent(const QString& airportIdent, const QString& ilsIdent);

/* Get runway end and try lower and higher numbers if nothing was found - adds a dummy entry with airport
* position if no runway ends were found */
void getRunwayEndByNameFuzzy(QList<map::MapRunwayEnd>& runwayEnds, const QString& name,
Expand Down Expand Up @@ -244,8 +249,8 @@ class MapQuery
atools::sql::SqlQuery *vorByIdentQuery = nullptr, *ndbByIdentQuery = nullptr, *ilsByIdentQuery = nullptr;

atools::sql::SqlQuery *vorByIdQuery = nullptr, *ndbByIdQuery = nullptr, *vorByWaypointIdQuery = nullptr,
*ndbByWaypointIdQuery = nullptr, *ilsByIdQuery = nullptr, *ilsQuerySimByName = nullptr,
*vorNearestQuery = nullptr, *ndbNearestQuery = nullptr;
*ndbByWaypointIdQuery = nullptr, *ilsByIdQuery = nullptr, *ilsQuerySimByAirportAndRw = nullptr,
*ilsQuerySimByAirportAndIdent = nullptr, *vorNearestQuery = nullptr, *ndbNearestQuery = nullptr;
};

#endif // LITTLENAVMAP_MAPQUERY_H
100 changes: 71 additions & 29 deletions src/route/route.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2899,46 +2899,88 @@ int Route::getAdjustedAltitude(int newAltitude) const
return newAltitude;
}

void Route::getApproachRunwayEndAndIls(QVector<map::MapIls>& ils, map::MapRunwayEnd *runwayEnd) const
void Route::getApproachRunwayEndAndIls(QVector<map::MapIls>& ilsVector, map::MapRunwayEnd *runwayEnd) const
{
QList<map::MapRunwayEnd> runwayEnds;
NavApp::getMapQuery()->getRunwayEndByNameFuzzy(runwayEnds, approachLegs.runwayEnd.name,
getDestinationAirportLeg().getAirport(),
false /* nav data */);
QString destIdent = getDestinationAirportLeg().getIdent();

if(runwayEnd != nullptr && !runwayEnds.isEmpty())
*runwayEnd = runwayEnds.first();

ils.clear();
if(approachLegs.runwayEnd.isValid())
if(!approachLegs.runwayEnd.name.isEmpty() && approachLegs.runwayEnd.name != "RW")
{
QString destIdent = getDestinationAirportLeg().getIdent();
// Get one or more ILS from flight plan leg as is
ils = NavApp::getMapQuery()->getIlsByAirportAndRunway(destIdent, approachLegs.runwayEnd.name);
// Runway name given ========================
QList<map::MapRunwayEnd> runwayEnds;
NavApp::getMapQuery()->getRunwayEndByNameFuzzy(runwayEnds, approachLegs.runwayEnd.name,
getDestinationAirportLeg().getAirport(),
false /* nav data */);

if(ils.isEmpty())
{
// ILS does not even match runway - try fuzzy
QStringList variants = atools::fs::util::runwayNameVariants(approachLegs.runwayEnd.name);
for(const QString& runwayVariant : variants)
ils.append(NavApp::getMapQuery()->getIlsByAirportAndRunway(destIdent, runwayVariant));
}
if(runwayEnd != nullptr && !runwayEnds.isEmpty())
*runwayEnd = runwayEnds.first();

if(ils.size() > 1)
ilsVector.clear();
if(approachLegs.runwayEnd.isValid())
{
for(const proc::MapProcedureLeg& leg : approachLegs.approachLegs)
// Have runway for approach ============================================
// Get one or more ILS from flight plan leg as is
ilsVector = NavApp::getMapQuery()->getIlsByAirportAndRunway(destIdent, approachLegs.runwayEnd.name);

if(ilsVector.isEmpty())
{
for(map::MapIls i : ils)
// ILS does not even match runway - try fuzzy to consider renamed runways
QStringList variants = atools::fs::util::runwayNameVariants(approachLegs.runwayEnd.name);
for(const QString& runwayVariant : variants)
ilsVector.append(NavApp::getMapQuery()->getIlsByAirportAndRunway(destIdent, runwayVariant));
}

if(ilsVector.size() > 1)
{
// Found more than one ILS for approach - look for recommended fix reference in approach legs
// Iterate backwards to catch the recommended fix closest to the runway
for(int i = approachLegs.approachLegs.size() - 1; i >= 0; i--)
{
if(leg.recFixIdent == i.ident)
const proc::MapProcedureLeg& leg = approachLegs.approachLegs.at(i);

// Do not look for NDB and waypoints - try VOR (V) and ILS/localizer (L)
if(!leg.isMissed() && !leg.recFixIdent.isEmpty() && leg.recFixType != "N" && leg.recFixType != "TW" &&
leg.recFixType != "TN" && leg.recFixType != "W")
{
ils.clear();
ils.append(i);
map::MapIls foundIls;
for(const map::MapIls& ils : ilsVector)
{
if(leg.recFixIdent == ils.ident)
{
foundIls = ils;
break;
}
}

if(foundIls.isValid())
{
// Recommended matches ILS in the list
ilsVector.clear();
ilsVector.append(foundIls);
}
}
}
}
} // for(int i = approachLegs.approachLegs.size() - 1; i >= 0; i--)
} // if(ilsVector.size() > 1)
} // if(approachLegs.runwayEnd.isValid())
} // if(!approachLegs.runwayEnd.name.isEmpty() && approachLegs.runwayEnd.name != "RW")

if(ilsVector.isEmpty())
{
// No runway for approach - circling ============================================
// Iterate backwards to catch the recommended fix closest to the runway
for(int i = approachLegs.approachLegs.size() - 1; i >= 0; i--)
{
const proc::MapProcedureLeg& leg = approachLegs.approachLegs.at(i);

// Do not look for NDB and waypoints - try VOR (V) and ILS/localizer (L)
if(!leg.isMissed() && !leg.recFixIdent.isEmpty() && leg.recFixType != "N" && leg.recFixType != "TW" &&
leg.recFixType != "TN" && leg.recFixType != "W")
// Get ILS referenced in the recommended fix
ilsVector = NavApp::getMapQuery()->getIlsByAirportAndIdent(destIdent, leg.recFixIdent);

if(!ilsVector.isEmpty())
break;
}
}
} // if(ilsVector.isEmpty())
}

bool Route::isTooFarToFlightPlan() const
Expand Down
2 changes: 1 addition & 1 deletion src/route/route.h
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ class Route :
void updateLegAltitudes();

/* Get a list of approach ILS (not localizer) and the used runway end. Only for approaches. */
void getApproachRunwayEndAndIls(QVector<map::MapIls>& ils, map::MapRunwayEnd *runwayEnd = nullptr) const;
void getApproachRunwayEndAndIls(QVector<map::MapIls>& ilsVector, map::MapRunwayEnd *runwayEnd = nullptr) const;

/* general distance in NM which is either cross track, previous or next waypoint */
float getDistanceToFlightPlan() const;
Expand Down
7 changes: 3 additions & 4 deletions src/route/routecontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3942,8 +3942,8 @@ void RouteController::updateTableModel()

// Get ILS for approach runway if it marks the end of an ILS or localizer approach procedure
QVector<map::MapIls> ilsByAirportAndRunway;
if(route.getApproachLegs().hasIlsGuidance() &&
leg.isAnyProcedure() && leg.getProcedureLeg().isApproach() && leg.getRunwayEnd().isValid())
if(route.getApproachLegs().hasIlsGuidance() && leg.isAnyProcedure() && leg.getProcedureLeg().isApproach() &&
leg.getRunwayEnd().isValid())
route.getApproachRunwayEndAndIls(ilsByAirportAndRunway);

// VOR/NDB type ===========================
Expand Down Expand Up @@ -3977,8 +3977,7 @@ void RouteController::updateTableModel()
}
else if(leg.getNdb().isValid())
itemRow[rcol::FREQ] = new QStandardItem(QLocale().toString(leg.getFrequency() / 100.f, 'f', 1));
else if(leg.isAnyProcedure() && !(leg.getProcedureLeg().isMissed()) &&
leg.getRunwayEnd().isValid())
else if(leg.isAnyProcedure() && !(leg.getProcedureLeg().isMissed()) && leg.getRunwayEnd().isValid())
{
// Add ILS frequencies
QStringList texts;
Expand Down

0 comments on commit d1a70e7

Please sign in to comment.