]> git.mxchange.org Git - flightgear.git/blob - src/Airports/simple.cxx
0907030fbd0a304bdbf0f4ec5984e743425f33c5
[flightgear.git] / src / Airports / simple.cxx
1 //
2 // simple.cxx -- a really simplistic class to manage airport ID,
3 //               lat, lon of the center of one of it's runways, and
4 //               elevation in feet.
5 //
6 // Written by Curtis Olson, started April 1998.
7 // Updated by Durk Talsma, started December, 2004.
8 //
9 // Copyright (C) 1998  Curtis L. Olson  - http://www.flightgear.org/~curt
10 //
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.
15 //
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.
20 //
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.
24 //
25 // $Id$
26
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30
31 #include "simple.hxx"
32
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>
37
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/dynamics.hxx>
43 #include <Airports/xmlloader.hxx>
44
45 // magic import of a helper which uses FGPositioned internals
46 extern char** searchAirportNamesAndIdents(const std::string& aFilter);
47
48 /***************************************************************************
49  * FGAirport
50  ***************************************************************************/
51
52 FGAirport::FGAirport(const string &id, const SGGeod& location, const SGGeod& tower_location,
53         const string &name, bool has_metar, Type aType) :
54     FGPositioned(aType, id, location),
55     _tower_location(tower_location),
56     _name(name),
57     _has_metar(has_metar),
58     _dynamics(0)
59 {
60 }
61
62
63 FGAirport::~FGAirport()
64 {
65     delete _dynamics;
66 }
67
68 bool FGAirport::isAirport() const
69 {
70   return type() == AIRPORT;
71 }
72
73 bool FGAirport::isSeaport() const
74 {
75   return type() == SEAPORT;
76 }
77
78 bool FGAirport::isHeliport() const
79 {
80   return type() == HELIPORT;
81 }
82
83 FGAirportDynamics * FGAirport::getDynamics()
84 {
85     if (_dynamics != 0) {
86         return _dynamics;
87     } else {
88         //cerr << "Trying to load dynamics for " << _id << endl;
89         _dynamics = new FGAirportDynamics(this);
90         XMLLoader::load(_dynamics);
91
92         FGRunwayPreference rwyPrefs(this);
93         XMLLoader::load(&rwyPrefs);
94         _dynamics->setRwyUse(rwyPrefs);
95    }
96     return _dynamics;
97 }
98
99 unsigned int FGAirport::numRunways() const
100 {
101   return mRunways.size();
102 }
103
104 FGRunway* FGAirport::getRunwayByIndex(unsigned int aIndex) const
105 {
106   assert(aIndex >= 0 && aIndex < mRunways.size());
107   return mRunways[aIndex];
108 }
109
110 bool FGAirport::hasRunwayWithIdent(const string& aIdent) const
111 {
112   return (getIteratorForRunwayIdent(aIdent) != mRunways.end());
113 }
114
115 FGRunway* FGAirport::getRunwayByIdent(const string& aIdent) const
116 {
117   Runway_iterator it = getIteratorForRunwayIdent(aIdent);
118   if (it == mRunways.end()) {
119     SG_LOG(SG_GENERAL, SG_ALERT, "no such runway '" << aIdent << "' at airport " << ident());
120     throw sg_range_exception("unknown runway " + aIdent + " at airport:" + ident(), "FGAirport::getRunwayByIdent");
121   }
122   
123   return *it;
124 }
125
126 FGAirport::Runway_iterator
127 FGAirport::getIteratorForRunwayIdent(const string& aIdent) const
128 {
129   string ident(aIdent);
130   if ((aIdent.size() == 1) || !isdigit(aIdent[1])) {
131     ident = "0" + aIdent;
132   }
133
134   Runway_iterator it = mRunways.begin();
135   for (; it != mRunways.end(); ++it) {
136     if ((*it)->ident() == ident) {
137       return it;
138     }
139   }
140
141   return it; // end()
142 }
143
144 FGRunway* FGAirport::findBestRunwayForHeading(double aHeading) const
145 {
146   Runway_iterator it = mRunways.begin();
147   FGRunway* result = NULL;
148   double currentBestQuality = 0.0;
149   
150   SGPropertyNode *param = fgGetNode("/sim/airport/runways/search", true);
151   double lengthWeight = param->getDoubleValue("length-weight", 0.01);
152   double widthWeight = param->getDoubleValue("width-weight", 0.01);
153   double surfaceWeight = param->getDoubleValue("surface-weight", 10);
154   double deviationWeight = param->getDoubleValue("deviation-weight", 1);
155     
156   for (; it != mRunways.end(); ++it) {
157     double good = (*it)->score(lengthWeight, widthWeight, surfaceWeight);
158     
159     double dev = aHeading - (*it)->headingDeg();
160     SG_NORMALIZE_RANGE(dev, -180.0, 180.0);
161     double bad = fabs(deviationWeight * dev) + 1e-20;
162     double quality = good / bad;
163     
164     if (quality > currentBestQuality) {
165       currentBestQuality = quality;
166       result = *it;
167     }
168   }
169
170   return result;
171 }
172
173 bool FGAirport::hasHardRunwayOfLengthFt(double aLengthFt) const
174 {
175   unsigned int numRunways(mRunways.size());
176   for (unsigned int r=0; r<numRunways; ++r) {
177     FGRunway* rwy = mRunways[r];
178     if (rwy->isReciprocal()) {
179       continue; // we only care about lengths, so don't do work twice
180     }
181
182     if (rwy->isHardSurface() && (rwy->lengthFt() >= aLengthFt)) {
183       return true; // we're done!
184     }
185   } // of runways iteration
186
187   return false;
188 }
189
190 unsigned int FGAirport::numTaxiways() const
191 {
192   return mTaxiways.size();
193 }
194
195 FGRunway* FGAirport::getTaxiwayByIndex(unsigned int aIndex) const
196 {
197   assert(aIndex >= 0 && aIndex < mTaxiways.size());
198   return mTaxiways[aIndex];
199 }
200
201 void FGAirport::addRunway(FGRunway* aRunway)
202 {
203   aRunway->setAirport(this);
204   
205   if (aRunway->isTaxiway()) {
206     mTaxiways.push_back(aRunway);
207   } else {
208     mRunways.push_back(aRunway);
209   }
210 }
211
212 FGRunway* FGAirport::getActiveRunwayForUsage() const
213 {
214   static FGEnvironmentMgr* envMgr = NULL;
215   if (!envMgr) {
216     envMgr = (FGEnvironmentMgr *) globals->get_subsystem("environment");
217   }
218   
219   FGEnvironment stationWeather(envMgr->getEnvironment(mPosition));
220   
221   double windSpeed = stationWeather.get_wind_speed_kt();
222   double hdg = stationWeather.get_wind_from_heading_deg();
223   if (windSpeed <= 0.0) {
224     hdg = 270;  // This forces West-facing rwys to be used in no-wind situations
225     // which is consistent with Flightgear's initial setup.
226   }
227   
228   return findBestRunwayForHeading(hdg);
229 }
230
231 FGAirport* FGAirport::findClosest(const SGGeod& aPos, double aCuttofNm, Filter* filter)
232 {
233   AirportFilter aptFilter;
234   if (filter == NULL) {
235     filter = &aptFilter;
236   }
237   
238   FGPositionedRef r = FGPositioned::findClosest(aPos, aCuttofNm, filter);
239   if (!r) {
240     return NULL;
241   }
242   
243   return static_cast<FGAirport*>(r.ptr());
244 }
245
246 FGAirport::HardSurfaceFilter::HardSurfaceFilter(double minLengthFt) :
247   mMinLengthFt(minLengthFt)
248 {
249 }
250       
251 bool FGAirport::HardSurfaceFilter::pass(FGPositioned* aPos) const
252 {
253   if (aPos->type() != AIRPORT) {
254     return false; // exclude seaports and heliports as well, we need a runways
255   }
256    
257   return static_cast<FGAirport*>(aPos)->hasHardRunwayOfLengthFt(mMinLengthFt);
258 }
259
260 FGAirport* FGAirport::findByIdent(const std::string& aIdent)
261 {
262   FGPositionedRef r;
263   AirportFilter filter;
264   r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
265   if (!r) {
266     return NULL; // we don't warn here, let the caller do that
267   }
268   return static_cast<FGAirport*>(r.ptr());
269 }
270
271 FGAirport* FGAirport::getByIdent(const std::string& aIdent)
272 {
273   FGPositionedRef r;
274   AirportFilter filter;
275   r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
276   if (!r) {
277     throw sg_range_exception("No such airport with ident: " + aIdent);
278   }
279   return static_cast<FGAirport*>(r.ptr());
280 }
281
282 char** FGAirport::searchNamesAndIdents(const std::string& aFilter)
283 {
284   // we delegate all the work to a horrible helper in FGPositioned, which can
285   // access the (private) index data.
286   return searchAirportNamesAndIdents(aFilter);
287 }
288
289 // find basic airport location info from airport database
290 const FGAirport *fgFindAirportID( const string& id)
291 {
292     if ( id.empty() ) {
293         return NULL;
294     }
295     
296     return FGAirport::findByIdent(id);
297 }
298
299
300 // get airport elevation
301 double fgGetAirportElev( const string& id )
302 {
303     SG_LOG( SG_GENERAL, SG_BULK,
304             "Finding elevation for airport: " << id );
305
306     const FGAirport *a=fgFindAirportID( id);
307     if (a) {
308         return a->getElevation();
309     } else {
310         return -9999.0;
311     }
312 }
313
314
315 // get airport position
316 Point3D fgGetAirportPos( const string& id )
317 {
318     SG_LOG( SG_ATC, SG_BULK,
319             "Finding position for airport: " << id );
320
321     const FGAirport *a = fgFindAirportID( id);
322
323     if (a) {
324         return Point3D(a->getLongitude(), a->getLatitude(), a->getElevation());
325     } else {
326         return Point3D(0.0, 0.0, -9999.0);
327     }
328 }