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.
30 #include <simgear/compiler.h>
32 #include <simgear/debug/logstream.hxx>
33 #include <Main/globals.hxx>
34 #include <Airports/runways.hxx>
36 #include "runwayprefs.hxx"
39 /******************************************************************************
41 ***************e*************************************************************/
42 void ScheduleTime::clear()
46 scheduleNames.clear();
50 ScheduleTime::ScheduleTime(const ScheduleTime &other)
53 timeVecConstIterator i;
54 for (i = other.start.begin(); i != other.start.end(); i++)
56 for (i = other.end.begin(); i != other.end.end(); i++)
58 stringVecConstIterator k;
59 for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
60 scheduleNames.push_back(*k);
63 //stringVec scheduleNames;
64 tailWind = other.tailWind;
65 crssWind = other.tailWind;
69 ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
73 timeVecConstIterator i;
74 for (i = other.start.begin(); i != other.start.end(); i++)
76 for (i = other.end.begin(); i != other.end.end(); i++)
78 stringVecConstIterator k;
79 for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
80 scheduleNames.push_back(*k);
83 //stringVec scheduleNames;
84 tailWind = other.tailWind;
85 crssWind = other.tailWind;
88 string ScheduleTime::getName(time_t dayStart)
90 if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
92 SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" );
97 int nrItems = start.size();
98 //cerr << "Nr of items to process: " << nrItems << endl;
101 for (unsigned int i = 0; i < start.size(); i++)
104 if ((dayStart >= start[i]) && (dayStart <= end[i]))
105 return scheduleNames[i];
108 //couldn't find one so return 0;
109 //cerr << "Returning 0 " << endl;
113 /******************************************************************************
115 *****************************************************************************/
117 RunwayList::RunwayList(const RunwayList &other)
120 stringVecConstIterator i;
121 for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
122 preferredRunways.push_back(*i);
124 RunwayList& RunwayList::operator= (const RunwayList &other)
127 preferredRunways.clear();
128 stringVecConstIterator i;
129 for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
130 preferredRunways.push_back(*i);
133 void RunwayList::set(const string &tp, const string &lst)
135 //weekday = atoi(timeCopy.substr(0,1).c_str());
136 // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
137 // timeCopy = timeCopy.substr(2,timeCopy.length());
141 while (rwys.find(",") != string::npos)
143 rwy = rwys.substr(0, rwys.find(",",0));
144 //cerr << "adding runway [" << rwy << "] to the list " << endl;
145 preferredRunways.push_back(rwy);
146 rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace
147 while (rwys[0] == ' ')
148 rwys.erase(0, 1); // Erase any leading whitespaces.
149 //cerr << "Remaining runway list " << rwys;
151 preferredRunways.push_back(rwys);
155 void RunwayList::clear()
158 preferredRunways.clear();
160 /****************************************************************************
162 ***************************************************************************/
164 RunwayGroup::RunwayGroup(const RunwayGroup &other)
167 RunwayListVecConstIterator i;
168 for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
169 rwyList.push_back(*i);
170 choice[0] = other.choice[0];
171 choice[1] = other.choice[1];
172 nrActive = other.nrActive;
174 RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
178 RunwayListVecConstIterator i;
179 for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
180 rwyList.push_back(*i);
181 choice[0] = other.choice[0];
182 choice[1] = other.choice[1];
183 nrActive = other.nrActive;
187 void RunwayGroup::setActive(const FGAirport* airport,
192 stringVec *currentlyActive)
196 int activeRwys = rwyList.size(); // get the number of runways active
198 // bool found = true;
205 int bestMatch = 0, bestChoice = 0;
209 // Now downward iterate across all the possible preferences
210 // starting by the least preferred choice working toward the most preferred choice
212 nrOfPreferences = rwyList[0].getRwyList()->size();
213 bool validSelection = true;
214 bool foundValidSelection = false;
215 for (int i = nrOfPreferences-1; i >= 0; i--)
220 // Test each runway listed in the preference to see if it's possible to use
221 // If one runway of the selection isn't allowed, we need to exclude this
222 // preference, however, we don't want to stop right there, because we also
223 // don't want to randomly swap runway preferences, unless there is a need to.
225 validSelection = true;
226 for (int j = 0; j < activeRwys; j++)
228 string ident(rwyList[j].getRwyList(i));
229 if (!airport->hasRunwayWithIdent(ident)) {
230 SG_LOG(SG_GENERAL, SG_WARN, "no such runway:" << ident << " at " << airport->ident());
234 rwy = airport->getRunwayByIdent(ident);
236 //cerr << "Succes" << endl;
237 hdgDiff = fabs(windHeading - rwy->headingDeg());
238 //cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
239 //cerr << "Wind Speed : " << windSpeed << endl;
241 hdgDiff = 360 - hdgDiff;
242 //cerr << "Heading diff: " << hdgDiff << endl;
243 hdgDiff *= ((2*M_PI)/360.0); // convert to radians
244 crossWind = windSpeed * sin(hdgDiff);
245 tailWind = -windSpeed * cos(hdgDiff);
246 //cerr << ". Tailwind : " << tailWind;
247 //cerr << ". Crosswnd : " << crossWind;
248 if ((tailWind > maxTail) || (crossWind > maxCross))
250 //cerr << ". [Invalid] " << endl;
251 validSelection = false;
255 //cerr << ". [Valid] ";
258 } // of active runways iteration
262 //cerr << "Valid selection : " << i << endl;;
263 foundValidSelection = true;
264 for (stringVecIterator it = currentlyActive->begin();
265 it != currentlyActive->end(); it++)
270 if (match >= bestMatch) {
275 //cerr << "Preference " << i << " bestMatch " << bestMatch << " choice " << bestChoice << endl;
277 if (foundValidSelection)
279 //cerr << "Valid runay selection : " << bestChoice << endl;
280 nrActive = activeRwys;
284 // If this didn't work, due to heavy winds, try again
285 // but select only one landing and one takeoff runway.
288 for (int i = activeRwys-1; i; i--)
290 if (rwyList[i].getType() == string("landing"))
292 if (rwyList[i].getType() == string("takeoff"))
295 //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
296 nrOfPreferences = rwyList[0].getRwyList()->size();
297 for (int i = 0; i < nrOfPreferences; i++)
299 bool validSelection = true;
300 for (int j = 0; j < 2; j++)
302 name = rwyList[choice[j]].getRwyList(i);
303 rwy = airport->getRunwayByIdent(name);
305 //cerr << "Succes" << endl;
306 hdgDiff = fabs(windHeading - rwy->headingDeg());
308 hdgDiff = 360 - hdgDiff;
309 hdgDiff *= ((2*M_PI)/360.0); // convert to radians
310 crossWind = windSpeed * sin(hdgDiff);
311 tailWind = -windSpeed * cos(hdgDiff);
312 if ((tailWind > maxTail) || (crossWind > maxCross))
313 validSelection = false;
319 //cerr << "Valid runay selection : " << i << endl;
330 void RunwayGroup::getActive(int i, string &name, string &type)
336 if (nrActive == (int)rwyList.size())
338 name = rwyList[i].getRwyList(active);
339 type = rwyList[i].getType();
343 name = rwyList[choice[i]].getRwyList(active);
344 type = rwyList[choice[i]].getType();
347 /*****************************************************************************
348 * FGRunway preference
349 ****************************************************************************/
350 FGRunwayPreference::FGRunwayPreference(FGAirport* ap) :
353 //cerr << "Running default Constructor" << endl;
357 FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
359 initialized = other.initialized;
361 comTimes = other.comTimes; // Commercial Traffic;
362 genTimes = other.genTimes; // General Aviation;
363 milTimes = other.milTimes; // Military Traffic;
365 PreferenceListConstIterator i;
366 for (i = other.preferences.begin(); i != other.preferences.end(); i++)
367 preferences.push_back(*i);
370 FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
372 initialized = other.initialized;
374 comTimes = other.comTimes; // Commercial Traffic;
375 genTimes = other.genTimes; // General Aviation;
376 milTimes = other.milTimes; // Military Traffic;
378 PreferenceListConstIterator i;
380 for (i = other.preferences.begin(); i != other.preferences.end(); i++)
381 preferences.push_back(*i);
385 ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
387 if (!(strcmp(trafficType, "com"))) {
390 if (!(strcmp(trafficType, "gen"))) {
393 if (!(strcmp(trafficType, "mil"))) {
399 RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
401 PreferenceListIterator i = preferences.begin();
402 if (preferences.begin() == preferences.end())
404 while (!(i == preferences.end() || i->getName() == groupName))
406 if (i != preferences.end())
412 string FGRunwayPreference::getId() {