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