]> git.mxchange.org Git - flightgear.git/commitdiff
Removed a lot of the remaining hardwired KEMT stuff, made the initialisation more...
authordaveluff <daveluff>
Wed, 5 Mar 2003 21:38:29 +0000 (21:38 +0000)
committerdaveluff <daveluff>
Wed, 5 Mar 2003 21:38:29 +0000 (21:38 +0000)
src/ATC/AILocalTraffic.cxx
src/ATC/AILocalTraffic.hxx
src/ATC/AIMgr.cxx
src/ATC/AIMgr.hxx

index a2757598f350ce0cae650c52b9fbf28a30592eb6..f4dc8dbeae79d01d0be2073b1bf5b7683f1dc8bf 100644 (file)
@@ -23,6 +23,7 @@
 #  include <config.h>
 #endif
 
+#include <Airports/runways.hxx>
 #include <Main/globals.hxx>
 #include <Main/location.hxx>
 #include <Scenery/scenery.hxx>
@@ -40,6 +41,10 @@ SG_USING_STD(string);
 #include "ATCutils.hxx"
 
 FGAILocalTraffic::FGAILocalTraffic() {
+       roll = 0.0;
+       pitch = 0.0;
+       hdg = 270.0;
+       
        //Hardwire initialisation for now - a lot of this should be read in from config eventually
        Vr = 70.0;
        best_rate_of_climb_speed = 70.0;
@@ -56,31 +61,105 @@ FGAILocalTraffic::FGAILocalTraffic() {
        nominalTaxiSpeed = 8.0;
        taxiTurnRadius = 8.0;
        wheelOffset = 1.45;     // Warning - hardwired to the C172 - we need to read this in from file.
+       elevInitGood = false;
        // Init the property nodes
        wind_from_hdg = fgGetNode("/environment/wind-from-heading-deg", true);
        wind_speed_knots = fgGetNode("/environment/wind-speed-kts", true);
        circuitsToFly = 0;
+       liningUp = false;
 }
 
 FGAILocalTraffic::~FGAILocalTraffic() {
 }
 
-void FGAILocalTraffic::Init() {
+
+// Get details of the active runway
+// This is a private internal function and it is assumed that by the 
+// time it is called the tower control and airport code will have been set up.
+void FGAILocalTraffic::GetRwyDetails() {
+       //cout << "GetRwyDetails called" << endl;
+       
+       // Based on the airport-id and wind get the active runway
+       SGPath path( globals->get_fg_root() );
+       path.append( "Airports" );
+       path.append( "runways.mk4" );
+       FGRunways runways( path.c_str() );
+       
+       //wind
+       double hdg = wind_from_hdg->getDoubleValue();
+       double speed = wind_speed_knots->getDoubleValue();
+       hdg = (speed == 0.0 ? 270.0 : hdg);
+       //cout << "Heading = " << hdg << '\n';
+       
+       FGRunway runway;
+       bool rwyGood = runways.search(airportID, int(hdg), &runway);
+       if(rwyGood) {
+               // Get the threshold position
+       hdg = runway.heading;
+               //cout << "hdg reset to " << hdg << '\n';
+               double other_way = hdg - 180.0;
+               while(other_way <= 0.0) {
+                       other_way += 360.0;
+               }
+
+       // move to the +l end/center of the runway
+               //cout << "Runway center is at " << runway.lon << ", " << runway.lat << '\n';
+       Point3D origin = Point3D(runway.lon, runway.lat, aptElev);
+               Point3D ref = origin;
+       double tshlon, tshlat, tshr;
+               double tolon, tolat, tor;
+               rwy.length = runway.length * SG_FEET_TO_METER;
+       geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), other_way, 
+                               rwy.length / 2.0 - 25.0, &tshlat, &tshlon, &tshr );
+       geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), hdg, 
+                               rwy.length / 2.0 - 25.0, &tolat, &tolon, &tor );
+               // Note - 25 meters in from the runway end is a bit of a hack to put the plane ahead of the user.
+               // now copy what we need out of runway into rwy
+       rwy.threshold_pos = Point3D(tshlon, tshlat, aptElev);
+               Point3D takeoff_end = Point3D(tolon, tolat, aptElev);
+               //cout << "Threshold position = " << tshlon << ", " << tshlat << ", " << aptElev << '\n';
+               //cout << "Takeoff position = " << tolon << ", " << tolat << ", " << aptElev << '\n';
+               rwy.hdg = hdg;
+               rwy.rwyID = runway.rwy_no;
+               // Set the projection for the local area
+               ortho.Init(rwy.threshold_pos, rwy.hdg); 
+               rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos);        // should come out as zero
+               rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
+               rwy.mag_var = 14.0;             // TODO - remove this last hardwired bit!! 
+               //(Although I don't think we even use the magvar any more?)
+               rwy.mag_hdg = rwy.hdg - rwy.mag_var;
+               rwy.ID = (int)rwy.mag_hdg / 10;         
+               //cout << "rwy.ID = " << rwy.ID << '\n';
+       } else {
+               SG_LOG(SG_GENERAL, SG_ALERT, "Help  - can't get good runway in FGAILocalTraffic!!\n");
+       }
+}
+
+/* 
+There are two possible scenarios during initialisation:
+The first is that the user is flying towards the airport, and hence the traffic
+could be initialised anywhere, as long as the AI planes are consistent with
+each other.
+The second is that the user has started the sim at or close to the airport, and
+hence the traffic must be initialised with respect to the user as well as each other.
+To a certain extent it's FGAIMgr that has to worry about this, but we need to provide
+sufficient initialisation functionality within the plane classes to allow the manager
+to initialy position them where and how required.
+*/
+bool FGAILocalTraffic::Init(string ICAO, OperatingState initialState, PatternLeg initialLeg) {
+       //cout << "FGAILocalTraffic.Init(...) called" << endl;
        // Hack alert - Hardwired path!!
        string planepath = "Aircraft/c172/Models/c172-dpm.ac";
        SGPath path = globals->get_fg_root();
        path.append(planepath);
        aip.init(planepath.c_str());
-       aip.setVisible(true);
+       aip.setVisible(false);          // This will be set to true once a valid ground elevation has been determined
        globals->get_scenery()->get_scene_graph()->addKid(aip.getSceneGraph());
-       // is it OK to leave it like this until the first time transform is called?
-       // Really ought to be started in a parking space unless otherwise specified?
        
        // Find the tower frequency - this is dependent on the ATC system being initialised before the AI system
-       // FIXME - ATM this is hardwired.
-       airportID = "KEMT";
+       airportID = ICAO;
        AirportATC a;
-       if(globals->get_ATC_mgr()->GetAirportATCDetails((string)airportID, &a)) {
+       if(globals->get_ATC_mgr()->GetAirportATCDetails(airportID, &a)) {
                if(a.tower_freq) {      // Has a tower
                        tower = (FGTower*)globals->get_ATC_mgr()->GetATCPointer((string)airportID, TOWER);      // Maybe need some error checking here
                        freq = (double)tower->get_freq() / 100.0;
@@ -92,94 +171,220 @@ void FGAILocalTraffic::Init() {
                //cout << "Unable to find airport details in FGAILocalTraffic::Init()\n";
        }
 
-       // Initiallise the FGAirportData structure
+       // Initialise the relevant FGGround
        // This needs a complete overhaul soon - what happens if we have 2 AI planes at same airport - they don't both need a structure
        // This needs to be handled by the ATC manager or similar so only one set of physical data per airport is instantiated
        // ie. TODO TODO FIXME FIXME
        airport.Init();
        
-}
+       // Get the airport elevation
+       aptElev = dclGetAirportElev(airportID.c_str()) * SG_FEET_TO_METER;
+       //cout << "Airport elev in AILocalTraffic = " << aptElev << '\n';
+       // WARNING - we use this elev for the whole airport - some assumptions in the code 
+       // might fall down with very slopey airports.
 
-// Commands to do something from higher level logic
-void FGAILocalTraffic::FlyCircuits(int numCircuits, bool tag) {
-       circuitsToFly += numCircuits - 1;       // Hack (-1) because we only test and decrement circuitsToFly after landing
-                                                                               // thus flying one to many circuits.  TODO - Need to sort this out better!
-       touchAndGo = tag;
-       
-       //At the moment we'll assume that we are always finished previous circuits when called,
-       //And just teleport to the threshold to start.
-       //This is a hack though, we need to check where we are and taxi out if appropriate.
-       operatingState = IN_PATTERN;
-
-       // Hardwire to KEMT for now
-       // Hardwired points at each end of KEMT runway
-       Point3D P010(-118.037483, 34.081358, 296 * SG_FEET_TO_METER);
-       Point3D P190(-118.032308, 34.090456, 299.395263 * SG_FEET_TO_METER);
-       Point3D takeoff_end;
-       bool d010 = true;       // use this to change the hardwired runway direction
-       if(d010) {
-               rwy.threshold_pos = P010;
-               takeoff_end = P190;
-               rwy.hdg = 25.32;        //from default.apt
-               rwy.ID = 1;
-               patternDirection = -1;  // Left
-               pos.setelev(rwy.threshold_pos.elev() + (-8.5 * SG_FEET_TO_METER));  // This is a complete hack - the rendered runway takes the underlying scenery elev rather than the published runway elev so I should use height above terrain or something.
-       } else {
-               rwy.threshold_pos = P190;
-               takeoff_end = P010;
-               rwy.hdg = 205.32;
-               rwy.ID = 19;
-               patternDirection = 1;   // Right
-               pos.setelev(rwy.threshold_pos.elev() + (-0.0 * SG_FEET_TO_METER));  // This is a complete hack - the rendered runway takes the underlying scenery elev rather than the published runway elev so I should use height above terrain or something.
+       //cout << "In Init(), initialState = " << initialState << '\n';
+       operatingState = initialState;
+       switch(operatingState) {
+       case PARKED:
+               ourGate = airport.GetGateNode();
+               if(ourGate == NULL) {
+                       // Implies no available gates - what shall we do?
+                       // For now just vanish the plane - possibly we can make this more elegant in the future
+                       SG_LOG(SG_GENERAL, SG_ALERT, "No gate found by FGAILocalTraffic whilst attempting Init at " << airportID << '\n');
+                       return(false);
+               }
+               pitch = 0.0;
+               roll = 0.0;
+               vel = 0.0;
+               slope = 0.0;
+               pos = ourGate->pos;
+               pos.setelev(aptElev);
+               hdg = ourGate->heading;
+               
+               // Now we've set the position we can do the ground elev
+               elevInitGood = false;
+               inAir = false;
+               DoGroundElev();
+               
+               Transform();
+               break;
+       case TAXIING:
+               // FIXME - implement this case properly
+               return(false);  // remove this line when fixed!
+               break;
+       case IN_PATTERN:
+               // For now we'll always start the in_pattern case on the threshold ready to take-off
+               // since we've got the implementation for this case already.
+               // TODO - implement proper generic in_pattern startup.
+               
+               // Get the active runway details (and copy them into rwy)
+               GetRwyDetails();
+
+               // Initial position on threshold for now
+               pos.setlat(rwy.threshold_pos.lat());
+               pos.setlon(rwy.threshold_pos.lon());
+               pos.setelev(rwy.threshold_pos.elev());
+               hdg = rwy.hdg;
+               
+               // Now we've set the position we can do the ground elev
+               // This might not always be necessary if we implement in-air start
+               elevInitGood = false;
+               inAir = false;
+               DoGroundElev();
+               
+               pitch = 0.0;
+               roll = 0.0;
+               leg = TAKEOFF_ROLL;
+               vel = 0.0;
+               slope = 0.0;
+               
+               circuitsToFly = 0;              // ie just fly this circuit and then stop
+               touchAndGo = false;
+               // FIXME TODO - pattern direction is still hardwired
+               patternDirection = -1;          // Left
+               // At the bare minimum we ought to make sure it goes the right way at dual parallel rwy airports!
+               if(rwy.rwyID.size() == 3) {
+                       patternDirection = (rwy.rwyID.substr(2,1) == "R" ? 1 : -1);
+               }
+               
+               operatingState = IN_PATTERN;
+               
+               Transform();
+               break;
+       default:
+               SG_LOG(SG_GENERAL, SG_ALERT, "Attempt to set unknown operating state in FGAILocalTraffic.Init(...)\n");
+               return(false);
        }
        
-       //rwy.threshold_pos.setlat(34.081358);
-       //rwy.threshold_pos.setlon(-118.037483);
-       //rwy.mag_hdg = 12.0;
-       //rwy.mag_var = 14.0;
-       //rwy.hdg = rwy.mag_hdg + rwy.mag_var;
-       //rwy.threshold_pos.setelev(296 * SG_FEET_TO_METER);
        
-       // Initial position on threshold for now
-       // TODO - check wind / default runway
-       pos.setlat(rwy.threshold_pos.lat());
-       pos.setlon(rwy.threshold_pos.lon());
-       hdg = rwy.hdg;
-       
-       pitch = 0.0;
-       roll = 0.0;
-       leg = TAKEOFF_ROLL;
-       vel = 0.0;
-       slope = 0.0;
+       return(true);
+}
+
+// Commands to do something from higher level logic
+void FGAILocalTraffic::FlyCircuits(int numCircuits, bool tag) {
+       //cout << "FlyCircuits called" << endl;
        
-       // Set the projection for the local area
-       ortho.Init(rwy.threshold_pos, rwy.hdg); 
-       rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos);        // should come out as zero
-       // Hardwire to KEMT for now
-       rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
-       //cout << "*********************************************************************************\n";
-       //cout << "*********************************************************************************\n";
-       //cout << "*********************************************************************************\n";
-       //cout << "end1ortho = " << rwy.end1ortho << '\n';
-       //cout << "end2ortho = " << rwy.end2ortho << '\n';      // end2ortho.x() should be zero or thereabouts
+       switch(operatingState) {
+       case IN_PATTERN:
+               circuitsToFly += numCircuits;
+               return;
+               break;
+       case TAXIING:
+               // For now we'll punt this and do nothing
+               break;
+       case PARKED:
+               circuitsToFly = numCircuits - 1;        // Hack (-1) because we only test and decrement circuitsToFly after landing
+                                                                               // thus flying one too many circuits.  TODO - Need to sort this out better!
+               touchAndGo = tag;
        
-       Transform();
+               // Get the active runway details (and copy them into rwy)
+               GetRwyDetails();
+               
+               // Get the takeoff node for the active runway, get a path to it and start taxiing
+               path = airport.GetPath(ourGate, rwy.rwyID);
+               if(path.size() < 2) {
+                       // something has gone wrong
+                       SG_LOG(SG_GENERAL, SG_ALERT, "Invalid path from gate to theshold in FGAILocalTraffic::FlyCircuits\n");
+                       return;
+               }
+               /*
+               cout << "path returned was:" << endl;
+               for(unsigned int i=0; i<path.size(); ++i) {
+                       switch(path[i]->struct_type) {
+                       case NODE:
+                               cout << "NODE " << ((node*)(path[i]))->nodeID << endl;
+                               break;
+                       case ARC:
+                               cout << "ARC\n";
+                               break;
+                       }
+               }
+               */
+               // pop the gate - we're here already!
+               path.erase(path.begin());
+               //path.erase(path.begin());
+               /*
+               cout << "path after popping front is:" << endl;
+               for(unsigned int i=0; i<path.size(); ++i) {
+                       switch(path[i]->struct_type) {
+                       case NODE:
+                               cout << "NODE " << ((node*)(path[i]))->nodeID << endl;
+                               break;
+                       case ARC:
+                               cout << "ARC\n";
+                               break;
+                       }
+               }
+               */
+               
+               taxiState = TD_OUTBOUND;
+               StartTaxi();
+               
+               // Maybe the below should be set when we get to the threshold and prepare for TO?
+               // FIXME TODO - pattern direction is still hardwired
+               patternDirection = -1;          // Left
+               // At the bare minimum we ought to make sure it goes the right way at dual parallel rwy airports!
+               if(rwy.rwyID.size() == 3) {
+                       patternDirection = (rwy.rwyID.substr(2,1) == "R" ? 1 : -1);
+               }
+
+               Transform();
+               break;
+       }
 }   
 
 // Run the internal calculations
 void FGAILocalTraffic::Update(double dt) {
        switch(operatingState) {
        case IN_PATTERN:
+               //cout << "In IN_PATTERN\n";
+               if(!inAir) DoGroundElev();
+               if(!elevInitGood) {
+                       if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
+                               pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
+                               //cout << "TAKEOFF_ROLL, POS = " << pos.lon() << ", " << pos.lat() << ", " << pos.elev() << '\n';
+                               //Transform();
+                               aip.setVisible(true);
+                               //cout << "Making plane visible!\n";
+                               elevInitGood = true;
+                       }
+               }
                FlyTrafficPattern(dt);
                Transform();
                break;
        case TAXIING:
+               //cout << "In TAXIING\n";
+               if(!elevInitGood) {
+                       //DoGroundElev();
+                       if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
+                               pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
+                               //Transform();
+                               aip.setVisible(true);
+                               //Transform();
+                               //cout << "Making plane visible!\n";
+                               elevInitGood = true;
+                       }
+               }
                DoGroundElev();
                Taxi(dt);
                Transform();
                break;
        case PARKED:
+               //cout << "In PARKED\n";
+               if(!elevInitGood) {
+                       DoGroundElev();
+                       if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
+                               pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
+                               //Transform();
+                               aip.setVisible(true);
+                               //Transform();
+                               //cout << "Making plane visible!\n";
+                               elevInitGood = true;
+                       }
+               }
                // Do nothing
+               Transform();
                break;
        default:
                break;
@@ -192,7 +397,6 @@ void FGAILocalTraffic::Update(double dt) {
 void FGAILocalTraffic::FlyTrafficPattern(double dt) {
        // Need to differentiate between in-air (IAS governed) and on-ground (vel governed)
        // Take-off is an interesting case - we are on the ground but takeoff speed is IAS governed.
-       bool inAir = true;      // FIXME - possibly make into a class variable
        
        static bool transmitted = false;        // FIXME - this is a hack
 
@@ -222,18 +426,22 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
 
        switch(leg) {
        case TAKEOFF_ROLL:
-               inAir = false;
+               //inAir = false;
                track = rwy.hdg;
                if(vel < 80.0) {
                        double dveldt = 5.0;
                        vel += dveldt * dt;
                }
+               if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
+                       pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
+               }
                IAS = vel + (cos((hdg - wind_from) * DCL_DEGREES_TO_RADIANS) * wind_speed);
                if(IAS >= 70) {
                        leg = CLIMBOUT;
                        pitch = 10.0;
                        IAS = best_rate_of_climb_speed;
                        slope = 7.0;
+                       inAir = true;
                }
                break;
        case CLIMBOUT:
@@ -348,15 +556,26 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
                // Try and track the extended centreline
                track = rwy.hdg - (0.2 * orthopos.x());
                //cout << "orthopos.x() = " << orthopos.x() << " hdg = " << hdg << '\n';
-               if(pos.elev() <= rwy.threshold_pos.elev()) {
-                       pos.setelev(rwy.threshold_pos.elev());// + (-8.5 * SG_FEET_TO_METER));  // This is a complete hack - the rendered runway takes the underlying scenery elev rather than the published runway elev so I should use height above terrain or something.
-                       slope = 0.0;
-                       pitch = 0.0;
-                       leg = LANDING_ROLL;
+               if(pos.elev() < (rwy.threshold_pos.elev()+20.0+wheelOffset)) {
+                       DoGroundElev(); // Need to call it here expicitly on final since it's only called
+                                       // for us in update(...) when the inAir flag is false.
+               }
+               if(pos.elev() < (rwy.threshold_pos.elev()+10.0+wheelOffset)) {
+                       if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
+                               if((aip.getFGLocation()->get_cur_elev_m() + wheelOffset) > pos.elev()) {
+                                       slope = 0.0;
+                                       pitch = 0.0;
+                                       leg = LANDING_ROLL;
+                                       inAir = false;
+                               }
+                       }       // else need a fallback position based on arpt elev in case ground elev determination fails?
                }
                break;
        case LANDING_ROLL:
-               inAir = false;
+               //inAir = false;
+               if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
+                       pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
+               }
                track = rwy.hdg;
                double dveldt = -5.0;
                vel += dveldt * dt;
@@ -506,8 +725,8 @@ void FGAILocalTraffic::ExitRunway(Point3D orthopos) {
                        }
                        ++nItr;
                }
-               in_dest = airport.GetGateNode();
-               if(in_dest == NULL) {
+               ourGate = airport.GetGateNode();
+               if(ourGate == NULL) {
                        // Implies no available gates - what shall we do?
                        // For now just vanish the plane - possibly we can make this more elegant in the future
                        SG_LOG(SG_GENERAL, SG_ALERT, "No gate found by FGAILocalTraffic whilst landing at " << airportID << '\n');
@@ -515,7 +734,7 @@ void FGAILocalTraffic::ExitRunway(Point3D orthopos) {
                        operatingState = PARKED;
                        return;
                }
-               path = airport.GetPath(rwyExit, in_dest);
+               path = airport.GetPath(rwyExit, ourGate);
                /*
                cout << "path returned was:" << endl;
                for(unsigned int i=0; i<path.size(); ++i) {
@@ -590,6 +809,40 @@ void FGAILocalTraffic::StartTaxi() {
        //cout << "First taxi heading is " << desiredTaxiHeading << endl;
 }
 
+// speed in knots, headings in degrees, radius in meters.
+static double TaxiTurnTowardsHeading(double current_hdg, double desired_hdg, double speed, double radius, double dt) {
+       // wrap heading - this prevents a logic bug where the plane would just go round in circles!!
+       while(current_hdg < 0.0) {
+               current_hdg += 360.0;
+       }
+       while(current_hdg > 360.0) {
+               current_hdg -= 360.0;
+       }
+       if(fabs(current_hdg - desired_hdg) > 0.1) {
+               // Which is the quickest direction to turn onto heading?
+               if(desired_hdg > current_hdg) {
+                       if((desired_hdg - current_hdg) <= 180) {
+                               // turn right
+                               current_hdg += ((speed * 0.514444 * dt) / (radius * DCL_PI)) * 180.0;
+                               // TODO - check that increments are less than the delta that we check for the right direction
+                               // Probably need to reduce convergence speed as convergence is reached
+                       } else {
+                               current_hdg -= ((speed * 0.514444 * dt) / (radius * DCL_PI)) * 180.0;   
+                       }
+               } else {
+                       if((current_hdg - desired_hdg) <= 180) {
+                               // turn left
+                               current_hdg -= ((speed * 0.514444 * dt) / (radius * DCL_PI)) * 180.0;
+                               // TODO - check that increments are less than the delta that we check for the right direction
+                               // Probably need to reduce convergence speed as convergence is reached
+                       } else {
+                               current_hdg += ((speed * 0.514444 * dt) / (radius * DCL_PI)) * 180.0;   
+                       }
+               }               
+       }
+       return(current_hdg);
+}
+
 void FGAILocalTraffic::Taxi(double dt) {
        //cout << "Taxi called" << endl;
        // Logic - if we are further away from next point than turn radius then head for it
@@ -598,6 +851,11 @@ void FGAILocalTraffic::Taxi(double dt) {
 
        //Point3D orthopos = ortho.ConvertToLocal(pos); // ortho position of the plane
        desiredTaxiHeading = GetHeadingFromTo(pos, nextTaxiNode->pos);
+       
+       bool lastNode = (taxiPathPos == path.size() ? true : false);
+       if(lastNode) {
+               //cout << "LAST NODE\n";
+       }
 
        // HACK ALERT! - for now we will taxi at constant speed for straights and turns
        
@@ -605,37 +863,16 @@ void FGAILocalTraffic::Taxi(double dt) {
        double dist_to_go = dclGetHorizontalSeparation(pos, nextTaxiNode->pos); // we may be able to do this more cheaply using orthopos
        //cout << "dist_to_go = " << dist_to_go << endl;
        if((nextTaxiNode->type == GATE) && (dist_to_go <= 0.1)) {
+               // This might be more robust to outward paths starting with a gate if we check for either
+               // last node or TD_INBOUND ?
                // park up
-               //taxiing = false;
-               //parked = true;
                operatingState = PARKED;
-       } else if((dist_to_go > taxiTurnRadius) || (nextTaxiNode->type == GATE)) {
+       } else if(((dist_to_go > taxiTurnRadius) || (nextTaxiNode->type == GATE)) && (!liningUp)){
                // if the turn radius is r, and speed is s, then in a time dt we turn through
                // ((s.dt)/(PI.r)) x 180 degrees
                // or alternatively (s.dt)/r radians
                //cout << "hdg = " << hdg << " desired taxi heading = " << desiredTaxiHeading << '\n';
-               if(fabs(hdg - desiredTaxiHeading) > 0.1) {
-                       // Which is the quickest direction to turn onto heading?
-                       if(desiredTaxiHeading > hdg) {
-                               if((desiredTaxiHeading - hdg) <= 180) {
-                                       // turn right
-                                       hdg += ((nominalTaxiSpeed * 0.514444 * dt) / (taxiTurnRadius * DCL_PI)) * 180.0;
-                                       // TODO - check that increments are less than the delta that we check for the right direction
-                                       // Probably need to reduce convergence speed as convergence is reached
-                               } else {
-                                       hdg -= ((nominalTaxiSpeed * 0.514444 * dt) / (taxiTurnRadius * DCL_PI)) * 180.0;        
-                               }
-                       } else {
-                               if((hdg - desiredTaxiHeading) <= 180) {
-                                       // turn left
-                                       hdg -= ((nominalTaxiSpeed * 0.514444 * dt) / (taxiTurnRadius * DCL_PI)) * 180.0;
-                                       // TODO - check that increments are less than the delta that we check for the right direction
-                                       // Probably need to reduce convergence speed as convergence is reached
-                               } else {
-                                       hdg += ((nominalTaxiSpeed * 0.514444 * dt) / (taxiTurnRadius * DCL_PI)) * 180.0;        
-                               }
-                       }               
-               }
+               hdg = TaxiTurnTowardsHeading(hdg, desiredTaxiHeading, nominalTaxiSpeed, taxiTurnRadius, dt);
                double vel = nominalTaxiSpeed;
                //cout << "vel = " << vel << endl;
                double dist = vel * 0.514444 * dt;
@@ -648,6 +885,33 @@ void FGAILocalTraffic::Taxi(double dt) {
                if(aip.getFGLocation()->get_cur_elev_m() > -9990) {
                        pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
                } // else don't change the elev until we get a valid ground elev again!
+       } else if(lastNode) {
+               if(taxiState == TD_OUTBOUND) {
+                       if((!liningUp) && (dist_to_go <= taxiTurnRadius)) {
+                               liningUp = true;
+                       }
+                       if(liningUp) {
+                               hdg = TaxiTurnTowardsHeading(hdg, rwy.hdg, nominalTaxiSpeed, taxiTurnRadius, dt);
+                               double vel = nominalTaxiSpeed;
+                               //cout << "vel = " << vel << endl;
+                               double dist = vel * 0.514444 * dt;
+                               //cout << "dist = " << dist << endl;
+                               double track = hdg;
+                               //cout << "track = " << track << endl;
+                               double slope = 0.0;
+                               pos = dclUpdatePosition(pos, track, slope, dist);
+                               //cout << "Updated position...\n";
+                               if(aip.getFGLocation()->get_cur_elev_m() > -9990) {
+                                       pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
+                               } // else don't change the elev until we get a valid ground elev again!
+                               if(fabs(hdg - rwy.hdg) <= 1.0) {
+                                       operatingState = IN_PATTERN;
+                                       leg = TAKEOFF_ROLL;
+                                       inAir = false;
+                                       liningUp = false;
+                               }
+                       }
+               } // else at the moment assume TD_INBOUND always ends in a gate in which case we can ignore it
        } else {
                // Time to turn (we've already checked it's not the end we're heading for).
                // set the target node to be the next node which will prompt automatically turning onto
index 12373988d0bbef20a5fd54b184610848c4a19514..e7b00d2694494ac9ed368ec00525255845a5c037 100644 (file)
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-/*****************************************************************
-*
-* WARNING - Curt has some ideas about AI traffic so anything in here
-* may get rewritten or scrapped.  Contact Curt curt@flightgear.org 
-* before spending any time or effort on this code!!!
-*
-******************************************************************/
-
 #ifndef _FG_AILocalTraffic_HXX
 #define _FG_AILocalTraffic_HXX
 
@@ -40,6 +32,9 @@
 #include "ATCProjection.hxx"
 #include "ground.hxx"
 
+#include <string>
+SG_USING_STD(string);
+
 typedef enum PatternLeg {
        TAKEOFF_ROLL,
        CLIMBOUT,
@@ -74,7 +69,9 @@ typedef struct RunwayDetails {
        double mag_hdg;
        double mag_var;
        double hdg;             // true runway heading
+       double length;  // In *METERS*
        int ID;         // 1 -> 36
+       string rwyID;
 };
 
 typedef struct StartofDescent {
@@ -91,7 +88,7 @@ public:
        ~FGAILocalTraffic();
        
        // Initialise
-       void Init();
+       bool Init(string ICAO, OperatingState initialState = PARKED, PatternLeg initialLeg = DOWNWIND);
        
        // Run the internal calculations
        void Update(double dt);
@@ -118,7 +115,8 @@ private:
        // and the runway aligned with the y axis.
        
        // Airport/runway/pattern details
-       char* airportID;        // The ICAO code of the airport that we're operating around
+       string airportID;       // The ICAO code of the airport that we're operating around
+       double aptElev;         // Airport elevation
        FGGround airport;       // FIXME FIXME FIXME This is a complete hardwired cop-out at the moment - we need to connect to the correct ground in the same way we do to the tower.
        FGTower* tower; // A pointer to the tower control.
        RunwayDetails rwy;
@@ -144,6 +142,8 @@ private:
        
        // Physical/rendering stuff
        double wheelOffset;             // Height above ground at which we need to render the plane whilst taxiing
+       bool elevInitGood;              // We have had at least one good elev reading
+       bool inAir;                             // True when off the ground 
        
        // environment - some of this might get moved into FGAIPlane
        SGPropertyNode* wind_from_hdg;  //degrees
@@ -165,11 +165,12 @@ private:
        double desiredTaxiHeading;
        double taxiTurnRadius;
        double nominalTaxiSpeed;
-       Gate* in_dest;
+       Gate* ourGate;
        ground_network_path_type path;  // a path through the ground network for the plane to taxi
-       int taxiPathPos;        // position of iterator in taxi path when applicable
+       unsigned int taxiPathPos;       // position of iterator in taxi path when applicable
        node* nextTaxiNode;     // next node in taxi path
        //Runway out_dest; //FIXME - implement this
+       bool liningUp;  // Set true when the turn onto the runway heading is commenced when taxiing out
 
        void FlyTrafficPattern(double dt);
 
@@ -188,6 +189,8 @@ private:
        void GetNextTaxiNode();
        
        void DoGroundElev();
+       
+       void GetRwyDetails();
 };
 
 #endif  // _FG_AILocalTraffic_HXX
index 5dd7bbee42ee65b522d2217afb544681d6f7c350..85ec947839a5a1289b6ef6caeee6b1a94d0f3ffa 100644 (file)
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-/*****************************************************************
-*
-* WARNING - Curt has some ideas about AI traffic so anything in here
-* may get rewritten or scrapped.  Contact Curt curt@flightgear.org 
-* before spending any time or effort on this code!!!
-*
-******************************************************************/
-
-
-
 #include <Main/fgfs.hxx>
 #include <Main/fg_props.hxx>
 
@@ -50,7 +40,8 @@ void FGAIMgr::init() {
        // Hard wire some local traffic for now.
        // This is regardless of location and hence *very* ugly but it is a start.
        FGAILocalTraffic* local_traffic = new FGAILocalTraffic;
-       local_traffic->Init();
+       //local_traffic->Init("KEMT", IN_PATTERN, TAKEOFF_ROLL);
+       local_traffic->Init("KEMT");
        local_traffic->FlyCircuits(1, true);    // Fly 2 circuits with touch & go in between
        ai_list.push_back(local_traffic);
 }
@@ -64,12 +55,15 @@ void FGAIMgr::unbind() {
 void FGAIMgr::update(double dt) {
        // Don't update any planes for first 50 runs through - this avoids some possible initialisation anomalies
        static int i = 0;
-       i++;
        if(i < 50) {
+               i++;
                return;
        }
        
        // Traverse the list of active planes and run all their update methods
+       // TODO - spread the load - not all planes should need updating every frame.
+       // Note that this will require dt to be calculated for each plane though
+       // since they rely on it to calculate distance travelled.
        ai_list_itr = ai_list.begin();
        while(ai_list_itr != ai_list.end()) {
                (*ai_list_itr)->Update(dt);
index 35276aeaedd5c14776f5615a7f0c4f673f9f5ff5..ec4c4e40ca06fee2a9fdaf0458ffc2ff5bd04e53 100644 (file)
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-/*****************************************************************
-*
-* WARNING - Curt has some ideas about AI traffic so anything in here
-* may get rewritten or scrapped.  Contact Curt curt@flightgear.org 
-* before spending any time or effort on this code!!!
-*
-******************************************************************/
-
 #ifndef _FG_AIMGR_HXX
 #define _FG_AIMGR_HXX