]> git.mxchange.org Git - flightgear.git/blob - src/Airports/runwayprefs.cxx
apt.dat parser: clearer log and exception messages
[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 <cmath>
29 #include <cstdlib>
30 #include <cstring>
31
32 #include <boost/foreach.hpp>
33
34 #include <simgear/compiler.h>
35 #include <simgear/debug/logstream.hxx>
36 #include <simgear/misc/strutils.hxx>
37 #include <simgear/structure/exception.hxx>
38
39 #include <Main/globals.hxx>
40 #include <Airports/runways.hxx>
41
42 #include "runwayprefs.hxx"
43 #include "airport.hxx"
44
45 using namespace simgear;
46
47 /******************************************************************************
48  * ScheduleTime
49  ***************e*************************************************************/
50 void ScheduleTime::clear()
51 {
52     start.clear();
53     end.clear();
54     scheduleNames.clear();
55 }
56
57
58 ScheduleTime::ScheduleTime(const ScheduleTime & other)
59 {
60     //timeVec   start;
61     timeVecConstIterator i;
62     for (i = other.start.begin(); i != other.start.end(); i++)
63         start.push_back(*i);
64     for (i = other.end.begin(); i != other.end.end(); i++)
65         end.push_back(*i);
66     stringVecConstIterator k;
67     for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
68          k++)
69         scheduleNames.push_back(*k);
70
71     //timeVec   end;
72     //stringVec scheduleNames;
73     tailWind = other.tailWind;
74     crssWind = other.tailWind;
75 }
76
77
78 ScheduleTime & ScheduleTime::operator=(const ScheduleTime & other)
79 {
80     //timeVec   start;
81     clear();
82     timeVecConstIterator i;
83     for (i = other.start.begin(); i != other.start.end(); i++)
84         start.push_back(*i);
85     for (i = other.end.begin(); i != other.end.end(); i++)
86         end.push_back(*i);
87     stringVecConstIterator k;
88     for (k = other.scheduleNames.begin(); k != other.scheduleNames.end();
89          k++)
90         scheduleNames.push_back(*k);
91
92     //timeVec   end;
93     //stringVec scheduleNames;
94     tailWind = other.tailWind;
95     crssWind = other.tailWind;
96     return *this;
97 }
98
99 std::string ScheduleTime::getName(time_t dayStart)
100 {
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");
105     } else {
106         int nrItems = start.size();
107         //cerr << "Nr of items to process: " << nrItems << endl;
108         if (nrItems > 0) {
109             for (unsigned int i = 0; i < start.size(); i++) {
110                 //cerr << i << endl;
111                 if ((dayStart >= start[i]) && (dayStart <= end[i]))
112                     return scheduleNames[i];
113             }
114         }
115         //couldn't find one so return 0;
116         //cerr << "Returning 0 " << endl;
117     }
118     return std::string("");
119 }
120
121 /******************************************************************************
122  * RunwayList
123  *****************************************************************************/
124
125 RunwayList::RunwayList(const RunwayList & other)
126 {
127     type = other.type;
128     stringVecConstIterator i;
129     for (i = other.preferredRunways.begin();
130          i != other.preferredRunways.end(); i++)
131         preferredRunways.push_back(*i);
132 }
133
134 RunwayList & RunwayList::operator=(const RunwayList & other)
135 {
136     type = other.type;
137     preferredRunways.clear();
138     stringVecConstIterator i;
139     for (i = other.preferredRunways.begin();
140          i != other.preferredRunways.end(); i++)
141         preferredRunways.push_back(*i);
142     return *this;
143 }
144
145 void RunwayList::set(const std::string & tp, const std::string & lst)
146 {
147     //weekday          = atoi(timeCopy.substr(0,1).c_str());
148     //    timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
149     //    timeCopy = timeCopy.substr(2,timeCopy.length());
150     type = tp;
151     
152     
153     
154     BOOST_FOREACH(std::string s, strutils::split(lst, ",")) {
155         std::string ident = strutils::strip(s);
156         
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 << "'");
160             ident = "0" + ident;
161         }
162         
163         preferredRunways.push_back(ident);
164     }
165 }
166
167 void RunwayList::clear()
168 {
169     type = "";
170     preferredRunways.clear();
171 }
172
173 /****************************************************************************
174  *
175  ***************************************************************************/
176
177 RunwayGroup::RunwayGroup(const RunwayGroup & other)
178 {
179     name = other.name;
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;
186 }
187
188 RunwayGroup & RunwayGroup::operator=(const RunwayGroup & other)
189 {
190     rwyList.clear();
191     name = other.name;
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;
198     return *this;
199 }
200
201 void RunwayGroup::setActive(const FGAirport * airport,
202                             double windSpeed,
203                             double windHeading,
204                             double maxTail,
205                             double maxCross, stringVec * currentlyActive)
206 {
207
208     FGRunway *rwy;
209     int activeRwys = rwyList.size();    // get the number of runways active
210     int nrOfPreferences;
211     // bool found = true;
212     // double heading;
213     double hdgDiff;
214     double crossWind;
215     double tailWind;
216     std::string name;
217     //stringVec names;
218     int bestMatch = 0, bestChoice = 0;
219
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
223
224         nrOfPreferences = rwyList[0].getRwyList()->size();
225         bool validSelection = true;
226         bool foundValidSelection = false;
227         for (int i = nrOfPreferences - 1; i >= 0; i--) {
228             int match = 0;
229
230
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. 
235             //
236             validSelection = true;
237             
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 " <<
243                            airport->ident());
244                     continue;
245                 }
246
247                 rwy = airport->getRunwayByIdent(ident);
248
249                 //cerr << "Succes" << endl;
250                 hdgDiff = fabs(windHeading - rwy->headingDeg());
251                 name    = rwy->name();
252
253
254                 if (hdgDiff > 180)
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;
266                 } else {
267                     //cerr << ". [Valid] ";
268                 }
269                 //cerr << endl;
270                 for (stringVecIterator it = currentlyActive->begin();
271                      it != currentlyActive->end(); it++) {
272                     //cerr << "Checking : \"" << (*it) << "\". vs \"" << name << "\"" << endl;
273                     if ((*it) == name) {
274                         match++;
275                     }
276                 }
277             }                   // of active runways iteration
278
279             if (validSelection) {
280                 //cerr << "Valid selection  : " << i << endl;;
281                 foundValidSelection = true;
282                 if (match >= bestMatch) {
283                     bestMatch = match;
284                     bestChoice = i;
285                 }
286             }
287             //cerr << "Preference " << i << "Match " << match << " bestMatch " << bestMatch << " choice " << bestChoice << " valid selection " << validSelection << endl;
288         }
289         if (foundValidSelection) {
290             //cerr << "Valid runay selection : " << bestChoice << endl;
291             nrActive = activeRwys;
292             active = bestChoice;
293             return;
294         }
295         // If this didn't work, due to heavy winds, try again
296         // but select only one landing and one takeoff runway. 
297         choice[0] = 0;
298         choice[1] = 0;
299         for (int i = activeRwys - 1; i; i--) {
300             if (rwyList[i].getType() == std::string("landing"))
301                 choice[0] = i;
302             if (rwyList[i].getType() == std::string("takeoff"))
303                 choice[1] = i;
304         }
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);
312
313                 //cerr << "Succes" << endl;
314                 hdgDiff = fabs(windHeading - rwy->headingDeg());
315                 if (hdgDiff > 180)
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;
322
323
324             }
325             if (validSelection) {
326                 //cerr << "Valid runay selection : " << i << endl;
327                 active = i;
328                 nrActive = 2;
329                 return;
330             }
331         }
332     }
333     active = -1;
334     nrActive = 0;
335 }
336
337 void RunwayGroup::getActive(int i, std::string & name, std::string & type)
338 {
339     if (i == -1) {
340         return;
341     }
342     if (nrActive == (int) rwyList.size()) {
343         name = rwyList[i].getRwyList(active);
344         type = rwyList[i].getType();
345     } else {
346         name = rwyList[choice[i]].getRwyList(active);
347         type = rwyList[choice[i]].getType();
348     }
349 }
350
351 /*****************************************************************************
352  * FGRunway preference
353  ****************************************************************************/
354 FGRunwayPreference::FGRunwayPreference(FGAirport * ap):
355 _ap(ap)
356 {
357     //cerr << "Running default Constructor" << endl;
358     initialized = false;
359 }
360
361 FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference & other)
362 {
363     initialized = other.initialized;
364
365     comTimes = other.comTimes;  // Commercial Traffic;
366     genTimes = other.genTimes;  // General Aviation;
367     milTimes = other.milTimes;  // Military Traffic;
368
369     PreferenceListConstIterator i;
370     for (i = other.preferences.begin(); i != other.preferences.end(); i++)
371         preferences.push_back(*i);
372 }
373
374 FGRunwayPreference & FGRunwayPreference::operator=(const FGRunwayPreference
375                                                    & other)
376 {
377     initialized = other.initialized;
378
379     comTimes = other.comTimes;  // Commercial Traffic;
380     genTimes = other.genTimes;  // General Aviation;
381     milTimes = other.milTimes;  // Military Traffic;
382
383     PreferenceListConstIterator i;
384     preferences.clear();
385     for (i = other.preferences.begin(); i != other.preferences.end(); i++)
386         preferences.push_back(*i);
387     return *this;
388 }
389
390 ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
391 {
392     if (!(strcmp(trafficType, "com"))) {
393         return &comTimes;
394     }
395     if (!(strcmp(trafficType, "gen"))) {
396         return &genTimes;
397     }
398     if (!(strcmp(trafficType, "mil"))) {
399         return &milTimes;
400     }
401     return 0;
402 }
403
404 RunwayGroup *FGRunwayPreference::getGroup(const std::string & groupName)
405 {
406     PreferenceListIterator i = preferences.begin();
407     if (preferences.begin() == preferences.end())
408         return 0;
409     while (!(i == preferences.end() || i->getName() == groupName))
410         i++;
411     if (i != preferences.end())
412         return &(*i);
413     else
414         return 0;
415 }
416
417 std::string FGRunwayPreference::getId()
418 {
419     return _ap->getId();
420 };