FlightGear next
AIFlightPlanCreateCruise.cxx
Go to the documentation of this file.
1/******************************************************************************
2 * AIFlightPlanCreateCruise.cxx
3 * Written by Durk Talsma, started February, 2006.
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 St, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 *
20 **************************************************************************/
21
22#ifdef HAVE_CONFIG_H
23# include <config.h>
24#endif
25
26#include <fstream>
27
28#include <Airports/airport.hxx>
29#include <Airports/runways.hxx>
30#include <Airports/dynamics.hxx>
31
34
35#include <Traffic/Schedule.hxx>
36
37#include "AIFlightPlan.hxx"
38#include "AIAircraft.hxx"
39#include "performancedata.hxx"
40
41using std::string;
42
43/*
44void FGAIFlightPlan::evaluateRoutePart(double deplat,
45 double deplon,
46 double arrlat,
47 double arrlon)
48{
49 // First do a prescan of all the waypoints that are within a reasonable distance of the
50 // ideal route.
51 intVec nodes;
52 int tmpNode, prevNode;
53
54 SGGeoc dep(SGGeoc::fromDegM(deplon, deplat, 100.0));
55 SGGeoc arr(SGGeoc::fromDegM(arrlon, arrlat, 100.0));
56
57 SGVec3d a = SGVec3d::fromGeoc(dep);
58 SGVec3d nb = normalize(SGVec3d::fromGeoc(arr));
59 SGVec3d na = normalize(a);
60
61 SGVec3d _cross = cross(nb, na);
62
63 double angle = acos(dot(na, nb));
64 const double angleStep = 0.05 * SG_DEGREES_TO_RADIANS;
65 tmpNode = 0;
66 for (double ang = 0.0; ang < angle; ang += angleStep)
67 {
68 SGQuatd q = SGQuatd::fromAngleAxis(ang, _cross);
69 SGGeod geod = SGGeod::fromCart(q.transform(a));
70
71 prevNode = tmpNode;
72 tmpNode = globals->get_airwaynet()->findNearestNode(geod);
73
74 FGNode* node = globals->get_airwaynet()->findNode(tmpNode);
75
76 if ((tmpNode != prevNode) && (SGGeodesy::distanceM(geod, node->getPosition()) < 25000)) {
77 nodes.push_back(tmpNode);
78 }
79 }
80
81 intVecIterator i = nodes.begin();
82 intVecIterator j = nodes.end();
83 while (i != nodes.end())
84 {
85 j = nodes.end();
86 while (j != i)
87 {
88 j--;
89 FGAirRoute routePart = globals->get_airwaynet()->findShortestRoute(*i, *j);
90 if (!(routePart.empty()))
91 {
92 airRoute.add(routePart);
93 i = j;
94 break;
95 }
96 }
97 i++;
98 }
99}
100
101*/
102/*
103void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep,
104 FGAirport *arr, double latitude,
105 double longitude, double speed, double alt)
106{
107 bool useInitialWayPoint = true;
108 bool useCurrentWayPoint = false;
109 double heading;
110 double lat, lon, az;
111 double lat2, lon2, az2;
112 double azimuth;
113 waypoint *wpt;
114 waypoint *init_waypoint;
115 intVec ids;
116 char buffer[32];
117 SGPath routefile = globals->get_fg_root();
118 init_waypoint = new waypoint;
119 init_waypoint->name = "Initial waypoint";
120 init_waypoint->latitude = latitude;
121 init_waypoint->longitude = longitude;;
122 //wpt->altitude = apt->getElevation(); // should maybe be tn->elev too
123 init_waypoint->altitude = alt;
124 init_waypoint->speed = 450; //speed;
125 init_waypoint->crossat = -10000;
126 init_waypoint->gear_down = false;
127 init_waypoint->flaps_down= false;
128 init_waypoint->finished = false;
129 init_waypoint->on_ground = false;
130 pushBackWaypoint(init_waypoint);
131 routefile.append("Data/AI/FlightPlans");
132 snprintf(buffer, 32, "%s-%s.txt",
133 dep->getId().c_str(),
134 arr->getId().c_str());
135 routefile.append(buffer);
136 SG_LOG(SG_AI, SG_DEBUG, "trying to read " << routefile.c_str());
137 //exit(1);
138 if (routefile.exists())
139 {
140 sg_gzifstream in( routefile.str() );
141 do {
142 in >> route;
143 } while (!(in.eof()));
144 }
145 else {
146 //int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat2, lon2);
147 //int startId = globals->get_airwaynet()->findNearestNode(dep->getLatitude(), dep->getLongitude());
148 //int endId = globals->get_airwaynet()->findNearestNode(arr->getLatitude(), arr->getLongitude());
149 //FGAirRoute route;
150 evaluateRoutePart(dep->getLatitude(), dep->getLongitude(),
151 arr->getLatitude(), arr->getLongitude());
152 //exit(1);
153 }
154 route.first();
155 int node;
156 if (route.empty()) {
157 // if no route could be found, create a direct gps route...
158 SG_LOG(SG_AI, SG_DEBUG, "still no route found from " << dep->getName() << " to << " << arr->getName());
159
160 //exit(1);
161 } else {
162 while(route.next(&node))
163 {
164 FGNode *fn = globals->get_airwaynet()->findNode(node);
165 SG_LOG(SG_AI, SG_BULK, "Checking status of each waypoint: " << fn->getIdent());
166
167 SGWayPoint first(init_waypoint->longitude,
168 init_waypoint->latitude,
169 alt);
170 SGWayPoint curr (fn->getLongitude(),
171 fn->getLatitude(),
172 alt);
173 SGWayPoint arr (arr->getLongitude(),
174 arr->getLatitude(),
175 alt);
176
177 double crse, crsDiff;
178 double dist;
179 first.CourseAndDistance(arr, &course, &distance);
180 first.CourseAndDistance(curr, &crse, &dist);
181
182 dist *= SG_METER_TO_NM;
183
184 // We're only interested in the absolute value of crsDiff
185 // wich should fall in the 0-180 deg range.
186 crsDiff = fabs(crse-course);
187 if (crsDiff > 180)
188 crsDiff = 360-crsDiff;
189 // These are the three conditions that we consider including
190 // in our flight plan:
191 // 1) current waypoint is less then 100 miles away OR
192 // 2) curren waypoint is ahead of us, at any distance
193 SG_LOG(SG_AI, SG_BULK, " Distance : " << dist << " : Course diff " << crsDiff
194 << " crs to dest : " << course
195 << " crs to wpt : " << crse);
196 if ((dist > 20.0) && (crsDiff > 90.0))
197 {
198 //useWpt = false;
199 // Once we start including waypoints, we have to continue, even though
200 // one of the following way point would suffice.
201 // so once is the useWpt flag is set to true, we cannot reset it to false.
202 SG_LOG(SG_AI, SG_BULK, " discarding ");
203 // << ": Course difference = " << crsDiff
204 // << "Course = " << course
205 // << "crse = " << crse);
206 }
207 else {
208 //i = ids.end()-1;
209 SG_LOG(SG_AI, SG_BULK, " accepting ")
210
211 //ids.pop_back();
212 wpt = new waypoint;
213 wpt->name = "Airway"; // fixme: should be the name of the waypoint
214 wpt->latitude = fn->getLatitude();
215 wpt->longitude = fn->getLongitude();
216 //wpt->altitude = apt->getElevation(); // should maybe be tn->elev too
217 wpt->altitude = alt;
218 wpt->speed = 450; //speed;
219 wpt->crossat = -10000;
220 wpt->gear_down = false;
221 wpt->flaps_down= false;
222 wpt->finished = false;
223 wpt->on_ground = false;
224 pushBackWaypoint(wpt);
225 }
226
227 if (!(routefile.exists()))
228 {
229 route.first();
230 fstream outf( routefile.c_str(), fstream::out );
231 while (route.next(&node))
232 outf << node << endl;
233 }
234 }
235 }
236 arr->getDynamics()->getActiveRunway("com", 2, activeRunway);
237 if (!(globals->get_runways()->search(arr->getId(),
238 activeRunway,
239 &rwy)))
240 {
241 SG_LOG(SG_AI, SG_WARN, "Failed to find runway for " << arr->getId());
242 // Hmm, how do we handle a potential error like this?
243 exit(1);
244 }
245 //string test;
246 //arr->getActiveRunway(string("com"), 1, test);
247 //exit(1);
248
249 SG_LOG(SG_AI, SG_DEBUG, "Altitude = " << alt);
250 SG_LOG(SG_AI, SG_DEBUG, "Done");
251 SG_LOG(SG_AI, SG_DEBUG, "Creating cruise to " << arr->getId() << " " << latitude << " " << longitude);
252 heading = rwy._heading;
253 azimuth = heading + 180.0;
254 while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
255
256
257 // Note: This places us at the location of the active
258 // runway during initial cruise. This needs to be
259 // fixed later.
260 geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
261 110000,
262 &lat2, &lon2, &az2 );
263 wpt = new waypoint;
264 wpt->name = "BOD"; //wpt_node->getStringValue("name", "END");
265 wpt->latitude = lat2;
266 wpt->longitude = lon2;
267 wpt->altitude = alt;
268 wpt->speed = speed;
269 wpt->crossat = alt;
270 wpt->gear_down = false;
271 wpt->flaps_down= false;
272 wpt->finished = false;
273 wpt->on_ground = false;
274 pushBackWaypoint(wpt);
275}
276*/
277
278
279/*******************************************************************
280 * CreateCruise
281 * initialize the Aircraft at the parking location
282 *
283 * Note that this is the original version that does not
284 * do any dynamic route computation.
285 ******************************************************************/
286bool FGAIFlightPlan::createCruise(FGAIAircraft *ac, bool firstFlight, FGAirport *dep,
287 FGAirport *arr,
288 const SGGeod& current,
289 double speed,
290 double alt,
291 const string& fltType)
292{
293 double vCruise = ac->getPerformance()->vCruise();
294 FGAIWaypoint *wpt;
295 //FIXME usually that will be "before" the next WP
296 wpt = createInAir(ac, "Cruise", current, alt, vCruise);
297 if (waypoints.size() == 0) {
298 pushBackWaypoint(wpt);
299 SG_LOG(SG_AI, SG_DEBUG, "Cruise spawn " << ac->getCallSign());
300 } else {
301 SG_LOG(SG_AI, SG_DEBUG, "Cruise start " << ac->getCallSign());
302 }
303 //
304
305 const string& rwyClass = getRunwayClassFromTrafficType(fltType);
306 double heading = ac->getTrafficRef()->getCourse();
307 arr->getDynamics()->getActiveRunway(rwyClass, RunwayAction::LANDING, activeRunway, heading);
308 if (!arr->hasRunwayWithIdent(activeRunway)) {
309 SG_LOG(SG_AI, SG_WARN, ac->getCallSign() << " cruise to" << arr->getId() << activeRunway << " not active");
310 return false;
311 }
312
313 FGRunway* rwy = arr->getRunwayByIdent(activeRunway);
314 assert( rwy != NULL );
315 // begin descent 110km out
316 double distanceOut = arr->getDynamics()->getRunwayQueue(rwy->name())->getApproachDistance(); //12 * SG_NM_TO_METER;
317
318 SGGeod beginDescentPoint = rwy->pointOnCenterline(-3*distanceOut);
319 SGGeod secondaryDescentPoint = rwy->pointOnCenterline(0);
320
321 double distanceToRwy = SGGeodesy::distanceM(current, secondaryDescentPoint);
322 if (distanceToRwy>4*distanceOut) {
323 FGAIWaypoint *bodWpt = createInAir(ac, "BOD", beginDescentPoint, alt, vCruise);
324 pushBackWaypoint(bodWpt);
325 FGAIWaypoint *bod2Wpt = createInAir(ac, "BOD2", secondaryDescentPoint, alt, vCruise);
326 pushBackWaypoint(bod2Wpt);
327 } else {
328 // We are too near. The descent leg takes care of this (teardrop etc)
329 FGAIWaypoint *bodWpt = createInAir(ac, "BOD", SGGeodesy::direct(current, ac->getTrueHeadingDeg(), 10000), alt, vCruise);
330 pushBackWaypoint(bodWpt);
331 FGAIWaypoint *bod2Wpt = createInAir(ac, "BOD2", SGGeodesy::direct(current, ac->getTrueHeadingDeg(), 15000), alt, vCruise);
332 pushBackWaypoint(bod2Wpt);
333 }
334 return true;
335}
PerformanceData * getPerformance()
FGAISchedule * getTrafficRef()
double getTrueHeadingDeg() const
Definition AIBase.hxx:152
const std::string & getCallSign() const
Definition AIBase.hxx:367
const char * getRunwayClassFromTrafficType(const std::string &fltType)
double getCourse()
Definition Schedule.hxx:124
FGAirportDynamicsRef getDynamics() const
Definition airport.cxx:1048
FGRunwayRef getRunwayByIdent(const std::string &aIdent) const
Definition airport.cxx:182
bool hasRunwayWithIdent(const std::string &aIdent) const
Definition airport.cxx:162
const std::string & getId() const
Definition airport.hxx:53
virtual const std::string & name() const
Return the name of this positioned.
SGGeod pointOnCenterline(double aOffset) const
Retrieve a position on the extended centerline.
double vCruise() const