]> git.mxchange.org Git - flightgear.git/blob - src/ATC/ground.cxx
Patches from Erik Hofman - use Plib's wave file loader plus IRIX fixes.
[flightgear.git] / src / ATC / ground.cxx
1 // FGGround - a class to provide ground control at larger airports.
2 //
3 // Written by David Luff, started March 2002.
4 //
5 // Copyright (C) 2002  David C. Luff - david.luff@nottingham.ac.uk
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 #include <simgear/math/sg_random.h>
22 #include <simgear/constants.h>
23
24 #include "ground.hxx"
25
26 FGGround::FGGround() {
27         display = false;
28 }
29
30 FGGround::~FGGround() {
31 }
32
33 void FGGround::Init() {
34         display = false;
35         
36         // Build hardwired (very simplified) logical network for KEMT for now
37         // Once it works we'll progress to reading KEMT data from file,
38         // and finally to reading any airport with specified taxiway data from file.
39
40         node* np;
41         arc* ap;
42         Gate* gp;
43         
44         // For now we'll hardwire the threshold end
45         Point3D P010(-118.037483, 34.081358, 296 * SG_FEET_TO_METER);
46         double hdg = 25.32;
47         ortho.Init(P010, hdg);
48
49         // HARDWIRED FOR TESTING - for now we'll only allow exit at each end of runway
50
51         ///////////////////////////////////////////////////////
52         // NODES
53         ///////////////////////////////////////////////////////
54
55         // node - runway01 threshold
56         Point3D p1(-118.0372167, 34.08178333, 0.0);
57         np = new node;
58         np->struct_type = NODE;
59         np->pos = p1;
60         np->orthoPos = ortho.ConvertToLocal(p1);
61         np->name = "rwy 01";
62         np->nodeID = 0;
63         np->type = JUNCTION;
64         runways[1].exits.push_back(np);
65         runways[19].exits.push_back(np);
66         //np->max_turn_radius = ...
67         network.push_back(np);
68
69         // node - runway19 threshold
70         Point3D p2(-118.0321833, 34.09066667, 0.0);
71         np = new node;
72         np->struct_type = NODE;
73         np->pos = p2;
74         np->orthoPos = ortho.ConvertToLocal(p2);
75         np->name = "rwy 19";
76         np->nodeID = 1;
77         np->type = JUNCTION;
78         runways[1].exits.push_back(np);
79         runways[19].exits.push_back(np);
80         //np->max_turn_radius = ...
81         network.push_back(np);
82
83         // node - AlphaSouth
84         Point3D p3(-118.0369167, 34.08166667, 0.0);
85         np = new node;
86         np->struct_type = NODE;
87         np->pos = p3;
88         np->orthoPos = ortho.ConvertToLocal(p3);
89         np->name = "";
90         np->nodeID = 2;
91         np->type = HOLD;
92         //np->max_turn_radius = ...
93         network.push_back(np);
94
95         // node - AlphaNorth
96         Point3D p4(-118.03185, 34.0906, 0.0);
97         np = new node;
98         np->struct_type = NODE;
99         np->pos = p4;
100         np->orthoPos = ortho.ConvertToLocal(p4);
101         np->name = "";
102         np->nodeID = 3;
103         np->type = HOLD;
104         //np->max_turn_radius = ...
105         network.push_back(np);
106
107         // node - southern turnoff to parking
108         Point3D p5(-118.03515, 34.0848, 0.0);
109         np = new node;
110         np->struct_type = NODE;
111         np->pos = p5;
112         np->orthoPos = ortho.ConvertToLocal(p5);
113         np->name = "";
114         np->nodeID = 4;
115         np->type = TJUNCTION;
116         //np->max_turn_radius = ...
117         network.push_back(np);
118
119         // node - northern turnoff to parking
120         Point3D p6(-118.0349667, 34.08511667, 0.0);
121         np = new node;
122         np->struct_type = NODE;
123         np->pos = p6;
124         np->orthoPos = ortho.ConvertToLocal(p6);
125         np->name = "";
126         np->nodeID = 5;
127         np->type = TJUNCTION;
128         //np->max_turn_radius = ...
129         network.push_back(np);
130
131         // GATES
132
133         // node - Turn into gate 1 (Western-most gate, ie. nearest rwy)
134         Point3D p7(-118.0348333, 34.08466667, 0.0);
135         np = new node;
136         np->struct_type = NODE;
137         np->pos = p7;
138         np->orthoPos = ortho.ConvertToLocal(p7);
139         np->name = "";
140         np->nodeID = 6;
141         np->type = TJUNCTION;
142         //np->max_turn_radius = ...
143         network.push_back(np);
144
145         // node - Gate 1
146         Point3D p8(-118.0347333, 34.08483333, 0.0);
147         gp = new Gate;
148         gp->struct_type = NODE;
149         gp->pos = p8;
150         gp->orthoPos = ortho.ConvertToLocal(p8);
151         gp->name = "";
152         gp->nodeID = 7;
153         gp->type = GATE;
154         gp->heading = 10;
155         //np->max_turn_radius = ...
156         network.push_back(gp);
157         gates[1] = *gp;
158
159         // node - Turn out of gate 1
160         Point3D p9(-118.03465, 34.08498333, 0.0);
161         np = new node;
162         np->struct_type = NODE;
163         np->pos = p9;
164         np->orthoPos = ortho.ConvertToLocal(p9);
165         np->name = "";
166         np->nodeID = 8;
167         np->type = TJUNCTION;
168         //np->max_turn_radius = ...
169         network.push_back(np);
170
171         // node - Turn into gate 2
172         Point3D p10(-118.0346, 34.08456667, 0.0);
173         np = new node;
174         np->struct_type = NODE;
175         np->pos = p10;
176         np->orthoPos = ortho.ConvertToLocal(p10);
177         np->name = "";
178         np->nodeID = 9;
179         np->type = TJUNCTION;
180         //np->max_turn_radius = ...
181         network.push_back(np);
182         gates[2] = *gp;
183
184         // node - Gate 2
185         Point3D p11(-118.0345167, 34.08473333, 0.0);
186         gp = new Gate;
187         gp->struct_type = NODE;
188         gp->pos = p11;
189         gp->orthoPos = ortho.ConvertToLocal(p11);
190         gp->name = "";
191         gp->nodeID = 10;
192         gp->type = GATE;
193         gp->heading = 10;
194         //np->max_turn_radius = ...
195         network.push_back(gp);
196
197         // node - Turn out of gate 2    
198         Point3D p12(-118.0344167, 34.0849, 0.0);
199         np = new node;
200         np->struct_type = NODE;
201         np->pos = p12;
202         np->orthoPos = ortho.ConvertToLocal(p12);
203         np->name = "";
204         np->nodeID = 11;
205         np->type = TJUNCTION;
206         //np->max_turn_radius = ...
207         network.push_back(np);
208
209         /////////////////////////////////////////////////////////
210         // ARCS
211         /////////////////////////////////////////////////////////
212
213         // Each arc connects two nodes
214         // Eventually the nodeID of the nodes that the arc connects will be read from file
215         // For now we just 'know' them !!
216
217         // arc - the runway - connects nodes 0 and 1
218         ap = new arc;
219         ap->struct_type = ARC;
220         ap->name = "";
221         ap->type = RUNWAY;
222         ap->directed = false;
223         ap->n1 = 0;
224         ap->n2 = 1;
225         network[0]->arcs.push_back(ap);
226         network[1]->arcs.push_back(ap);
227
228         // arc - the exit from 01 threshold to alpha - connects nodes 0 and 2
229         ap = new arc;
230         ap->struct_type = ARC;
231         ap->name = "";
232         ap->type = TAXIWAY;
233         ap->directed = false;
234         ap->n1 = 0;
235         ap->n2 = 2;
236         network[0]->arcs.push_back(ap);
237         network[2]->arcs.push_back(ap);
238
239         // arc - the exit from 19 threshold to alpha - connects nodes 1 and 3
240         ap = new arc;
241         ap->struct_type = ARC;
242         ap->name = "";
243         ap->type = TAXIWAY;
244         ap->directed = false;
245         ap->n1 = 1;
246         ap->n2 = 3;
247         network[1]->arcs.push_back(ap);
248         network[3]->arcs.push_back(ap);
249
250         // arc - Alpha south - connects nodes 2 and 4
251         ap = new arc;
252         ap->struct_type = ARC;
253         ap->name = "";
254         ap->type = TAXIWAY;
255         ap->directed = false;
256         ap->n1 = 2;
257         ap->n2 = 4;
258         network[2]->arcs.push_back(ap);
259         network[4]->arcs.push_back(ap);
260
261         // arc - Alpha middle - connects nodes 4 and 5
262         ap = new arc;
263         ap->struct_type = ARC;
264         ap->name = "";
265         ap->type = TAXIWAY;
266         ap->directed = false;
267         ap->n1 = 4;
268         ap->n2 = 5;
269         network[4]->arcs.push_back(ap);
270         network[5]->arcs.push_back(ap);
271
272         // arc - Alpha North - connects nodes 3 and 5
273         ap = new arc;
274         ap->struct_type = ARC;
275         ap->name = "";
276         ap->type = TAXIWAY;
277         ap->directed = false;
278         ap->n1 = 3;
279         ap->n2 = 5;
280         network[3]->arcs.push_back(ap);
281         network[5]->arcs.push_back(ap);
282
283         // arc - connects nodes 4 and 6
284         ap = new arc;
285         ap->struct_type = ARC;
286         ap->name = "";
287         ap->type = TAXIWAY;
288         ap->directed = true;
289         ap->n1 = 4;
290         ap->n2 = 6;
291         network[4]->arcs.push_back(ap);
292         network[6]->arcs.push_back(ap);
293
294         // arc - connects nodes 6 and 9
295         ap = new arc;
296         ap->struct_type = ARC;
297         ap->name = "";
298         ap->type = TAXIWAY;
299         ap->directed = true;
300         ap->n1 = 6;
301         ap->n2 = 9;
302         network[6]->arcs.push_back(ap);
303         network[9]->arcs.push_back(ap);
304
305         // arc - connects nodes 5 and 8
306         ap = new arc;
307         ap->struct_type = ARC;
308         ap->name = "";
309         ap->type = TAXIWAY;
310         ap->directed = true;
311         ap->n1 = 5;
312         ap->n2 = 8;     
313         network[5]->arcs.push_back(ap);
314         network[8]->arcs.push_back(ap);
315
316         // arc - connects nodes 8 and 11
317         ap = new arc;
318         ap->struct_type = ARC;
319         ap->name = "";
320         ap->type = TAXIWAY;
321         ap->directed = true;
322         ap->n1 = 8;
323         ap->n2 = 11;
324         network[8]->arcs.push_back(ap);
325         network[11]->arcs.push_back(ap);
326
327         // arc - connects nodes 6 and 7
328         ap = new arc;
329         ap->struct_type = ARC;
330         ap->name = "";
331         ap->type = TAXIWAY;
332         ap->directed = true;
333         ap->n1 = 6;
334         ap->n2 = 7;
335         network[6]->arcs.push_back(ap);
336         network[7]->arcs.push_back(ap);
337
338         // arc - connects nodes 7 and 8
339         ap = new arc;
340         ap->struct_type = ARC;
341         ap->name = "";
342         ap->type = TAXIWAY;
343         ap->directed = true;
344         ap->n1 = 7;
345         ap->n2 = 8;
346         network[7]->arcs.push_back(ap);
347         network[8]->arcs.push_back(ap);
348
349         // arc - connects nodes 9 and 10
350         ap = new arc;
351         ap->struct_type = ARC;
352         ap->name = "";
353         ap->type = TAXIWAY;
354         ap->directed = true;
355         ap->n1 = 9;
356         ap->n2 = 10;
357         network[9]->arcs.push_back(ap);
358         network[10]->arcs.push_back(ap);
359
360         // arc - connects nodes 10 and 11
361         ap = new arc;
362         ap->struct_type = ARC;
363         ap->name = "";
364         ap->type = TAXIWAY;
365         ap->directed = true;
366         ap->n1 = 10;
367         ap->n2 = 11;
368         network[10]->arcs.push_back(ap);
369         network[11]->arcs.push_back(ap);
370 }
371
372 void FGGround::Update() {
373         // Each time step, what do we need to do?
374         // We need to go through the list of outstanding requests and acknowedgements
375         // and process at least one of them.
376         // We need to go through the list of planes under our control and check if
377         // any need to be addressed.
378         // We need to check for planes not under our control coming within our 
379         // control area and address if necessary.
380         
381         // Lets take the example of a plane which has just contacted ground
382         // following landing - presumably requesting where to go?
383         // First we need to establish the position of the plane within the logical network.
384         // Next we need to decide where its going. 
385 }
386
387 // FIXME - at the moment this assumes there is at least one gate and crashes if none
388 // FIXME - In fact, at the moment this routine doesn't work at all and hence is munged to always return Gate 1 !!!!
389 int FGGround::GetRandomGateID() {
390         //cout << "GetRandomGateID called" << endl;
391         return(1);
392
393         gate_vec_type gateVec;
394         //gate_vec_iterator gateVecItr;
395         int num = 0;
396         int thenum;
397         int ID;
398         
399         gatesItr = gates.begin();
400         while(gatesItr != gates.end()) {
401                 if(gatesItr->second.used == false) {
402                         gateVec.push_back(gatesItr->second);
403                         num++;
404                 }
405                 ++gatesItr;
406         }
407         
408         // Randomly select one from the list
409         thenum = (int)(sg_random() * gateVec.size());
410         ID = gateVec[thenum].id;
411         //cout << "Returning gate ID " << ID << " from GetRandomGateID" << endl;
412         return(ID);
413 }
414
415 // Return a pointer to a gate node based on the gate ID
416 Gate* FGGround::GetGateNode(int gateID) {
417         //TODO - ought to add some sanity checking here - ie does a gate of this ID exist?!
418         return(&(gates[gateID]));
419 }
420
421 // Get a path from a point on a runway to a gate
422
423 // Get a path from a node to another node
424 // Eventually we will need complex algorithms for this taking other traffic,
425 // shortest path and suitable paths into accout.  For now we're going to hardwire for KEMT!!!!
426 ground_network_path_type FGGround::GetPath(node* A, node* B) {
427         ground_network_path_type path;
428         //arc_array_iterator arcItr;
429         //bool found;
430
431         // VERY HARDWIRED - this hardwires a path from the far end of R01 to Gate 1.
432         // In fact in real life the area between R01/19 and Taxiway Alpha at KEMT is tarmaced and planes
433         // are supposed to exit the rwy asap.
434         // OK - for now very hardwire this for testing
435         path.push_back(network[1]);
436         path.push_back(network[1]->arcs[1]);    // ONLY BECAUSE WE KNOW THIS IS THE ONE !!!!!
437         path.push_back(network[3]);
438         path.push_back(network[3]->arcs[1]);
439         path.push_back(network[5]);
440         path.push_back(network[5]->arcs[0]);
441         path.push_back(network[4]);
442         path.push_back(network[4]->arcs[2]);
443         path.push_back(network[6]);
444         path.push_back(network[6]->arcs[2]);
445         path.push_back(network[7]);                             // THE GATE!!  Note that for now we're not even looking at the requested exit and gate passed in !!!!!
446
447 #if 0   
448         // In this hardwired scheme there are two possibilities - taxiing from rwy to gate or gate to rwy.
449         if(B->type == GATE) {
450                 //return an inward path
451                 path.push_back(A);
452                 // In this hardwired scheme we know A is a rwy exit and should have one taxiway arc only
453                 // THIS WILL NOT HOLD TRUE IN THE GENERAL CASE
454                 arcItr = A->arcs.begin();
455                 found = false;
456                 while(arcItr != A->arcs.end()) {
457                         if(arcItr->type == TAXIWAY) {
458                                 path.push_back(&(*arcItr));
459                                 found = true;
460                                 break;
461                         }
462                 }
463                 if(found == false) {
464                         //cout << "AI/ATC SUBSYSTEM ERROR - no taxiway from runway exit in airport.cxx" << endl;
465                 }
466                 // Then push back the start of taxiway node
467                 // Then push back the taxiway arc
468                 arcItr = A->arcs.begin();
469                 found = false;
470                 while(arcItr != A->arcs.end()) {
471                         if(arcItr->type == TAXIWAY) { // FIXME - OOPS - two taxiways go off this node
472                                 // How are we going to differentiate, apart from one called Alpha.
473                                 // I suppose eventually the traversal algorithms will select.
474                                 path.push_back(&(*arcItr));
475                                 found = true;
476                                 break;
477                 }
478                 }
479                 if(found == false) {
480                 //cout << "AI/ATC SUBSYSTEM ERROR - no taxiway from runway exit in airport.cxx" << endl;
481                 }
482                 // Then push back the junction node
483                 // Planes always face one way in the parking, so depending on which parking exit we have either take it or push back another taxiway node
484                 // Repeat if necessary
485                 // Then push back the gate B
486                 path.push_back(B);
487         } else {
488                 //return an outward path
489         }       
490
491         // WARNING TODO FIXME - this is VERY FRAGILE - eg taxi to apron!!! but should be enough to
492         // see an AI plane physically taxi.
493 #endif  // 0
494         
495         return(path);
496 };
497
498
499 // Randomly or otherwise populate some of the gates with parked planes
500 // (might eventually be done by the AIMgr if and when lots of AI traffic is generated)
501
502 // Return a list of exits from a given runway
503 node_array_type FGGround::GetExits(int rwyID) {
504         return(runways[rwyID].exits);
505 }
506 #if 0
507 void FGGround::NewArrival(plane_rec plane) {
508         // What are we going to do here?
509         // We need to start a new ground_rec and add the plane_rec to it
510         // We need to decide what gate we are going to clear it to.
511         // Then we need to add clearing it to that gate to the pending transmissions queue? - or simply transmit?
512         // Probably simply transmit for now and think about a transmission queue later if we need one.
513         // We might need one though in order to add a little delay for response time.
514         ground_rec* g = new ground_rec;
515         g->plane_rec = plane;
516         g->current_pos = ConvertWGS84ToXY(plane.pos);
517         g->node = GetNode(g->current_pos);  // TODO - might need to sort out node/arc here
518         AssignGate(g);
519         g->cleared = false;
520         ground_traffic.push_back(g);
521         NextClearance(g);
522 }
523
524 void FGGround::NewContact(plane_rec plane) {
525         // This is a bit of a convienience function at the moment and is likely to change.
526         if(at a gate or apron)
527                 NewDeparture(plane);
528         else
529                 NewArrival(plane);
530 }
531
532 void FGGround::NextClearance(ground_rec &g) {
533         // Need to work out where we can clear g to.
534         // Assume the pilot doesn't need progressive instructions
535         // We *should* already have a gate or holding point assigned by the time we get here
536         // but it wouldn't do any harm to check.
537         
538         // For now though we will hardwire it to clear to the final destination.
539 }
540
541 void FGGround::AssignGate(ground_rec &g) {
542         // We'll cheat for now - since we only have the user's aircraft and a couple of airports implemented
543         // we'll hardwire the gate!
544         // In the long run the logic of which gate or area to send the plane to could be somewhat non-trivial.
545 }
546 #endif //0