]> git.mxchange.org Git - flightgear.git/blobdiff - src/ATC/AILocalTraffic.cxx
Migrate FlightGear code to use "#include SG_GL*" defined in
[flightgear.git] / src / ATC / AILocalTraffic.cxx
index 99a8aae8f4eeed50a26540c85cfaae5e23166690..2988f2e06b098aca2626fd0f6a84dc100eaeb52d 100644 (file)
@@ -38,6 +38,7 @@ during descent to avoid occasionally landing short or long.
 
 #include <Airports/runways.hxx>
 #include <Main/globals.hxx>
+#include <Main/viewer.hxx>
 #include <Scenery/scenery.hxx>
 #include <Scenery/tilemgr.hxx>
 #include <simgear/math/point3d.hxx>
@@ -106,6 +107,7 @@ FGAILocalTraffic::FGAILocalTraffic() {
        contactTower = false;
        contactGround = false;
        _taxiToGA = false;
+       _removeSelf = false;
        
        descending = false;
        targetDescentRate = 0.0;
@@ -118,6 +120,8 @@ FGAILocalTraffic::FGAILocalTraffic() {
        _savedSlope = 0.0;
        
        _controlled = false;
+       
+       _invisible = false;
 }
 
 FGAILocalTraffic::~FGAILocalTraffic() {
@@ -128,7 +132,7 @@ void FGAILocalTraffic::GetAirportDetails(string id) {
        AirportATC a;
        if(ATC->GetAirportATCDetails(airportID, &a)) {
                if(a.tower_freq) {      // Has a tower - TODO - check the opening hours!!!
-                       tower = (FGTower*)ATC->GetATCPointer(airportID, TOWER); // Maybe need some error checking here
+                       tower = (FGTower*)ATC->GetATCPointer(airportID, TOWER);
                        if(tower == NULL) {
                                // Something has gone wrong - abort or carry on with un-towered operation?
                                SG_LOG(SG_ATC, SG_ALERT, "ERROR - can't get a tower pointer from tower control for " << airportID << " in FGAILocalTraffic::GetAirportDetails() :-(");
@@ -163,11 +167,12 @@ void FGAILocalTraffic::GetAirportDetails(string id) {
 void FGAILocalTraffic::GetRwyDetails(string id) {
        //cout << "GetRwyDetails called" << endl;
        
-       rwy.rwyID = tower->GetActiveRunway();
-       //cout << "id = " << id << '\n';
-       //cout << "Returned id is " << tower->get_ident() << '\n';
-       //cout << "Returned name is " << tower->get_name() << '\n';
-       //cout << "rwy.rwyID = " << rwy.rwyID << '\n';
+       if(_controlled) {
+               rwy.rwyID = tower->GetActiveRunway();
+       } else {
+               // TODO - get a proper runway ID from uncontrolled airports
+               rwy.rwyID = "00";
+       }
        
        // Now we need to get the threshold position and rwy heading
        
@@ -243,11 +248,15 @@ bool FGAILocalTraffic::Init(const string& callsign, string ICAO, OperatingState
                patternDirection = (rwy.rwyID.substr(2,1) == "R" ? 1 : -1);
        }
        
-       // TODO - this assumes a controlled airport - make sure we revert to CTAF etc if uncontrolled or after-hours.
-       if((initialState == PARKED) || (initialState == TAXIING)) {
-               freq = (double)ground->get_freq() / 100.0;
+       if(_controlled) {
+               if((initialState == PARKED) || (initialState == TAXIING)) {
+                       freq = (double)ground->get_freq() / 100.0;
+               } else {
+                       freq = (double)tower->get_freq() / 100.0;
+               }
        } else {
-               freq = (double)tower->get_freq() / 100.0;
+               freq = 122.8;
+               // TODO - find the proper freq if CTAF or unicom or after-hours.
        }
 
        //cout << "In Init(), initialState = " << initialState << endl;
@@ -283,7 +292,11 @@ bool FGAILocalTraffic::Init(const string& callsign, string ICAO, OperatingState
                // FIXME - implement this case properly
                // For now we'll assume that the plane should start at the hold short in this case
                // and that we're working without ground network elements.  Ie. an airport with no facility file.
-               tuned_station = tower;
+               if(_controlled) {
+                       tuned_station = tower;
+               } else {
+                       tuned_station = NULL;
+               }
                freeTaxi = true;
                // Set a position and orientation in an approximate place for hold short.
                //cout << "rwy.width = " << rwy.width << '\n';
@@ -320,7 +333,11 @@ bool FGAILocalTraffic::Init(const string& callsign, string ICAO, OperatingState
                
                //cout << "Starting in pattern...\n";
                
-               tuned_station = tower;
+               if(_controlled) {
+                       tuned_station = tower;
+               } else {
+                       tuned_station = NULL;
+               }
                
                circuitsToFly = 0;              // ie just fly this circuit and then stop
                touchAndGo = false;
@@ -339,7 +356,9 @@ bool FGAILocalTraffic::Init(const string& callsign, string ICAO, OperatingState
                        IAS = 90.0;
                        descending = false;
                        _aip.setVisible(true);
-                       tower->RegisterAIPlane(plane, this, CIRCUIT, DOWNWIND);
+                       if(_controlled) {
+                               tower->RegisterAIPlane(plane, this, CIRCUIT, DOWNWIND);
+                       }
                        Transform();
                } else {                        
                        // Default to initial position on threshold for now
@@ -452,6 +471,16 @@ void FGAILocalTraffic::FlyCircuits(int numCircuits, bool tag) {
 // Run the internal calculations
 void FGAILocalTraffic::Update(double dt) {
        //cout << "U" << flush;
+       
+       // we shouldn't really need this since there's a LOD of 10K on the whole plane anyway I think.
+       // At the moment though I need to to avoid DList overflows - the whole plane LOD obviously isn't getting picked up.
+       if(!_invisible) {
+               if(dclGetHorizontalSeparation(_pos, Point3D(fgGetDouble("/position/longitude-deg"), fgGetDouble("/position/latitude-deg"), 0.0)) > 8000) _aip.setVisible(false);
+               else _aip.setVisible(true);
+       } else {
+               _aip.setVisible(false);
+       }
+       
        //double responseTime = 10.0;           // seconds - this should get more sophisticated at some point
        responseCounter += dt;
        if((contactTower) && (responseCounter >= 8.0)) {
@@ -493,16 +522,28 @@ void FGAILocalTraffic::Update(double dt) {
                string trns = "GA Parking, Thank you and Good Day";
                //double f = globals->get_ATC_mgr()->GetFrequency(airportID, GROUND) / 100.0;   
                pending_transmission = trns;
-               ConditionalTransmit(5.0);
-               tower->DeregisterAIPlane(plane.callsign);
+               ConditionalTransmit(5.0, 99);
                _taxiToGA = false;
-               // HACK - check if we are at a simple airport or not first
-               globals->get_AI_mgr()->ScheduleRemoval(plane.callsign);
-       }               
+               if(_controlled) {
+                       tower->DeregisterAIPlane(plane.callsign);
+               }
+               // NOTE - we can't delete this instance yet since then the frequency won't get release when the message display finishes.
+       }
+
+       if((_removeSelf) && (responseCounter >= 8.0)) {
+               _removeSelf = false;
+               // MEGA HACK - check if we are at a simple airport or not first instead of simply hardwiring KEMT as the only non-simple airport.
+               // TODO FIXME TODO FIXME !!!!!!!
+               if(airportID != "KEMT") globals->get_AI_mgr()->ScheduleRemoval(plane.callsign);
+       }
        
        if((changeFreq) && (responseCounter > 8.0)) {
                switch(changeFreqType) {
                case TOWER:
+                       if(!tower) {
+                               SG_LOG(SG_ATC, SG_ALERT, "ERROR: Trying to change frequency to tower in FGAILocalTraffic, but tower is NULL!!!");
+                               break;
+                       }
                        tuned_station = tower;
                        freq = (double)tower->get_freq() / 100.0;
                        //Transmit("DING!");
@@ -520,12 +561,17 @@ void FGAILocalTraffic::Update(double dt) {
                        Transmit(2);
                        break;
                case GROUND:
+                       if(!tower) {
+                               SG_LOG(SG_ATC, SG_ALERT, "ERROR: Trying to change frequency to ground in FGAILocalTraffic, but tower is NULL!!!");
+                               break;
+                       }
+                       if(!ground) {
+                               SG_LOG(SG_ATC, SG_ALERT, "ERROR: Trying to change frequency to ground in FGAILocalTraffic, but ground is NULL!!!");
+                               break;
+                       }
                        tower->DeregisterAIPlane(plane.callsign);
                        tuned_station = ground;
                        freq = (double)ground->get_freq() / 100.0;
-                       // HACK - check if we are at a simple airport or not first
-                       // TODO FIXME TODO FIXME !!!!!!!
-                       if(airportID != "KEMT") globals->get_AI_mgr()->ScheduleRemoval(plane.callsign);
                        break;
                // And to avoid compiler warnings...
                case APPROACH:  break;
@@ -669,8 +715,13 @@ void FGAILocalTraffic::Update(double dt) {
                                // Do some communication
                                // airport name + tower + airplane callsign + location + request taxi for + operation type + ?
                                string trns = "";
-                               trns += tower->get_name();
-                               trns += " tower ";
+                               if(_controlled) {
+                                       trns += tower->get_name();
+                                       trns += " tower ";
+                               } else {
+                                       trns += "Traffic ";
+                                       // TODO - get the airport name somehow if uncontrolled
+                               }
                                trns += plane.callsign;
                                trns += " on apron parking request taxi for traffic pattern";
                                //cout << "trns = " << trns << endl;
@@ -1256,6 +1307,10 @@ void FGAILocalTraffic::ProcessCallback(int code) {
                tower->ReportDownwind(plane.callsign);
        } else if(code == 13) {
                tower->ReportFinal(plane.callsign);
+       } else if(code == 99) { // Flag this instance for deletion
+               responseCounter = 0;
+               _removeSelf = true;
+               SG_LOG(SG_ATC, SG_INFO, "AI local traffic " << plane.callsign << " delete instance callback called.");
        }
 }
 
@@ -1325,9 +1380,10 @@ void FGAILocalTraffic::ExitRunway(Point3D orthopos) {
        } else {
                // Something must have gone wrong with the ground network file - or there is only a rwy here and no exits defined
                SG_LOG(SG_ATC, SG_INFO, "No exits found by FGAILocalTraffic from runway " << rwy.rwyID << " at " << airportID << '\n');
-               //cout << "No exits found by " << plane.callsign << " from runway " << rwy.rwyID << " at " << airportID << '\n';
+               //if(airportID == "KRHV") cout << "No exits found by " << plane.callsign << " from runway " << rwy.rwyID << " at " << airportID << '\n';
                // What shall we do - just remove the plane from sight?
                _aip.setVisible(false);
+               _invisible = true;
                //cout << "Setting visible false\n";
                //tower->ReportRunwayVacated(plane.callsign);
                string trns = "Clear of the runway ";
@@ -1511,17 +1567,24 @@ void FGAILocalTraffic::Taxi(double dt) {
 // Either this function or the logic of how often it is called
 // will almost certainly change.
 void FGAILocalTraffic::DoGroundElev() {
-
        // It would be nice if we could set the correct tile center here in order to get a correct
        // answer with one call to the function, but what I tried in the two commented-out lines
        // below only intermittently worked, and I haven't quite groked why yet.
        //SGBucket buck(pos.lon(), pos.lat());
        //aip.getSGLocation()->set_tile_center(Point3D(buck.get_center_lon(), buck.get_center_lat(), 0.0));
        
+       // Only do the proper hitlist stuff if we are within visible range of the viewer.
        double visibility_meters = fgGetDouble("/environment/visibility-m");
+       FGViewer* vw = globals->get_current_view();
+       if(dclGetHorizontalSeparation(_pos, Point3D(vw->getLongitude_deg(), vw->getLatitude_deg(), 0.0)) > visibility_meters) {
+               _aip.getSGLocation()->set_cur_elev_m(aptElev);
+               return;
+       }
+       
+       
        //globals->get_tile_mgr()->prep_ssg_nodes( acmodel_location,
        globals->get_tile_mgr()->prep_ssg_nodes( _aip.getSGLocation(),  visibility_meters );
-        Point3D scenery_center = globals->get_scenery()->get_center();
+       Point3D scenery_center = globals->get_scenery()->get_center();
        globals->get_tile_mgr()->update( _aip.getSGLocation(), visibility_meters, (_aip.getSGLocation())->get_absolute_view_pos( scenery_center ) );
        // save results of update in SGLocation for fdm...