diff --git a/src/Airports/apt_loader.cxx b/src/Airports/apt_loader.cxx index a8af8ca47..320a57150 100644 --- a/src/Airports/apt_loader.cxx +++ b/src/Airports/apt_loader.cxx @@ -286,6 +286,9 @@ private: displ_thresh2, stopway2, surface_code, true); runways.push_back(reciprocal); + + rwy->setReciprocalRunway(reciprocal); + reciprocal->setReciprocalRunway(rwy); } } @@ -335,6 +338,9 @@ private: pos, heading_2, length, width, displ_thresh2, stopway2, surface_code, true); runways.push_back(reciprocal); + + rwy->setReciprocalRunway(reciprocal); + reciprocal->setReciprocalRunway(rwy); } void parseWaterRunwayLine850(const vector& token) @@ -373,6 +379,9 @@ private: pos, heading_2, length, width, 0.0, 0.0, 13, true); runways.push_back(reciprocal); + + rwy->setReciprocalRunway(reciprocal); + reciprocal->setReciprocalRunway(rwy); } void parseHelipadLine850(const vector& token) diff --git a/src/Airports/runways.cxx b/src/Airports/runways.cxx index f97cd14e8..c076d8cfc 100644 --- a/src/Airports/runways.cxx +++ b/src/Airports/runways.cxx @@ -71,7 +71,8 @@ FGRunway::FGRunway(FGAirport* aAirport, const string& aIdent, bool reciprocal) : FGRunwayBase(RUNWAY, cleanRunwayNo(aIdent), aGeod, heading, length, width, surface_code, true), _airport(aAirport), - _reciprocal(reciprocal), + _isReciprocal(reciprocal), + _reciprocal(NULL), _displ_thresh(displ_thresh), _stopway(stopway), _ils(NULL) @@ -158,3 +159,12 @@ void FGRunway::processThreshold(SGPropertyNode* aThreshold) SGGeodesy::direct(newThreshold, _heading, offsetFt * SG_FEET_TO_METER, newCenter, dummy); mPosition = newCenter; } + +void FGRunway::setReciprocalRunway(FGRunway* other) +{ + assert(_reciprocal==NULL); + assert((other->_reciprocal == NULL) || (other->_reciprocal == this)); + + _reciprocal = other; +} + diff --git a/src/Airports/runways.hxx b/src/Airports/runways.hxx index 15d39c2af..e6f97ea95 100644 --- a/src/Airports/runways.hxx +++ b/src/Airports/runways.hxx @@ -36,7 +36,8 @@ class SGPropertyNode; class FGRunway : public FGRunwayBase { FGAirport* _airport; - bool _reciprocal; + bool _isReciprocal; + FGRunway* _reciprocal; double _displ_thresh; double _stopway; FGNavRecord* _ils; @@ -68,7 +69,7 @@ public: * over runways to avoid counting runways twice, if desired. */ bool isReciprocal() const - { return _reciprocal; } + { return _isReciprocal; } /** * Get the runway begining point - this is syntatic sugar, equivalent to @@ -106,6 +107,10 @@ public: FGNavRecord* ILS() const { return _ils; } void setILS(FGNavRecord* nav) { _ils = nav; } + FGRunway* reciprocalRunway() const + { return _reciprocal; } + void setReciprocalRunway(FGRunway* other); + /** * Helper to process property data loaded from an ICAO.threshold.xml file */ diff --git a/src/Navaids/navlist.cxx b/src/Navaids/navlist.cxx index f49052125..bbe3eb424 100644 --- a/src/Navaids/navlist.cxx +++ b/src/Navaids/navlist.cxx @@ -31,6 +31,8 @@ #include "navlist.hxx" +#include + using std::string; // FGNavList ------------------------------------------------------------------ @@ -108,49 +110,38 @@ FGNavRecord *FGNavList::findByIdentAndFreq(const string& ident, const double fre return NULL; } -// LOC, ILS, GS, and DME antenna's could potentially be -// installed at the opposite end of the runway. So it's not -// enough to simply find the closest antenna with the right -// frequency. We need the closest antenna with the right -// frequency that is most oriented towards us. (We penalize -// stations that are facing away from us by adding 5000 meters -// which is further than matching stations would ever be -// placed from each other. (Do the expensive check only for -// directional atennas and only when there is a chance it is -// the closest station.) - -static bool penaltyForNav(FGNavRecord* aNav, const SGGeod &aGeod) +// discount navids if they conflict with another on the same frequency +// this only applies to navids associated with opposite ends of a runway, +// with matching frequencies. +static bool navidUsable(FGNavRecord* aNav, const SGGeod &aircraft) { - switch (aNav->type()) { - case FGPositioned::ILS: - case FGPositioned::LOC: - case FGPositioned::GS: -// FIXME -// case FGPositioned::DME: we can't get the heading for a DME transmitter, oops - break; - default: - return false; + FGRunway* r(aNav->runway()); + if (!r || !r->reciprocalRunway()) { + return true; } - double hdg_deg = 0.0; - if (aNav->type() == FGPositioned::GS) { - int tmp = (int)(aNav->get_multiuse() / 1000.0); - hdg_deg = aNav->get_multiuse() - (tmp * 1000); - } else { - hdg_deg = aNav->get_multiuse(); +// check if the runway frequency is paired + FGNavRecord* locA = r->ILS(); + FGNavRecord* locB = r->reciprocalRunway()->ILS(); + + if (!locA || !locB || (locA->get_freq() != locB->get_freq())) { + return true; // not paired, ok } - double az1, az2, s; - SGGeodesy::inverse(aGeod, aNav->geod(), az1, az2, s); - az1 = az1 - hdg_deg; - SG_NORMALIZE_RANGE(az1, -180.0, 180.0); - return fabs(az1) > 90.0; +// okay, both ends have an ILS, and they're paired. We need to select based on +// aircraft position. What we're going to use is *runway* (not navid) position, +// ie whichever runway end we are closer too. This makes back-course / missed +// approach behaviour incorrect, but that's the price we accept. + double crs = SGGeodesy::courseDeg(aircraft, r->geod()); + double hdgDiff = crs - r->headingDeg(); + SG_NORMALIZE_RANGE(hdgDiff, -180.0, 180.0); + return (fabs(hdgDiff) < 90.0); } -// Given a point and a list of stations, return the closest one to the -// specified point. -FGNavRecord *FGNavList::findNavFromList( const SGGeod &aircraft, - const nav_list_type &stations ) +// Given a point and a list of stations, return the closest one to +// the specified point. +FGNavRecord* FGNavList::findNavFromList( const SGGeod &aircraft, + const nav_list_type &stations ) { FGNavRecord *nav = NULL; double d2; // in meters squared @@ -163,18 +154,13 @@ FGNavRecord *FGNavList::findNavFromList( const SGGeod &aircraft, // find the closest station within a sensible range (FG_NAV_MAX_RANGE) for ( it = stations.begin(); it != end; ++it ) { FGNavRecord *station = *it; - // cout << "testing " << current->get_ident() << endl; d2 = distSqr(station->cart(), aircraftCart); - if ( d2 < min_dist && penaltyForNav(station, aircraft)) - { - double dist = sqrt(d2); - d2 = (dist + 5000) * (dist + 5000); + if ( d2 > min_dist || !navidUsable(station, aircraft)) { + continue; } - if ( d2 < min_dist ) { - min_dist = d2; - nav = station; - } + min_dist = d2; + nav = station; } return nav; diff --git a/src/Navaids/navrecord.cxx b/src/Navaids/navrecord.cxx index 26dfa2532..6bb71a54c 100644 --- a/src/Navaids/navrecord.cxx +++ b/src/Navaids/navrecord.cxx @@ -101,7 +101,7 @@ void FGNavRecord::initAirportRelation() mPosition.setElevationFt(mRunway->elevation()); } - if (type() == ILS) { + if (type() == ILS || type() == LOC) { mRunway->setILS(this); }