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