]> git.mxchange.org Git - flightgear.git/blob - src/Airports/simple.cxx
02d7025b8c62c8c1ecd45270efed823d63ad7528
[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 FGTaxiway* FGAirport::getTaxiwayByIndex(unsigned int aIndex) const
196 {
197   assert(aIndex >= 0 && aIndex < mTaxiways.size());
198   return mTaxiways[aIndex];
199 }
200
201 void FGAirport::setRunwaysAndTaxiways(vector<FGRunwayPtr>& rwys,
202        vector<FGTaxiwayPtr>& txwys)
203 {
204   mRunways.swap(rwys);
205   Runway_iterator it = mRunways.begin();
206   for (; it != mRunways.end(); ++it) {
207     (*it)->setAirport(this);
208   }
209   
210   mTaxiways.swap(txwys);
211 }
212
213 FGRunway* FGAirport::getActiveRunwayForUsage() const
214 {
215   static FGEnvironmentMgr* envMgr = NULL;
216   if (!envMgr) {
217     envMgr = (FGEnvironmentMgr *) globals->get_subsystem("environment");
218   }
219   
220   FGEnvironment stationWeather(envMgr->getEnvironment(mPosition));
221   
222   double windSpeed = stationWeather.get_wind_speed_kt();
223   double hdg = stationWeather.get_wind_from_heading_deg();
224   if (windSpeed <= 0.0) {
225     hdg = 270;  // This forces West-facing rwys to be used in no-wind situations
226     // which is consistent with Flightgear's initial setup.
227   }
228   
229   return findBestRunwayForHeading(hdg);
230 }
231
232 FGAirport* FGAirport::findClosest(const SGGeod& aPos, double aCuttofNm, Filter* filter)
233 {
234   AirportFilter aptFilter;
235   if (filter == NULL) {
236     filter = &aptFilter;
237   }
238   
239   FGPositionedRef r = FGPositioned::findClosest(aPos, aCuttofNm, filter);
240   if (!r) {
241     return NULL;
242   }
243   
244   return static_cast<FGAirport*>(r.ptr());
245 }
246
247 FGAirport::HardSurfaceFilter::HardSurfaceFilter(double minLengthFt) :
248   mMinLengthFt(minLengthFt)
249 {
250 }
251       
252 bool FGAirport::HardSurfaceFilter::passAirport(FGAirport* aApt) const
253 {
254   return aApt->hasHardRunwayOfLengthFt(mMinLengthFt);
255 }
256
257 FGAirport* FGAirport::findByIdent(const std::string& aIdent)
258 {
259   FGPositionedRef r;
260   AirportFilter filter;
261   r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
262   if (!r) {
263     return NULL; // we don't warn here, let the caller do that
264   }
265   return static_cast<FGAirport*>(r.ptr());
266 }
267
268 FGAirport* FGAirport::getByIdent(const std::string& aIdent)
269 {
270   FGPositionedRef r;
271   AirportFilter filter;
272   r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
273   if (!r) {
274     throw sg_range_exception("No such airport with ident: " + aIdent);
275   }
276   return static_cast<FGAirport*>(r.ptr());
277 }
278
279 char** FGAirport::searchNamesAndIdents(const std::string& aFilter)
280 {
281   // we delegate all the work to a horrible helper in FGPositioned, which can
282   // access the (private) index data.
283   return searchAirportNamesAndIdents(aFilter);
284 }
285
286 // find basic airport location info from airport database
287 const FGAirport *fgFindAirportID( const string& id)
288 {
289     if ( id.empty() ) {
290         return NULL;
291     }
292     
293     return FGAirport::findByIdent(id);
294 }
295
296
297 // get airport elevation
298 double fgGetAirportElev( const string& id )
299 {
300     SG_LOG( SG_GENERAL, SG_BULK,
301             "Finding elevation for airport: " << id );
302
303     const FGAirport *a=fgFindAirportID( id);
304     if (a) {
305         return a->getElevation();
306     } else {
307         return -9999.0;
308     }
309 }
310
311
312 // get airport position
313 Point3D fgGetAirportPos( const string& id )
314 {
315     SG_LOG( SG_ATC, SG_BULK,
316             "Finding position for airport: " << id );
317
318     const FGAirport *a = fgFindAirportID( id);
319
320     if (a) {
321         return Point3D(a->getLongitude(), a->getLatitude(), a->getElevation());
322     } else {
323         return Point3D(0.0, 0.0, -9999.0);
324     }
325 }