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 <boost/foreach.hpp>
34 #include <simgear/compiler.h>
35 #include <simgear/debug/logstream.hxx>
36 #include <simgear/misc/strutils.hxx>
37 #include <simgear/structure/exception.hxx>
39 #include <Main/globals.hxx>
40 #include <Airports/runways.hxx>
42 #include "runwayprefs.hxx"
43 #include "airport.hxx"
45 using namespace simgear;
47 /******************************************************************************
49 ***************e*************************************************************/
50 void ScheduleTime::clear()
54 scheduleNames.clear();
58 ScheduleTime::ScheduleTime(const ScheduleTime & other)
61 timeVecConstIterator i;
62 for (i = other.start.begin(); i != other.start.end(); i++)
64 for (i = other.end.begin(); i != other.end.end(); i++)
66 stringVecConstIterator k;
67 for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
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();
90 scheduleNames.push_back(*k);
93 //stringVec scheduleNames;
94 tailWind = other.tailWind;
95 crssWind = other.tailWind;
99 std::string ScheduleTime::getName(time_t dayStart)
101 if ((start.size() != end.size())
102 || (start.size() != scheduleNames.size())) {
103 SG_LOG(SG_GENERAL, SG_INFO, "Unable to parse schedule times");
104 throw sg_exception("Unable to parse schedule times");
106 int nrItems = start.size();
107 //cerr << "Nr of items to process: " << nrItems << endl;
109 for (unsigned int i = 0; i < start.size(); i++) {
111 if ((dayStart >= start[i]) && (dayStart <= end[i]))
112 return scheduleNames[i];
115 //couldn't find one so return 0;
116 //cerr << "Returning 0 " << endl;
118 return std::string("");
121 /******************************************************************************
123 *****************************************************************************/
125 RunwayList::RunwayList(const RunwayList & other)
128 stringVecConstIterator i;
129 for (i = other.preferredRunways.begin();
130 i != other.preferredRunways.end(); i++)
131 preferredRunways.push_back(*i);
134 RunwayList & RunwayList::operator=(const RunwayList & other)
137 preferredRunways.clear();
138 stringVecConstIterator i;
139 for (i = other.preferredRunways.begin();
140 i != other.preferredRunways.end(); i++)
141 preferredRunways.push_back(*i);
145 void RunwayList::set(const std::string & tp, const std::string & lst)
147 //weekday = atoi(timeCopy.substr(0,1).c_str());
148 // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
149 // timeCopy = timeCopy.substr(2,timeCopy.length());
154 BOOST_FOREACH(std::string s, strutils::split(lst, ",")) {
155 std::string ident = strutils::strip(s);
157 // http://code.google.com/p/flightgear-bugs/issues/detail?id=1137
158 if ((ident.size() < 2) || !isdigit(ident[1])) {
159 SG_LOG(SG_GENERAL, SG_INFO, "RunwayList::set: padding runway ident '" << ident << "'");
163 preferredRunways.push_back(ident);
167 void RunwayList::clear()
170 preferredRunways.clear();
173 /****************************************************************************
175 ***************************************************************************/
177 RunwayGroup::RunwayGroup(const RunwayGroup & other)
180 RunwayListVecConstIterator i;
181 for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
182 rwyList.push_back(*i);
183 choice[0] = other.choice[0];
184 choice[1] = other.choice[1];
185 nrActive = other.nrActive;
188 RunwayGroup & RunwayGroup::operator=(const RunwayGroup & other)
192 RunwayListVecConstIterator i;
193 for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
194 rwyList.push_back(*i);
195 choice[0] = other.choice[0];
196 choice[1] = other.choice[1];
197 nrActive = other.nrActive;
201 void RunwayGroup::setActive(const FGAirport * airport,
205 double maxCross, stringVec * currentlyActive)
209 int activeRwys = rwyList.size(); // get the number of runways active
211 // bool found = true;
218 int bestMatch = 0, bestChoice = 0;
220 if (activeRwys > 0) {
221 // Now downward iterate across all the possible preferences
222 // starting by the least preferred choice working toward the most preferred choice
224 nrOfPreferences = rwyList[0].getRwyList()->size();
225 bool validSelection = true;
226 bool foundValidSelection = false;
227 for (int i = nrOfPreferences - 1; i >= 0; i--) {
231 // Test each runway listed in the preference to see if it's possible to use
232 // If one runway of the selection isn't allowed, we need to exclude this
233 // preference, however, we don't want to stop right there, because we also
234 // don't want to randomly swap runway preferences, unless there is a need to.
236 validSelection = true;
238 for (int j = 0; j < activeRwys; j++) {
239 std::string ident(rwyList[j].getRwyList(i));
240 if (!airport->hasRunwayWithIdent(ident)) {
241 SG_LOG(SG_GENERAL, SG_WARN,
242 "no such runway:" << ident << " at " <<
247 rwy = airport->getRunwayByIdent(ident);
249 //cerr << "Succes" << endl;
250 hdgDiff = fabs(windHeading - rwy->headingDeg());
255 hdgDiff = 360 - hdgDiff;
256 //cerr << "Heading diff: " << hdgDiff << endl;
257 hdgDiff *= ((2 * M_PI) / 360.0); // convert to radians
258 crossWind = windSpeed * sin(hdgDiff);
259 tailWind = -windSpeed * cos(hdgDiff);
260 //cerr << "Runway : " << rwy->name() << ": " << rwy->headingDeg() << endl;
261 //cerr << ". Tailwind : " << tailWind;
262 //cerr << ". Crosswnd : " << crossWind;
263 if ((tailWind > maxTail) || (crossWind > maxCross)) {
264 //cerr << ". [Invalid] " << endl;
265 validSelection = false;
267 //cerr << ". [Valid] ";
270 for (stringVecIterator it = currentlyActive->begin();
271 it != currentlyActive->end(); it++) {
272 //cerr << "Checking : \"" << (*it) << "\". vs \"" << name << "\"" << endl;
277 } // of active runways iteration
279 if (validSelection) {
280 //cerr << "Valid selection : " << i << endl;;
281 foundValidSelection = true;
282 if (match >= bestMatch) {
287 //cerr << "Preference " << i << "Match " << match << " bestMatch " << bestMatch << " choice " << bestChoice << " valid selection " << validSelection << endl;
289 if (foundValidSelection) {
290 //cerr << "Valid runay selection : " << bestChoice << endl;
291 nrActive = activeRwys;
295 // If this didn't work, due to heavy winds, try again
296 // but select only one landing and one takeoff runway.
299 for (int i = activeRwys - 1; i; i--) {
300 if (rwyList[i].getType() == std::string("landing"))
302 if (rwyList[i].getType() == std::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++) {
308 bool validSelection = true;
309 for (int j = 0; j < 2; j++) {
310 name = rwyList[choice[j]].getRwyList(i);
311 rwy = airport->getRunwayByIdent(name);
313 //cerr << "Succes" << endl;
314 hdgDiff = fabs(windHeading - rwy->headingDeg());
316 hdgDiff = 360 - hdgDiff;
317 hdgDiff *= ((2 * M_PI) / 360.0); // convert to radians
318 crossWind = windSpeed * sin(hdgDiff);
319 tailWind = -windSpeed * cos(hdgDiff);
320 if ((tailWind > maxTail) || (crossWind > maxCross))
321 validSelection = false;
325 if (validSelection) {
326 //cerr << "Valid runay selection : " << i << endl;
337 void RunwayGroup::getActive(int i, std::string & name, std::string & type)
342 if (nrActive == (int) rwyList.size()) {
343 name = rwyList[i].getRwyList(active);
344 type = rwyList[i].getType();
346 name = rwyList[choice[i]].getRwyList(active);
347 type = rwyList[choice[i]].getType();
351 /*****************************************************************************
352 * FGRunway preference
353 ****************************************************************************/
354 FGRunwayPreference::FGRunwayPreference(FGAirport * ap):
357 //cerr << "Running default Constructor" << endl;
361 FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference & other)
363 initialized = other.initialized;
365 comTimes = other.comTimes; // Commercial Traffic;
366 genTimes = other.genTimes; // General Aviation;
367 milTimes = other.milTimes; // Military Traffic;
369 PreferenceListConstIterator i;
370 for (i = other.preferences.begin(); i != other.preferences.end(); i++)
371 preferences.push_back(*i);
374 FGRunwayPreference & FGRunwayPreference::operator=(const FGRunwayPreference
377 initialized = other.initialized;
379 comTimes = other.comTimes; // Commercial Traffic;
380 genTimes = other.genTimes; // General Aviation;
381 milTimes = other.milTimes; // Military Traffic;
383 PreferenceListConstIterator i;
385 for (i = other.preferences.begin(); i != other.preferences.end(); i++)
386 preferences.push_back(*i);
390 ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
392 if (!(strcmp(trafficType, "com"))) {
395 if (!(strcmp(trafficType, "gen"))) {
398 if (!(strcmp(trafficType, "mil"))) {
404 RunwayGroup *FGRunwayPreference::getGroup(const std::string & groupName)
406 PreferenceListIterator i = preferences.begin();
407 if (preferences.begin() == preferences.end())
409 while (!(i == preferences.end() || i->getName() == groupName))
411 if (i != preferences.end())
417 std::string FGRunwayPreference::getId()