#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/structure/exception.hxx>
-SG_USING_STD(string);
+using std::string;
#include "Airports/runways.hxx"
#include "Airports/simple.hxx"
return heading_add(h, 180);
}
-// Searches for the closest airport whose Manhattan distance to
-// @lat,@lon is inferior to @min_manhattan_distance (expressed in
-// degrees) and for which @test_airport returns true. Returns NULL if
-// no airport was found.
-template <class C>
-static const FGAirport *
-get_closest_airport (double lat,
- double lon,
- double min_manhattan_distance,
- C &obj,
- bool (C::*test_airport) (const FGAirport *))
-{
- const FGAirport *airport = NULL;
- const airport_list *airport_list = globals->get_airports()->getAirportList();
-
- for (size_t i = 0; i < airport_list->size(); i++)
- {
- const FGAirport *a = (*airport_list)[i];
- double dist = fabs(lat - a->getLatitude()) + fabs(lon - a->getLongitude());
- if (dist < min_manhattan_distance && (obj.*test_airport)(a))
- {
- airport = a;
- min_manhattan_distance = dist;
- }
- }
-
- return airport;
-}
-
///////////////////////////////////////////////////////////////////////////////
// PropertiesHandler //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool
MK_VIII::Mode6Handler::test_runway (const FGRunway *_runway)
{
- if (_runway->_length < mk->conf.runway_database)
+ if (_runway->lengthFt() < mk->conf.runway_database)
return false;
- // get position of threshold
- double latitude, longitude, az;
- geo_direct_wgs_84(0,
- _runway->_lat,
- _runway->_lon,
- get_reciprocal_heading(_runway->_heading),
- _runway->_length / 2 * SG_FEET_TO_METER,
- &latitude,
- &longitude,
- &az);
-
+ SGGeod pos(
+ SGGeod::fromDeg(mk_data(gps_longitude).get(), mk_data(gps_latitude).get()));
+
// get distance to threshold
double distance, az1, az2;
- geo_inverse_wgs_84(0,
- mk_data(gps_latitude).get(),
- mk_data(gps_longitude).get(),
- latitude,
- longitude,
- &az1, &az2, &distance);
-
+ SGGeodesy::inverse(pos, _runway->threshold(), az1, az2, distance);
return distance * SG_METER_TO_NM <= 5;
}
bool
MK_VIII::Mode6Handler::test_airport (const FGAirport *airport)
{
- FGRunway r;
- if (globals->get_runways()->search(airport->getId(), &r))
- do
- {
- if (test_runway(&r))
- return true;
-
- // reciprocal runway
- r._heading = get_reciprocal_heading(r._heading);
- if (test_runway(&r))
- return true;
- }
- while (globals->get_runways()->next(&r) && r._id == airport->getId());
+ for (unsigned int r=0; r<airport->numRunways(); ++r) {
+ FGRunway* rwy(airport->getRunwayByIndex(r));
+
+ if (test_runway(rwy)) return true;
+ }
return false;
}
+bool MK_VIII::Mode6Handler::AirportFilter::pass(FGPositioned* a) const
+{
+ if (a->type() != FGPositioned::AIRPORT) {
+ return false;
+ }
+
+ bool ok = self->test_airport(static_cast<FGAirport*>(a));
+ return ok;
+}
+
void
MK_VIII::Mode6Handler::update_runway ()
{
- if (! mk_data(gps_latitude).ncd && ! mk_data(gps_longitude).ncd)
- {
- // Search for the closest runway threshold in range 5
- // nm. Passing 0.5 degrees (approximatively 30 nm) to
- // get_closest_airport() provides enough margin for large
- // airports, which may have a runway located far away from the
- // airport's reference point.
-
- const FGAirport *airport = get_closest_airport(mk_data(gps_latitude).get(),
- mk_data(gps_longitude).get(),
- 0.5,
- *this,
- &MK_VIII::Mode6Handler::test_airport);
-
- if (airport)
- runway.elevation = airport->getElevation();
-
- has_runway.set(airport != NULL);
- }
- else
- has_runway.unset();
+
+ if (mk_data(gps_latitude).ncd || mk_data(gps_longitude).ncd) {
+ has_runway.unset();
+ return;
+ }
+
+ // Search for the closest runway threshold in range 5
+ // nm. Passing 30nm to
+ // get_closest_airport() provides enough margin for large
+ // airports, which may have a runway located far away from the
+ // airport's reference point.
+ AirportFilter filter(this);
+ FGPositionedRef apt = FGPositioned::findClosest(
+ SGGeod::fromDeg(mk_data(gps_longitude).get(), mk_data(gps_latitude).get()),
+ 30.0, &filter);
+ if (apt) {
+ runway.elevation = apt->elevation();
+ }
+
+ has_runway.set(apt != NULL);
}
void
{
return get_azimuth_difference(mk_data(gps_latitude).get(),
mk_data(gps_longitude).get(),
- _runway->_lat,
- _runway->_lon,
- _runway->_heading);
+ _runway->latitude(),
+ _runway->longitude(),
+ _runway->headingDeg());
}
// Selects the most likely intended destination runway of @airport,
// This selection algorithm is not specified in [SPEC], but
// http://www.egpws.com/general_information/description/runway_select.htm
// talks about automatic runway selection.
-void
-MK_VIII::TCFHandler::select_runway (const FGAirport *airport,
- FGRunway *_runway)
+FGRunway*
+MK_VIII::TCFHandler::select_runway (const FGAirport *airport)
{
- FGRunway r;
- bool status = globals->get_runways()->search(airport->getId(), &r);
- assert(status);
-
+ FGRunway* _runway = 0;
double min_diff = 360;
- do
- {
- double diff;
-
- diff = get_azimuth_difference(&r);
- if (diff < min_diff)
- {
- min_diff = diff;
- *_runway = r;
- }
-
- // reciprocal runway
- r._heading = get_reciprocal_heading(r._heading);
- diff = get_azimuth_difference(&r);
- if (diff < min_diff)
- {
- min_diff = diff;
- *_runway = r;
- }
+
+ for (unsigned int r=0; r<airport->numRunways(); ++r) {
+ FGRunway* rwy(airport->getRunwayByIndex(r));
+ double diff = get_azimuth_difference(rwy);
+ if (diff < min_diff)
+ {
+ min_diff = diff;
+ _runway = rwy;
}
- while (globals->get_runways()->next(&r) && r._id == airport->getId());
+ } // of airport runways iteration
+ return _runway;
}
-bool
-MK_VIII::TCFHandler::test_airport (const FGAirport *airport)
+bool MK_VIII::TCFHandler::AirportFilter::pass(FGPositioned* aPos) const
{
- FGRunway r;
- if (globals->get_runways()->search(airport->getId(), &r))
- do
- {
- if (r._length >= mk->conf.runway_database)
- return true;
- }
- while (globals->get_runways()->next(&r) && r._id == airport->getId());
-
- return false;
+ if (aPos->type() != FGPositioned::AIRPORT) {
+ return false;
+ }
+
+ FGAirport* apt = static_cast<FGAirport*>(aPos);
+ return apt->hasHardRunwayOfLengthFt(mk->conf.runway_database);
}
-
+
void
MK_VIII::TCFHandler::update_runway ()
{
has_runway = false;
- if (! mk_data(gps_latitude).ncd && ! mk_data(gps_longitude).ncd)
- {
- // Search for the intended destination runway of the closest
- // airport in range 15 nm. Passing 0.5 degrees (approximatively
- // 30 nm) to get_closest_airport() provides enough margin for
- // large airports, which may have a runway located far away from
- // the airport's reference point.
-
- const FGAirport *airport = get_closest_airport(mk_data(gps_latitude).get(),
- mk_data(gps_longitude).get(),
- 0.5,
- *this,
- &MK_VIII::TCFHandler::test_airport);
-
- if (airport)
- {
+ if (mk_data(gps_latitude).ncd || mk_data(gps_longitude).ncd) {
+ return;
+ }
+
+ // Search for the intended destination runway of the closest
+ // airport in range 15 nm. Passing 30nm to get_closest_airport()
+ // provides enough margin for
+ // large airports, which may have a runway located far away from
+ // the airport's reference point.
+ AirportFilter filter(mk);
+ FGAirport* apt = FGAirport::findClosest(
+ SGGeod::fromDeg(mk_data(gps_longitude).get(), mk_data(gps_latitude).get()),
+ 30.0, &filter);
+
+ if (!apt) return;
+
has_runway = true;
- FGRunway _runway;
- select_runway(airport, &_runway);
+ FGRunway* _runway = select_runway(apt);
+
+ runway.center.latitude = _runway->latitude();
+ runway.center.longitude = _runway->longitude();
- runway.center.latitude = _runway._lat;
- runway.center.longitude = _runway._lon;
+ runway.elevation = apt->elevation();
- runway.elevation = airport->getElevation();
-
- double half_length_m = _runway._length / 2 * SG_FEET_TO_METER;
+ double half_length_m = _runway->lengthM() * 0.5;
runway.half_length = half_length_m * SG_METER_TO_NM;
// b3 ________________ b0
// b2 b1
// get heading to runway threshold (h0) and end (h1)
- runway.edges[0].heading = _runway._heading;
- runway.edges[1].heading = get_reciprocal_heading(_runway._heading);
+ runway.edges[0].heading = _runway->headingDeg();
+ runway.edges[1].heading = get_reciprocal_heading(_runway->headingDeg());
double az;
&runway.edges[1].position.longitude,
&az);
- double half_width_m = _runway._width / 2 * SG_FEET_TO_METER;
+ double half_width_m = _runway->widthM() * 0.5;
// get position of threshold bias area edges (b0 and b1)
get_bias_area_edges(&runway.edges[0].position,
half_width_m,
&runway.bias_area[2],
&runway.bias_area[3]);
- }
- }
}
void