]> git.mxchange.org Git - flightgear.git/blob - src/Airports/runwayprefs.cxx
Merge branch 'next' of gitorious.org:fg/flightgear into next
[flightgear.git] / src / Airports / runwayprefs.cxx
1 // runwayprefs.cxx - class implementations corresponding to runwayprefs.hxx
2 // assignments by the AI code
3 //
4 // Written by Durk Talsma, started January 2005.
5 //
6 // Copyright (C) 2004 Durk Talsma.
7 //
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.
12 //
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.
17 //
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.
21 //
22 // $Id$
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <math.h>
29 #include <cstdlib>
30 #include <cstring>
31
32 #include <simgear/compiler.h>
33
34 #include <simgear/debug/logstream.hxx>
35 #include <Main/globals.hxx>
36 #include <Airports/runways.hxx>
37
38 #include "runwayprefs.hxx"
39 #include "simple.hxx"
40
41 /******************************************************************************
42  * ScheduleTime
43  ***************e*************************************************************/
44 void ScheduleTime::clear()
45 {
46     start.clear();
47     end.clear();
48     scheduleNames.clear();
49 }
50
51
52 ScheduleTime::ScheduleTime(const ScheduleTime & other)
53 {
54     //timeVec   start;
55     timeVecConstIterator i;
56     for (i = other.start.begin(); i != other.start.end(); i++)
57         start.push_back(*i);
58     for (i = other.end.begin(); i != other.end.end(); i++)
59         end.push_back(*i);
60     stringVecConstIterator k;
61     for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
62          k++)
63         scheduleNames.push_back(*k);
64
65     //timeVec   end;
66     //stringVec scheduleNames;
67     tailWind = other.tailWind;
68     crssWind = other.tailWind;
69 }
70
71
72 ScheduleTime & ScheduleTime::operator=(const ScheduleTime & other)
73 {
74     //timeVec   start;
75     clear();
76     timeVecConstIterator i;
77     for (i = other.start.begin(); i != other.start.end(); i++)
78         start.push_back(*i);
79     for (i = other.end.begin(); i != other.end.end(); i++)
80         end.push_back(*i);
81     stringVecConstIterator k;
82     for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
83          k++)
84         scheduleNames.push_back(*k);
85
86     //timeVec   end;
87     //stringVec scheduleNames;
88     tailWind = other.tailWind;
89     crssWind = other.tailWind;
90     return *this;
91 }
92
93 string ScheduleTime::getName(time_t dayStart)
94 {
95     if ((start.size() != end.size())
96         || (start.size() != scheduleNames.size())) {
97         SG_LOG(SG_GENERAL, SG_INFO, "Unable to parse schedule times");
98         exit(1);
99     } else {
100         int nrItems = start.size();
101         //cerr << "Nr of items to process: " << nrItems << endl;
102         if (nrItems > 0) {
103             for (unsigned int i = 0; i < start.size(); i++) {
104                 //cerr << i << endl;
105                 if ((dayStart >= start[i]) && (dayStart <= end[i]))
106                     return scheduleNames[i];
107             }
108         }
109         //couldn't find one so return 0;
110         //cerr << "Returning 0 " << endl;
111     }
112     return string("");
113 }
114
115 /******************************************************************************
116  * RunwayList
117  *****************************************************************************/
118
119 RunwayList::RunwayList(const RunwayList & other)
120 {
121     type = other.type;
122     stringVecConstIterator i;
123     for (i = other.preferredRunways.begin();
124          i != other.preferredRunways.end(); i++)
125         preferredRunways.push_back(*i);
126 }
127
128 RunwayList & RunwayList::operator=(const RunwayList & other)
129 {
130     type = other.type;
131     preferredRunways.clear();
132     stringVecConstIterator i;
133     for (i = other.preferredRunways.begin();
134          i != other.preferredRunways.end(); i++)
135         preferredRunways.push_back(*i);
136     return *this;
137 }
138
139 void RunwayList::set(const string & tp, const string & lst)
140 {
141     //weekday          = atoi(timeCopy.substr(0,1).c_str());
142     //    timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
143     //    timeCopy = timeCopy.substr(2,timeCopy.length());
144     type = tp;
145     string rwys = lst;
146     string rwy;
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;
155     }
156     preferredRunways.push_back(rwys);
157     //exit(1);
158 }
159
160 void RunwayList::clear()
161 {
162     type = "";
163     preferredRunways.clear();
164 }
165
166 /****************************************************************************
167  *
168  ***************************************************************************/
169
170 RunwayGroup::RunwayGroup(const RunwayGroup & other)
171 {
172     name = other.name;
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;
179 }
180
181 RunwayGroup & RunwayGroup::operator=(const RunwayGroup & other)
182 {
183     rwyList.clear();
184     name = other.name;
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;
191     return *this;
192 }
193
194 void RunwayGroup::setActive(const FGAirport * airport,
195                             double windSpeed,
196                             double windHeading,
197                             double maxTail,
198                             double maxCross, stringVec * currentlyActive)
199 {
200
201     FGRunway *rwy;
202     int activeRwys = rwyList.size();    // get the number of runways active
203     int nrOfPreferences;
204     // bool found = true;
205     // double heading;
206     double hdgDiff;
207     double crossWind;
208     double tailWind;
209     string name;
210     //stringVec names;
211     int bestMatch = 0, bestChoice = 0;
212
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
216
217         nrOfPreferences = rwyList[0].getRwyList()->size();
218         bool validSelection = true;
219         bool foundValidSelection = false;
220         for (int i = nrOfPreferences - 1; i >= 0; i--) {
221             int match = 0;
222
223
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. 
228             //
229             validSelection = true;
230             
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 " <<
236                            airport->ident());
237                     continue;
238                 }
239
240                 rwy = airport->getRunwayByIdent(ident);
241
242                 //cerr << "Succes" << endl;
243                 hdgDiff = fabs(windHeading - rwy->headingDeg());
244                 name    = rwy->name();
245
246
247                 if (hdgDiff > 180)
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;
259                 } else {
260                     //cerr << ". [Valid] ";
261                 }
262                 //cerr << endl;
263                 for (stringVecIterator it = currentlyActive->begin();
264                      it != currentlyActive->end(); it++) {
265                     //cerr << "Checking : \"" << (*it) << "\". vs \"" << name << "\"" << endl;
266                     if ((*it) == name) {
267                         match++;
268                     }
269                 }
270             }                   // of active runways iteration
271
272             if (validSelection) {
273                 //cerr << "Valid selection  : " << i << endl;;
274                 foundValidSelection = true;
275                 if (match >= bestMatch) {
276                     bestMatch = match;
277                     bestChoice = i;
278                 }
279             }
280             //cerr << "Preference " << i << "Match " << match << " bestMatch " << bestMatch << " choice " << bestChoice << " valid selection " << validSelection << endl;
281         }
282         if (foundValidSelection) {
283             //cerr << "Valid runay selection : " << bestChoice << endl;
284             nrActive = activeRwys;
285             active = bestChoice;
286             return;
287         }
288         // If this didn't work, due to heavy winds, try again
289         // but select only one landing and one takeoff runway. 
290         choice[0] = 0;
291         choice[1] = 0;
292         for (int i = activeRwys - 1; i; i--) {
293             if (rwyList[i].getType() == string("landing"))
294                 choice[0] = i;
295             if (rwyList[i].getType() == string("takeoff"))
296                 choice[1] = i;
297         }
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);
305
306                 //cerr << "Succes" << endl;
307                 hdgDiff = fabs(windHeading - rwy->headingDeg());
308                 if (hdgDiff > 180)
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;
315
316
317             }
318             if (validSelection) {
319                 //cerr << "Valid runay selection : " << i << endl;
320                 active = i;
321                 nrActive = 2;
322                 return;
323             }
324         }
325     }
326     active = -1;
327     nrActive = 0;
328 }
329
330 void RunwayGroup::getActive(int i, string & name, string & type)
331 {
332     if (i == -1) {
333         return;
334     }
335     if (nrActive == (int) rwyList.size()) {
336         name = rwyList[i].getRwyList(active);
337         type = rwyList[i].getType();
338     } else {
339         name = rwyList[choice[i]].getRwyList(active);
340         type = rwyList[choice[i]].getType();
341     }
342 }
343
344 /*****************************************************************************
345  * FGRunway preference
346  ****************************************************************************/
347 FGRunwayPreference::FGRunwayPreference(FGAirport * ap):
348 _ap(ap)
349 {
350     //cerr << "Running default Constructor" << endl;
351     initialized = false;
352 }
353
354 FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference & other)
355 {
356     initialized = other.initialized;
357
358     comTimes = other.comTimes;  // Commercial Traffic;
359     genTimes = other.genTimes;  // General Aviation;
360     milTimes = other.milTimes;  // Military Traffic;
361
362     PreferenceListConstIterator i;
363     for (i = other.preferences.begin(); i != other.preferences.end(); i++)
364         preferences.push_back(*i);
365 }
366
367 FGRunwayPreference & FGRunwayPreference::operator=(const FGRunwayPreference
368                                                    & other)
369 {
370     initialized = other.initialized;
371
372     comTimes = other.comTimes;  // Commercial Traffic;
373     genTimes = other.genTimes;  // General Aviation;
374     milTimes = other.milTimes;  // Military Traffic;
375
376     PreferenceListConstIterator i;
377     preferences.clear();
378     for (i = other.preferences.begin(); i != other.preferences.end(); i++)
379         preferences.push_back(*i);
380     return *this;
381 }
382
383 ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
384 {
385     if (!(strcmp(trafficType, "com"))) {
386         return &comTimes;
387     }
388     if (!(strcmp(trafficType, "gen"))) {
389         return &genTimes;
390     }
391     if (!(strcmp(trafficType, "mil"))) {
392         return &milTimes;
393     }
394     return 0;
395 }
396
397 RunwayGroup *FGRunwayPreference::getGroup(const string & groupName)
398 {
399     PreferenceListIterator i = preferences.begin();
400     if (preferences.begin() == preferences.end())
401         return 0;
402     while (!(i == preferences.end() || i->getName() == groupName))
403         i++;
404     if (i != preferences.end())
405         return &(*i);
406     else
407         return 0;
408 }
409
410 string FGRunwayPreference::getId()
411 {
412     return _ap->getId();
413 };