]> git.mxchange.org Git - flightgear.git/commitdiff
Vivian MEAZZA:
authormfranz <mfranz>
Mon, 5 Mar 2007 21:40:39 +0000 (21:40 +0000)
committermfranz <mfranz>
Mon, 5 Mar 2007 21:40:39 +0000 (21:40 +0000)
"Implement 'flightplans' for AIShips. This patch also introduces the concept
of a 'WAIT' token for AIShips: when the flightplan reaches a 'WAIT', the
AIShip stops and pauses for the specified time (secs)."

src/AIModel/AIFlightPlan.cxx
src/AIModel/AIFlightPlan.hxx
src/AIModel/AIShip.cxx
src/AIModel/AIShip.hxx

index 8f03b93a7d4e58037af1ba7e6f664a8b0f861e4b..693b7d22ba70357f877f46edcac2fdb89c106b28 100644 (file)
@@ -78,6 +78,7 @@ FGAIFlightPlan::FGAIFlightPlan(const string& filename)
      wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
      wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
      wpt->on_ground = wpt_node->getBoolValue("on-ground", false);
+     wpt->wait_time = wpt_node->getDoubleValue("wait-time-sec", 0);
 
      if (wpt->name == "END") wpt->finished = true;
      else wpt->finished = false;
index 775cacbb9a51d2e1b80091eed7a68534f20de1d9..0fee8c43c3319ec57236a60db29b3acda9a8ebbd 100644 (file)
@@ -49,6 +49,7 @@ public:
    bool flaps_down;
    bool on_ground;
     int routeIndex;  // For AI/ATC purposes;
+   double wait_time;
   } waypoint;
 
    FGAIFlightPlan(const string& filename);
index 5ea0c0976f96e40092b5c3b34f7c9737cbad560e..849a3b6a0872a795b1b7459530e0b336a53adb37 100644 (file)
@@ -1,7 +1,7 @@
 // FGAIShip - FGAIBase-derived class creates an AI ship
 //
 // Written by David Culp, started October 2003.
-// - davidculp2@comcast.net
+// with major amendments and additions by Vivian Meazza, 2004 - 2007
 //
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
 #  include <config.h>
 #endif
 
-#include <simgear/math/point3d.hxx>
+#ifdef _MSC_VER
+#  include <float.h>
+#  define finite _finite
+#elif defined(__sun) || defined(sgi)
+#  include <ieeefp.h>
+#endif
+
 #include <math.h>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/math/sg_random.h>
 
-#include "AIFlightPlan.hxx"
 #include "AIShip.hxx"
 
 
-FGAIShip::FGAIShip(object_type ot) : FGAIBase(ot) {
+FGAIShip::FGAIShip(object_type ot) :
+    FGAIBase(ot),
+    _dt_count(0),
+    _next_run(0)
+{
 }
 
 FGAIShip::~FGAIShip() {
 }
 
 void FGAIShip::readFromScenario(SGPropertyNode* scFileNode) {
-  if (!scFileNode)
-    return;
-
-  FGAIBase::readFromScenario(scFileNode);
-
-  setRudder(scFileNode->getFloatValue("rudder", 0.0));
-  setName(scFileNode->getStringValue("name", "Titanic"));
-  
-  std::string flightplan = scFileNode->getStringValue("flightplan");
-  if (!flightplan.empty()){
-    FGAIFlightPlan* fp = new FGAIFlightPlan(flightplan);
-    setFlightPlan(fp);
-  }
+    if (!scFileNode)
+        return;
+
+    FGAIBase::readFromScenario(scFileNode);
+
+    setRudder(scFileNode->getFloatValue("rudder", 0.0));
+    setName(scFileNode->getStringValue("name", "Titanic"));
+    setRadius(scFileNode->getDoubleValue("turn-radius-ft", 2000));
+    std::string flightplan = scFileNode->getStringValue("flightplan");
+    setRepeat(scFileNode->getBoolValue("repeat", false));
+
+    if (!flightplan.empty()) {
+        FGAIFlightPlan* fp = new FGAIFlightPlan(flightplan);
+        setFlightPlan(fp);
+    }
+
 }
 
 bool FGAIShip::init(bool search_in_AI_path) {
-   
-   hdg_lock = false;
-   rudder = 0.0;
-   no_roll = false;
-    
-   rudder_constant = 0.5;
-   roll_constant = 0.001;
-   speed_constant = 0.05;
-   hdg_constant = 0.01;
-   
-   return FGAIBase::init(search_in_AI_path);
+    prev = 0; // the one behind you
+    curr = 0; // the one ahead
+    next = 0; // the next plus 1
+
+    props->setStringValue("name", _name.c_str());
+    props->setStringValue("position/waypoint-name-prev", _prev_name.c_str());
+    props->setStringValue("position/waypoint-name-curr", _curr_name.c_str());
+    props->setStringValue("position/waypoint-name-next", _next_name.c_str());
+
+    _hdg_lock = false;
+    _rudder = 0.0;
+    no_roll = false;
+
+    _rudder_constant = 0.5;
+    _roll_constant = 0.001;
+    _speed_constant = 0.05;
+    _hdg_constant = 0.01;
+
+    _rd_turn_radius_ft = _sp_turn_radius_ft = turn_radius_ft;
+
+    _fp_init = false;
+    _missed = false;
+    _waiting = false;
+    _new_waypoint = true;
+
+    _missed_count = 0;
+    _wait_count = 0;
+    _missed_time_sec = 30;
+
+    _wp_range = _old_range = 0;
+    _range_rate = 0;
+
+    if (fp)
+        _fp_init = initFlightPlan();
+
+    return FGAIBase::init(search_in_AI_path);
 }
 
+
 void FGAIShip::bind() {
     FGAIBase::bind();
 
     props->tie("surface-positions/rudder-pos-deg",
-                SGRawValuePointer<float>(&rudder));
+        SGRawValuePointer<float>(&_rudder));
     props->tie("controls/heading-lock",
-                SGRawValuePointer<bool>(&hdg_lock));
+        SGRawValuePointer<bool>(&_hdg_lock));
     props->tie("controls/tgt-speed-kts",
-                SGRawValuePointer<double>(&tgt_speed));
+        SGRawValuePointer<double>(&tgt_speed));
     props->tie("controls/tgt-heading-degs",
-                SGRawValuePointer<double>(&tgt_heading)); 
+        SGRawValuePointer<double>(&tgt_heading));
     props->tie("controls/constants/rudder",
-                SGRawValuePointer<double>(&rudder_constant));
+        SGRawValuePointer<double>(&_rudder_constant));
     props->tie("controls/constants/roll",
-                SGRawValuePointer<double>(&roll_constant));
+        SGRawValuePointer<double>(&_roll_constant));
     props->tie("controls/constants/rudder",
-                SGRawValuePointer<double>(&rudder_constant));
+        SGRawValuePointer<double>(&_rudder_constant));
     props->tie("controls/constants/speed",
-                SGRawValuePointer<double>(&speed_constant)); 
-
-    props->setStringValue("name", name.c_str());
+        SGRawValuePointer<double>(&_speed_constant));
+    props->tie("position/waypoint-range-nm",
+        SGRawValuePointer<double>(&_wp_range));
+    props->tie("position/waypoint-range-old-nm",
+        SGRawValuePointer<double>(&_old_range));
+    props->tie("position/waypoint-range-rate-nm-sec",
+        SGRawValuePointer<double>(&_range_rate));
+    props->tie("position/waypoint-new",
+        SGRawValuePointer<bool>(&_new_waypoint));
+    props->tie("position/waypoint-missed",
+        SGRawValuePointer<bool>(&_missed));
+    props->tie("position/waypoint-missed-count",
+        SGRawValuePointer<double>(&_missed_count));
+    props->tie("position/waypoint-missed-time-sec",
+        SGRawValuePointer<double>(&_missed_time_sec));
+    props->tie("position/waypoint-wait-count",
+        SGRawValuePointer<double>(&_wait_count));
+    props->tie("position/waypoint-waiting",
+        SGRawValuePointer<bool>(&_waiting));
 }
 
 void FGAIShip::unbind() {
@@ -95,195 +151,437 @@ void FGAIShip::unbind() {
     props->untie("controls/tgt-heading-degs");
     props->untie("controls/constants/roll");
     props->untie("controls/constants/rudder");
-    props->untie("controls/constants/speed");           
-
+    props->untie("controls/constants/speed");
+    props->untie("position/waypoint-range-nm");
+    props->untie("position/waypoint-range-old-nm");
+    props->untie("position/waypoint-range-rate-nm-sec");
+    props->untie("position/waypoint-new");
+    props->untie("position/waypoint-missed");
+    props->untie("position/waypoint-wait-count");
+    props->untie("position/waypoint-waiting");
+    props->untie("position/waypoint-missed-time-sec");
 }
 
 void FGAIShip::update(double dt) {
-
-   FGAIBase::update(dt);
-   Run(dt);
-   Transform();
+    FGAIBase::update(dt);
+    Run(dt);
+    Transform();
 }
 
+void FGAIShip::Run(double dt) {
 
+    if (_fp_init)
+        ProcessFlightPlan(dt);
 
-void FGAIShip::Run(double dt) {
+    double speed_north_deg_sec;
+    double speed_east_deg_sec;
+    double alpha;
+    double rudder_limit;
+    double raw_roll;
+
+    // adjust speed
+    double speed_diff = tgt_speed - speed;
+
+    if (fabs(speed_diff) > 0.1) {
 
-   if (fp) ProcessFlightPlan(dt);
-
-   double sp_turn_radius_ft;
-   double rd_turn_radius_ft;
-   double speed_north_deg_sec;
-   double speed_east_deg_sec;
-   double dist_covered_ft;
-   double alpha;
-   double rudder_limit;
-   double raw_roll;   
-
-   // adjust speed
-   double speed_diff = tgt_speed - speed;
-   if (fabs(speed_diff) > 0.1) {
-     if (speed_diff > 0.0) speed += speed_constant * dt;
-     if (speed_diff < 0.0) speed -= speed_constant * dt;
-   } 
-   
-   // convert speed to degrees per second
-   speed_north_deg_sec = cos( hdg / SGD_RADIANS_TO_DEGREES )
-                          * speed * 1.686 / ft_per_deg_lat;
-   speed_east_deg_sec  = sin( hdg / SGD_RADIANS_TO_DEGREES )
-                          * speed * 1.686 / ft_per_deg_lon;
-
-   // set new position
-   pos.setLatitudeDeg( pos.getLatitudeDeg() + speed_north_deg_sec * dt);
-   pos.setLongitudeDeg( pos.getLongitudeDeg() + speed_east_deg_sec * dt); 
-
-   
-   // adjust heading based on current rudder angle
-   if (rudder <= -0.25 || rudder >= 0.25)  {
-   /*  turn_radius_ft = 0.088362 * speed * speed
-                       / tan( fabs(rudder) / SG_RADIANS_TO_DEGREES );
-     turn_circum_ft = SGD_2PI * turn_radius_ft;
-     dist_covered_ft = speed * 1.686 * dt; 
-     alpha = dist_covered_ft / turn_circum_ft * 360.0;*/
-     
-     if (turn_radius_ft <= 0) turn_radius_ft = 0; // don't allow nonsense values
-     if (rudder > 45) rudder = 45;
-     if (rudder < -45) rudder = -45;
-
-// adjust turn radius for speed. The equation is very approximate.
-     sp_turn_radius_ft = 10 * pow ((speed - 15),2) + turn_radius_ft;
-//     cout << " speed turn radius " << sp_turn_radius_ft ; 
-
-// adjust turn radius for rudder angle. The equation is even more approximate.     
-     float a = 19;
-     float b = -0.2485;
-     float c = 0.543;
-     
-     rd_turn_radius_ft = (a * exp(b * fabs(rudder)) + c) * sp_turn_radius_ft;
-     
-//     cout <<" rudder turn radius " << rd_turn_radius_ft << endl;
-          
-// calculate the angle, alpha, subtended by the arc traversed in time dt        
-     alpha = ((speed * 1.686 * dt)/rd_turn_radius_ft) * SG_RADIANS_TO_DEGREES;
-
-   
-// make sure that alpha is applied in the right direction   
-     hdg += alpha * sign( rudder );
-     if ( hdg > 360.0 ) hdg -= 360.0;
-     if ( hdg < 0.0) hdg += 360.0;
-
-//adjust roll for rudder angle and speed. Another bit of voodoo    
-     raw_roll =  -0.0166667 * speed * rudder;
-   }
-   else
-   {
-// rudder angle is 0  
-     raw_roll = 0;
-//     cout << " roll "<< roll << endl;
-   }
+        if (speed_diff > 0.0)
+            speed += _speed_constant * dt;
+
+        if (speed_diff < 0.0)
+            speed -= _speed_constant * dt;
+    }
+
+    // do not allow unreasonable ship speeds
+    if (speed > 40)
+        speed = 40;
+
+    // convert speed to degrees per second
+    speed_north_deg_sec = cos(hdg / SGD_RADIANS_TO_DEGREES)
+        * speed * 1.686 / ft_per_deg_lat;
+    speed_east_deg_sec = sin(hdg / SGD_RADIANS_TO_DEGREES)
+        * speed * 1.686 / ft_per_deg_lon;
+
+    // set new position
+    pos.setLatitudeDeg(pos.getLatitudeDeg() + speed_north_deg_sec * dt);
+    pos.setLongitudeDeg(pos.getLongitudeDeg() + speed_east_deg_sec * dt);
+
+    // adjust heading based on current _rudder angle
+
+    //cout << "turn_radius_ft " << turn_radius_ft ;
+
+    if (turn_radius_ft <= 0)
+        turn_radius_ft = 0; // don't allow nonsense values
+
+    if (_rudder > 45)
+        _rudder = 45;
+
+    if (_rudder < -45)
+        _rudder = -45;
+
+    //we assume that at slow speed ships will manoeuvre using engines/bow thruster
+    if (fabs(speed)<=5)
+        _sp_turn_radius_ft = 500;
+    else
+        // adjust turn radius for speed. The equation is very approximate.
+        // we need to allow for negative speeds
+        _sp_turn_radius_ft = 10 * pow ((fabs(speed) - 15), 2) + turn_radius_ft;
+
+    //cout << " speed turn radius " << _sp_turn_radius_ft ;
+
+    if (_rudder <= -0.25 || _rudder >= 0.25) {
+        // adjust turn radius for _rudder angle. The equation is even more approximate.
+        float a = 19;
+        float b = -0.2485;
+        float c = 0.543;
+
+        _rd_turn_radius_ft = (a * exp(b * fabs(_rudder)) + c) * _sp_turn_radius_ft;
+
+        //cout <<" _rudder turn radius " << _rd_turn_radius_ft << endl;
+
+        // calculate the angle, alpha, subtended by the arc traversed in time dt
+        alpha = ((speed * 1.686 * dt) / _rd_turn_radius_ft) * SG_RADIANS_TO_DEGREES;
+
+        // make sure that alpha is applied in the right direction
+        hdg += alpha * sign(_rudder);
+
+        if (hdg > 360.0)
+            hdg -= 360.0;
+
+        if (hdg < 0.0)
+            hdg += 360.0;
+
+        //adjust roll for _rudder angle and speed. Another bit of voodoo
+        raw_roll = -0.0166667 * speed * _rudder;
+    } else {
+        // _rudder angle is 0
+        raw_roll = 0;
+    }
 
     //low pass filter
-     roll = (raw_roll * roll_constant) + (roll * (1 - roll_constant));
-         
-     /*cout  << " rudder: " << rudder << " raw roll: "<< raw_roll<<" roll: " << roll ;
-     cout  << " hdg: " << hdg << endl ;*/
-
-   // adjust target rudder angle if heading lock engaged
-   if (hdg_lock) {
-     double rudder_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) { 
-       rudder_sense = 1.0;
-     } else {
-       rudder_sense = -1.0;
-     } 
-     if (diff < 15){ 
-         tgt_rudder = diff * rudder_sense;
-         }
-         else
-         {
-         tgt_rudder = 45 * rudder_sense;
-     }     
-   }
-
-   // adjust rudder angle
-    double rudder_diff = tgt_rudder - rudder;
-    // set the rudder limit by speed
-    if (speed <= 40 ){
-       rudder_limit = (-0.825 * speed) + 35;
-    }else{
-       rudder_limit = 2;
-   }
-
-    if (fabs(rudder_diff) > 0.1) {
-        if (rudder_diff > 0.0){
-            rudder += rudder_constant * dt;
-            if (rudder > rudder_limit) rudder = rudder_limit;// apply the rudder limit
-        } else if (rudder_diff < 0.0){
-            rudder -= rudder_constant * dt;
-            if (rudder < -rudder_limit) rudder = -rudder_limit;
-        }
-}
+    if (speed < 0)
+        roll = -roll;
 
+    roll = (raw_roll * _roll_constant) + (roll * (1 - _roll_constant));
 
+    // adjust target _rudder angle if heading lock engaged
+    if (_hdg_lock) {
+        double rudder_sense = 0.0;
+        double diff = fabs(hdg - tgt_heading);
+        //cout << "_rudder diff" << diff << endl;
+        if (diff > 180)
+            diff = fabs(diff - 360);
 
-}//end function
+        double sum = hdg + diff;
+
+        if (sum > 360.0)
+            sum -= 360.0;
 
+        if (fabs(sum - tgt_heading)< 1.0)
+            rudder_sense = 1.0;
+        else
+            rudder_sense = -1.0;
+
+        if (speed < 0)
+            rudder_sense = -rudder_sense;
+
+        if (diff < 15)
+            _tgt_rudder = diff * rudder_sense;
+        else
+            _tgt_rudder = 45 * rudder_sense;
+    }
+
+    // adjust _rudder angle
+    double rudder_diff = _tgt_rudder - _rudder;
+    // set the _rudder limit by speed
+    if (speed <= 40)
+        rudder_limit = (-0.825 * speed) + 35;
+    else
+        rudder_limit = 2;
+
+    if (fabs(rudder_diff)> 0.1) { // apply dead zone
+
+        if (rudder_diff > 0.0) {
+            _rudder += _rudder_constant * dt;
+
+            if (_rudder > rudder_limit) // apply the _rudder limit
+                _rudder = rudder_limit;
+
+        } else if (rudder_diff < 0.0) {
+            _rudder -= _rudder_constant * dt;
+
+            if (_rudder < -rudder_limit)
+                _rudder = -rudder_limit;
+
+        }
+
+    }
+}//end function
 
 void FGAIShip::AccelTo(double speed) {
-   tgt_speed = speed;
+    tgt_speed = speed;
 }
 
 void FGAIShip::PitchTo(double angle) {
-   tgt_pitch = angle;
+    tgt_pitch = angle;
 }
 
-
 void FGAIShip::RollTo(double angle) {
-   tgt_roll = angle;
+    tgt_roll = angle;
 }
 
-
 void FGAIShip::YawTo(double angle) {
 }
 
-
 void FGAIShip::ClimbTo(double altitude) {
 }
 
 
 void FGAIShip::TurnTo(double heading) {
-   tgt_heading = heading;
-   hdg_lock = true;
+    tgt_heading = heading;
+    _hdg_lock = true;
 }
 
-
 double FGAIShip::sign(double x) {
-
-  if ( x < 0.0 ) { return -1.0; }
-  else { return 1.0; }
+    if (x < 0.0)
+        return -1.0;
+    else
+        return 1.0;
 }
 
 void FGAIShip::setFlightPlan(FGAIFlightPlan* f) {
-  fp = f;
+    fp = f;
 }
 
 void FGAIShip::setName(const string& n) {
-  name = n;
+    _name = n;
 }
 
-void FGAIShip::ProcessFlightPlan(double dt) {
-  // not implemented yet
+void FGAIShip::setCurrName(const string& c) {
+    _curr_name = c;
+    props->setStringValue("position/waypoint-name-curr", _curr_name.c_str());
 }
 
+void FGAIShip::setNextName(const string& n) {
+    _next_name = n;
+    props->setStringValue("position/waypoint-name-next", _next_name.c_str());
+}
+
+void FGAIShip::setPrevName(const string& p) {
+    _prev_name = p;
+    props->setStringValue("position/waypoint-name-prev", _prev_name.c_str());
+}
+
+void FGAIShip::setRepeat(bool r) {
+    _repeat = r;
+}
+
+void FGAIShip::setMissed(bool m) {
+    _missed = m;
+    props->setBoolValue("position/waypoint-missed", _missed);
+}
+
+void FGAIShip::ProcessFlightPlan(double dt) {
+
+    _missed = false;
+    _dt_count += dt;
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Check Execution time (currently once every 1 sec)
+    // Add a bit of randomization to prevent the execution of all flight plans
+    // in synchrony, which can add significant periodic framerate flutter.
+    ///////////////////////////////////////////////////////////////////////////
+    if (_dt_count < _next_run)
+        return;
+
+    _next_run = 1.0 + (0.5 * sg_random());
+
+    // check to see if we've reached the point for our next turn
+    // if the range to the waypoint is less than the calculated turn
+    // radius we can start the turn to the next leg
+    _wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
+    _range_rate = (_wp_range - _old_range) / _dt_count;
+    double sp_turn_radius_nm = _sp_turn_radius_ft / 6076.1155;
+
+    // we need to try to identify a _missed waypoint
+
+    // calculate the time needed to turn through an arc of 90 degrees, and allow an error of 30 secs
+    if (speed != 0)
+        _missed_time_sec = 30 + ((SGD_PI * sp_turn_radius_nm * 60 * 60) / (2 * fabs(speed)));
+    else
+        _missed_time_sec = 30;
+
+    if ((_range_rate > 0) && (_wp_range < 3 * sp_turn_radius_nm) && !_new_waypoint)
+        _missed_count += _dt_count;
+
+
+    if (_missed_count >= _missed_time_sec) {
+        setMissed(true);
+    } else {
+        setMissed(false);
+    }
+
+    _old_range = _wp_range;
+
+    if ((_wp_range < sp_turn_radius_nm) || _missed || _waiting && !_new_waypoint) {
+
+        if (_next_name == "END") {
+
+            if (_repeat) {
+                SG_LOG(SG_GENERAL, SG_INFO, "AIShip: Flightplan restarting ");
+                fp->restart();
+                prev = curr;
+                curr = fp->getCurrentWaypoint();
+                next = fp->getNextWaypoint();
+                setWPNames();
+                _wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
+                _old_range = _wp_range;
+                _range_rate = 0;
+                _new_waypoint = true;
+                _missed_count = 0;
+                AccelTo(prev->speed);
+            } else {
+                SG_LOG(SG_GENERAL, SG_INFO, "AIShip: Flightplan dieing ");
+                setDie(true);
+                _dt_count = 0;
+                return;
+            }
+
+        } else if (_next_name == "WAIT") {
+
+            if (_wait_count < next->wait_time) {
+                SG_LOG(SG_GENERAL, SG_INFO, "AIShip: " << _name << " _waiting ");
+                setSpeed(0);
+                _waiting = true;
+                _wait_count += _dt_count;
+                _dt_count = 0;
+                return;
+            } else {
+                SG_LOG(SG_GENERAL, SG_INFO, "AIShip: " << _name << " wait done: getting new waypoints ");
+                prev = curr;
+                fp->IncrementWaypoint(false);
+                fp->IncrementWaypoint(false);  // do it twice
+                curr = fp->getCurrentWaypoint();
+                next = fp->getNextWaypoint();
+                _waiting = false;
+                _wait_count = 0;
+            }
+
+        } else {
+            //now reorganise the waypoints, so that next becomes current and so on
+            SG_LOG(SG_GENERAL, SG_INFO, "AIShip: " << _name << " getting new waypoints ");
+            fp->IncrementWaypoint(false);
+            prev = fp->getPreviousWaypoint(); //first waypoint
+            curr = fp->getCurrentWaypoint();  //second waypoint
+            next = fp->getNextWaypoint();     //third waypoint (might not exist!)
+        }
+
+        setWPNames();
+        _new_waypoint = true;
+        _missed_count = 0;
+        _range_rate = 0;
+        _wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
+        _old_range = _wp_range;
+        AccelTo(prev->speed);
+    } else {
+        _new_waypoint = false;
+    }
+
+    //   now revise the required course for the next way point
+    double course = getCourse(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
+
+    if (finite(course))
+        TurnTo(course);
+    else
+        SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: Bearing or Range is not a finite number");
+
+     _dt_count = 0;
+} // end Processing FlightPlan
+
 void FGAIShip::setRudder(float r) {
-  rudder = r;
+    _rudder = r;
 }
 
 void FGAIShip::setRoll(double rl) {
-   roll = rl;
+    roll = rl;
+}
+
+double FGAIShip::getRange(double lat, double lon, double lat2, double lon2) const {
+
+    double course, distance, az2;
+
+    //calculate the bearing and range of the second pos from the first
+    geo_inverse_wgs_84(lat, lon, lat2, lon2, &course, &az2, &distance);
+    distance *= SG_METER_TO_NM;
+    return distance;
+}
+
+double FGAIShip::getCourse(double lat, double lon, double lat2, double lon2) const {
+
+    double course, distance, recip;
+
+    //calculate the bearing and range of the second pos from the first
+    geo_inverse_wgs_84(lat, lon, lat2, lon2, &course, &recip, &distance);
+    if (tgt_speed >= 0) {
+        return course;
+    } else {
+        return recip;
+    }
+}
+
+bool FGAIShip::initFlightPlan() {
+    SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " initialising waypoints ");
+    fp->restart();
+    fp->IncrementWaypoint(false);
+
+    prev = fp->getPreviousWaypoint(); //first waypoint
+    curr = fp->getCurrentWaypoint();  //second waypoint
+    next = fp->getNextWaypoint();     //third waypoint (might not exist!)
+
+    if (curr->name == "WAIT") {  // don't wait when initialising
+        SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " re-initialising waypoints ");
+        fp->IncrementWaypoint(false);
+        curr = fp->getCurrentWaypoint();
+        next = fp->getNextWaypoint();
+    }
+
+    setWPNames();
+    setLatitude(prev->latitude);
+    setLongitude(prev->longitude);
+    setSpeed(prev->speed);
+    setHeading(getCourse(prev->latitude, prev->longitude, curr->latitude, curr->longitude));
+    _hdg_lock = true;
+    _wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
+    _old_range = _wp_range;
+    _range_rate = 0;
+    _missed = false;
+    _missed_count = 0;
+    _new_waypoint = true;
+
+    SG_LOG(SG_GENERAL, SG_INFO, "AIShip: " << _name << " done initialising waypoints ");
+
+    if (prev)
+        return true;
+    else
+        return false;
+
+} // end of initialization
+
+void FGAIShip::setWPNames() {
+
+    if (prev != 0)
+        setPrevName(prev->name);
+    else
+        setPrevName("");
+
+    setCurrName(curr->name);
+
+    if (next != 0)
+        setNextName(next->name);
+    else
+        setNextName("");
+
+    SG_LOG(SG_GENERAL, SG_INFO, "AIShip: prev wp name " << prev->name);
+    SG_LOG(SG_GENERAL, SG_INFO, "AIShip: current wp name " << curr->name);
+    SG_LOG(SG_GENERAL, SG_INFO, "AIShip: next wp name " << next->name);
+
 }
index 78fd6702a8620919b4fa976db97cd10089b7fec5..50c604fe36d58c6575c4cf6b0396980b1ac6ba96 100644 (file)
@@ -1,6 +1,7 @@
 // FGAIShip - AIBase derived class creates an AI ship
 //
 // Written by David Culp, started November 2003.
+// with major amendments and additions by Vivian Meazza, 2004 - 2007 
 //
 // Copyright (C) 2003  David P. Culp - davidculp2@comcast.net
 //
 #define _FG_AISHIP_HXX
 
 #include "AIBase.hxx"
+#include "AIFlightPlan.hxx"
+
 class FGAIManager;
 
 class FGAIShip : public FGAIBase {
-       
+
 public:
-       
-        FGAIShip(object_type ot = otShip);
-       virtual ~FGAIShip();
-       
-        virtual void readFromScenario(SGPropertyNode* scFileNode);
-
-       virtual bool init(bool search_in_AI_path=false);
-        virtual void bind();
-        virtual void unbind();
-       virtual void update(double dt);
-        void setFlightPlan(FGAIFlightPlan* f);
-        void setName(const string&);
-        void setRudder(float r);
-        void setRoll(double rl);
-        
-        void ProcessFlightPlan( double dt );
-
-        void AccelTo(double speed);
-        void PitchTo(double angle);
-        void RollTo(double angle);
-        void YawTo(double angle);
-        void ClimbTo(double altitude);
-        void TurnTo(double heading);
-           bool hdg_lock;
-
-        virtual const char* getTypeString(void) const { return "ship"; }
-       
+
+    FGAIShip(object_type ot = otShip);
+    virtual ~FGAIShip();
+
+    virtual void readFromScenario(SGPropertyNode* scFileNode);
+
+    virtual bool init(bool search_in_AI_path=false);
+    virtual void bind();
+    virtual void unbind();
+    virtual void update(double dt);
+    void setFlightPlan(FGAIFlightPlan* f);
+    void setName(const string&);
+    void setRudder(float r);
+    void setRoll(double rl);
+    void ProcessFlightPlan( double dt);
+    void AccelTo(double speed);
+    void PitchTo(double angle);
+    void RollTo(double angle);
+    void YawTo(double angle);
+    void ClimbTo(double altitude);
+    void TurnTo(double heading);
+    void setCurrName(const string&);
+    void setNextName(const string&);
+    void setPrevName(const string&);
+
+    bool _hdg_lock;
+
+    virtual const char* getTypeString(void) const { return "ship"; }
+
 protected:
 
-       string name; // The name of this ship.
+    string _name; // The _name of this ship.
 
 private:
 
-        float rudder, tgt_rudder;
-        double rudder_constant, roll_constant, speed_constant, hdg_constant;
+    FGAIFlightPlan::waypoint* prev; // the one behind you
+    FGAIFlightPlan::waypoint* curr; // the one ahead
+    FGAIFlightPlan::waypoint* next; // the next plus 1
+
+    virtual void reinit() { init(); }
+
+    void setRepeat(bool r);
+    void setMissed(bool m);
+    void setWPNames();
+    void Run(double dt);
+    double getRange(double lat, double lon, double lat2, double lon2) const;
+    double getCourse(double lat, double lon, double lat2, double lon2) const;
+    double sign(double x);
+
+    bool initFlightPlan();
+
+    float _rudder, _tgt_rudder;
+
+    double _rudder_constant, _roll_constant, _speed_constant, _hdg_constant;
+    double _sp_turn_radius_ft, _rd_turn_radius_ft;
+    double _wp_range, _old_range, _range_rate;
+    double _dt_count, _missed_count, _wait_count;
+    double _next_run;
+    double _missed_time_sec;
+
+    string _prev_name, _curr_name, _next_name;
+
+    bool _repeat;
+    bool _fp_init;
+    bool _new_waypoint;
+    bool _missed, _waiting;
 
-       void Run(double dt);
-        double sign(double x); 
 };
 
 #endif  // _FG_AISHIP_HXX