]> git.mxchange.org Git - flightgear.git/blob - src/Airports/simple.cxx
fix warnings in Multiplayer, Scripting, and Time
[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/pavement.hxx>
43 #include <Airports/dynamics.hxx>
44 #include <Airports/xmlloader.hxx>
45
46 // magic import of a helper which uses FGPositioned internals
47 extern char** searchAirportNamesAndIdents(const std::string& aFilter);
48
49 /***************************************************************************
50  * FGAirport
51  ***************************************************************************/
52
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),
57     _name(name),
58     _has_metar(has_metar),
59     _dynamics(0)
60 {
61 }
62
63
64 FGAirport::~FGAirport()
65 {
66     delete _dynamics;
67 }
68
69 bool FGAirport::isAirport() const
70 {
71   return type() == AIRPORT;
72 }
73
74 bool FGAirport::isSeaport() const
75 {
76   return type() == SEAPORT;
77 }
78
79 bool FGAirport::isHeliport() const
80 {
81   return type() == HELIPORT;
82 }
83
84 FGAirportDynamics * FGAirport::getDynamics()
85 {
86     if (_dynamics != 0) {
87         return _dynamics;
88     } else {
89         //cerr << "Trying to load dynamics for " << _id << endl;
90         _dynamics = new FGAirportDynamics(this);
91         XMLLoader::load(_dynamics);
92
93         FGRunwayPreference rwyPrefs(this);
94         XMLLoader::load(&rwyPrefs);
95         _dynamics->setRwyUse(rwyPrefs);
96
97         //FGSidStar SIDs(this);
98         XMLLoader::load(_dynamics->getSIDs());
99    }
100     return _dynamics;
101 }
102
103 unsigned int FGAirport::numRunways() const
104 {
105   return mRunways.size();
106 }
107
108 FGRunway* FGAirport::getRunwayByIndex(unsigned int aIndex) const
109 {
110   assert(aIndex >= 0 && aIndex < mRunways.size());
111   return mRunways[aIndex];
112 }
113
114 bool FGAirport::hasRunwayWithIdent(const string& aIdent) const
115 {
116   return (getIteratorForRunwayIdent(aIdent) != mRunways.end());
117 }
118
119 FGRunway* FGAirport::getRunwayByIdent(const string& aIdent) const
120 {
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");
125   }
126   
127   return *it;
128 }
129
130 FGAirport::Runway_iterator
131 FGAirport::getIteratorForRunwayIdent(const string& aIdent) const
132 {
133   string ident(aIdent);
134   if ((aIdent.size() == 1) || !isdigit(aIdent[1])) {
135     ident = "0" + aIdent;
136   }
137
138   Runway_iterator it = mRunways.begin();
139   for (; it != mRunways.end(); ++it) {
140     if ((*it)->ident() == ident) {
141       return it;
142     }
143   }
144
145   return it; // end()
146 }
147
148 FGRunway* FGAirport::findBestRunwayForHeading(double aHeading) const
149 {
150   Runway_iterator it = mRunways.begin();
151   FGRunway* result = NULL;
152   double currentBestQuality = 0.0;
153   
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);
159     
160   for (; it != mRunways.end(); ++it) {
161     double good = (*it)->score(lengthWeight, widthWeight, surfaceWeight);
162     
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;
167     
168     if (quality > currentBestQuality) {
169       currentBestQuality = quality;
170       result = *it;
171     }
172   }
173
174   return result;
175 }
176
177 bool FGAirport::hasHardRunwayOfLengthFt(double aLengthFt) const
178 {
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
184     }
185
186     if (rwy->isHardSurface() && (rwy->lengthFt() >= aLengthFt)) {
187       return true; // we're done!
188     }
189   } // of runways iteration
190
191   return false;
192 }
193
194 unsigned int FGAirport::numTaxiways() const
195 {
196   return mTaxiways.size();
197 }
198
199 FGTaxiway* FGAirport::getTaxiwayByIndex(unsigned int aIndex) const
200 {
201   assert(aIndex >= 0 && aIndex < mTaxiways.size());
202   return mTaxiways[aIndex];
203 }
204
205 unsigned int FGAirport::numPavements() const
206 {
207   return mPavements.size();
208 }
209
210 FGPavement* FGAirport::getPavementByIndex(unsigned int aIndex) const
211 {
212   assert(aIndex >= 0 && aIndex < mPavements.size());
213   return mPavements[aIndex];
214 }
215
216 void FGAirport::setRunwaysAndTaxiways(vector<FGRunwayPtr>& rwys,
217        vector<FGTaxiwayPtr>& txwys,
218        vector<FGPavementPtr>& pvts)
219 {
220   mRunways.swap(rwys);
221   Runway_iterator it = mRunways.begin();
222   for (; it != mRunways.end(); ++it) {
223     (*it)->setAirport(this);
224   }
225
226   mTaxiways.swap(txwys);
227   mPavements.swap(pvts);
228 }
229
230 FGRunway* FGAirport::getActiveRunwayForUsage() const
231 {
232   static FGEnvironmentMgr* envMgr = NULL;
233   if (!envMgr) {
234     envMgr = (FGEnvironmentMgr *) globals->get_subsystem("environment");
235   }
236   
237   FGEnvironment stationWeather(envMgr->getEnvironment(mPosition));
238   
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.
244   }
245   
246   return findBestRunwayForHeading(hdg);
247 }
248
249 FGAirport* FGAirport::findClosest(const SGGeod& aPos, double aCuttofNm, Filter* filter)
250 {
251   AirportFilter aptFilter;
252   if (filter == NULL) {
253     filter = &aptFilter;
254   }
255   
256   FGPositionedRef r = FGPositioned::findClosest(aPos, aCuttofNm, filter);
257   if (!r) {
258     return NULL;
259   }
260   
261   return static_cast<FGAirport*>(r.ptr());
262 }
263
264 FGAirport::HardSurfaceFilter::HardSurfaceFilter(double minLengthFt) :
265   mMinLengthFt(minLengthFt)
266 {
267 }
268       
269 bool FGAirport::HardSurfaceFilter::passAirport(FGAirport* aApt) const
270 {
271   return aApt->hasHardRunwayOfLengthFt(mMinLengthFt);
272 }
273
274 FGAirport* FGAirport::findByIdent(const std::string& aIdent)
275 {
276   FGPositionedRef r;
277   AirportFilter filter;
278   r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
279   if (!r) {
280     return NULL; // we don't warn here, let the caller do that
281   }
282   return static_cast<FGAirport*>(r.ptr());
283 }
284
285 FGAirport* FGAirport::getByIdent(const std::string& aIdent)
286 {
287   FGPositionedRef r;
288   AirportFilter filter;
289   r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
290   if (!r) {
291     throw sg_range_exception("No such airport with ident: " + aIdent);
292   }
293   return static_cast<FGAirport*>(r.ptr());
294 }
295
296 char** FGAirport::searchNamesAndIdents(const std::string& aFilter)
297 {
298   // we delegate all the work to a horrible helper in FGPositioned, which can
299   // access the (private) index data.
300   return searchAirportNamesAndIdents(aFilter);
301 }
302
303 // find basic airport location info from airport database
304 const FGAirport *fgFindAirportID( const string& id)
305 {
306     if ( id.empty() ) {
307         return NULL;
308     }
309     
310     return FGAirport::findByIdent(id);
311 }
312
313
314 // get airport elevation
315 double fgGetAirportElev( const string& id )
316 {
317     SG_LOG( SG_GENERAL, SG_BULK,
318             "Finding elevation for airport: " << id );
319
320     const FGAirport *a=fgFindAirportID( id);
321     if (a) {
322         return a->getElevation();
323     } else {
324         return -9999.0;
325     }
326 }
327
328
329 // get airport position
330 SGGeod fgGetAirportPos( const string& id )
331 {
332     SG_LOG( SG_ATC, SG_BULK,
333             "Finding position for airport: " << id );
334
335     const FGAirport *a = fgFindAirportID( id);
336
337     if (a) {
338         return SGGeod::fromDegM(a->getLongitude(), a->getLatitude(), a->getElevation());
339     } else {
340         return SGGeod::fromDegM(0.0, 0.0, -9999.0);
341     }
342 }