1 // runwayprefs.cxx - class implementations corresponding to runwayprefs.hxx
2 // assignments by the AI code
4 // Written by Durk Talsma, started January 2005.
6 // Copyright (C) 2004 Durk Talsma.
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.
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.
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.
29 //#include <algorithm>
31 #include <simgear/compiler.h>
33 //#include <plib/sg.h>
34 //#include <plib/ul.h>
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>
46 #include "runwayprefs.hxx"
48 /******************************************************************************
50 ***************e*************************************************************/
51 void ScheduleTime::clear()
55 scheduleNames.clear();
59 ScheduleTime::ScheduleTime(const ScheduleTime &other)
62 timeVecConstIterator i;
63 for (i = other.start.begin(); i != other.start.end(); i++)
65 for (i = other.end.begin(); i != other.end.end(); i++)
67 stringVecConstIterator k;
68 for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
69 scheduleNames.push_back(*k);
72 //stringVec scheduleNames;
73 tailWind = other.tailWind;
74 crssWind = other.tailWind;
78 ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
82 timeVecConstIterator i;
83 for (i = other.start.begin(); i != other.start.end(); i++)
85 for (i = other.end.begin(); i != other.end.end(); i++)
87 stringVecConstIterator k;
88 for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
89 scheduleNames.push_back(*k);
92 //stringVec scheduleNames;
93 tailWind = other.tailWind;
94 crssWind = other.tailWind;
97 string ScheduleTime::getName(time_t dayStart)
99 if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
101 SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" );
106 int nrItems = start.size();
107 //cerr << "Nr of items to process: " << nrItems << endl;
110 for (unsigned int i = 0; i < start.size(); i++)
113 if ((dayStart >= start[i]) && (dayStart <= end[i]))
114 return scheduleNames[i];
117 //couldn't find one so return 0;
118 //cerr << "Returning 0 " << endl;
122 /******************************************************************************
124 *****************************************************************************/
126 RunwayList::RunwayList(const RunwayList &other)
129 stringVecConstIterator i;
130 for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
131 preferredRunways.push_back(*i);
133 RunwayList& RunwayList::operator= (const RunwayList &other)
136 preferredRunways.clear();
137 stringVecConstIterator i;
138 for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
139 preferredRunways.push_back(*i);
142 void RunwayList::set(const string &tp, const string &lst)
144 //weekday = atoi(timeCopy.substr(0,1).c_str());
145 // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
146 // timeCopy = timeCopy.substr(2,timeCopy.length());
150 while (rwys.find(",") != string::npos)
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;
160 preferredRunways.push_back(rwys);
164 void RunwayList::clear()
167 preferredRunways.clear();
169 /****************************************************************************
171 ***************************************************************************/
173 RunwayGroup::RunwayGroup(const RunwayGroup &other)
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;
183 RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
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;
196 void RunwayGroup::setActive(const string &aptId,
201 stringVec *currentlyActive)
205 int activeRwys = rwyList.size(); // get the number of runways active
207 // bool found = true;
214 int bestMatch = 0, bestChoice = 0;
218 // Now downward iterate across all the possible preferences
219 // starting by the least preferred choice working toward the most preferred choice
221 nrOfPreferences = rwyList[0].getRwyList()->size();
222 bool validSelection = true;
223 bool foundValidSelection = false;
224 for (int i = nrOfPreferences-1; i >= 0; i--)
229 // Test each runway listed in the preference to see if it's possible to use
230 // If one runway of the selection isn't allowed, we need to exclude this
231 // preference, however, we don't want to stop right there, because we also
232 // don't want to randomly swap runway preferences, unless there is a need to.
235 for (int j = 0; j < activeRwys; j++)
237 validSelection = true;
238 name = rwyList[j].getRwyList(i);
239 //cerr << "Name of Runway: " << name << endl;
240 if (globals->get_runways()->search( aptId,
244 //cerr << "Succes" << endl;
245 hdgDiff = fabs(windHeading - rwy._heading);
246 //cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
247 //cerr << "Wind Speed : " << windSpeed << endl;
249 hdgDiff = 360 - hdgDiff;
250 //cerr << "Heading diff: " << hdgDiff << endl;
251 hdgDiff *= ((2*M_PI)/360.0); // convert to radians
252 crossWind = windSpeed * sin(hdgDiff);
253 tailWind = -windSpeed * cos(hdgDiff);
254 //cerr << "Tailwind : " << tailWind << endl;
255 //cerr << "Crosswnd : " << crossWind << endl;
256 if ((tailWind > maxTail) || (crossWind > maxCross))
258 //cerr << "Invalid : ";
259 validSelection = false;
263 //cerr << "Valid : ";
266 SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId );
272 //cerr << "Valid : ";
273 foundValidSelection = true;
274 for (stringVecIterator it = currentlyActive->begin();
275 it != currentlyActive->end(); it++)
279 if (match >= bestMatch) {
285 //cerr << "Preference " << i << " bestMatch " << bestMatch << " choice " << bestChoice << endl;
287 if (foundValidSelection)
289 //cerr << "Valid runay selection : " << bestChoice << endl;
290 nrActive = activeRwys;
294 // If this didn't work, due to heavy winds, try again
295 // but select only one landing and one takeoff runway.
298 for (int i = activeRwys-1; i; i--)
300 if (rwyList[i].getType() == string("landing"))
302 if (rwyList[i].getType() == string("takeoff"))
305 //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
306 nrOfPreferences = rwyList[0].getRwyList()->size();
307 for (int i = 0; i < nrOfPreferences; i++)
309 bool validSelection = true;
310 for (int j = 0; j < 2; j++)
312 //cerr << "I J " << i << " " << j << endl;
313 name = rwyList[choice[j]].getRwyList(i);
314 //cerr << "Name of Runway: " << name << endl;
315 if (globals->get_runways()->search( aptId,
319 //cerr << "Succes" << endl;
320 hdgDiff = fabs(windHeading - rwy._heading);
322 hdgDiff = 360 - hdgDiff;
323 hdgDiff *= ((2*M_PI)/360.0); // convert to radians
324 crossWind = windSpeed * sin(hdgDiff);
325 tailWind = -windSpeed * cos(hdgDiff);
326 if ((tailWind > maxTail) || (crossWind > maxCross))
327 validSelection = false;
329 SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId );
336 //cerr << "Valid runay selection : " << i << endl;
347 void RunwayGroup::getActive(int i, string &name, string &type)
353 if (nrActive == (int)rwyList.size())
355 name = rwyList[i].getRwyList(active);
356 type = rwyList[i].getType();
360 name = rwyList[choice[i]].getRwyList(active);
361 type = rwyList[choice[i]].getType();
364 /*****************************************************************************
365 * FGRunway preference
366 ****************************************************************************/
367 FGRunwayPreference::FGRunwayPreference()
369 //cerr << "Running default Constructor" << endl;
373 FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
375 initialized = other.initialized;
377 scheduleName = other.scheduleName;
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;
384 rwyList = other.rwyList;
385 rwyGroup = other.rwyGroup;
386 PreferenceListConstIterator i;
387 for (i = other.preferences.begin(); i != other.preferences.end(); i++)
388 preferences.push_back(*i);
391 FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
393 initialized = other.initialized;
395 scheduleName = other.scheduleName;
397 comTimes = other.comTimes; // Commercial Traffic;
398 genTimes = other.genTimes; // General Aviation;
399 milTimes = other.milTimes; // Military Traffic;
400 currTimes= other.currTimes; // Needed for parsing;
402 rwyList = other.rwyList;
403 rwyGroup = other.rwyGroup;
404 PreferenceListConstIterator i;
406 for (i = other.preferences.begin(); i != other.preferences.end(); i++)
407 preferences.push_back(*i);
411 ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
413 if (!(strcmp(trafficType, "com"))) {
416 if (!(strcmp(trafficType, "gen"))) {
419 if (!(strcmp(trafficType, "mil"))) {
425 RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
427 PreferenceListIterator i = preferences.begin();
428 if (preferences.begin() == preferences.end())
430 while (!(i == preferences.end() || i->getName() == groupName))
432 if (i != preferences.end())
438 void FGRunwayPreference::startXML () {
439 // cout << "Start XML" << endl;
442 void FGRunwayPreference::endXML () {
443 cout << "End XML" << endl;
446 void FGRunwayPreference::startElement (const char * name, const XMLAttributes &atts) {
447 //cout << "StartElement " << name << endl;
449 if (!(strcmp(name, "wind"))) {
450 //cerr << "Will be processing Wind" << endl;
451 for (int i = 0; i < atts.size(); i++)
453 //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
454 //attname = atts.getName(i);
455 if (atts.getName(i) == string("tail")) {
456 //cerr << "Tail Wind = " << atts.getValue(i) << endl;
457 currTimes.setTailWind(atof(atts.getValue(i)));
459 if (atts.getName(i) == string("cross")) {
460 //cerr << "Cross Wind = " << atts.getValue(i) << endl;
461 currTimes.setCrossWind(atof(atts.getValue(i)));
465 if (!(strcmp(name, "time"))) {
466 //cerr << "Will be processing time" << endl;
467 for (int i = 0; i < atts.size(); i++)
469 if (atts.getName(i) == string("start")) {
470 //cerr << "Start Time = " << atts.getValue(i) << endl;
471 currTimes.addStartTime(processTime(atts.getValue(i)));
473 if (atts.getName(i) == string("end")) {
474 //cerr << "End time = " << atts.getValue(i) << endl;
475 currTimes.addEndTime(processTime(atts.getValue(i)));
477 if (atts.getName(i) == string("schedule")) {
478 //cerr << "Schedule Name = " << atts.getValue(i) << endl;
479 currTimes.addScheduleName(atts.getValue(i));
483 if (!(strcmp(name, "takeoff"))) {
486 if (!(strcmp(name, "landing")))
490 if (!(strcmp(name, "schedule"))) {
491 for (int i = 0; i < atts.size(); i++)
493 //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
494 //attname = atts.getName(i);
495 if (atts.getName(i) == string("name")) {
496 //cerr << "Schedule name = " << atts.getValue(i) << endl;
497 scheduleName = atts.getValue(i);
503 //based on a string containing hour and minute, return nr seconds since day start.
504 time_t FGRunwayPreference::processTime(const string &tme)
506 string hour = tme.substr(0, tme.find(":",0));
507 string minute = tme.substr(tme.find(":",0)+1, tme.length());
509 //cerr << "hour = " << hour << " Minute = " << minute << endl;
510 return (atoi(hour.c_str()) * 3600 + atoi(minute.c_str()) * 60);
513 void FGRunwayPreference::endElement (const char * name) {
514 //cout << "End element " << name << endl;
515 if (!(strcmp(name, "rwyuse"))) {
518 if (!(strcmp(name, "com"))) { // Commercial Traffic
519 //cerr << "Setting time table for commerical traffic" << endl;
520 comTimes = currTimes;
523 if (!(strcmp(name, "gen"))) { // General Aviation
524 //cerr << "Setting time table for general aviation" << endl;
525 genTimes = currTimes;
528 if (!(strcmp(name, "mil"))) { // Military Traffic
529 //cerr << "Setting time table for military traffic" << endl;
530 genTimes = currTimes;
534 if (!(strcmp(name, "takeoff"))) {
535 //cerr << "Adding takeoff: " << value << endl;
536 rwyList.set(name, value);
537 rwyGroup.add(rwyList);
539 if (!(strcmp(name, "landing"))) {
540 //cerr << "Adding landing: " << value << endl;
541 rwyList.set(name, value);
542 rwyGroup.add(rwyList);
544 if (!(strcmp(name, "schedule"))) {
545 //cerr << "Adding schedule" << scheduleName << endl;
546 rwyGroup.setName(scheduleName);
547 //rwyGroup.addRunways(rwyList);
548 preferences.push_back(rwyGroup);
554 void FGRunwayPreference::data (const char * s, int len) {
555 string token = string(s,len);
556 //cout << "Character data " << string(s,len) << endl;
557 //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
560 // value = string("");
564 void FGRunwayPreference::pi (const char * target, const char * data) {
565 //cout << "Processing instruction " << target << ' ' << data << endl;
568 void FGRunwayPreference::warning (const char * message, int line, int column) {
569 cout << "Warning: " << message << " (" << line << ',' << column << ')'
573 void FGRunwayPreference::error (const char * message, int line, int column) {
574 cout << "Error: " << message << " (" << line << ',' << column << ')'