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