]> git.mxchange.org Git - flightgear.git/blobdiff - src/AIModel/AIAircraft.cxx
merging in topic/makej
[flightgear.git] / src / AIModel / AIAircraft.cxx
index 8cc5089ad4e3c0de814af03691e43b51a29d0417..3f8bb05a871351cf1dbf559baf0e86cead70a246 100644 (file)
@@ -1,4 +1,4 @@
-// FGAIAircraft - FGAIBase-derived class creates an AI airplane
+// // // FGAIAircraft - FGAIBase-derived class creates an AI airplane
 //
 // Written by David Culp, started October 2003.
 //
 #  include <config.h>
 #endif
 
-#include <simgear/math/point3d.hxx>
 #include <simgear/route/waypoint.hxx>
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
 #include <Main/viewer.hxx>
 #include <Scenery/scenery.hxx>
 #include <Scenery/tilemgr.hxx>
+#include <Airports/dynamics.hxx>
 
 #include <string>
 #include <math.h>
@@ -40,7 +40,7 @@
 #  include <ieeefp.h>
 #endif
 
-SG_USING_STD(string);
+using std::string;
 
 #include "AIAircraft.hxx"
 #include "performancedata.hxx"
@@ -55,8 +55,10 @@ class FP_Inactive{};
 
 FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) {
     trafficRef = ref;
-    if (trafficRef)
+    if (trafficRef) {
         groundOffset = trafficRef->getGroundOffset();
+       setCallSign(trafficRef->getCallSign());
+    }
     else
         groundOffset = 0;
 
@@ -81,6 +83,7 @@ FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) {
     holdPos = false;
 
     _performance = 0; //TODO initialize to JET_TRANSPORT from PerformanceDB
+    
 }
 
 
@@ -110,7 +113,6 @@ void FGAIAircraft::bind() {
     props->tie("controls/gear/gear-down",
                SGRawValueMethods<FGAIAircraft,bool>(*this,
                                                     &FGAIAircraft::_getGearDown));
-    props->setStringValue("callsign", callsign.c_str());
 }
 
 
@@ -148,15 +150,36 @@ void FGAIAircraft::setPerformance(const std::string& acclass) {
          return;
      }
      catch (FP_Inactive) {
-         return;
+         //return;
+         groundTargetSpeed = 0;
      }
 
      handleATCRequests(); // ATC also has a word to say
      updateSecondaryTargetValues(); // target roll, vertical speed, pitch
      updateActualState(); 
      UpdateRadar(manager);
+     checkVisibility();
   }
 
+void FGAIAircraft::checkVisibility() 
+{
+     double visibility_meters = fgGetDouble("/environment/visibility-m");
+
+     FGViewer* vw = globals->get_current_view();
+     double course, distance;
+
+     SGWayPoint current(pos.getLongitudeDeg(), pos.getLatitudeDeg(), 0);
+     SGWayPoint view (vw->getLongitude_deg(), vw->getLatitude_deg(), 0);
+     view.CourseAndDistance(current, &course, &distance);
+     if (distance > visibility_meters) {
+         //aip.getSGLocation()->set_cur_elev_m(aptElev);
+         //return;
+         invisible = true;
+      } else {
+         invisible = false;
+      }
+}
+
 
 
 void FGAIAircraft::AccelTo(double speed) {
@@ -264,7 +287,10 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
         //TODO let the fp handle this (loading of next leg)
         fp->IncrementWaypoint((bool) trafficRef);
         if (!(fp->getNextWaypoint()) && trafficRef)
-            loadNextLeg();
+            if (!loadNextLeg()) {
+                setDie(true);
+                return;
+            }
 
         prev = fp->getPreviousWaypoint();
         curr = fp->getCurrentWaypoint();
@@ -288,7 +314,7 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) {
         }
 
         if (next) {
-            fp->setLeadDistance(speed, tgt_heading, curr, next);
+            fp->setLeadDistance(tgt_speed, tgt_heading, curr, next);
         }
 
         if (!(prev->on_ground))  // only update the tgt altitude from flightplan if not on the ground
@@ -319,11 +345,14 @@ bool FGAIAircraft::_getGearDown() const {
 }
 
 
-void FGAIAircraft::loadNextLeg() {
+bool FGAIAircraft::loadNextLeg() {
 
     int leg;
     if ((leg = fp->getLeg())  == 10) {
-        trafficRef->next();
+        if (!trafficRef->next()) {
+            return false;
+        }
+        setCallSign(trafficRef->getCallSign());
         leg = 1;
         fp->setLeg(leg);
     }
@@ -336,10 +365,11 @@ void FGAIAircraft::loadNextLeg() {
     } else {
         double cruiseAlt = trafficRef->getCruiseAlt() * 100;
 
-        fp->create (dep,
+        fp->create (this,
+                    dep,
                     arr,
                     leg,
-                    cruiseAlt,           //(trafficRef->getCruiseAlt() * 100), // convert from FL to feet
+                    cruiseAlt,
                     trafficRef->getSpeed(),
                     _getLatitude(),
                     _getLongitude(),
@@ -348,7 +378,9 @@ void FGAIAircraft::loadNextLeg() {
                     trafficRef->getFlightType(),
                     acType,
                     company);
+       //cerr << "created  leg " << leg << " for " << trafficRef->getCallSign() << endl;
     }
+    return true;
 }
 
 
@@ -361,7 +393,7 @@ void FGAIAircraft::getGroundElev(double dt) {
     dt_elev_count += dt;
 
     // Update minimally every three secs, but add some randomness
-    // to prevent all IA objects doing this in synchrony
+    // to prevent all AI objects doing this in synchrony
     if (dt_elev_count < (3.0) + (rand() % 10))
         return;
 
@@ -397,11 +429,6 @@ void FGAIAircraft::getGroundElev(double dt) {
 }
 
 
-void FGAIAircraft::setCallSign(const string& s) {
-    callsign = s;
-}
-
-
 void FGAIAircraft::doGroundAltitude() {
     if (fabs(altitude_ft - (tgt_altitude_ft+groundOffset)) > 1000.0)
         altitude_ft = (tgt_altitude_ft + groundOffset);
@@ -414,10 +441,14 @@ void FGAIAircraft::announcePositionToController() {
     if (trafficRef) {
         int leg = fp->getLeg();
 
-        // Note that leg was been incremented after creating the current leg, so we should use
+        // Note that leg has been incremented after creating the current leg, so we should use
         // leg numbers here that are one higher than the number that is used to create the leg
         //
         switch (leg) {
+          case 2:              // Startup and Push back
+            if (trafficRef->getDepartureAirport()->getDynamics())
+                controller = trafficRef->getDepartureAirport()->getDynamics()->getStartupController();
+            break;
         case 3:              // Taxiing to runway
             if (trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork()->exists())
                 controller = trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork();
@@ -426,12 +457,14 @@ void FGAIAircraft::announcePositionToController() {
             if (trafficRef->getDepartureAirport()->getDynamics()) {
                 controller = trafficRef->getDepartureAirport()->getDynamics()->getTowerController();
                 //if (trafficRef->getDepartureAirport()->getId() == "EHAM") {
-                //cerr << trafficRef->getCallSign() << " at runway " << fp->getRunway() << "Ready for departure "
-                //   << trafficRef->getFlightType() << " to " << trafficRef->getArrivalAirport()->getId() << endl;
+                //string trns = trafficRef->getCallSign() + " at runway " + fp->getRunway() + 
+                //              ". Ready for departure. " + trafficRef->getFlightType() + " to " +
+                //              trafficRef->getArrivalAirport()->getId();
+                //fgSetString("/sim/messages/atc", trns.c_str());
                 //  if (controller == 0) {
                 //cerr << "Error in assigning controller at " << trafficRef->getDepartureAirport()->getId() << endl;
                 //}
-
+                //}
             } else {
                 cerr << "Error: Could not find Dynamics at airport : " << trafficRef->getDepartureAirport()->getId() << endl;
             }
@@ -447,29 +480,17 @@ void FGAIAircraft::announcePositionToController() {
 
         if ((controller != prevController) && (prevController != 0)) {
             prevController->signOff(getID());
-            string callsign =  trafficRef->getCallSign();
-            if ( trafficRef->getHeavy())
-                callsign += "Heavy";
-            switch (leg) {
-            case 3:
-                //cerr << callsign << " ready to taxi to runway " << fp->getRunway() << endl;
-                break;
-            case 4:
-                //cerr << callsign << " at runway " << fp->getRunway() << "Ready for take-off. "
-                //     << trafficRef->getFlightRules() << " to " << trafficRef->getArrivalAirport()->getId()
-                //     << "(" << trafficRef->getArrivalAirport()->getName() << ")."<< endl;
-                break;
-            }
         }
         prevController = controller;
         if (controller) {
             controller->announcePosition(getID(), fp, fp->getCurrentWaypoint()->routeIndex,
                                          _getLatitude(), _getLongitude(), hdg, speed, altitude_ft,
-                                         trafficRef->getRadius(), leg, trafficRef->getCallSign());
+                                         trafficRef->getRadius(), leg, this);
         }
     }
 }
 
+// Process ATC instructions and report back
 
 void FGAIAircraft::processATC(FGATCInstruction instruction) {
     if (instruction.getCheckForCircularWait()) {
@@ -495,7 +516,7 @@ void FGAIAircraft::processATC(FGATCInstruction instruction) {
     } else {
         if (holdPos) {
             //if (trafficRef)
-            // cerr << trafficRef->getCallSign() << " Resuming Taxi " << endl;
+            // cerr << trafficRef->getCallSign() << " Resuming Taxi." << endl;
             holdPos = false;
         }
         // Change speed Instruction. This can only be excecuted when there is no
@@ -523,6 +544,7 @@ void FGAIAircraft::processATC(FGATCInstruction instruction) {
 
 void FGAIAircraft::handleFirstWaypoint() {
     bool eraseWaypoints;         //TODO YAGNI
+    headingError = 0;
     if (trafficRef) {
         eraseWaypoints = true;
     } else {
@@ -539,7 +561,10 @@ void FGAIAircraft::handleFirstWaypoint() {
     //TODO fp should handle this
     fp->IncrementWaypoint(eraseWaypoints);
     if (!(fp->getNextWaypoint()) && trafficRef)
-        loadNextLeg();
+        if (!loadNextLeg()) {
+            setDie(true);
+            return;
+        }
 
     prev = fp->getPreviousWaypoint();   //first waypoint
     curr = fp->getCurrentWaypoint();    //second waypoint
@@ -610,7 +635,6 @@ bool FGAIAircraft::leadPointReached(FGAIFlightPlan::waypoint* curr) {
 
     //cerr << "2" << endl;
     double lead_dist = fp->getLeadDistance();
-    //cerr << " Distance : " << dist_to_go << ": Lead distance " << lead_dist << endl;
     // experimental: Use fabs, because speed can be negative (I hope) during push_back.
 
     if (lead_dist < fabs(2*speed)) {
@@ -620,6 +644,12 @@ bool FGAIAircraft::leadPointReached(FGAIFlightPlan::waypoint* curr) {
     }
 
     //prev_dist_to_go = dist_to_go;
+    //if (dist_to_go < lead_dist)
+    //     cerr << trafficRef->getCallSign() << " Distance : " 
+    //          << dist_to_go << ": Lead distance " 
+    //          << lead_dist << " " << curr->name 
+    //          << " Ground target speed " << groundTargetSpeed << endl;
+         
     return dist_to_go < lead_dist;
 }
 
@@ -634,7 +664,7 @@ bool FGAIAircraft::aiTrafficVisible() {
 
     user.CourseAndDistance(current, &course, &distance);
 
-    return ((distance * SG_METER_TO_NM) <= TRAFFICTOAIDIST);
+    return ((distance * SG_METER_TO_NM) <= TRAFFICTOAIDISTTODIE);
 }
 
 
@@ -657,8 +687,12 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIFlightPlan::waypoint* prev, time_t
 
     // This waypoint marks the fact that the aircraft has passed the initial taxi
     // departure waypoint, so it can release the parking.
-    if (prev->name == "park2") {
+    //cerr << trafficRef->getCallSign() << " has passed waypoint " << prev->name << " at speed " << speed << endl;
+    if (prev->name == "PushBackPoint") {
         dep->getDynamics()->releaseParking(fp->getGate());
+        time_t holdUntil = now + 120;
+       fp->setTime(holdUntil);
+       //cerr << _getCallsign() << "Holding at pushback point" << endl;
     }
 
     // This is the last taxi waypoint, and marks the the end of the flight plan
@@ -692,7 +726,7 @@ void FGAIAircraft::controlHeading(FGAIFlightPlan::waypoint* curr) {
 
     if (finite(calc_bearing)) {
         double hdg_error = calc_bearing - tgt_heading;
-        if (fabs(hdg_error) > 1.0) {
+        if (fabs(hdg_error) > 0.01) {
             TurnTo( calc_bearing );
         }
 
@@ -719,7 +753,9 @@ void FGAIAircraft::controlSpeed(FGAIFlightPlan::waypoint* curr, FGAIFlightPlan::
 
     if (fabs(speed_diff) > 10) {
         prevSpeed = speed;
-        fp->setLeadDistance(speed, tgt_heading, curr, next);
+        if (next) {
+            fp->setLeadDistance(speed, tgt_heading, curr, next);
+        }
     }
 }
 
@@ -734,29 +770,31 @@ void FGAIAircraft::updatePrimaryTargetValues() {
         time_t now = time(NULL) + fgGetLong("/sim/time/warp");
         //cerr << "UpateTArgetValues() " << endl;
         ProcessFlightPlan(dt, now);
-        if (! fp->isActive(now)) {
-            // Do execute Ground elev for inactive aircraft, so they
-            // Are repositioned to the correct ground altitude when the user flies within visibility range.
-            // In addition, check whether we are out of user range, so this aircraft
-            // can be deleted.
-            if (onGround()) {
+
+        // Do execute Ground elev for inactive aircraft, so they
+        // Are repositioned to the correct ground altitude when the user flies within visibility range.
+        // In addition, check whether we are out of user range, so this aircraft
+        // can be deleted.
+        if (onGround()) {
                 Transform();     // make sure aip is initialized.
-                if (trafficRef) {
-                    //cerr << trafficRef->getRegistration() << " Setting altitude to " << altitude_ft;
-                    if (! aiTrafficVisible()) {
-                        setDie(true);
-                        throw AI_OutOfSight();
-                    }
-                    getGroundElev(dt);
-                    doGroundAltitude();
-                    // Transform();
-                    pos.setElevationFt(altitude_ft);
-                }
+                getGroundElev(dt);
+                doGroundAltitude();
+                // Transform();
+                pos.setElevationFt(altitude_ft);
+        }
+        if (trafficRef) {
+           //cerr << trafficRef->getRegistration() << " Setting altitude to " << altitude_ft;
+            if (! aiTrafficVisible()) {
+                setDie(true);
+                //cerr << trafficRef->getRegistration() << " is set to die " << endl;
+                throw AI_OutOfSight();
             }
+        }
+        timeElapsed = now - fp->getStartTime();
+        if (! fp->isActive(now)) { 
             throw FP_Inactive();
         }
-    }
-    else {
+    } else {
         // no flight plan, update target heading, speed, and altitude
         // from control properties.  These default to the initial
         // settings in the config file, but can be changed "on the
@@ -814,30 +852,63 @@ void FGAIAircraft::updateHeading() {
         // If on ground, calculate heading change directly
         if (onGround()) {
             double headingDiff = fabs(hdg-tgt_heading);
+            double bank_sense = 0.0;
+        /*
+        double diff = fabs(hdg - tgt_heading);
+        if (diff > 180)
+            diff = fabs(diff - 360);
 
+        double sum = hdg + diff;
+        if (sum > 360.0)
+            sum -= 360.0;
+        if (fabs(sum - tgt_heading) < 1.0) {
+            bank_sense = 1.0;    // right turn
+        } else {
+            bank_sense = -1.0;   // left turn
+        }*/
             if (headingDiff > 180)
                 headingDiff = fabs(headingDiff - 360);
-
-            groundTargetSpeed = tgt_speed - (tgt_speed * (headingDiff/45));
+            double sum = hdg + headingDiff;
+            if (sum > 360.0) 
+                sum -= 360.0;
+            if (fabs(sum - tgt_heading) > 0.0001) {
+                bank_sense = -1.0;
+            } else {
+                bank_sense = 1.0;
+            }
+            //if (trafficRef)
+               //cerr << trafficRef->getCallSign() << " Heading " 
+                //     << hdg << ". Target " << tgt_heading <<  ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << endl;
+            //if (headingDiff > 60) {
+            groundTargetSpeed = tgt_speed; // * cos(headingDiff * SG_DEGREES_TO_RADIANS);
+                //groundTargetSpeed = tgt_speed - tgt_speed * (headingDiff/180);
+            //} else {
+            //    groundTargetSpeed = tgt_speed;
+            //}
             if (sign(groundTargetSpeed) != sign(tgt_speed))
                 groundTargetSpeed = 0.21 * sign(tgt_speed); // to prevent speed getting stuck in 'negative' mode
 
             if (headingDiff > 30.0) {
                 // invert if pushed backward
-                headingChangeRate += dt * sign(roll);
-
-                if (headingChangeRate > 30)
-                    headingChangeRate = 30;
-                else if (headingChangeRate < -30)
-                    headingChangeRate = -30;
-
+                headingChangeRate += 10.0 * dt * sign(roll);
+
+                // Clamp the maximum steering rate to 30 degrees per second,
+                // But only do this when the heading error is decreasing.
+                if ((headingDiff < headingError)) {
+                    if (headingChangeRate > 30)
+                        headingChangeRate = 30;
+                    else if (headingChangeRate < -30)
+                        headingChangeRate = -30;
+                }
             } else {
-                if (fabs(headingChangeRate) > headingDiff)
-                    headingChangeRate = headingDiff*sign(roll);
-                else
-                    headingChangeRate += dt * sign(roll);
+                   if (fabs(headingChangeRate) > headingDiff)
+                       headingChangeRate = headingDiff*sign(roll);
+                   else
+                       headingChangeRate += dt * sign(roll);
             }
-            hdg += headingChangeRate * dt;
+
+           hdg += headingChangeRate * dt * (fabs(speed) / 15);
+            headingError = headingDiff;
         } else {
             if (fabs(speed) > 1.0) {
                 turn_radius_ft = 0.088362 * speed * speed
@@ -940,6 +1011,20 @@ void FGAIAircraft::updatePitchAngleTarget() {
     }
 }
 
+string FGAIAircraft::atGate() {
+     string tmp("");
+     if (fp->getLeg() < 3) {
+         if (trafficRef) {
+             if (fp->getGate() > 0) {
+                 FGParking *park =
+                     trafficRef->getDepartureAirport()->getDynamics()->getParking(fp->getGate());
+                 tmp = park->getName();
+             }
+         }
+     }
+     return tmp;
+}
+
 void FGAIAircraft::handleATCRequests() {
     //TODO implement NullController for having no ATC to save the conditionals
     if (controller) {