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.
32 #include <simgear/compiler.h>
34 #include <simgear/debug/logstream.hxx>
35 #include <Main/globals.hxx>
36 #include <Airports/runways.hxx>
38 #include "runwayprefs.hxx"
39 #include "airport.hxx"
41 /******************************************************************************
43 ***************e*************************************************************/
44 void ScheduleTime::clear()
48 scheduleNames.clear();
52 ScheduleTime::ScheduleTime(const ScheduleTime & other)
55 timeVecConstIterator i;
56 for (i = other.start.begin(); i != other.start.end(); i++)
58 for (i = other.end.begin(); i != other.end.end(); i++)
60 stringVecConstIterator k;
61 for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
63 scheduleNames.push_back(*k);
66 //stringVec scheduleNames;
67 tailWind = other.tailWind;
68 crssWind = other.tailWind;
72 ScheduleTime & ScheduleTime::operator=(const ScheduleTime & other)
76 timeVecConstIterator i;
77 for (i = other.start.begin(); i != other.start.end(); i++)
79 for (i = other.end.begin(); i != other.end.end(); i++)
81 stringVecConstIterator k;
82 for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
84 scheduleNames.push_back(*k);
87 //stringVec scheduleNames;
88 tailWind = other.tailWind;
89 crssWind = other.tailWind;
93 string ScheduleTime::getName(time_t dayStart)
95 if ((start.size() != end.size())
96 || (start.size() != scheduleNames.size())) {
97 SG_LOG(SG_GENERAL, SG_INFO, "Unable to parse schedule times");
100 int nrItems = start.size();
101 //cerr << "Nr of items to process: " << nrItems << endl;
103 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;
115 /******************************************************************************
117 *****************************************************************************/
119 RunwayList::RunwayList(const RunwayList & other)
122 stringVecConstIterator i;
123 for (i = other.preferredRunways.begin();
124 i != other.preferredRunways.end(); i++)
125 preferredRunways.push_back(*i);
128 RunwayList & RunwayList::operator=(const RunwayList & other)
131 preferredRunways.clear();
132 stringVecConstIterator i;
133 for (i = other.preferredRunways.begin();
134 i != other.preferredRunways.end(); i++)
135 preferredRunways.push_back(*i);
139 void RunwayList::set(const string & tp, const string & lst)
141 //weekday = atoi(timeCopy.substr(0,1).c_str());
142 // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
143 // timeCopy = timeCopy.substr(2,timeCopy.length());
147 while (rwys.find(",") != string::npos) {
148 rwy = rwys.substr(0, rwys.find(",", 0));
149 //cerr << "adding runway [" << rwy << "] to the list " << endl;
150 preferredRunways.push_back(rwy);
151 rwys.erase(0, rwys.find(",", 0) + 1); // erase until after the first whitspace
152 while (rwys[0] == ' ')
153 rwys.erase(0, 1); // Erase any leading whitespaces.
154 //cerr << "Remaining runway list " << rwys;
156 preferredRunways.push_back(rwys);
160 void RunwayList::clear()
163 preferredRunways.clear();
166 /****************************************************************************
168 ***************************************************************************/
170 RunwayGroup::RunwayGroup(const RunwayGroup & other)
173 RunwayListVecConstIterator i;
174 for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
175 rwyList.push_back(*i);
176 choice[0] = other.choice[0];
177 choice[1] = other.choice[1];
178 nrActive = other.nrActive;
181 RunwayGroup & RunwayGroup::operator=(const RunwayGroup & other)
185 RunwayListVecConstIterator i;
186 for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
187 rwyList.push_back(*i);
188 choice[0] = other.choice[0];
189 choice[1] = other.choice[1];
190 nrActive = other.nrActive;
194 void RunwayGroup::setActive(const FGAirport * airport,
198 double maxCross, stringVec * currentlyActive)
202 int activeRwys = rwyList.size(); // get the number of runways active
204 // bool found = true;
211 int bestMatch = 0, bestChoice = 0;
213 if (activeRwys > 0) {
214 // Now downward iterate across all the possible preferences
215 // starting by the least preferred choice working toward the most preferred choice
217 nrOfPreferences = rwyList[0].getRwyList()->size();
218 bool validSelection = true;
219 bool foundValidSelection = false;
220 for (int i = nrOfPreferences - 1; i >= 0; i--) {
224 // Test each runway listed in the preference to see if it's possible to use
225 // If one runway of the selection isn't allowed, we need to exclude this
226 // preference, however, we don't want to stop right there, because we also
227 // don't want to randomly swap runway preferences, unless there is a need to.
229 validSelection = true;
231 for (int j = 0; j < activeRwys; j++) {
232 string ident(rwyList[j].getRwyList(i));
233 if (!airport->hasRunwayWithIdent(ident)) {
234 SG_LOG(SG_GENERAL, SG_WARN,
235 "no such runway:" << ident << " at " <<
240 rwy = airport->getRunwayByIdent(ident);
242 //cerr << "Succes" << endl;
243 hdgDiff = fabs(windHeading - rwy->headingDeg());
248 hdgDiff = 360 - hdgDiff;
249 //cerr << "Heading diff: " << hdgDiff << endl;
250 hdgDiff *= ((2 * M_PI) / 360.0); // convert to radians
251 crossWind = windSpeed * sin(hdgDiff);
252 tailWind = -windSpeed * cos(hdgDiff);
253 //cerr << "Runway : " << rwy->name() << ": " << rwy->headingDeg() << endl;
254 //cerr << ". Tailwind : " << tailWind;
255 //cerr << ". Crosswnd : " << crossWind;
256 if ((tailWind > maxTail) || (crossWind > maxCross)) {
257 //cerr << ". [Invalid] " << endl;
258 validSelection = false;
260 //cerr << ". [Valid] ";
263 for (stringVecIterator it = currentlyActive->begin();
264 it != currentlyActive->end(); it++) {
265 //cerr << "Checking : \"" << (*it) << "\". vs \"" << name << "\"" << endl;
270 } // of active runways iteration
272 if (validSelection) {
273 //cerr << "Valid selection : " << i << endl;;
274 foundValidSelection = true;
275 if (match >= bestMatch) {
280 //cerr << "Preference " << i << "Match " << match << " bestMatch " << bestMatch << " choice " << bestChoice << " valid selection " << validSelection << endl;
282 if (foundValidSelection) {
283 //cerr << "Valid runay selection : " << bestChoice << endl;
284 nrActive = activeRwys;
288 // If this didn't work, due to heavy winds, try again
289 // but select only one landing and one takeoff runway.
292 for (int i = activeRwys - 1; i; i--) {
293 if (rwyList[i].getType() == string("landing"))
295 if (rwyList[i].getType() == string("takeoff"))
298 //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
299 nrOfPreferences = rwyList[0].getRwyList()->size();
300 for (int i = 0; i < nrOfPreferences; i++) {
301 bool validSelection = true;
302 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;
318 if (validSelection) {
319 //cerr << "Valid runay selection : " << i << endl;
330 void RunwayGroup::getActive(int i, string & name, string & type)
335 if (nrActive == (int) rwyList.size()) {
336 name = rwyList[i].getRwyList(active);
337 type = rwyList[i].getType();
339 name = rwyList[choice[i]].getRwyList(active);
340 type = rwyList[choice[i]].getType();
344 /*****************************************************************************
345 * FGRunway preference
346 ****************************************************************************/
347 FGRunwayPreference::FGRunwayPreference(FGAirport * ap):
350 //cerr << "Running default Constructor" << endl;
354 FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference & other)
356 initialized = other.initialized;
358 comTimes = other.comTimes; // Commercial Traffic;
359 genTimes = other.genTimes; // General Aviation;
360 milTimes = other.milTimes; // Military Traffic;
362 PreferenceListConstIterator i;
363 for (i = other.preferences.begin(); i != other.preferences.end(); i++)
364 preferences.push_back(*i);
367 FGRunwayPreference & FGRunwayPreference::operator=(const FGRunwayPreference
370 initialized = other.initialized;
372 comTimes = other.comTimes; // Commercial Traffic;
373 genTimes = other.genTimes; // General Aviation;
374 milTimes = other.milTimes; // Military Traffic;
376 PreferenceListConstIterator i;
378 for (i = other.preferences.begin(); i != other.preferences.end(); i++)
379 preferences.push_back(*i);
383 ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
385 if (!(strcmp(trafficType, "com"))) {
388 if (!(strcmp(trafficType, "gen"))) {
391 if (!(strcmp(trafficType, "mil"))) {
397 RunwayGroup *FGRunwayPreference::getGroup(const string & groupName)
399 PreferenceListIterator i = preferences.begin();
400 if (preferences.begin() == preferences.end())
402 while (!(i == preferences.end() || i->getName() == groupName))
404 if (i != preferences.end())
410 string FGRunwayPreference::getId()