2 // simple.cxx -- a really simplistic class to manage airport ID,
3 // lat, lon of the center of one of it's runways, and
6 // Written by Curtis Olson, started April 1998.
7 // Updated by Durk Talsma, started December, 2004.
9 // Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
11 // This program is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU General Public License as
13 // published by the Free Software Foundation; either version 2 of the
14 // License, or (at your option) any later version.
16 // This program is distributed in the hope that it will be useful, but
17 // WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
33 #include <simgear/misc/sg_path.hxx>
34 #include <simgear/props/props.hxx>
35 #include <simgear/debug/logstream.hxx>
36 #include <simgear/sg_inlines.h>
38 #include <Environment/environment_mgr.hxx>
39 #include <Environment/environment.hxx>
40 #include <Main/fg_props.hxx>
41 #include <Airports/runways.hxx>
42 #include <Airports/pavement.hxx>
43 #include <Airports/dynamics.hxx>
44 #include <Airports/xmlloader.hxx>
46 // magic import of a helper which uses FGPositioned internals
47 extern char** searchAirportNamesAndIdents(const std::string& aFilter);
49 /***************************************************************************
51 ***************************************************************************/
53 FGAirport::FGAirport(const string &id, const SGGeod& location, const SGGeod& tower_location,
54 const string &name, bool has_metar, Type aType) :
55 FGPositioned(aType, id, location),
56 _tower_location(tower_location),
58 _has_metar(has_metar),
64 FGAirport::~FGAirport()
69 bool FGAirport::isAirport() const
71 return type() == AIRPORT;
74 bool FGAirport::isSeaport() const
76 return type() == SEAPORT;
79 bool FGAirport::isHeliport() const
81 return type() == HELIPORT;
84 FGAirportDynamics * FGAirport::getDynamics()
89 //cerr << "Trying to load dynamics for " << _id << endl;
90 _dynamics = new FGAirportDynamics(this);
91 XMLLoader::load(_dynamics);
93 FGRunwayPreference rwyPrefs(this);
94 XMLLoader::load(&rwyPrefs);
95 _dynamics->setRwyUse(rwyPrefs);
97 //FGSidStar SIDs(this);
98 XMLLoader::load(_dynamics->getSIDs());
103 unsigned int FGAirport::numRunways() const
105 return mRunways.size();
108 FGRunway* FGAirport::getRunwayByIndex(unsigned int aIndex) const
110 assert(aIndex >= 0 && aIndex < mRunways.size());
111 return mRunways[aIndex];
114 bool FGAirport::hasRunwayWithIdent(const string& aIdent) const
116 return (getIteratorForRunwayIdent(aIdent) != mRunways.end());
119 FGRunway* FGAirport::getRunwayByIdent(const string& aIdent) const
121 Runway_iterator it = getIteratorForRunwayIdent(aIdent);
122 if (it == mRunways.end()) {
123 SG_LOG(SG_GENERAL, SG_ALERT, "no such runway '" << aIdent << "' at airport " << ident());
124 throw sg_range_exception("unknown runway " + aIdent + " at airport:" + ident(), "FGAirport::getRunwayByIdent");
130 FGAirport::Runway_iterator
131 FGAirport::getIteratorForRunwayIdent(const string& aIdent) const
133 string ident(aIdent);
134 if ((aIdent.size() == 1) || !isdigit(aIdent[1])) {
135 ident = "0" + aIdent;
138 Runway_iterator it = mRunways.begin();
139 for (; it != mRunways.end(); ++it) {
140 if ((*it)->ident() == ident) {
148 FGRunway* FGAirport::findBestRunwayForHeading(double aHeading) const
150 Runway_iterator it = mRunways.begin();
151 FGRunway* result = NULL;
152 double currentBestQuality = 0.0;
154 SGPropertyNode *param = fgGetNode("/sim/airport/runways/search", true);
155 double lengthWeight = param->getDoubleValue("length-weight", 0.01);
156 double widthWeight = param->getDoubleValue("width-weight", 0.01);
157 double surfaceWeight = param->getDoubleValue("surface-weight", 10);
158 double deviationWeight = param->getDoubleValue("deviation-weight", 1);
160 for (; it != mRunways.end(); ++it) {
161 double good = (*it)->score(lengthWeight, widthWeight, surfaceWeight);
163 double dev = aHeading - (*it)->headingDeg();
164 SG_NORMALIZE_RANGE(dev, -180.0, 180.0);
165 double bad = fabs(deviationWeight * dev) + 1e-20;
166 double quality = good / bad;
168 if (quality > currentBestQuality) {
169 currentBestQuality = quality;
177 bool FGAirport::hasHardRunwayOfLengthFt(double aLengthFt) const
179 unsigned int numRunways(mRunways.size());
180 for (unsigned int r=0; r<numRunways; ++r) {
181 FGRunway* rwy = mRunways[r];
182 if (rwy->isReciprocal()) {
183 continue; // we only care about lengths, so don't do work twice
186 if (rwy->isHardSurface() && (rwy->lengthFt() >= aLengthFt)) {
187 return true; // we're done!
189 } // of runways iteration
194 unsigned int FGAirport::numTaxiways() const
196 return mTaxiways.size();
199 FGTaxiway* FGAirport::getTaxiwayByIndex(unsigned int aIndex) const
201 assert(aIndex >= 0 && aIndex < mTaxiways.size());
202 return mTaxiways[aIndex];
205 unsigned int FGAirport::numPavements() const
207 return mPavements.size();
210 FGPavement* FGAirport::getPavementByIndex(unsigned int aIndex) const
212 assert(aIndex >= 0 && aIndex < mPavements.size());
213 return mPavements[aIndex];
216 void FGAirport::setRunwaysAndTaxiways(vector<FGRunwayPtr>& rwys,
217 vector<FGTaxiwayPtr>& txwys,
218 vector<FGPavementPtr>& pvts)
221 Runway_iterator it = mRunways.begin();
222 for (; it != mRunways.end(); ++it) {
223 (*it)->setAirport(this);
226 mTaxiways.swap(txwys);
227 mPavements.swap(pvts);
230 FGRunway* FGAirport::getActiveRunwayForUsage() const
232 static FGEnvironmentMgr* envMgr = NULL;
234 envMgr = (FGEnvironmentMgr *) globals->get_subsystem("environment");
237 FGEnvironment stationWeather(envMgr->getEnvironment(mPosition));
239 double windSpeed = stationWeather.get_wind_speed_kt();
240 double hdg = stationWeather.get_wind_from_heading_deg();
241 if (windSpeed <= 0.0) {
242 hdg = 270; // This forces West-facing rwys to be used in no-wind situations
243 // which is consistent with Flightgear's initial setup.
246 return findBestRunwayForHeading(hdg);
249 FGAirport* FGAirport::findClosest(const SGGeod& aPos, double aCuttofNm, Filter* filter)
251 AirportFilter aptFilter;
252 if (filter == NULL) {
256 FGPositionedRef r = FGPositioned::findClosest(aPos, aCuttofNm, filter);
261 return static_cast<FGAirport*>(r.ptr());
264 FGAirport::HardSurfaceFilter::HardSurfaceFilter(double minLengthFt) :
265 mMinLengthFt(minLengthFt)
269 bool FGAirport::HardSurfaceFilter::passAirport(FGAirport* aApt) const
271 return aApt->hasHardRunwayOfLengthFt(mMinLengthFt);
274 FGAirport* FGAirport::findByIdent(const std::string& aIdent)
277 AirportFilter filter;
278 r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
280 return NULL; // we don't warn here, let the caller do that
282 return static_cast<FGAirport*>(r.ptr());
285 FGAirport* FGAirport::getByIdent(const std::string& aIdent)
288 AirportFilter filter;
289 r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
291 throw sg_range_exception("No such airport with ident: " + aIdent);
293 return static_cast<FGAirport*>(r.ptr());
296 char** FGAirport::searchNamesAndIdents(const std::string& aFilter)
298 // we delegate all the work to a horrible helper in FGPositioned, which can
299 // access the (private) index data.
300 return searchAirportNamesAndIdents(aFilter);
303 // find basic airport location info from airport database
304 const FGAirport *fgFindAirportID( const string& id)
310 return FGAirport::findByIdent(id);
314 // get airport elevation
315 double fgGetAirportElev( const string& id )
317 SG_LOG( SG_GENERAL, SG_BULK,
318 "Finding elevation for airport: " << id );
320 const FGAirport *a=fgFindAirportID( id);
322 return a->getElevation();
329 // get airport position
330 SGGeod fgGetAirportPos( const string& id )
332 SG_LOG( SG_ATC, SG_BULK,
333 "Finding position for airport: " << id );
335 const FGAirport *a = fgFindAirportID( id);
338 return SGGeod::fromDegM(a->getLongitude(), a->getLatitude(), a->getElevation());
340 return SGGeod::fromDegM(0.0, 0.0, -9999.0);