]> git.mxchange.org Git - flightgear.git/blob - src/Airports/runwayprefs.cxx
Port over remaining Point3D usage to the more type and unit safe SG* classes.
[flightgear.git] / src / Airports / runwayprefs.cxx
1 // runwayprefs.cxx - class implementations corresponding to runwayprefs.hxx
2 // assignments by the AI code
3 //
4 // Written by Durk Talsma, started January 2005.
5 //
6 // Copyright (C) 2004 Durk Talsma.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 //
22 // $Id$
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <math.h>
29
30 #include <simgear/compiler.h>
31
32 #include <simgear/debug/logstream.hxx>
33 #include <Main/globals.hxx>
34 #include <Airports/runways.hxx>
35
36 #include "runwayprefs.hxx"
37 #include "simple.hxx"
38
39 /******************************************************************************
40  * ScheduleTime
41  ***************e*************************************************************/
42 void ScheduleTime::clear()
43
44   start.clear();
45   end.clear();
46   scheduleNames.clear();
47 }
48
49
50 ScheduleTime::ScheduleTime(const ScheduleTime &other) 
51 {
52   //timeVec   start;
53   timeVecConstIterator i;
54   for (i = other.start.begin(); i != other.start.end(); i++)
55     start.push_back(*i);
56    for (i = other.end.begin(); i != other.end.end(); i++)
57     end.push_back(*i);
58    stringVecConstIterator k;
59    for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
60      scheduleNames.push_back(*k);
61   
62   //timeVec   end;
63   //stringVec scheduleNames;
64   tailWind = other.tailWind;
65   crssWind = other.tailWind;
66 }
67
68
69 ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other) 
70 {
71   //timeVec   start;
72   clear();
73   timeVecConstIterator i;
74   for (i = other.start.begin(); i != other.start.end(); i++)
75     start.push_back(*i);
76    for (i = other.end.begin(); i != other.end.end(); i++)
77     end.push_back(*i);
78    stringVecConstIterator k;
79    for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
80      scheduleNames.push_back(*k);
81   
82   //timeVec   end;
83   //stringVec scheduleNames;
84   tailWind = other.tailWind;
85   crssWind = other.tailWind;
86   return *this;
87 }
88 string ScheduleTime::getName(time_t dayStart)
89 {
90   if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
91     {
92       SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" );
93       exit(1);
94     }
95   else
96     {
97       int nrItems = start.size();
98       //cerr << "Nr of items to process: " << nrItems << endl;
99       if (nrItems > 0)
100         {
101           for (unsigned int i = 0; i < start.size(); i++)
102             {
103               //cerr << i << endl;
104               if ((dayStart >= start[i]) && (dayStart <= end[i]))
105                 return scheduleNames[i];
106             }
107         }
108       //couldn't find one so return 0;
109       //cerr << "Returning 0 " << endl;
110     }
111     return string("");
112 }                             
113 /******************************************************************************
114  * RunwayList
115  *****************************************************************************/
116
117 RunwayList::RunwayList(const RunwayList &other)
118 {
119   type = other.type;
120   stringVecConstIterator i;
121   for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
122     preferredRunways.push_back(*i);
123 }
124 RunwayList& RunwayList::operator= (const RunwayList &other)
125 {
126   type = other.type;
127   preferredRunways.clear();
128   stringVecConstIterator i;
129   for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
130     preferredRunways.push_back(*i);
131   return *this;
132 }
133 void RunwayList::set(const string &tp, const string &lst)
134 {
135   //weekday          = atoi(timeCopy.substr(0,1).c_str());
136   //    timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
137   //    timeCopy = timeCopy.substr(2,timeCopy.length());
138   type = tp;
139   string rwys = lst;
140   string rwy;
141   while (rwys.find(",") != string::npos)
142     {
143       rwy = rwys.substr(0, rwys.find(",",0));
144       //cerr << "adding runway [" << rwy << "] to the list " << endl;
145       preferredRunways.push_back(rwy);
146       rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace
147       while (rwys[0] == ' ')
148         rwys.erase(0, 1); // Erase any leading whitespaces.
149       //cerr << "Remaining runway list " << rwys;
150     } 
151   preferredRunways.push_back(rwys);
152   //exit(1);
153 }
154
155 void RunwayList::clear() 
156 {
157   type = "";
158   preferredRunways.clear();
159 }
160 /****************************************************************************
161  *
162  ***************************************************************************/
163
164 RunwayGroup::RunwayGroup(const RunwayGroup &other)
165 {
166   name = other.name; 
167   RunwayListVecConstIterator i;
168   for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
169     rwyList.push_back(*i);
170   choice[0] = other.choice[0];
171   choice[1] = other.choice[1];
172   nrActive = other.nrActive;
173 }
174 RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
175
176   rwyList.clear();
177   name = other.name; 
178   RunwayListVecConstIterator i;
179   for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
180     rwyList.push_back(*i); 
181   choice[0] = other.choice[0];
182   choice[1] = other.choice[1];
183   nrActive = other.nrActive;
184   return *this;
185 }
186
187 void RunwayGroup::setActive(const FGAirport* airport, 
188                             double windSpeed, 
189                             double windHeading, 
190                             double maxTail, 
191                             double maxCross,
192                             stringVec *currentlyActive)
193 {
194
195   FGRunway* rwy;
196   int activeRwys = rwyList.size(); // get the number of runways active
197   int nrOfPreferences;
198   // bool found = true;
199   // double heading;
200   double hdgDiff;
201   double crossWind;
202   double tailWind;
203   string name;
204   //stringVec names;
205   int bestMatch = 0, bestChoice = 0;
206
207   if (activeRwys > 0)
208     {  
209       // Now downward iterate across all the possible preferences
210       // starting by the least preferred choice working toward the most preferred choice
211
212       nrOfPreferences = rwyList[0].getRwyList()->size();
213       bool validSelection = true;
214       bool foundValidSelection = false;
215       for (int i = nrOfPreferences-1; i >= 0; i--)
216         {
217           int match = 0;
218           
219
220           // Test each runway listed in the preference to see if it's possible to use
221           // If one runway of the selection isn't allowed, we need to exclude this
222           // preference, however, we don't want to stop right there, because we also
223           // don't want to randomly swap runway preferences, unless there is a need to. 
224           //
225           validSelection = true;
226           for (int j = 0; j < activeRwys; j++)
227     {
228              rwy = airport->getRunwayByIdent(rwyList[j].getRwyList(i));
229        
230                           //cerr << "Succes" << endl;
231                   hdgDiff = fabs(windHeading - rwy->headingDeg());
232                   //cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
233                   //cerr << "Wind Speed  : " << windSpeed << endl;
234                   if (hdgDiff > 180)
235                     hdgDiff = 360 - hdgDiff;
236                   //cerr << "Heading diff: " << hdgDiff << endl;
237                   hdgDiff *= ((2*M_PI)/360.0); // convert to radians
238                   crossWind = windSpeed * sin(hdgDiff);
239                   tailWind  = -windSpeed * cos(hdgDiff);
240                   //cerr << ". Tailwind : " << tailWind;
241                   //cerr << ". Crosswnd : " << crossWind;
242                   if ((tailWind > maxTail) || (crossWind > maxCross))
243                     {
244                       //cerr << ". [Invalid] " << endl;
245                       validSelection = false;
246                    }
247                   else 
248                     {
249                       //cerr << ". [Valid] ";
250                   }
251                               //cerr << endl;
252     } // of active runways iteration
253       
254           if (validSelection) 
255             {
256               //cerr << "Valid selection  : " << i << endl;;
257               foundValidSelection = true;
258               for (stringVecIterator it = currentlyActive->begin(); 
259                    it != currentlyActive->end(); it++)
260                 {
261                   if ((*it) == name)
262                     match++;
263                 }
264               if (match >= bestMatch) {
265                 bestMatch = match;
266                 bestChoice = i;
267               }
268             } 
269           //cerr << "Preference " << i << " bestMatch " << bestMatch << " choice " << bestChoice << endl;
270         }
271       if (foundValidSelection)
272         {
273           //cerr << "Valid runay selection : " << bestChoice << endl;
274           nrActive = activeRwys;
275           active = bestChoice;
276           return;
277         }
278       // If this didn't work, due to heavy winds, try again
279       // but select only one landing and one takeoff runway. 
280       choice[0] = 0;
281       choice[1] = 0;
282       for (int i = activeRwys-1;  i; i--)
283         {
284           if (rwyList[i].getType() == string("landing"))
285             choice[0] = i;
286           if (rwyList[i].getType() == string("takeoff"))
287             choice[1] = i;
288         }
289       //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
290       nrOfPreferences = rwyList[0].getRwyList()->size();
291       for (int i = 0; i < nrOfPreferences; i++)
292         {
293           bool validSelection = true;
294           for (int j = 0; j < 2; j++)
295             {
296         name = rwyList[choice[j]].getRwyList(i);
297         rwy = airport->getRunwayByIdent(name);
298         
299                   //cerr << "Succes" << endl;
300                   hdgDiff = fabs(windHeading - rwy->headingDeg());
301                   if (hdgDiff > 180)
302                     hdgDiff = 360 - hdgDiff;
303                   hdgDiff *= ((2*M_PI)/360.0); // convert to radians
304                   crossWind = windSpeed * sin(hdgDiff);
305                   tailWind  = -windSpeed * cos(hdgDiff);
306                   if ((tailWind > maxTail) || (crossWind > maxCross))
307                     validSelection = false;
308                 
309
310             }
311           if (validSelection)
312             {
313               //cerr << "Valid runay selection : " << i << endl;
314               active = i;
315               nrActive = 2;
316               return;
317             }
318         }
319     }
320   active = -1;
321   nrActive = 0;
322 }
323
324 void RunwayGroup::getActive(int i, string &name, string &type)
325 {
326   if (i == -1)
327     {
328       return;
329     }
330   if (nrActive == (int)rwyList.size())
331     {
332       name = rwyList[i].getRwyList(active);
333       type = rwyList[i].getType();
334     }
335   else
336     { 
337       name = rwyList[choice[i]].getRwyList(active);
338       type = rwyList[choice[i]].getType();
339     }
340 }
341 /*****************************************************************************
342  * FGRunway preference
343  ****************************************************************************/
344 FGRunwayPreference::FGRunwayPreference(FGAirport* ap) : 
345   _ap(ap)
346 {
347   //cerr << "Running default Constructor" << endl;
348   initialized = false;
349 }
350
351 FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
352 {
353   initialized = other.initialized;
354
355   comTimes = other.comTimes; // Commercial Traffic;
356   genTimes = other.genTimes; // General Aviation;
357   milTimes = other.milTimes; // Military Traffic;
358
359   PreferenceListConstIterator i;
360   for (i = other.preferences.begin(); i != other.preferences.end(); i++)
361     preferences.push_back(*i);
362 }
363   
364 FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
365 {
366   initialized = other.initialized;
367   
368   comTimes = other.comTimes; // Commercial Traffic;
369   genTimes = other.genTimes; // General Aviation;
370   milTimes = other.milTimes; // Military Traffic;
371   
372   PreferenceListConstIterator i;
373   preferences.clear();
374   for (i = other.preferences.begin(); i != other.preferences.end(); i++)
375     preferences.push_back(*i);
376   return *this;
377 }
378
379 ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
380 {
381   if (!(strcmp(trafficType, "com"))) {
382     return &comTimes;
383   }
384   if (!(strcmp(trafficType, "gen"))) {
385     return &genTimes;
386   }
387   if (!(strcmp(trafficType, "mil"))) {
388     return &milTimes;
389   }
390   return 0;
391 }
392
393 RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
394 {
395   PreferenceListIterator i = preferences.begin();
396   if (preferences.begin() == preferences.end())
397     return 0;
398   while (!(i == preferences.end() || i->getName() == groupName))
399     i++;
400   if (i != preferences.end())
401     return &(*i);
402   else
403     return 0;
404 }
405
406  string FGRunwayPreference::getId() { 
407    return _ap->getId(); 
408  };