]> git.mxchange.org Git - flightgear.git/blob - src/Airports/simple.cxx
Merge branch 'rj/ttw' into next
[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::pass(FGPositioned* aPos) const
253 {
254   if (aPos->type() != AIRPORT) {
255     return false; // exclude seaports and heliports as well, we need a runways
256   }
257    
258   return static_cast<FGAirport*>(aPos)->hasHardRunwayOfLengthFt(mMinLengthFt);
259 }
260
261 FGAirport* FGAirport::findByIdent(const std::string& aIdent)
262 {
263   FGPositionedRef r;
264   AirportFilter filter;
265   r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
266   if (!r) {
267     return NULL; // we don't warn here, let the caller do that
268   }
269   return static_cast<FGAirport*>(r.ptr());
270 }
271
272 FGAirport* FGAirport::getByIdent(const std::string& aIdent)
273 {
274   FGPositionedRef r;
275   AirportFilter filter;
276   r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
277   if (!r) {
278     throw sg_range_exception("No such airport with ident: " + aIdent);
279   }
280   return static_cast<FGAirport*>(r.ptr());
281 }
282
283 char** FGAirport::searchNamesAndIdents(const std::string& aFilter)
284 {
285   // we delegate all the work to a horrible helper in FGPositioned, which can
286   // access the (private) index data.
287   return searchAirportNamesAndIdents(aFilter);
288 }
289
290 // find basic airport location info from airport database
291 const FGAirport *fgFindAirportID( const string& id)
292 {
293     if ( id.empty() ) {
294         return NULL;
295     }
296     
297     return FGAirport::findByIdent(id);
298 }
299
300
301 // get airport elevation
302 double fgGetAirportElev( const string& id )
303 {
304     SG_LOG( SG_GENERAL, SG_BULK,
305             "Finding elevation for airport: " << id );
306
307     const FGAirport *a=fgFindAirportID( id);
308     if (a) {
309         return a->getElevation();
310     } else {
311         return -9999.0;
312     }
313 }
314
315
316 // get airport position
317 Point3D fgGetAirportPos( const string& id )
318 {
319     SG_LOG( SG_ATC, SG_BULK,
320             "Finding position for airport: " << id );
321
322     const FGAirport *a = fgFindAirportID( id);
323
324     if (a) {
325         return Point3D(a->getLongitude(), a->getLatitude(), a->getElevation());
326     } else {
327         return Point3D(0.0, 0.0, -9999.0);
328     }
329 }