]> git.mxchange.org Git - flightgear.git/blob - src/Airports/runwayprefs.cxx
Merge branch 'next' into durk-atc
[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 <cstring>
30
31 #include <simgear/compiler.h>
32
33 #include <simgear/debug/logstream.hxx>
34 #include <Main/globals.hxx>
35 #include <Airports/runways.hxx>
36
37 #include "runwayprefs.hxx"
38 #include "simple.hxx"
39
40 /******************************************************************************
41  * ScheduleTime
42  ***************e*************************************************************/
43 void ScheduleTime::clear()
44 {
45     start.clear();
46     end.clear();
47     scheduleNames.clear();
48 }
49
50
51 ScheduleTime::ScheduleTime(const ScheduleTime & other)
52 {
53     //timeVec   start;
54     timeVecConstIterator i;
55     for (i = other.start.begin(); i != other.start.end(); i++)
56         start.push_back(*i);
57     for (i = other.end.begin(); i != other.end.end(); i++)
58         end.push_back(*i);
59     stringVecConstIterator k;
60     for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
61          k++)
62         scheduleNames.push_back(*k);
63
64     //timeVec   end;
65     //stringVec scheduleNames;
66     tailWind = other.tailWind;
67     crssWind = other.tailWind;
68 }
69
70
71 ScheduleTime & ScheduleTime::operator=(const ScheduleTime & other)
72 {
73     //timeVec   start;
74     clear();
75     timeVecConstIterator i;
76     for (i = other.start.begin(); i != other.start.end(); i++)
77         start.push_back(*i);
78     for (i = other.end.begin(); i != other.end.end(); i++)
79         end.push_back(*i);
80     stringVecConstIterator k;
81     for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
82          k++)
83         scheduleNames.push_back(*k);
84
85     //timeVec   end;
86     //stringVec scheduleNames;
87     tailWind = other.tailWind;
88     crssWind = other.tailWind;
89     return *this;
90 }
91
92 string ScheduleTime::getName(time_t dayStart)
93 {
94     if ((start.size() != end.size())
95         || (start.size() != scheduleNames.size())) {
96         SG_LOG(SG_GENERAL, SG_INFO, "Unable to parse schedule times");
97         exit(1);
98     } else {
99         int nrItems = start.size();
100         //cerr << "Nr of items to process: " << nrItems << endl;
101         if (nrItems > 0) {
102             for (unsigned int i = 0; i < start.size(); i++) {
103                 //cerr << i << endl;
104                 if ((dayStart >= start[i]) && (dayStart <= end[i]))
105                     return scheduleNames[i];
106             }
107         }
108         //couldn't find one so return 0;
109         //cerr << "Returning 0 " << endl;
110     }
111     return string("");
112 }
113
114 /******************************************************************************
115  * RunwayList
116  *****************************************************************************/
117
118 RunwayList::RunwayList(const RunwayList & other)
119 {
120     type = other.type;
121     stringVecConstIterator i;
122     for (i = other.preferredRunways.begin();
123          i != other.preferredRunways.end(); i++)
124         preferredRunways.push_back(*i);
125 }
126
127 RunwayList & RunwayList::operator=(const RunwayList & other)
128 {
129     type = other.type;
130     preferredRunways.clear();
131     stringVecConstIterator i;
132     for (i = other.preferredRunways.begin();
133          i != other.preferredRunways.end(); i++)
134         preferredRunways.push_back(*i);
135     return *this;
136 }
137
138 void RunwayList::set(const string & tp, const string & lst)
139 {
140     //weekday          = atoi(timeCopy.substr(0,1).c_str());
141     //    timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
142     //    timeCopy = timeCopy.substr(2,timeCopy.length());
143     type = tp;
144     string rwys = lst;
145     string rwy;
146     while (rwys.find(",") != string::npos) {
147         rwy = rwys.substr(0, rwys.find(",", 0));
148         //cerr << "adding runway [" << rwy << "] to the list " << endl;
149         preferredRunways.push_back(rwy);
150         rwys.erase(0, rwys.find(",", 0) + 1);   // erase until after the first whitspace
151         while (rwys[0] == ' ')
152             rwys.erase(0, 1);   // Erase any leading whitespaces.
153         //cerr << "Remaining runway list " << rwys;
154     }
155     preferredRunways.push_back(rwys);
156     //exit(1);
157 }
158
159 void RunwayList::clear()
160 {
161     type = "";
162     preferredRunways.clear();
163 }
164
165 /****************************************************************************
166  *
167  ***************************************************************************/
168
169 RunwayGroup::RunwayGroup(const RunwayGroup & other)
170 {
171     name = other.name;
172     RunwayListVecConstIterator i;
173     for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
174         rwyList.push_back(*i);
175     choice[0] = other.choice[0];
176     choice[1] = other.choice[1];
177     nrActive = other.nrActive;
178 }
179
180 RunwayGroup & RunwayGroup::operator=(const RunwayGroup & other)
181 {
182     rwyList.clear();
183     name = other.name;
184     RunwayListVecConstIterator i;
185     for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
186         rwyList.push_back(*i);
187     choice[0] = other.choice[0];
188     choice[1] = other.choice[1];
189     nrActive = other.nrActive;
190     return *this;
191 }
192
193 void RunwayGroup::setActive(const FGAirport * airport,
194                             double windSpeed,
195                             double windHeading,
196                             double maxTail,
197                             double maxCross, stringVec * currentlyActive)
198 {
199
200     FGRunway *rwy;
201     int activeRwys = rwyList.size();    // get the number of runways active
202     int nrOfPreferences;
203     // bool found = true;
204     // double heading;
205     double hdgDiff;
206     double crossWind;
207     double tailWind;
208     string name;
209     //stringVec names;
210     int bestMatch = 0, bestChoice = 0;
211
212     if (activeRwys > 0) {
213         // Now downward iterate across all the possible preferences
214         // starting by the least preferred choice working toward the most preferred choice
215
216         nrOfPreferences = rwyList[0].getRwyList()->size();
217         bool validSelection = true;
218         bool foundValidSelection = false;
219         for (int i = nrOfPreferences - 1; i >= 0; i--) {
220             int match = 0;
221
222
223             // Test each runway listed in the preference to see if it's possible to use
224             // If one runway of the selection isn't allowed, we need to exclude this
225             // preference, however, we don't want to stop right there, because we also
226             // don't want to randomly swap runway preferences, unless there is a need to. 
227             //
228             validSelection = true;
229             
230             for (int j = 0; j < activeRwys; j++) {
231                 string ident(rwyList[j].getRwyList(i));
232                 if (!airport->hasRunwayWithIdent(ident)) {
233                     SG_LOG(SG_GENERAL, SG_WARN,
234                            "no such runway:" << ident << " at " <<
235                            airport->ident());
236                     continue;
237                 }
238
239                 rwy = airport->getRunwayByIdent(ident);
240
241                 //cerr << "Succes" << endl;
242                 hdgDiff = fabs(windHeading - rwy->headingDeg());
243                 name    = rwy->name();
244
245
246                 if (hdgDiff > 180)
247                     hdgDiff = 360 - hdgDiff;
248                 //cerr << "Heading diff: " << hdgDiff << endl;
249                 hdgDiff *= ((2 * M_PI) / 360.0);        // convert to radians
250                 crossWind = windSpeed * sin(hdgDiff);
251                 tailWind = -windSpeed * cos(hdgDiff);
252                 //cerr << "Runway : " << rwy->name() << ": " << rwy->headingDeg() << endl;
253                 //cerr << ". Tailwind : " << tailWind;
254                 //cerr << ". Crosswnd : " << crossWind;
255                 if ((tailWind > maxTail) || (crossWind > maxCross)) {
256                     //cerr << ". [Invalid] " << endl;
257                     validSelection = false;
258                 } else {
259                     //cerr << ". [Valid] ";
260                 }
261                 //cerr << endl;
262                 for (stringVecIterator it = currentlyActive->begin();
263                      it != currentlyActive->end(); it++) {
264                     //cerr << "Checking : \"" << (*it) << "\". vs \"" << name << "\"" << endl;
265                     if ((*it) == name) {
266                         match++;
267                     }
268                 }
269             }                   // of active runways iteration
270
271             if (validSelection) {
272                 //cerr << "Valid selection  : " << i << endl;;
273                 foundValidSelection = true;
274                 if (match >= bestMatch) {
275                     bestMatch = match;
276                     bestChoice = i;
277                 }
278             }
279             //cerr << "Preference " << i << "Match " << match << " bestMatch " << bestMatch << " choice " << bestChoice << " valid selection " << validSelection << endl;
280         }
281         if (foundValidSelection) {
282             //cerr << "Valid runay selection : " << bestChoice << endl;
283             nrActive = activeRwys;
284             active = bestChoice;
285             return;
286         }
287         // If this didn't work, due to heavy winds, try again
288         // but select only one landing and one takeoff runway. 
289         choice[0] = 0;
290         choice[1] = 0;
291         for (int i = activeRwys - 1; i; i--) {
292             if (rwyList[i].getType() == string("landing"))
293                 choice[0] = i;
294             if (rwyList[i].getType() == string("takeoff"))
295                 choice[1] = i;
296         }
297         //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
298         nrOfPreferences = rwyList[0].getRwyList()->size();
299         for (int i = 0; i < nrOfPreferences; i++) {
300             bool validSelection = true;
301             for (int j = 0; j < 2; j++) {
302                 name = rwyList[choice[j]].getRwyList(i);
303                 rwy = airport->getRunwayByIdent(name);
304
305                 //cerr << "Succes" << endl;
306                 hdgDiff = fabs(windHeading - rwy->headingDeg());
307                 if (hdgDiff > 180)
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;
314
315
316             }
317             if (validSelection) {
318                 //cerr << "Valid runay selection : " << i << endl;
319                 active = i;
320                 nrActive = 2;
321                 return;
322             }
323         }
324     }
325     active = -1;
326     nrActive = 0;
327 }
328
329 void RunwayGroup::getActive(int i, string & name, string & type)
330 {
331     if (i == -1) {
332         return;
333     }
334     if (nrActive == (int) rwyList.size()) {
335         name = rwyList[i].getRwyList(active);
336         type = rwyList[i].getType();
337     } else {
338         name = rwyList[choice[i]].getRwyList(active);
339         type = rwyList[choice[i]].getType();
340     }
341 }
342
343 /*****************************************************************************
344  * FGRunway preference
345  ****************************************************************************/
346 FGRunwayPreference::FGRunwayPreference(FGAirport * ap):
347 _ap(ap)
348 {
349     //cerr << "Running default Constructor" << endl;
350     initialized = false;
351 }
352
353 FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference & other)
354 {
355     initialized = other.initialized;
356
357     comTimes = other.comTimes;  // Commercial Traffic;
358     genTimes = other.genTimes;  // General Aviation;
359     milTimes = other.milTimes;  // Military Traffic;
360
361     PreferenceListConstIterator i;
362     for (i = other.preferences.begin(); i != other.preferences.end(); i++)
363         preferences.push_back(*i);
364 }
365
366 FGRunwayPreference & FGRunwayPreference::operator=(const FGRunwayPreference
367                                                    & other)
368 {
369     initialized = other.initialized;
370
371     comTimes = other.comTimes;  // Commercial Traffic;
372     genTimes = other.genTimes;  // General Aviation;
373     milTimes = other.milTimes;  // Military Traffic;
374
375     PreferenceListConstIterator i;
376     preferences.clear();
377     for (i = other.preferences.begin(); i != other.preferences.end(); i++)
378         preferences.push_back(*i);
379     return *this;
380 }
381
382 ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
383 {
384     if (!(strcmp(trafficType, "com"))) {
385         return &comTimes;
386     }
387     if (!(strcmp(trafficType, "gen"))) {
388         return &genTimes;
389     }
390     if (!(strcmp(trafficType, "mil"))) {
391         return &milTimes;
392     }
393     return 0;
394 }
395
396 RunwayGroup *FGRunwayPreference::getGroup(const string & groupName)
397 {
398     PreferenceListIterator i = preferences.begin();
399     if (preferences.begin() == preferences.end())
400         return 0;
401     while (!(i == preferences.end() || i->getName() == groupName))
402         i++;
403     if (i != preferences.end())
404         return &(*i);
405     else
406         return 0;
407 }
408
409 string FGRunwayPreference::getId()
410 {
411     return _ap->getId();
412 };