]> git.mxchange.org Git - flightgear.git/blob - src/Airports/runwayprefs.cxx
Fix line endings
[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., 675 Mass Ave, Cambridge, MA 02139, USA.
21 //
22 // $Id$
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <math.h>
29 //#include <algorithm>
30
31 #include <simgear/compiler.h>
32
33 //#include <plib/sg.h>
34 //#include <plib/ul.h>
35
36 //#include <Environment/environment_mgr.hxx>
37 //#include <Environment/environment.hxx>
38 //#include <simgear/misc/sg_path.hxx>
39 //#include <simgear/props/props.hxx>
40 //#include <simgear/structure/subsystem_mgr.hxx>
41 #include <simgear/debug/logstream.hxx>
42 #include <Main/globals.hxx>
43 //#include <Main/fg_props.hxx>
44 #include <Airports/runways.hxx>
45
46 #include "runwayprefs.hxx"
47
48 /******************************************************************************
49  * ScheduleTime
50  ***************e*************************************************************/
51 void ScheduleTime::clear()
52
53   start.clear();
54   end.clear();
55   scheduleNames.clear();
56 }
57
58
59 ScheduleTime::ScheduleTime(const ScheduleTime &other) 
60 {
61   //timeVec   start;
62   timeVecConstIterator i;
63   for (i = other.start.begin(); i != other.start.end(); i++)
64     start.push_back(*i);
65    for (i = other.end.begin(); i != other.end.end(); i++)
66     end.push_back(*i);
67    stringVecConstIterator k;
68    for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
69      scheduleNames.push_back(*k);
70   
71   //timeVec   end;
72   //stringVec scheduleNames;
73   tailWind = other.tailWind;
74   crssWind = other.tailWind;
75 }
76
77
78 ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other) 
79 {
80   //timeVec   start;
81   clear();
82   timeVecConstIterator i;
83   for (i = other.start.begin(); i != other.start.end(); i++)
84     start.push_back(*i);
85    for (i = other.end.begin(); i != other.end.end(); i++)
86     end.push_back(*i);
87    stringVecConstIterator k;
88    for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
89      scheduleNames.push_back(*k);
90   
91   //timeVec   end;
92   //stringVec scheduleNames;
93   tailWind = other.tailWind;
94   crssWind = other.tailWind;
95   return *this;
96 }
97 string ScheduleTime::getName(time_t dayStart)
98 {
99   if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
100     {
101       SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" );
102       exit(1);
103     }
104   else
105     {
106       int nrItems = start.size();
107       //cerr << "Nr of items to process: " << nrItems << endl;
108       if (nrItems > 0)
109         {
110           for (unsigned int i = 0; i < start.size(); i++)
111             {
112               //cerr << i << endl;
113               if ((dayStart >= start[i]) && (dayStart <= end[i]))
114                 return scheduleNames[i];
115             }
116         }
117       //couldn't find one so return 0;
118       //cerr << "Returning 0 " << endl;
119     }
120     return string(0);
121 }                             
122 /******************************************************************************
123  * RunwayList
124  *****************************************************************************/
125
126 RunwayList::RunwayList(const RunwayList &other)
127 {
128   type = other.type;
129   stringVecConstIterator i;
130   for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
131     preferredRunways.push_back(*i);
132 }
133 RunwayList& RunwayList::operator= (const RunwayList &other)
134 {
135   type = other.type;
136   preferredRunways.clear();
137   stringVecConstIterator i;
138   for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
139     preferredRunways.push_back(*i);
140   return *this;
141 }
142 void RunwayList::set(const string &tp, const string &lst)
143 {
144   //weekday          = atoi(timeCopy.substr(0,1).c_str());
145   //    timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
146   //    timeCopy = timeCopy.substr(2,timeCopy.length());
147   type = tp;
148   string rwys = lst;
149   string rwy;
150   while (rwys.find(",") != string::npos)
151     {
152       rwy = rwys.substr(0, rwys.find(",",0));
153       //cerr << "adding runway [" << rwy << "] to the list " << endl;
154       preferredRunways.push_back(rwy);
155       rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace
156       while (rwys[0] == ' ')
157         rwys.erase(0, 1); // Erase any leading whitespaces.
158       //cerr << "Remaining runway list " << rwys;
159     } 
160   preferredRunways.push_back(rwys);
161   //exit(1);
162 }
163
164 void RunwayList::clear() 
165 {
166   type = "";
167   preferredRunways.clear();
168 }
169 /****************************************************************************
170  *
171  ***************************************************************************/
172
173 RunwayGroup::RunwayGroup(const RunwayGroup &other)
174 {
175   name = other.name; 
176   RunwayListVecConstIterator i;
177   for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
178     rwyList.push_back(*i);
179   choice[0] = other.choice[0];
180   choice[1] = other.choice[1];
181   nrActive = other.nrActive;
182 }
183 RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
184
185   rwyList.clear();
186   name = other.name; 
187   RunwayListVecConstIterator i;
188   for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
189     rwyList.push_back(*i); 
190   choice[0] = other.choice[0];
191   choice[1] = other.choice[1];
192   nrActive = other.nrActive;
193   return *this;
194 }
195
196 void RunwayGroup::setActive(const string &aptId, 
197                             double windSpeed, 
198                             double windHeading, 
199                             double maxTail, 
200                             double maxCross)
201 {
202
203   FGRunway rwy;
204   int activeRwys = rwyList.size(); // get the number of runways active
205   int nrOfPreferences;
206   // bool found = true;
207   // double heading;
208   double hdgDiff;
209   double crossWind;
210   double tailWind;
211   string name;
212
213   if (activeRwys > 0)
214     {
215       nrOfPreferences = rwyList[0].getRwyList()->size();
216       for (int i = 0; i < nrOfPreferences; i++)
217         {
218           bool validSelection = true;
219           for (int j = 0; j < activeRwys; j++)
220             {
221               //cerr << "I J " << i << " " << j << endl;
222               name = rwyList[j].getRwyList(i);
223               //cerr << "Name of Runway: " << name << endl;
224               if (globals->get_runways()->search( aptId, 
225                                                   name, 
226                                                   &rwy))
227                 {
228                   //cerr << "Succes" << endl;
229                   hdgDiff = fabs(windHeading - rwy._heading);
230                   //cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
231                   //cerr << "Wind Speed  : " << windSpeed << endl;
232                   if (hdgDiff > 180)
233                     hdgDiff = 360 - hdgDiff;
234                   //cerr << "Heading diff: " << hdgDiff << endl;
235                   hdgDiff *= ((2*M_PI)/360.0); // convert to radians
236                   crossWind = windSpeed * sin(hdgDiff);
237                   tailWind  = -windSpeed * cos(hdgDiff);
238                   //cerr << "Tailwind : " << tailWind << endl;
239                   //cerr << "Crosswnd : " << crossWind << endl;
240                   if ((tailWind > maxTail) || (crossWind > maxCross))
241                     validSelection = false;
242                 }else {
243                   SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId );
244                   exit(1);
245                 }
246
247             }
248           if (validSelection)
249             {
250               //cerr << "Valid runay selection : " << i << endl;
251               nrActive = activeRwys;
252               active = i;
253               return;
254             }
255         }
256       // If this didn't work, due to heavy winds, try again
257       // but select only one landing and one takeoff runway. 
258       choice[0] = 0;
259       choice[1] = 0;
260       for (int i = activeRwys-1;  i; i--)
261         {
262           if (rwyList[i].getType() == string("landing"))
263             choice[0] = i;
264           if (rwyList[i].getType() == string("takeoff"))
265             choice[1] = i;
266         }
267       //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
268       nrOfPreferences = rwyList[0].getRwyList()->size();
269       for (int i = 0; i < nrOfPreferences; i++)
270         {
271           bool validSelection = true;
272           for (int j = 0; j < 2; j++)
273             {
274               //cerr << "I J " << i << " " << j << endl;
275               name = rwyList[choice[j]].getRwyList(i);
276               //cerr << "Name of Runway: " << name << endl;
277               if (globals->get_runways()->search( aptId, 
278                                                   name, 
279                                                   &rwy))
280                 {
281                   //cerr << "Succes" << endl;
282                   hdgDiff = fabs(windHeading - rwy._heading);
283                   //cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
284                   //cerr << "Wind Speed  : " << windSpeed << endl;
285                   if (hdgDiff > 180)
286                     hdgDiff = 360 - hdgDiff;
287                   //cerr << "Heading diff: " << hdgDiff << endl;
288                   hdgDiff *= ((2*M_PI)/360.0); // convert to radians
289                   crossWind = windSpeed * sin(hdgDiff);
290                   tailWind  = -windSpeed * cos(hdgDiff);
291                   //cerr << "Tailwind : " << tailWind << endl;
292                   //cerr << "Crosswnd : " << crossWind << endl;
293                   if ((tailWind > maxTail) || (crossWind > maxCross))
294                     validSelection = false;
295                 }else {
296                   SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId );
297                   exit(1);
298                 }
299
300             }
301           if (validSelection)
302             {
303               //cerr << "Valid runay selection : " << i << endl;
304               active = i;
305               nrActive = 2;
306               return;
307             }
308         }
309     }
310   active = -1;
311   //RunwayListVectorIterator i; // = rwlist.begin();
312   //stringVecIterator j;
313   //for (i = rwyList.begin(); i != rwyList.end(); i++)
314   //  {
315   //    cerr << i->getType();
316   //    for (j = i->getRwyList()->begin(); j != i->getRwyList()->end(); j++)
317   //    {                                 
318   //      cerr << (*j);
319   //    }
320   //    cerr << endl;
321   //  }
322   //for (int
323
324 }
325
326 void RunwayGroup::getActive(int i, string &name, string &type)
327 {
328   if (i == -1)
329     {
330       return;
331     }
332   if (nrActive == (int)rwyList.size())
333     {
334       name = rwyList[i].getRwyList(active);
335       type = rwyList[i].getType();
336     }
337   else
338     { 
339       name = rwyList[choice[i]].getRwyList(active);
340       type = rwyList[choice[i]].getType();
341     }
342 }
343 /*****************************************************************************
344  * FGRunway preference
345  ****************************************************************************/
346 FGRunwayPreference::FGRunwayPreference()
347 {
348   //cerr << "Running default Constructor" << endl;
349   initialized = false;
350 }
351
352 FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
353 {
354   initialized = other.initialized;
355   value = other.value;
356   scheduleName = other.scheduleName;
357
358   comTimes = other.comTimes; // Commercial Traffic;
359   genTimes = other.genTimes; // General Aviation;
360   milTimes = other.milTimes; // Military Traffic;
361   currTimes= other.currTimes; // Needed for parsing;
362
363   rwyList = other.rwyList;
364   rwyGroup = other.rwyGroup;
365   PreferenceListConstIterator i;
366   for (i = other.preferences.begin(); i != other.preferences.end(); i++)
367     preferences.push_back(*i);
368 }
369   
370 FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
371 {
372   initialized = other.initialized;
373   value = other.value;
374   scheduleName = other.scheduleName;
375   
376   comTimes = other.comTimes; // Commercial Traffic;
377   genTimes = other.genTimes; // General Aviation;
378   milTimes = other.milTimes; // Military Traffic;
379   currTimes= other.currTimes; // Needed for parsing;
380   
381   rwyList = other.rwyList;
382   rwyGroup = other.rwyGroup;
383   PreferenceListConstIterator i;
384   preferences.clear();
385   for (i = other.preferences.begin(); i != other.preferences.end(); i++)
386     preferences.push_back(*i);
387   return *this;
388 }
389
390 ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
391 {
392   if (!(strcmp(trafficType, "com"))) {
393     return &comTimes;
394   }
395   if (!(strcmp(trafficType, "gen"))) {
396     return &genTimes;
397   }
398   if (!(strcmp(trafficType, "mil"))) {
399     return &milTimes;
400   }
401   return 0;
402 }
403
404 RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
405 {
406   PreferenceListIterator i = preferences.begin();
407   if (preferences.begin() == preferences.end())
408     return 0;
409   while (!(i == preferences.end() || i->getName() == groupName))
410     i++;
411   if (i != preferences.end())
412     return &(*i);
413   else
414     return 0;
415 }
416
417 void  FGRunwayPreference::startXML () {
418   //  cout << "Start XML" << endl;
419 }
420
421 void  FGRunwayPreference::endXML () {
422   cout << "End XML" << endl;
423 }
424
425 void  FGRunwayPreference::startElement (const char * name, const XMLAttributes &atts) {
426   //cout << "StartElement " << name << endl;
427   value = string("");
428   if (!(strcmp(name, "wind"))) {
429     //cerr << "Will be processing Wind" << endl;
430     for (int i = 0; i < atts.size(); i++)
431       {
432         //cout << "  " << atts.getName(i) << '=' << atts.getValue(i) << endl; 
433         //attname = atts.getName(i);
434         if (atts.getName(i) == string("tail")) {
435           //cerr << "Tail Wind = " << atts.getValue(i) << endl;
436           currTimes.setTailWind(atof(atts.getValue(i)));
437         }       
438         if (atts.getName(i) == string("cross")) {
439           //cerr << "Cross Wind = " << atts.getValue(i) << endl;
440           currTimes.setCrossWind(atof(atts.getValue(i)));
441         }
442      }
443   }
444     if (!(strcmp(name, "time"))) {
445       //cerr << "Will be processing time" << endl;      
446     for (int i = 0; i < atts.size(); i++)
447       {
448         if (atts.getName(i) == string("start")) {
449           //cerr << "Start Time = " << atts.getValue(i) << endl;
450           currTimes.addStartTime(processTime(atts.getValue(i)));
451         }
452         if (atts.getName(i) == string("end")) {
453           //cerr << "End time = " << atts.getValue(i) << endl;
454           currTimes.addEndTime(processTime(atts.getValue(i)));
455         }
456         if (atts.getName(i) == string("schedule")) {
457           //cerr << "Schedule Name  = " << atts.getValue(i) << endl;
458           currTimes.addScheduleName(atts.getValue(i));
459         }       
460     }
461   }
462   if (!(strcmp(name, "takeoff"))) {
463     rwyList.clear();
464   }
465   if  (!(strcmp(name, "landing")))
466     {
467       rwyList.clear();
468     }
469   if (!(strcmp(name, "schedule"))) {
470     for (int i = 0; i < atts.size(); i++)
471       {
472         //cout << "  " << atts.getName(i) << '=' << atts.getValue(i) << endl; 
473         //attname = atts.getName(i);
474         if (atts.getName(i) == string("name")) {
475           //cerr << "Schedule name = " << atts.getValue(i) << endl;
476           scheduleName = atts.getValue(i);
477         }
478       }
479   }
480 }
481
482 //based on a string containing hour and minute, return nr seconds since day start.
483 time_t FGRunwayPreference::processTime(const string &tme)
484 {
485   string hour   = tme.substr(0, tme.find(":",0));
486   string minute = tme.substr(tme.find(":",0)+1, tme.length());
487
488   //cerr << "hour = " << hour << " Minute = " << minute << endl;
489   return (atoi(hour.c_str()) * 3600 + atoi(minute.c_str()) * 60);
490 }
491
492 void  FGRunwayPreference::endElement (const char * name) {
493   //cout << "End element " << name << endl;
494   if (!(strcmp(name, "rwyuse"))) {
495     initialized = true;
496   }
497   if (!(strcmp(name, "com"))) { // Commercial Traffic
498     //cerr << "Setting time table for commerical traffic" << endl;
499     comTimes = currTimes;
500     currTimes.clear();
501   }
502   if (!(strcmp(name, "gen"))) { // General Aviation
503     //cerr << "Setting time table for general aviation" << endl;
504     genTimes = currTimes;
505     currTimes.clear();
506   }  
507   if (!(strcmp(name, "mil"))) { // Military Traffic
508     //cerr << "Setting time table for military traffic" << endl;
509     genTimes = currTimes;
510     currTimes.clear();
511   }
512
513   if (!(strcmp(name, "takeoff"))) {
514     //cerr << "Adding takeoff: " << value << endl;
515     rwyList.set(name, value);
516     rwyGroup.add(rwyList);
517   }
518   if (!(strcmp(name, "landing"))) {
519     //cerr << "Adding landing: " << value << endl;
520     rwyList.set(name, value);
521     rwyGroup.add(rwyList);
522   }
523   if (!(strcmp(name, "schedule"))) {
524     //cerr << "Adding schedule" << scheduleName << endl;
525     rwyGroup.setName(scheduleName);
526     //rwyGroup.addRunways(rwyList);
527     preferences.push_back(rwyGroup);
528     rwyGroup.clear();
529     //exit(1);
530   }
531 }
532
533 void  FGRunwayPreference::data (const char * s, int len) {
534   string token = string(s,len);
535   //cout << "Character data " << string(s,len) << endl;
536   //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
537   //  value += token;
538   //else
539   //  value = string("");
540   value += token;
541 }
542
543 void  FGRunwayPreference::pi (const char * target, const char * data) {
544   //cout << "Processing instruction " << target << ' ' << data << endl;
545 }
546
547 void  FGRunwayPreference::warning (const char * message, int line, int column) {
548   cout << "Warning: " << message << " (" << line << ',' << column << ')'   
549        << endl;
550 }
551
552 void  FGRunwayPreference::error (const char * message, int line, int column) {
553   cout << "Error: " << message << " (" << line << ',' << column << ')'
554        << endl;
555 }