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.
31 #include <simgear/compiler.h>
33 #include <simgear/debug/logstream.hxx>
34 #include <Main/globals.hxx>
35 #include <Airports/runways.hxx>
37 #include "runwayprefs.hxx"
40 /******************************************************************************
42 ***************e*************************************************************/
43 void ScheduleTime::clear()
47 scheduleNames.clear();
51 ScheduleTime::ScheduleTime(const ScheduleTime &other)
54 timeVecConstIterator i;
55 for (i = other.start.begin(); i != other.start.end(); i++)
57 for (i = other.end.begin(); i != other.end.end(); i++)
59 stringVecConstIterator k;
60 for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
61 scheduleNames.push_back(*k);
64 //stringVec scheduleNames;
65 tailWind = other.tailWind;
66 crssWind = other.tailWind;
70 ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
74 timeVecConstIterator i;
75 for (i = other.start.begin(); i != other.start.end(); i++)
77 for (i = other.end.begin(); i != other.end.end(); i++)
79 stringVecConstIterator k;
80 for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
81 scheduleNames.push_back(*k);
84 //stringVec scheduleNames;
85 tailWind = other.tailWind;
86 crssWind = other.tailWind;
89 string ScheduleTime::getName(time_t dayStart)
91 if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
93 SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" );
98 int nrItems = start.size();
99 //cerr << "Nr of items to process: " << nrItems << endl;
102 for (unsigned int i = 0; i < start.size(); i++)
105 if ((dayStart >= start[i]) && (dayStart <= end[i]))
106 return scheduleNames[i];
109 //couldn't find one so return 0;
110 //cerr << "Returning 0 " << endl;
114 /******************************************************************************
116 *****************************************************************************/
118 RunwayList::RunwayList(const RunwayList &other)
121 stringVecConstIterator i;
122 for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
123 preferredRunways.push_back(*i);
125 RunwayList& RunwayList::operator= (const RunwayList &other)
128 preferredRunways.clear();
129 stringVecConstIterator i;
130 for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
131 preferredRunways.push_back(*i);
134 void RunwayList::set(const string &tp, const string &lst)
136 //weekday = atoi(timeCopy.substr(0,1).c_str());
137 // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
138 // timeCopy = timeCopy.substr(2,timeCopy.length());
142 while (rwys.find(",") != string::npos)
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;
152 preferredRunways.push_back(rwys);
156 void RunwayList::clear()
159 preferredRunways.clear();
161 /****************************************************************************
163 ***************************************************************************/
165 RunwayGroup::RunwayGroup(const RunwayGroup &other)
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;
175 RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
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;
188 void RunwayGroup::setActive(const FGAirport* airport,
193 stringVec *currentlyActive)
197 int activeRwys = rwyList.size(); // get the number of runways active
199 // bool found = true;
206 int bestMatch = 0, bestChoice = 0;
210 // Now downward iterate across all the possible preferences
211 // starting by the least preferred choice working toward the most preferred choice
213 nrOfPreferences = rwyList[0].getRwyList()->size();
214 bool validSelection = true;
215 bool foundValidSelection = false;
216 for (int i = nrOfPreferences-1; i >= 0; i--)
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.
226 validSelection = true;
227 for (int j = 0; j < activeRwys; j++)
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());
235 rwy = airport->getRunwayByIdent(ident);
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;
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))
251 //cerr << ". [Invalid] " << endl;
252 validSelection = false;
256 //cerr << ". [Valid] ";
259 } // of active runways iteration
263 //cerr << "Valid selection : " << i << endl;;
264 foundValidSelection = true;
265 for (stringVecIterator it = currentlyActive->begin();
266 it != currentlyActive->end(); it++)
271 if (match >= bestMatch) {
276 //cerr << "Preference " << i << " bestMatch " << bestMatch << " choice " << bestChoice << endl;
278 if (foundValidSelection)
280 //cerr << "Valid runay selection : " << bestChoice << endl;
281 nrActive = activeRwys;
285 // If this didn't work, due to heavy winds, try again
286 // but select only one landing and one takeoff runway.
289 for (int i = activeRwys-1; i; i--)
291 if (rwyList[i].getType() == string("landing"))
293 if (rwyList[i].getType() == string("takeoff"))
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++)
300 bool validSelection = true;
301 for (int j = 0; j < 2; j++)
303 name = rwyList[choice[j]].getRwyList(i);
304 rwy = airport->getRunwayByIdent(name);
306 //cerr << "Succes" << endl;
307 hdgDiff = fabs(windHeading - rwy->headingDeg());
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;
320 //cerr << "Valid runay selection : " << i << endl;
331 void RunwayGroup::getActive(int i, string &name, string &type)
337 if (nrActive == (int)rwyList.size())
339 name = rwyList[i].getRwyList(active);
340 type = rwyList[i].getType();
344 name = rwyList[choice[i]].getRwyList(active);
345 type = rwyList[choice[i]].getType();
348 /*****************************************************************************
349 * FGRunway preference
350 ****************************************************************************/
351 FGRunwayPreference::FGRunwayPreference(FGAirport* ap) :
354 //cerr << "Running default Constructor" << endl;
358 FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
360 initialized = other.initialized;
362 comTimes = other.comTimes; // Commercial Traffic;
363 genTimes = other.genTimes; // General Aviation;
364 milTimes = other.milTimes; // Military Traffic;
366 PreferenceListConstIterator i;
367 for (i = other.preferences.begin(); i != other.preferences.end(); i++)
368 preferences.push_back(*i);
371 FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
373 initialized = other.initialized;
375 comTimes = other.comTimes; // Commercial Traffic;
376 genTimes = other.genTimes; // General Aviation;
377 milTimes = other.milTimes; // Military Traffic;
379 PreferenceListConstIterator i;
381 for (i = other.preferences.begin(); i != other.preferences.end(); i++)
382 preferences.push_back(*i);
386 ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
388 if (!(strcmp(trafficType, "com"))) {
391 if (!(strcmp(trafficType, "gen"))) {
394 if (!(strcmp(trafficType, "mil"))) {
400 RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
402 PreferenceListIterator i = preferences.begin();
403 if (preferences.begin() == preferences.end())
405 while (!(i == preferences.end() || i->getName() == groupName))
407 if (i != preferences.end())
413 string FGRunwayPreference::getId() {