FlightGear next
SchedFlight.cxx
Go to the documentation of this file.
1/******************************************************************************
2 * SchedFlight.cxx
3 * Written by Durk Talsma, started May 5, 2004.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 *
20 **************************************************************************/
21
22/* This a prototype version of a top-level flight plan manager for Flightgear.
23 * It parses the fgtraffic.txt file and determine for a specific time/date,
24 * where each aircraft listed in this file is at the current time.
25 *
26 * I'm currently assuming the following simplifications:
27 * 1) The earth is a perfect sphere
28 * 2) Each aircraft flies a perfect great circle route.
29 * 3) Each aircraft flies at a constant speed (with infinite accelerations and
30 * decelerations)
31 * 4) Each aircraft leaves at exactly the departure time.
32 * 5) Each aircraft arrives at exactly the specified arrival time.
33 *
34 * TODO:
35 * - Check the code for known portability issues
36 *
37 *****************************************************************************/
38
39#ifdef HAVE_CONFIG_H
40# include "config.h"
41#endif
42
43#include <stdlib.h>
44#include <time.h>
45#include <iostream>
46#include <fstream>
47#include <string>
48#include <vector>
49
50#include <simgear/compiler.h>
51#include <simgear/props/props.hxx>
52#include <simgear/structure/subsystem_mgr.hxx>
53#include <simgear/timing/sg_time.hxx>
54#include <simgear/xml/easyxml.hxx>
55
57#include <AIModel/AIManager.hxx>
58#include <Airports/airport.hxx>
59
60#include <Main/globals.hxx>
61
62#include "SchedFlight.hxx"
63
64using std::string;
65
66
67/******************************************************************************
68 * FGScheduledFlight stuff
69 *****************************************************************************/
70
71std::map<std::string, std::string> FGScheduledFlight::missingAirports = std::map<std::string, std::string>();
72
73FGScheduledFlight::FGScheduledFlight() : departurePort{nullptr},
74 arrivalPort{nullptr},
75 departureTime{0},
76 arrivalTime{0},
77 repeatPeriod{0}
78{
79 cruiseAltitude = 0;
80 initialized = false;
81 available = true;
82}
83
84FGScheduledFlight::FGScheduledFlight(const FGScheduledFlight &other) : callsign{other.callsign},
85 fltRules{other.fltRules},
86 departurePort{other.departurePort},
87 arrivalPort{other.arrivalPort},
88 depId{other.depId},
89 arrId{other.arrId},
90 requiredAircraft{other.requiredAircraft},
91 departureTime{other.departureTime},
92 arrivalTime{other.arrivalTime},
93 repeatPeriod{other.repeatPeriod}
94{
95 cruiseAltitude = other.cruiseAltitude;
96 initialized = other.initialized;
97 available = other.available;
98}
99
106
108 const string& fr,
109 const string& depPrt,
110 const string& arrPrt,
111 int cruiseAlt,
112 const string& deptime,
113 const string& arrtime,
114 const string& rep,
115 const string& reqAC) : callsign{cs},
116 fltRules{fr},
117 departurePort{nullptr},
118 arrivalPort{nullptr},
119 depId{depPrt},
120 arrId{arrPrt},
121 requiredAircraft{reqAC}
122{
123 //departurePort.setId(depPrt);
124 //arrivalPort.setId(arrPrt);
125
126 //cerr << "Constructor: departure " << depId << ". arrival " << arrId << endl;
127 //departureTime = processTimeString(deptime);
128 //arrivalTime = processTimeString(arrtime);
129 cruiseAltitude = cruiseAlt;
130
131 // Process the repeat period string
132 if (rep.find("WEEK",0) != string::npos)
133 {
134 repeatPeriod = 7*24*60*60; // in seconds
135 }
136 else if (rep.find("Hr", 0) != string::npos)
137 {
138 repeatPeriod = 60*60*atoi(rep.substr(0,2).c_str());
139 }
140 else
141 {
142 repeatPeriod = 365*24*60*60;
143 SG_LOG( SG_AI, SG_ALERT, "Unknown repeat period in flight plan "
144 "of flight '" << cs << "': " << rep );
145 }
146 if (!repeatPeriod) {
147 SG_LOG( SG_AI, SG_ALERT, "Zero repeat period in flight plan "
148 "of flight '" << cs << "': " << rep );
149 available = false;
150 return;
151 }
152
153
154 // What we still need to do is preprocess the departure and
155 // arrival times.
156 departureTime = processTimeString(deptime);
157 arrivalTime = processTimeString(arrtime);
158 //departureTime += rand() % 300; // Make sure departure times are not limited to 5 minute increments.
159 if (departureTime > arrivalTime)
160 {
161 departureTime -= repeatPeriod;
162 }
163 initialized = false;
164 available = true;
165}
166
167
171
172time_t FGScheduledFlight::processTimeString(const string& theTime)
173{
174 int timeOffsetInDays = 0;
175 int targetHour;
176 int targetMinute;
177 int targetSecond;
178
179 tm targetTimeDate;
180 SGTime* currTimeDate = globals->get_time_params();
181
182 string timeCopy = theTime;
183
184
185 // okay first split theTime string into
186 // weekday, hour, minute, second;
187 // Check if a week day is specified
188 const auto daySeparatorPos = timeCopy.find("/", 0);
189 if (daySeparatorPos != string::npos) {
190 const int weekday = std::stoi(timeCopy.substr(0, daySeparatorPos));
191 timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
192 timeCopy = theTime.substr(daySeparatorPos + 1);
193 }
194
195 const auto timeTokens = simgear::strutils::split(timeCopy, ":");
196 if (timeTokens.size() != 3) {
197 SG_LOG(SG_AI, SG_DEV_WARN, "FGScheduledFlight: Timestring too short. " << theTime << " Defaulted to now");
198 return currTimeDate->get_cur_time();
199 }
200
201
202 targetHour = std::stoi(timeTokens.at(0));
203 targetMinute = std::stoi(timeTokens.at(1));
204 targetSecond = std::stoi(timeTokens.at(2));
205 targetTimeDate.tm_year = currTimeDate->getGmt()->tm_year;
206 targetTimeDate.tm_mon = currTimeDate->getGmt()->tm_mon;
207 targetTimeDate.tm_mday = currTimeDate->getGmt()->tm_mday;
208 targetTimeDate.tm_hour = targetHour;
209 targetTimeDate.tm_min = targetMinute;
210 targetTimeDate.tm_sec = targetSecond;
211
212 time_t processedTime = sgTimeGetGMT(&targetTimeDate);
213 processedTime += timeOffsetInDays * 24 * 60 * 60;
214 if (processedTime < currTimeDate->get_cur_time()) {
215 processedTime += repeatPeriod;
216 }
217 //tm *temp = currTimeDate->getGmt();
218 //char buffer[512];
219 //sgTimeFormatTime(&targetTimeDate, buffer);
220 //cout << "Scheduled Time " << buffer << endl;
221 //cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl;
222 return processedTime;
223}
224
226{
227 departureTime += repeatPeriod;
228 arrivalTime += repeatPeriod;
229}
230
234
236{
237 // Make sure that the arrival time is in between
238 // the current time and the next repeat period.
239 while ((arrivalTime < now) || (arrivalTime > now + repeatPeriod)) {
240 if (arrivalTime < now) {
241 departureTime += repeatPeriod;
242 arrivalTime += repeatPeriod;
243 SG_LOG(SG_AI, SG_BULK, "Adjusted schedule forward : " << callsign << " " << now << " " << departureTime << " " << arrivalTime);
244 } else if (arrivalTime > now + repeatPeriod) {
245 departureTime -= repeatPeriod;
246 arrivalTime -= repeatPeriod;
247 SG_LOG(SG_AI, SG_BULK, "Adjusted schedule backward : " << callsign << " " << now << " " << departureTime << " " << arrivalTime);
248 } else {
249 SG_LOG(SG_AI, SG_BULK, "Not Adjusted schedule : " << now);
250 }
251 }
252}
253
254
256{
257 if (!(initialized))
258 {
260 }
261 if (initialized)
262 return departurePort;
263 else
264 return 0;
265}
266
268{
269 if (!(initialized))
270 {
272 }
273 if (initialized)
274 return arrivalPort;
275 else
276 return 0;
277}
278
279// Upon the first time of requesting airport information
280// for this scheduled flight, these data need to be
281// looked up in the main FlightGear database.
282// Missing or bogus Airport codes are currently ignored,
283// but we should improve that. The best idea is probably to cancel
284// this flight entirely by removing it from the schedule, if one
285// of the airports cannot be found.
287{
288 //cerr << "Initializing using : " << depId << " " << arrId << endl;
289 departurePort = FGAirport::findByIdent(depId);
290 if(departurePort == nullptr)
291 {
292 if (!FGScheduledFlight::missingAirports.count(depId)) {
293 FGScheduledFlight::missingAirports.insert(std::pair<std::string,std::string>(depId, depId));
294 SG_LOG( SG_AI, SG_DEBUG, "Traffic manager could not find airport : " << depId);
295 }
296 return false;
297 }
298 arrivalPort = FGAirport::findByIdent(arrId);
299 if(arrivalPort == nullptr)
300 {
301 if (!FGScheduledFlight::missingAirports.count(arrId)) {
302 FGScheduledFlight::missingAirports.insert(std::pair<std::string,std::string>(arrId, arrId));
303 SG_LOG( SG_AI, SG_DEBUG, "Traffic manager could not find airport : " << arrId);
304 }
305 return false;
306 }
307
308 //cerr << "Found : " << departurePort->getId() << endl;
309 //cerr << "Found : " << arrivalPort->getId() << endl;
310 initialized = true;
311 return true;
312}
313
315{
316 return (*a) < (*b);
317};
static FGAirportRef findByIdent(const std::string &aIdent)
Helper to look up an FGAirport instance by unique ident.
Definition airport.cxx:489
FGAirport * getArrivalAirport()
FGAirport * getDepartureAirport()
void adjustTime(time_t now)
//FIXME Doesn't have to be an iteration / when sitting at departure why adjust based on arrival
static bool compareScheduledFlights(const FGScheduledFlight *a, const FGScheduledFlight *b)
time_t processTimeString(const std::string &time)
FGGlobals * globals
Definition globals.cxx:142
static int atoi(const string &str)
Definition options.cxx:113