1998-08-25 17:19:13 +00:00
|
|
|
//
|
1999-02-26 22:08:34 +00:00
|
|
|
// simple.cxx -- a really simplistic class to manage airport ID,
|
2006-07-10 11:36:38 +00:00
|
|
|
// lat, lon of the center of one of it's runways, and
|
2003-08-28 20:53:08 +00:00
|
|
|
// elevation in feet.
|
1998-08-25 17:19:13 +00:00
|
|
|
//
|
|
|
|
// Written by Curtis Olson, started April 1998.
|
2005-02-10 09:01:51 +00:00
|
|
|
// Updated by Durk Talsma, started December, 2004.
|
1998-08-25 17:19:13 +00:00
|
|
|
//
|
2004-11-19 22:10:41 +00:00
|
|
|
// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
|
1998-08-25 17:19:13 +00:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful, but
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
2006-02-21 01:16:04 +00:00
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
1998-08-25 17:19:13 +00:00
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
|
2000-04-27 03:26:36 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2004-02-23 09:48:10 +00:00
|
|
|
#include <math.h>
|
2005-02-18 10:16:30 +00:00
|
|
|
#include <algorithm>
|
2004-02-23 09:48:10 +00:00
|
|
|
|
2000-02-15 03:30:01 +00:00
|
|
|
#include <simgear/compiler.h>
|
2005-02-25 19:41:53 +00:00
|
|
|
|
|
|
|
#include <plib/sg.h>
|
2005-10-18 18:44:37 +00:00
|
|
|
#include <plib/ul.h>
|
2005-02-25 19:41:53 +00:00
|
|
|
|
2005-02-10 09:01:51 +00:00
|
|
|
#include <Environment/environment_mgr.hxx>
|
|
|
|
#include <Environment/environment.hxx>
|
|
|
|
#include <simgear/misc/sg_path.hxx>
|
|
|
|
#include <simgear/props/props.hxx>
|
|
|
|
#include <simgear/structure/subsystem_mgr.hxx>
|
2005-12-29 13:58:21 +00:00
|
|
|
//#include <simgear/route/waypoint.hxx>
|
2000-02-16 23:01:03 +00:00
|
|
|
#include <simgear/debug/logstream.hxx>
|
2005-02-10 09:01:51 +00:00
|
|
|
#include <Main/globals.hxx>
|
|
|
|
#include <Main/fg_props.hxx>
|
|
|
|
#include <Airports/runways.hxx>
|
2008-08-14 18:13:39 +00:00
|
|
|
#include <Airports/dynamics.hxx>
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
#include <Airports/runways.hxx>
|
1998-08-25 17:19:13 +00:00
|
|
|
|
2008-07-25 18:38:29 +00:00
|
|
|
#include <string>
|
1998-08-25 17:19:13 +00:00
|
|
|
|
1999-02-26 22:08:34 +00:00
|
|
|
#include "simple.hxx"
|
2007-07-04 17:39:03 +00:00
|
|
|
#include "xmlloader.hxx"
|
1999-02-26 22:08:34 +00:00
|
|
|
|
2008-07-27 16:25:13 +00:00
|
|
|
using std::sort;
|
|
|
|
using std::random_shuffle;
|
2002-04-04 06:05:51 +00:00
|
|
|
|
2005-10-20 08:48:32 +00:00
|
|
|
|
2005-02-10 09:01:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* FGAirport
|
|
|
|
***************************************************************************/
|
2007-10-05 12:59:43 +00:00
|
|
|
FGAirport::FGAirport() : _dynamics(0)
|
2005-02-10 09:01:51 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-10-05 12:59:43 +00:00
|
|
|
FGAirport::FGAirport(const string &id, const SGGeod& location, const SGGeod& tower_location,
|
|
|
|
const string &name, bool has_metar, bool is_airport, bool is_seaport,
|
|
|
|
bool is_heliport) :
|
|
|
|
_id(id),
|
|
|
|
_location(location),
|
|
|
|
_tower_location(tower_location),
|
|
|
|
_name(name),
|
|
|
|
_has_metar(has_metar),
|
|
|
|
_is_airport(is_airport),
|
|
|
|
_is_seaport(is_seaport),
|
|
|
|
_is_heliport(is_heliport),
|
|
|
|
_dynamics(0)
|
2005-02-10 09:01:51 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-07-10 11:36:38 +00:00
|
|
|
|
2005-12-29 13:58:21 +00:00
|
|
|
FGAirport::~FGAirport()
|
2005-10-18 18:44:37 +00:00
|
|
|
{
|
2007-10-05 12:59:43 +00:00
|
|
|
delete _dynamics;
|
2005-10-18 18:44:37 +00:00
|
|
|
}
|
|
|
|
|
2005-02-10 09:01:51 +00:00
|
|
|
|
2005-12-29 13:58:21 +00:00
|
|
|
FGAirportDynamics * FGAirport::getDynamics()
|
2005-02-10 09:01:51 +00:00
|
|
|
{
|
2007-10-05 12:59:43 +00:00
|
|
|
if (_dynamics != 0) {
|
|
|
|
return _dynamics;
|
2006-07-10 11:36:38 +00:00
|
|
|
} else {
|
2006-10-12 21:48:18 +00:00
|
|
|
//cerr << "Trying to load dynamics for " << _id << endl;
|
2007-10-05 12:59:43 +00:00
|
|
|
_dynamics = new FGAirportDynamics(this);
|
|
|
|
XMLLoader::load(_dynamics);
|
2007-07-04 17:39:03 +00:00
|
|
|
|
|
|
|
FGRunwayPreference rwyPrefs(this);
|
|
|
|
XMLLoader::load(&rwyPrefs);
|
2007-10-05 12:59:43 +00:00
|
|
|
_dynamics->setRwyUse(rwyPrefs);
|
2007-07-04 17:39:03 +00:00
|
|
|
}
|
2007-10-05 12:59:43 +00:00
|
|
|
return _dynamics;
|
2005-10-18 18:44:37 +00:00
|
|
|
}
|
|
|
|
|
2008-08-14 18:13:39 +00:00
|
|
|
unsigned int FGAirport::numRunways() const
|
|
|
|
{
|
|
|
|
return mRunways.size();
|
|
|
|
}
|
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
FGRunway* FGAirport::getRunwayByIndex(unsigned int aIndex) const
|
2008-08-14 18:13:39 +00:00
|
|
|
{
|
|
|
|
assert(aIndex >= 0 && aIndex < mRunways.size());
|
|
|
|
return mRunways[aIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FGAirport::hasRunwayWithIdent(const string& aIdent) const
|
|
|
|
{
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
return (getIteratorForRunwayIdent(aIdent) != mRunways.end());
|
2008-08-14 18:13:39 +00:00
|
|
|
}
|
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
FGRunway* FGAirport::getRunwayByIdent(const string& aIdent) const
|
2008-08-14 18:13:39 +00:00
|
|
|
{
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
Runway_iterator it = getIteratorForRunwayIdent(aIdent);
|
2008-08-14 18:13:39 +00:00
|
|
|
if (it == mRunways.end()) {
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "no such runway '" << aIdent << "' at airport " << _id);
|
|
|
|
throw sg_range_exception("unknown runway " + aIdent + " at airport:" + _id, "FGAirport::getRunwayByIdent");
|
|
|
|
}
|
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
return *it;
|
2008-08-14 18:13:39 +00:00
|
|
|
}
|
2005-10-18 18:44:37 +00:00
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
FGAirport::Runway_iterator
|
|
|
|
FGAirport::getIteratorForRunwayIdent(const string& aIdent) const
|
2008-08-14 18:13:39 +00:00
|
|
|
{
|
|
|
|
string ident(aIdent);
|
|
|
|
if ((aIdent.size() == 1) || !isdigit(aIdent[1])) {
|
|
|
|
ident = "0" + aIdent;
|
|
|
|
}
|
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
Runway_iterator it = mRunways.begin();
|
2008-08-14 18:13:39 +00:00
|
|
|
for (; it != mRunways.end(); ++it) {
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
if ((*it)->ident() == ident) {
|
2008-08-14 18:13:39 +00:00
|
|
|
return it;
|
|
|
|
}
|
|
|
|
}
|
2005-10-18 18:44:37 +00:00
|
|
|
|
2008-08-14 18:13:39 +00:00
|
|
|
return it; // end()
|
|
|
|
}
|
|
|
|
|
|
|
|
static double normaliseBearing(double aBearing)
|
|
|
|
{
|
2008-08-24 09:04:24 +00:00
|
|
|
while (aBearing < 0.0) {
|
2008-08-14 18:13:39 +00:00
|
|
|
aBearing += 360.0;
|
|
|
|
}
|
|
|
|
|
2008-08-24 09:04:24 +00:00
|
|
|
while (aBearing > 360.0) {
|
|
|
|
aBearing -= 360.0;
|
2008-08-14 18:13:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return aBearing;
|
|
|
|
}
|
2005-10-18 18:44:37 +00:00
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
FGRunway* FGAirport::findBestRunwayForHeading(double aHeading) const
|
2008-08-14 18:13:39 +00:00
|
|
|
{
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
Runway_iterator it = mRunways.begin();
|
|
|
|
FGRunway* result = NULL;
|
2008-08-14 18:13:39 +00:00
|
|
|
double currentBestQuality = 0.0;
|
|
|
|
|
|
|
|
SGPropertyNode *param = fgGetNode("/sim/airport/runways/search", true);
|
|
|
|
double lengthWeight = param->getDoubleValue("length-weight", 0.01);
|
|
|
|
double widthWeight = param->getDoubleValue("width-weight", 0.01);
|
|
|
|
double surfaceWeight = param->getDoubleValue("surface-weight", 10);
|
|
|
|
double deviationWeight = param->getDoubleValue("deviation-weight", 1);
|
|
|
|
|
|
|
|
for (; it != mRunways.end(); ++it) {
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
double good = (*it)->score(lengthWeight, widthWeight, surfaceWeight);
|
2008-08-14 18:13:39 +00:00
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
double dev = normaliseBearing(aHeading - (*it)->headingDeg());
|
2008-08-14 18:13:39 +00:00
|
|
|
double bad = fabs(deviationWeight * dev) + 1e-20;
|
|
|
|
double quality = good / bad;
|
|
|
|
|
|
|
|
if (quality > currentBestQuality) {
|
|
|
|
currentBestQuality = quality;
|
|
|
|
result = *it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int FGAirport::numTaxiways() const
|
|
|
|
{
|
|
|
|
return mTaxiways.size();
|
|
|
|
}
|
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
FGRunway* FGAirport::getTaxiwayByIndex(unsigned int aIndex) const
|
2008-08-14 18:13:39 +00:00
|
|
|
{
|
|
|
|
assert(aIndex >= 0 && aIndex < mTaxiways.size());
|
|
|
|
return mTaxiways[aIndex];
|
|
|
|
}
|
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
void FGAirport::addRunway(FGRunway* aRunway)
|
2008-08-14 18:13:39 +00:00
|
|
|
{
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
aRunway->setAirport(this);
|
|
|
|
|
|
|
|
if (aRunway->isTaxiway()) {
|
2008-08-14 18:13:39 +00:00
|
|
|
mTaxiways.push_back(aRunway);
|
|
|
|
} else {
|
|
|
|
mRunways.push_back(aRunway);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
FGRunway* FGAirport::getActiveRunwayForUsage() const
|
2008-08-14 18:13:39 +00:00
|
|
|
{
|
|
|
|
static FGEnvironmentMgr* envMgr = NULL;
|
|
|
|
if (!envMgr) {
|
|
|
|
envMgr = (FGEnvironmentMgr *) globals->get_subsystem("environment");
|
|
|
|
}
|
|
|
|
|
|
|
|
FGEnvironment stationWeather(envMgr->getEnvironment(_location));
|
|
|
|
|
|
|
|
double windSpeed = stationWeather.get_wind_speed_kt();
|
|
|
|
double hdg = stationWeather.get_wind_from_heading_deg();
|
|
|
|
if (windSpeed <= 0.0) {
|
|
|
|
hdg = 270; // This forces West-facing rwys to be used in no-wind situations
|
|
|
|
// which is consistent with Flightgear's initial setup.
|
|
|
|
}
|
|
|
|
|
|
|
|
return findBestRunwayForHeading(hdg);
|
|
|
|
}
|
2005-10-18 18:44:37 +00:00
|
|
|
|
2005-02-10 09:01:51 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* FGAirportList
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2005-05-27 17:06:13 +00:00
|
|
|
// Populates a list of subdirectories of $FG_ROOT/Airports/AI so that
|
|
|
|
// the add() method doesn't have to try opening 2 XML files in each of
|
|
|
|
// thousands of non-existent directories. FIXME: should probably add
|
|
|
|
// code to free this list after parsing of apt.dat is finished;
|
|
|
|
// non-issue at the moment, however, as there are no AI subdirectories
|
|
|
|
// in the base package.
|
2005-12-29 13:58:21 +00:00
|
|
|
//
|
|
|
|
// Note: 2005/12/23: This is probably not necessary anymore, because I'm
|
2006-07-10 11:36:38 +00:00
|
|
|
// Switching to runtime airport dynamics loading (DT).
|
2005-05-27 17:06:13 +00:00
|
|
|
FGAirportList::FGAirportList()
|
|
|
|
{
|
2005-12-29 13:58:21 +00:00
|
|
|
// ulDir* d;
|
|
|
|
// ulDirEnt* dent;
|
|
|
|
// SGPath aid( globals->get_fg_root() );
|
|
|
|
// aid.append( "/Airports/AI" );
|
|
|
|
// if((d = ulOpenDir(aid.c_str())) == NULL)
|
|
|
|
// return;
|
|
|
|
// while((dent = ulReadDir(d)) != NULL) {
|
|
|
|
// SG_LOG( SG_GENERAL, SG_DEBUG, "Dent: " << dent->d_name );
|
|
|
|
// ai_dirs.insert(dent->d_name);
|
|
|
|
// }
|
|
|
|
// ulCloseDir(d);
|
2005-05-27 17:06:13 +00:00
|
|
|
}
|
2002-04-04 06:05:51 +00:00
|
|
|
|
2005-09-20 20:26:57 +00:00
|
|
|
|
2006-07-10 11:36:38 +00:00
|
|
|
FGAirportList::~FGAirportList( void )
|
|
|
|
{
|
|
|
|
for (unsigned int i = 0; i < airports_array.size(); ++i) {
|
2005-09-20 20:26:57 +00:00
|
|
|
delete airports_array[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-12-22 23:57:07 +00:00
|
|
|
// add an entry to the list
|
2008-08-14 18:13:39 +00:00
|
|
|
FGAirport* FGAirportList::add( const string &id, const SGGeod& location, const SGGeod& tower_location,
|
2007-10-05 12:59:43 +00:00
|
|
|
const string &name, bool has_metar, bool is_airport, bool is_seaport,
|
|
|
|
bool is_heliport)
|
2002-04-04 06:05:51 +00:00
|
|
|
{
|
2007-10-05 12:59:43 +00:00
|
|
|
FGAirport* a = new FGAirport(id, location, tower_location, name, has_metar,
|
|
|
|
is_airport, is_seaport, is_heliport);
|
|
|
|
|
2005-09-20 20:26:57 +00:00
|
|
|
airports_by_id[a->getId()] = a;
|
2005-02-10 09:01:51 +00:00
|
|
|
// try and read in an auxilary file
|
2007-10-05 12:59:43 +00:00
|
|
|
|
2005-09-20 20:26:57 +00:00
|
|
|
airports_array.push_back( a );
|
2007-09-09 23:21:48 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_BULK, "Adding " << id << " pos = " << location.getLongitudeDeg()
|
|
|
|
<< ", " << location.getLatitudeDeg() << " elev = " << location.getElevationFt() );
|
2008-08-14 18:13:39 +00:00
|
|
|
|
|
|
|
return a;
|
2000-03-29 20:21:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-08-25 17:19:13 +00:00
|
|
|
// search for the specified id
|
2006-07-10 11:36:38 +00:00
|
|
|
FGAirport* FGAirportList::search( const string& id)
|
|
|
|
{
|
|
|
|
airport_map_iterator itr = airports_by_id.find(id);
|
|
|
|
return (itr == airports_by_id.end() ? NULL : itr->second);
|
2004-02-23 01:37:26 +00:00
|
|
|
}
|
|
|
|
|
2008-08-22 11:22:22 +00:00
|
|
|
// wrap an FGIdentOrdering in an STL-compatible functor. not the most
|
|
|
|
// efficent / pretty thing in the world, but avoids template nastiness in the
|
|
|
|
// headers, and we're only doing O(log(N)) comparisoms per search
|
|
|
|
class orderingFunctor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
orderingFunctor(FGIdentOrdering* aOrder) :
|
|
|
|
mOrdering(aOrder)
|
|
|
|
{ assert(aOrder); }
|
|
|
|
|
|
|
|
bool operator()(const airport_map::value_type& aA, const std::string& aB) const
|
|
|
|
{
|
|
|
|
return mOrdering->compare(aA.first,aB);
|
|
|
|
}
|
2008-08-31 18:32:43 +00:00
|
|
|
|
|
|
|
bool operator()(const std::string& aA, const airport_map::value_type& aB) const
|
|
|
|
{
|
|
|
|
return mOrdering->compare(aA, aB.first);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(const airport_map::value_type& aA, const airport_map::value_type& aB) const
|
|
|
|
{
|
|
|
|
return mOrdering->compare(aA.first, aB.first);
|
|
|
|
}
|
2008-08-22 11:22:22 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
FGIdentOrdering* mOrdering;
|
|
|
|
};
|
2005-09-20 20:26:57 +00:00
|
|
|
|
2008-08-22 11:22:22 +00:00
|
|
|
const FGAirport* FGAirportList::findFirstById(const std::string& aIdent, FGIdentOrdering* aOrder)
|
2006-07-10 11:36:38 +00:00
|
|
|
{
|
2008-08-22 11:22:22 +00:00
|
|
|
airport_map_iterator itr;
|
|
|
|
if (aOrder) {
|
|
|
|
orderingFunctor func(aOrder);
|
|
|
|
itr = std::lower_bound(airports_by_id.begin(),airports_by_id.end(), aIdent, func);
|
|
|
|
} else {
|
|
|
|
itr = airports_by_id.lower_bound(aIdent);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (itr == airports_by_id.end()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return itr->second;
|
2005-02-10 09:01:51 +00:00
|
|
|
}
|
2004-02-23 01:37:26 +00:00
|
|
|
|
|
|
|
// search for the airport nearest the specified position
|
2008-08-15 18:48:11 +00:00
|
|
|
FGAirport* FGAirportList::search(double lon_deg, double lat_deg, double max_range)
|
2007-10-05 21:54:52 +00:00
|
|
|
{
|
|
|
|
static FGAirportSearchFilter accept_any;
|
2008-08-15 18:48:11 +00:00
|
|
|
return search(lon_deg, lat_deg, max_range, accept_any);
|
2007-10-05 21:54:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// search for the airport nearest the specified position and
|
|
|
|
// passing the filter
|
|
|
|
FGAirport* FGAirportList::search(double lon_deg, double lat_deg,
|
2008-08-15 18:48:11 +00:00
|
|
|
double max_range,
|
2007-10-11 07:53:17 +00:00
|
|
|
FGAirportSearchFilter& filter)
|
2006-07-10 11:36:38 +00:00
|
|
|
{
|
2008-08-15 18:48:11 +00:00
|
|
|
double min_dist = max_range;
|
2008-08-22 11:22:22 +00:00
|
|
|
|
2007-10-05 21:54:52 +00:00
|
|
|
airport_list_iterator it = airports_array.begin();
|
|
|
|
airport_list_iterator end = airports_array.end();
|
|
|
|
airport_list_iterator closest = end;
|
|
|
|
for (; it != end; ++it) {
|
2007-10-11 07:53:17 +00:00
|
|
|
if (!filter.pass(*it))
|
2007-10-05 21:54:52 +00:00
|
|
|
continue;
|
|
|
|
|
2004-02-23 01:37:26 +00:00
|
|
|
// crude manhatten distance based on lat/lon difference
|
2007-10-05 21:54:52 +00:00
|
|
|
double d = fabs(lon_deg - (*it)->getLongitude())
|
|
|
|
+ fabs(lat_deg - (*it)->getLatitude());
|
|
|
|
if (d < min_dist) {
|
|
|
|
closest = it;
|
|
|
|
min_dist = d;
|
2004-02-23 01:37:26 +00:00
|
|
|
}
|
|
|
|
}
|
2007-10-05 21:54:52 +00:00
|
|
|
return closest != end ? *closest : 0;
|
1998-08-25 17:19:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-27 23:37:03 +00:00
|
|
|
int
|
|
|
|
FGAirportList::size () const
|
|
|
|
{
|
2004-02-23 01:37:26 +00:00
|
|
|
return airports_array.size();
|
2003-11-27 23:37:03 +00:00
|
|
|
}
|
|
|
|
|
2006-07-10 11:36:38 +00:00
|
|
|
|
2005-09-20 20:26:57 +00:00
|
|
|
const FGAirport *FGAirportList::getAirport( unsigned int index ) const
|
2003-11-27 23:37:03 +00:00
|
|
|
{
|
2006-07-10 11:36:38 +00:00
|
|
|
if (index < airports_array.size()) {
|
2005-09-20 20:26:57 +00:00
|
|
|
return(airports_array[index]);
|
|
|
|
} else {
|
|
|
|
return(NULL);
|
|
|
|
}
|
2004-02-23 01:37:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mark the specified airport record as not having metar
|
|
|
|
*/
|
2006-07-10 11:36:38 +00:00
|
|
|
void FGAirportList::no_metar( const string &id )
|
|
|
|
{
|
|
|
|
if(airports_by_id.find(id) != airports_by_id.end()) {
|
2005-09-20 20:26:57 +00:00
|
|
|
airports_by_id[id]->setMetar(false);
|
|
|
|
}
|
2004-12-22 23:57:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mark the specified airport record as (yes) having metar
|
|
|
|
*/
|
2006-07-10 11:36:38 +00:00
|
|
|
void FGAirportList::has_metar( const string &id )
|
|
|
|
{
|
|
|
|
if(airports_by_id.find(id) != airports_by_id.end()) {
|
2005-09-20 20:26:57 +00:00
|
|
|
airports_by_id[id]->setMetar(true);
|
|
|
|
}
|
2003-11-27 23:37:03 +00:00
|
|
|
}
|
2005-12-29 13:58:21 +00:00
|
|
|
|
2006-07-10 11:36:38 +00:00
|
|
|
|
2005-12-29 13:58:21 +00:00
|
|
|
// find basic airport location info from airport database
|
2006-07-10 11:36:38 +00:00
|
|
|
const FGAirport *fgFindAirportID( const string& id)
|
|
|
|
{
|
2005-12-29 13:58:21 +00:00
|
|
|
const FGAirport* result = NULL;
|
|
|
|
if ( id.length() ) {
|
2006-02-18 00:18:20 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_BULK, "Searching for airport code = " << id );
|
2005-12-29 13:58:21 +00:00
|
|
|
|
|
|
|
result = globals->get_airports()->search( id );
|
|
|
|
|
|
|
|
if ( result == NULL ) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
|
|
"Failed to find " << id << " in apt.dat.gz" );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-02-18 00:18:20 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_BULK,
|
2005-12-29 13:58:21 +00:00
|
|
|
"Position for " << id << " is ("
|
|
|
|
<< result->getLongitude() << ", "
|
|
|
|
<< result->getLatitude() << ")" );
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// get airport elevation
|
2006-07-10 11:36:38 +00:00
|
|
|
double fgGetAirportElev( const string& id )
|
|
|
|
{
|
2006-02-18 00:18:20 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_BULK,
|
2005-12-29 13:58:21 +00:00
|
|
|
"Finding elevation for airport: " << id );
|
|
|
|
|
|
|
|
const FGAirport *a=fgFindAirportID( id);
|
|
|
|
if (a) {
|
|
|
|
return a->getElevation();
|
|
|
|
} else {
|
|
|
|
return -9999.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-07-10 11:36:38 +00:00
|
|
|
// get airport position
|
|
|
|
Point3D fgGetAirportPos( const string& id )
|
|
|
|
{
|
2006-02-18 00:18:20 +00:00
|
|
|
SG_LOG( SG_ATC, SG_BULK,
|
2005-12-29 13:58:21 +00:00
|
|
|
"Finding position for airport: " << id );
|
|
|
|
|
|
|
|
const FGAirport *a = fgFindAirportID( id);
|
2006-07-10 11:36:38 +00:00
|
|
|
|
2005-12-29 13:58:21 +00:00
|
|
|
if (a) {
|
|
|
|
return Point3D(a->getLongitude(), a->getLatitude(), a->getElevation());
|
|
|
|
} else {
|
|
|
|
return Point3D(0.0, 0.0, -9999.0);
|
|
|
|
}
|
|
|
|
}
|