]> git.mxchange.org Git - flightgear.git/blob - src/Airports/simple.cxx
Port over remaining Point3D usage to the more type and unit safe SG* classes.
[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         //FGSidStar SIDs(this);
97         XMLLoader::load(_dynamics->getSIDs());
98    }
99     return _dynamics;
100 }
101
102 unsigned int FGAirport::numRunways() const
103 {
104   return mRunways.size();
105 }
106
107 FGRunway* FGAirport::getRunwayByIndex(unsigned int aIndex) const
108 {
109   assert(aIndex >= 0 && aIndex < mRunways.size());
110   return mRunways[aIndex];
111 }
112
113 bool FGAirport::hasRunwayWithIdent(const string& aIdent) const
114 {
115   return (getIteratorForRunwayIdent(aIdent) != mRunways.end());
116 }
117
118 FGRunway* FGAirport::getRunwayByIdent(const string& aIdent) const
119 {
120   Runway_iterator it = getIteratorForRunwayIdent(aIdent);
121   if (it == mRunways.end()) {
122     SG_LOG(SG_GENERAL, SG_ALERT, "no such runway '" << aIdent << "' at airport " << ident());
123     throw sg_range_exception("unknown runway " + aIdent + " at airport:" + ident(), "FGAirport::getRunwayByIdent");
124   }
125   
126   return *it;
127 }
128
129 FGAirport::Runway_iterator
130 FGAirport::getIteratorForRunwayIdent(const string& aIdent) const
131 {
132   string ident(aIdent);
133   if ((aIdent.size() == 1) || !isdigit(aIdent[1])) {
134     ident = "0" + aIdent;
135   }
136
137   Runway_iterator it = mRunways.begin();
138   for (; it != mRunways.end(); ++it) {
139     if ((*it)->ident() == ident) {
140       return it;
141     }
142   }
143
144   return it; // end()
145 }
146
147 FGRunway* FGAirport::findBestRunwayForHeading(double aHeading) const
148 {
149   Runway_iterator it = mRunways.begin();
150   FGRunway* result = NULL;
151   double currentBestQuality = 0.0;
152   
153   SGPropertyNode *param = fgGetNode("/sim/airport/runways/search", true);
154   double lengthWeight = param->getDoubleValue("length-weight", 0.01);
155   double widthWeight = param->getDoubleValue("width-weight", 0.01);
156   double surfaceWeight = param->getDoubleValue("surface-weight", 10);
157   double deviationWeight = param->getDoubleValue("deviation-weight", 1);
158     
159   for (; it != mRunways.end(); ++it) {
160     double good = (*it)->score(lengthWeight, widthWeight, surfaceWeight);
161     
162     double dev = aHeading - (*it)->headingDeg();
163     SG_NORMALIZE_RANGE(dev, -180.0, 180.0);
164     double bad = fabs(deviationWeight * dev) + 1e-20;
165     double quality = good / bad;
166     
167     if (quality > currentBestQuality) {
168       currentBestQuality = quality;
169       result = *it;
170     }
171   }
172
173   return result;
174 }
175
176 bool FGAirport::hasHardRunwayOfLengthFt(double aLengthFt) const
177 {
178   unsigned int numRunways(mRunways.size());
179   for (unsigned int r=0; r<numRunways; ++r) {
180     FGRunway* rwy = mRunways[r];
181     if (rwy->isReciprocal()) {
182       continue; // we only care about lengths, so don't do work twice
183     }
184
185     if (rwy->isHardSurface() && (rwy->lengthFt() >= aLengthFt)) {
186       return true; // we're done!
187     }
188   } // of runways iteration
189
190   return false;
191 }
192
193 unsigned int FGAirport::numTaxiways() const
194 {
195   return mTaxiways.size();
196 }
197
198 FGTaxiway* FGAirport::getTaxiwayByIndex(unsigned int aIndex) const
199 {
200   assert(aIndex >= 0 && aIndex < mTaxiways.size());
201   return mTaxiways[aIndex];
202 }
203
204 void FGAirport::setRunwaysAndTaxiways(vector<FGRunwayPtr>& rwys,
205        vector<FGTaxiwayPtr>& txwys)
206 {
207   mRunways.swap(rwys);
208   Runway_iterator it = mRunways.begin();
209   for (; it != mRunways.end(); ++it) {
210     (*it)->setAirport(this);
211   }
212   
213   mTaxiways.swap(txwys);
214 }
215
216 FGRunway* FGAirport::getActiveRunwayForUsage() const
217 {
218   static FGEnvironmentMgr* envMgr = NULL;
219   if (!envMgr) {
220     envMgr = (FGEnvironmentMgr *) globals->get_subsystem("environment");
221   }
222   
223   FGEnvironment stationWeather(envMgr->getEnvironment(mPosition));
224   
225   double windSpeed = stationWeather.get_wind_speed_kt();
226   double hdg = stationWeather.get_wind_from_heading_deg();
227   if (windSpeed <= 0.0) {
228     hdg = 270;  // This forces West-facing rwys to be used in no-wind situations
229     // which is consistent with Flightgear's initial setup.
230   }
231   
232   return findBestRunwayForHeading(hdg);
233 }
234
235 FGAirport* FGAirport::findClosest(const SGGeod& aPos, double aCuttofNm, Filter* filter)
236 {
237   AirportFilter aptFilter;
238   if (filter == NULL) {
239     filter = &aptFilter;
240   }
241   
242   FGPositionedRef r = FGPositioned::findClosest(aPos, aCuttofNm, filter);
243   if (!r) {
244     return NULL;
245   }
246   
247   return static_cast<FGAirport*>(r.ptr());
248 }
249
250 FGAirport::HardSurfaceFilter::HardSurfaceFilter(double minLengthFt) :
251   mMinLengthFt(minLengthFt)
252 {
253 }
254       
255 bool FGAirport::HardSurfaceFilter::passAirport(FGAirport* aApt) const
256 {
257   return aApt->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 SGGeod 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 SGGeod::fromDegM(a->getLongitude(), a->getLatitude(), a->getElevation());
325     } else {
326         return SGGeod::fromDegM(0.0, 0.0, -9999.0);
327     }
328 }