FlightGear next
AIFlightPlanCreatePushBack.cxx
Go to the documentation of this file.
1/****************************************************************************
2* AIFlightPlanCreatePushBack.cxx
3* Written by Durk Talsma, started August 1, 2007.
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#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
24
25#include <cstdlib>
26#include <cstdio>
27
28#include <simgear/math/sg_geodesy.hxx>
29
30#include <Airports/airport.hxx>
31#include <Airports/runways.hxx>
32#include <Airports/dynamics.hxx>
34
37
38#include "AIFlightPlan.hxx"
39#include "AIAircraft.hxx"
40#include "performancedata.hxx"
41
42using std::string;
43
44// TODO: Use James Turner's createOnGround functions.
46 bool firstFlight,
47 FGAirport *dep,
48 double radius,
49 const string& fltType,
50 const string& aircraftType,
51 const string& airline)
52{
53 double vTaxi = ac->getPerformance()->vTaxi();
54 double vTaxiBackward = vTaxi * (-2.0/3.0);
55 double vTaxiReduced = vTaxi * (2.0/3.0);
56
57 // Active runway can be conditionally set by ATC, so at the start of a new flight, this
58 // must be reset.
59 activeRunway.clear();
60
61 if (!(dep->getDynamics()->getGroundController()->exists())) {
62 //cerr << "Push Back fallback" << endl;
63 SG_LOG(SG_AI, SG_DEV_WARN, "No groundcontroller createPushBackFallBack at " << dep->getId());
64 createPushBackFallBack(ac, firstFlight, dep,
65 radius, fltType, aircraftType, airline);
66 return true;
67 }
68
69 if (firstFlight || !dep->getDynamics()->hasParking(gate.parking())) {
70 // establish the parking position / gate
71 // if the airport has no parking positions defined, don't log
72 // the warning below.
73 if (!dep->getDynamics()->hasParkings()) {
74 return false;
75 }
76 gate = dep->getDynamics()->getAvailableParking(radius, fltType,
77 aircraftType, airline);
78 if (!gate.isValid()) {
79 SG_LOG(SG_AI, SG_DEV_WARN, "Could not find parking for a " <<
80 aircraftType <<
81 " of flight type " << fltType <<
82 " of airline " << airline <<
83 " at airport " << dep->getId());
84 return false;
85 }
86 }
87
88
89 if (!gate.isValid()) {
90 SG_LOG(SG_AI, SG_DEV_WARN, "Gate " << gate.parking()->ident() << " not valid createPushBackFallBack at " << dep->getId());
91 createPushBackFallBack(ac, firstFlight, dep,
92 radius, fltType, aircraftType, airline);
93 return true;
94
95 }
96
97 FGGroundNetwork* groundNet = dep->groundNetwork();
98 FGParking *parking = gate.parking();
99 if (parking && parking->getPushBackPoint() != nullptr) {
100 FGTaxiRoute route = groundNet->findShortestRoute(parking, parking->getPushBackPoint(), false);
101 SG_LOG(SG_AI, SG_BULK, "Creating Pushback from " << parking->ident() << " to " << parking->getPushBackPoint()->getIndex());
102
103 int size = route.size();
104 if (size < 2) {
105 SG_LOG(SG_AI, SG_DEV_WARN, "Push back route from gate " << parking->ident() << " has only " << size << " nodes.\n" << "Using " << parking->getPushBackPoint());
106 }
107
108 route.first();
109 FGTaxiNodeRef node;
110 int rte;
111
112 if (waypoints.size()>0) {
113 // This will be a parking from a previous leg which still contains the forward speed
114 waypoints.back()->setSpeed(vTaxiBackward);
115 }
116
117 while (route.next(node, &rte))
118 {
119 char buffer[20];
120 snprintf (buffer, sizeof(buffer), "pushback-%03d", (short)node->getIndex());
121 FGAIWaypoint *wpt = createOnGround(ac, string(buffer), node->geod(), dep->getElevation(), vTaxiBackward);
122
123 /*
124 if (previous) {
125 FGTaxiSegment* segment = groundNet->findSegment(previous, node);
126 wpt->setRouteIndex(segment->getIndex());
127 } else {
128 // not on the route yet, make up a unique segment ID
129 int x = (int) tn->guid();
130 wpt->setRouteIndex(x);
131 }*/
132
133 wpt->setRouteIndex(rte);
134 pushBackWaypoint(wpt);
135 //previous = node;
136 }
137 // some special considerations for the last point:
138 // This will trigger the release of parking
139 waypoints.back()->setName(string("PushBackPoint"));
140 waypoints.back()->setSpeed(vTaxi);
141 ac->setTaxiClearanceRequest(true);
142 } else { // In case of a push forward departure...
143 ac->setTaxiClearanceRequest(false);
144 double az2 = 0.0;
145
146 FGTaxiSegment* pushForwardSegment = dep->groundNetwork()->findSegmentByHeading(parking, parking->getHeading());
147
148 if (!pushForwardSegment) {
149 // there aren't any routes for this parking, so create a simple segment straight ahead for 2 meters based on the parking heading
150 SG_LOG(SG_AI, SG_DEV_WARN, "Gate " << parking->ident() << " at " << dep->getId()
151 << " doesn't seem to have pushforward routes associated with it.");
152
153 FGAIWaypoint *wpt = createOnGround(ac, string("park"), parking->geod(), dep->getElevation(), vTaxiReduced);
154 pushBackWaypoint(wpt);
155
156 SGGeod coord;
157 SGGeodesy::direct(parking->geod(), parking->getHeading(), 2.0, coord, az2);
158 wpt = createOnGround(ac, string("taxiStart"), coord, dep->getElevation(), vTaxiReduced);
159 pushBackWaypoint(wpt);
160 return true;
161 }
162
163 lastNodeVisited = pushForwardSegment->getEnd();
164 double distance = pushForwardSegment->getLength();
165
166 double parkingHeading = parking->getHeading();
167
168 SG_LOG(SG_AI, SG_BULK, "Creating Pushforward from ID " << pushForwardSegment->getEnd()->getIndex() << " Length : \t" << distance);
169// Add the parking if on first leg and not repeat
170 if (waypoints.size() == 0) {
171 pushBackWaypoint( createOnGround(ac, parking->getName(), parking->geod(), dep->getElevation(), vTaxiReduced));
172 }
173// Make sure we have at least three WPs
174 int numSegments = distance>15?(distance/5.0):3;
175 for (int i = 1; i < numSegments; i++) {
176 SGGeod pushForwardPt;
177
178 SGGeodesy::direct(parking->geod(), parkingHeading,
179 (((double)i / numSegments) * distance), pushForwardPt, az2);
180 char buffer[20];
181 snprintf(buffer, sizeof(buffer), "pushforward-%03d", (short)i);
182 FGAIWaypoint *wpt = createOnGround(ac, string(buffer), pushForwardPt, dep->getElevation(), vTaxiReduced);
183
184 wpt->setRouteIndex(pushForwardSegment->getIndex());
185 pushBackWaypoint(wpt);
186 }
187
188 // This will trigger the release of parking
189 waypoints.back()->setName(string("PushBackPoint-pushforward"));
190 }
191
192 return true;
193}
194/*******************************************************************
195* createPushBackFallBack
196* This is the backup function for airports that don't have a
197* network yet.
198******************************************************************/
199void FGAIFlightPlan::createPushBackFallBack(FGAIAircraft *ac, bool firstFlight, FGAirport *dep,
200 double radius,
201 const string& fltType,
202 const string& aircraftType,
203 const string& airline)
204{
205 double az2 = 0.0;
206
207 double vTaxi = ac->getPerformance()->vTaxi();
208 double vTaxiBackward = vTaxi * (-2.0/3.0);
209 double vTaxiReduced = vTaxi * (2.0/3.0);
210
211 double heading = 180.0; // this is a completely arbitrary heading!
212 FGAIWaypoint *wpt = createOnGround(ac, string("park"), dep->geod(), dep->getElevation(), vTaxiBackward);
213
214 pushBackWaypoint(wpt);
215
216 SGGeod coord;
217 SGGeodesy::direct(dep->geod(), heading, 10, coord, az2);
218 wpt = createOnGround(ac, string("park2"), coord, dep->getElevation(), vTaxiBackward);
219
220 pushBackWaypoint(wpt);
221
222 SGGeodesy::direct(dep->geod(), heading, 2.2 * radius, coord, az2);
223 wpt = createOnGround(ac, string("taxiStart"), coord, dep->getElevation(), vTaxiReduced);
224 pushBackWaypoint(wpt);
225
226}
#define i(x)
SGSharedPtr< FGTaxiNode > FGTaxiNodeRef
PerformanceData * getPerformance()
void setTaxiClearanceRequest(bool arg)
bool createPushBack(FGAIAircraft *, bool, FGAirport *, double radius, const std::string &, const std::string &, const std::string &)
void setRouteIndex(int rte)
FGAirportDynamicsRef getDynamics() const
Definition airport.cxx:1048
double getElevation() const
Definition airport.hxx:61
const std::string & getId() const
Definition airport.hxx:53
FGGroundNetwork * groundNetwork() const
Definition airport.cxx:1053
FGTaxiSegment * findSegmentByHeading(const FGTaxiNode *from, const double heading) const
Find the taxiway segment best matching the heading.
FGTaxiRoute findShortestRoute(FGTaxiNode *start, FGTaxiNode *end, bool fullSearch=true)
double getHeading() const
Definition parking.hxx:57
std::string getName() const
Definition parking.hxx:62
FGTaxiNodeRef getPushBackPoint()
Definition parking.hxx:65
virtual const SGGeod & geod() const
const std::string & ident() const
bool next(FGTaxiNodeRef &nde, int *rte)
FGTaxiNodeRef getEnd() const
double getLength() const
int getIndex() const
double vTaxi() const