]> git.mxchange.org Git - flightgear.git/commitdiff
David Culp:
authorehofman <ehofman>
Fri, 27 Feb 2004 10:20:17 +0000 (10:20 +0000)
committerehofman <ehofman>
Fri, 27 Feb 2004 10:20:17 +0000 (10:20 +0000)
Here's a new batch of AI code which includes a working radar instrument.

I put the radar calculations into the existing AIAircraft class.  It was
easier that way, and it can always be migrated out later if we have to.
Every tenth sim cycle the AIManager makes a copy of the current user state
information.  When the AIAircraft updates it uses this information to
calculate the radar numbers.  It calculates:

1) bearing from user to target
2) range to target in nautical miles
3) "horizontal offset" to target.  This is the angle from the nose to the
   target, in degrees, from -180 to 180.  This will be useful later for a HUD.
4) elevation, in degrees (vertical angle from user's position to target
   position)
5) vertical offset, in degrees (this is elevation corrected for user's pitch)
6) rdot (range rate in knots, note:  not working yet, so I commented it out)

and three items used by the radar instrument to place the "blip"

7) y_shift, in nautical miles
8) x_shift, in nautical miles
9) rotation, in degrees

The radar instrument uses the above three items, and applies a scale factor to
the x-shift and y-shift in order to match the instrument's scale.  Changing
the display scale can be done entirely in the XML code for the instrument.
Right now it's set up only to display a 40 mile scale.

The radar is an AWACS view, which is not very realistic, but it is useful and
demonstrates the technology.  With just a little more work I can get a HUD
marker.  All I need to do there is make a bank angle adjustment to the
current values.

src/AIModel/AIAircraft.cxx
src/AIModel/AIAircraft.hxx
src/AIModel/AIBallistic.cxx
src/AIModel/AIBallistic.hxx
src/AIModel/AIBase.cxx
src/AIModel/AIBase.hxx
src/AIModel/AIManager.cxx
src/AIModel/AIManager.hxx
src/AIModel/AIShip.cxx
src/AIModel/AIShip.hxx

index 66360d8a5c567f8da131a4db8b598393b69e3e54..40c790a16543d89174b75f7370c59cf52c261756 100644 (file)
@@ -51,7 +51,8 @@ const FGAIAircraft::PERF_STRUCT FGAIAircraft::settings[] = {
 
 FGAIAircraft *FGAIAircraft::_self = NULL;
 
-FGAIAircraft::FGAIAircraft() {
+FGAIAircraft::FGAIAircraft(FGAIManager* mgr) {
+   manager = mgr;   
    _self = this;
 
    // set heading and altitude locks
@@ -173,10 +174,10 @@ void FGAIAircraft::Run(double dt) {
 
    // adjust altitude (meters) based on current vertical speed (fpm)
    altitude += vs * 0.0166667 * dt * SG_FEET_TO_METER;  
+   double altitude_ft = altitude * SG_METER_TO_FEET;
 
    // find target vertical speed if altitude lock engaged
    if (alt_lock) {
-     double altitude_ft = altitude * SG_METER_TO_FEET;
      if (altitude_ft < tgt_altitude) {
        tgt_vs = tgt_altitude - altitude_ft;
        if (tgt_vs > performance->climb_rate)
@@ -203,6 +204,74 @@ void FGAIAircraft::Run(double dt) {
    // match pitch angle to vertical speed
    pitch = vs * 0.005;
 
+   //###########################//
+   // do calculations for radar //
+   //###########################//
+
+   // copy values from the AIManager
+   double user_latitude  = manager->get_user_latitude();
+   double user_longitude = manager->get_user_longitude();
+   double user_altitude  = manager->get_user_altitude();
+   double user_heading   = manager->get_user_heading();
+   double user_pitch     = manager->get_user_pitch();
+   double user_yaw       = manager->get_user_yaw();
+   double user_speed     = manager->get_user_speed();
+
+   // calculate range to target in feet and nautical miles
+   double lat_range = fabs(pos.lat() - user_latitude) * ft_per_deg_lat;
+   double lon_range = fabs(pos.lon() - user_longitude) * ft_per_deg_lon;
+   double range_ft = sqrt( lat_range*lat_range + lon_range*lon_range );
+   range = range_ft / 6076.11549;
+
+   // calculate bearing to target
+   if (pos.lat() >= user_latitude) {   
+      bearing = atan2(lat_range, lon_range) * SG_RADIANS_TO_DEGREES;
+        if (pos.lon() >= user_longitude) {
+           bearing = 90.0 - bearing;
+        } else {
+           bearing = 270.0 + bearing;
+        }
+   } else {
+      bearing = atan2(lon_range, lat_range) * SG_RADIANS_TO_DEGREES;
+        if (pos.lon() >= user_longitude) {
+           bearing = 180.0 - bearing;
+        } else {
+           bearing = 180.0 + bearing;
+        }
+   }
+
+   // calculate look left/right to target, without yaw correction
+   horiz_offset = bearing - user_heading;
+   if (horiz_offset > 180.0) horiz_offset -= 360.0;
+   if (horiz_offset < -180.0) horiz_offset += 360.0;
+
+   // calculate elevation to target
+   elevation = atan2( altitude_ft - user_altitude, range_ft )
+                      * SG_RADIANS_TO_DEGREES;
+   
+   // calculate look up/down to target
+   vert_offset = elevation + user_pitch;
+
+/* this calculation needs to be fixed
+   // calculate range rate
+   double recip_bearing = bearing + 180.0;
+   if (recip_bearing > 360.0) recip_bearing -= 360.0;
+   double my_horiz_offset = recip_bearing - hdg;
+   if (my_horiz_offset > 180.0) my_horiz_offset -= 360.0;
+   if (my_horiz_offset < -180.0) my_horiz_offset += 360.0;
+   rdot = (-user_speed * cos( horiz_offset * SG_DEGREES_TO_RADIANS ))
+               + (-speed * 1.686 * cos( my_horiz_offset * SG_DEGREES_TO_RADIANS ));
+*/
+   
+   // now correct look left/right for yaw
+   horiz_offset += user_yaw;
+
+   // calculate values for radar display
+   y_shift = range * cos( horiz_offset * SG_DEGREES_TO_RADIANS);
+   x_shift = range * sin( horiz_offset * SG_DEGREES_TO_RADIANS);
+   rotation = hdg - user_heading;
+   if (rotation < 0.0) rotation += 360.0; 
+
 }
 
 
index 8d16f381e57136aa1134af72c1dad05750d40c30..6ea34c092fbfbe51d7440b3235d73125dd63f504 100644 (file)
@@ -49,7 +49,7 @@ public:
         enum aircraft_e {LIGHT=0, WW2_FIGHTER, JET_TRANSPORT, JET_FIGHTER};
         static const PERF_STRUCT settings[];
        
-       FGAIAircraft();
+       FGAIAircraft(FGAIManager* mgr);
        ~FGAIAircraft();
        
        bool init();
index 86703da9c6065e471369d5ae235865aca3de0a07..0e7249e4e0c4cd6df51f22ee00f67f66771126d7 100644 (file)
@@ -27,7 +27,8 @@
 #include "AIBallistic.hxx"
 
 
-FGAIBallistic::FGAIBallistic() {
+FGAIBallistic::FGAIBallistic(FGAIManager* mgr) {
+    manager = mgr;
     _type_str = "ballistic";
 }
 
index 3878778b9c79b3132484080602c002de9db78065..479dc44e565e895ab8733a9e6c2a1e2d4fd64ee9 100644 (file)
@@ -28,7 +28,7 @@ class FGAIBallistic : public FGAIBase {
        
 public:
        
-    FGAIBallistic();
+    FGAIBallistic(FGAIManager* mgr);
     ~FGAIBallistic();
        
     bool init();
index 16f956ec67d60233493b3676a353fd4c5ec3cac7..baa13f8655f669d15a7b094bb30f821124e009db 100644 (file)
@@ -48,9 +48,12 @@ FGAIBase::FGAIBase() {
     _self = this;
     _type_str = "model";
     tgt_roll = roll = tgt_pitch = tgt_yaw = tgt_vs = vs = pitch = 0.0;
+    bearing = elevation = range = rdot = 0.0;
+    x_shift = y_shift = rotation = 0.0;
 }
 
 FGAIBase::~FGAIBase() {
+    unbind();
     _self = NULL;
 }
 
@@ -91,7 +94,8 @@ bool FGAIBase::init() {
 }
 
 void FGAIBase::bind() {
-   props->tie("velocities/airspeed-kt",  SGRawValuePointer<double>(&speed));
+   props->tie("id", SGRawValuePointer<int>(&id));
+   props->tie("velocities/true-airspeed-kt",  SGRawValuePointer<double>(&speed));
    props->tie("velocities/vertical-speed-fps",
                SGRawValueFunctions<double>(FGAIBase::_getVS_fps,
                                            FGAIBase::_setVS_fps));
@@ -108,7 +112,17 @@ void FGAIBase::bind() {
 
    props->tie("orientation/pitch-deg",   SGRawValuePointer<double>(&pitch));
    props->tie("orientation/roll-deg",    SGRawValuePointer<double>(&roll));
-   props->tie("orientation/heading-deg", SGRawValuePointer<double>(&hdg));
+   props->tie("orientation/true-heading-deg", SGRawValuePointer<double>(&hdg));
+
+   props->tie("radar/bearing-deg",   SGRawValueFunctions<double>(FGAIBase::_getBearing));
+   props->tie("radar/elevation-deg", SGRawValueFunctions<double>(FGAIBase::_getElevation));
+   props->tie("radar/range-nm",      SGRawValueFunctions<double>(FGAIBase::_getRange));
+//   props->tie("radar/rdot-kts",      SGRawValueFunctions<double>(FGAIBase::_getRdot));
+   props->tie("radar/h-offset", SGRawValueFunctions<double>(FGAIBase::_getH_offset));
+   props->tie("radar/v-offset", SGRawValueFunctions<double>(FGAIBase::_getV_offset)); 
+   props->tie("radar/x-shift", SGRawValueFunctions<double>(FGAIBase::_getX_shift));
+   props->tie("radar/y-shift", SGRawValueFunctions<double>(FGAIBase::_getY_shift));
+   props->tie("radar/rotation", SGRawValueFunctions<double>(FGAIBase::_getRotation));
 
    props->tie("controls/lighting/nav-lights",
                SGRawValueFunctions<bool>(FGAIBase::_isNight));
@@ -117,7 +131,8 @@ void FGAIBase::bind() {
 }
 
 void FGAIBase::unbind() {
-    props->untie("velocities/airspeed-kt");
+    props->untie("id");
+    props->untie("velocities/true-airspeed-kt");
     props->untie("velocities/vertical-speed-fps");
 
     props->untie("position/altitude-ft");
@@ -126,7 +141,17 @@ void FGAIBase::unbind() {
 
     props->untie("orientation/pitch-deg");
     props->untie("orientation/roll-deg");
-    props->untie("orientation/heading-deg");
+    props->untie("orientation/true-heading-deg");
+
+    props->untie("radar/bearing-deg");
+    props->untie("radar/elevation-deg");
+    props->untie("radar/range-nm");
+//    props->untie("radar/rdot-kts");
+    props->untie("radar/h-offset");
+    props->untie("radar/v-offset");
+    props->untie("radar/x-shift");
+    props->untie("radar/y-shift");
+    props->untie("radar/rotation");
 
     props->untie("controls/controls/lighting/nav-lights");
 }
index 568469542cccc699fc5500b6c1847a07b4719cbd..63e0128fe0c8801fa6deed41b4382384dc71973c 100644 (file)
@@ -30,6 +30,8 @@
 
 SG_USING_STD(string);
 
+class FGAIManager;
+
 class FGAIBase {
 
 public:
@@ -51,21 +53,26 @@ public:
     void setLongitude( double longitude );
     void setBank( double bank );
 
+    void setID( int ID );
+    int  getID();
     void setDie( bool die );
     bool getDie();
 
 protected:
 
     SGPropertyNode *props;
+    FGAIManager* manager;
 
+    // these describe the model's actual state
     Point3D pos;       // WGS84 lat & lon in degrees, elev above sea-level in meters
     double hdg;                // True heading in degrees
     double roll;       // degrees, left is negative
     double pitch;      // degrees, nose-down is negative
     double speed;       // knots true airspeed
     double altitude;    // meters above sea level
-    double vs;           // vertical speed, feet per minute   
+    double vs;          // vertical speed, feet per minute   
 
+    // these describe the model's desired state
     double tgt_heading;  // target heading, degrees true
     double tgt_altitude; // target altitude, *feet* above sea level
     double tgt_speed;    // target speed, KTAS
@@ -74,10 +81,22 @@ protected:
     double tgt_yaw;
     double tgt_vs;
 
+    // these describe radar information for the user
+    double bearing;      // true bearing from user to this model
+    double elevation;    // elevation in degrees from user to this model
+    double range;        // range from user to this model, nm
+    double rdot;         // range rate, in knots
+    double horiz_offset; // look left/right from user to me, deg
+    double vert_offset;  // look up/down from user to me, deg
+    double x_shift;      // value used by radar display instrument
+    double y_shift;      // value used by radar display instrument
+    double rotation;     // value used by radar display instrument
+
 
     string model_path;    //Path to the 3D model
     SGModelPlacement aip;
     bool delete_me;
+    int id;
 
     void Transform();
 
@@ -98,6 +117,16 @@ public:
     static double _getLongitude();
     static double _getLatitude ();
 
+    static double _getBearing();
+    static double _getElevation();
+    static double _getRange();
+    static double _getRdot();
+    static double _getH_offset();
+    static double _getV_offset();
+    static double _getX_shift();
+    static double _getY_shift();
+    static double _getRotation();
+
     static bool _isNight();
 };
 
@@ -143,6 +172,16 @@ inline void FGAIBase::_setLatitude ( double latitude )  {
 inline double FGAIBase::_getLongitude() { return _self->pos.lon(); }
 inline double FGAIBase::_getLatitude () { return _self->pos.lat(); }
 
+inline double FGAIBase::_getBearing()   { return _self->bearing; }
+inline double FGAIBase::_getElevation() { return _self->elevation; }
+inline double FGAIBase::_getRange()     { return _self->range; }
+inline double FGAIBase::_getRdot()      { return _self->rdot; }
+inline double FGAIBase::_getH_offset()  { return _self->horiz_offset; }
+inline double FGAIBase::_getV_offset()  { return _self->vert_offset; }
+inline double FGAIBase::_getX_shift()   { return _self->x_shift; }
+inline double FGAIBase::_getY_shift()   { return _self->y_shift; }
+inline double FGAIBase::_getRotation()  { return _self->rotation; }
+
 inline double FGAIBase::_getVS_fps() { return _self->vs*60.0; }
 inline void FGAIBase::_setVS_fps( double _vs ) { _self->vs = _vs/60.0; }
 
@@ -157,5 +196,8 @@ inline bool FGAIBase::_isNight() {
     return (fgGetFloat("/sim/time/sun-angle-rad") > 1.57);
 }
 
+inline void FGAIBase::setID( int ID ) { id = ID; }
+inline int  FGAIBase::getID() { return id; }
+
 #endif  // _FG_AIBASE_HXX
 
index 52a1c0fd18c58f84a7fc9c6d783f91fb2c466e6d..b3d3060da74ce6772e3d96dc4ec53fbc8c656ea3 100644 (file)
@@ -34,72 +34,61 @@ SG_USING_STD(list);
 
 FGAIManager::FGAIManager() {
   initDone = false;
+  numObjects = 0;
+  dt_count = 9;
 }
 
 FGAIManager::~FGAIManager() {
+  ai_list_itr = ai_list.begin();
+  while(ai_list_itr != ai_list.end()) {
+      delete (*ai_list_itr);
+      ++ai_list_itr;
+    }
   ai_list.clear();
+  ids.clear();
 }
 
+
 void FGAIManager::init() {
-  SGPropertyNode * node = fgGetNode("sim/ai", true);
+  int rval;
+  root = fgGetNode("sim/ai", true);
 
-  for (int i = 0; i < node->nChildren(); i++) {
-    const SGPropertyNode * entry = node->getChild(i);
+  for (int i = 0; i < root->nChildren(); i++) {
+    const SGPropertyNode * entry = root->getChild(i);
 
     if (!strcmp(entry->getName(), "entry")) {
       if (!strcmp(entry->getStringValue("type", ""), "aircraft")) { 
-        FGAIAircraft* ai_plane = new FGAIAircraft;
-        ai_list.push_back(ai_plane);
 
-        string model_class = entry->getStringValue("class", "");
-        if (model_class == "light") {
-          ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::LIGHT]);
+        rval = createAircraft( entry->getStringValue("class", ""),
+                               entry->getStringValue("path"),
+                               entry->getDoubleValue("latitude"),
+                               entry->getDoubleValue("longitude"),
+                               entry->getDoubleValue("altitude-ft"),
+                               entry->getDoubleValue("heading"),
+                               entry->getDoubleValue("speed-KTAS"),
+                               0.0, 
+                               entry->getDoubleValue("bank") );
 
-        } else if (model_class == "ww2_fighter") {
-          ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::WW2_FIGHTER]);
-
-        } else if (model_class ==  "jet_transport") {
-          ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_TRANSPORT]);
+      } else if (!strcmp(entry->getStringValue("type", ""), "ship")) {
 
-        } else if (model_class == "jet_fighter") {
-          ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_FIGHTER]);
-        }
+        rval = createShip( entry->getStringValue("path"),
+                           entry->getDoubleValue("latitude"),
+                           entry->getDoubleValue("longitude"),
+                           entry->getDoubleValue("altitude-ft"),
+                           entry->getDoubleValue("heading"),
+                           entry->getDoubleValue("speed-KTAS"),
+                           entry->getDoubleValue("rudder") );
 
-        ai_plane->setHeading(entry->getDoubleValue("heading"));
-        ai_plane->setSpeed(entry->getDoubleValue("speed-KTAS"));
-        ai_plane->setPath(entry->getStringValue("path"));
-        ai_plane->setAltitude(entry->getDoubleValue("altitude-ft"));
-        ai_plane->setLongitude(entry->getDoubleValue("longitude"));
-        ai_plane->setLatitude(entry->getDoubleValue("latitude"));
-        ai_plane->setBank(entry->getDoubleValue("bank"));
-        ai_plane->init();
-        ai_plane->bind();
+      } else if (!strcmp(entry->getStringValue("type", ""), "ballistic")) {
 
-      } else if (!strcmp(entry->getStringValue("type", ""), "ship")) {
-        FGAIShip* ai_ship = new FGAIShip;
-        ai_list.push_back(ai_ship);
-        ai_ship->setHeading(entry->getDoubleValue("heading"));
-        ai_ship->setSpeed(entry->getDoubleValue("speed-KTAS"));
-        ai_ship->setPath(entry->getStringValue("path"));
-        ai_ship->setAltitude(entry->getDoubleValue("altitude-ft"));
-        ai_ship->setLongitude(entry->getDoubleValue("longitude"));
-        ai_ship->setLatitude(entry->getDoubleValue("latitude"));
-        ai_ship->setBank(entry->getDoubleValue("rudder"));
-        ai_ship->init();
-        ai_ship->bind();
+        rval = createBallistic( entry->getStringValue("path"),
+                                entry->getDoubleValue("latitude"),
+                                entry->getDoubleValue("longitude"),
+                                entry->getDoubleValue("altitude-ft"),
+                                entry->getDoubleValue("azimuth"),
+                                entry->getDoubleValue("elevation"),
+                                entry->getDoubleValue("speed") );
 
-      } else if (!strcmp(entry->getStringValue("type", ""), "ballistic")) {
-        FGAIBallistic* ai_ballistic = new FGAIBallistic;
-        ai_list.push_back(ai_ballistic);
-        ai_ballistic->setAzimuth(entry->getDoubleValue("azimuth"));
-        ai_ballistic->setElevation(entry->getDoubleValue("elevation"));
-        ai_ballistic->setSpeed(entry->getDoubleValue("speed-fps"));
-        ai_ballistic->setPath(entry->getStringValue("path"));
-        ai_ballistic->setAltitude(entry->getDoubleValue("altitude-ft"));
-        ai_ballistic->setLongitude(entry->getDoubleValue("longitude"));
-        ai_ballistic->setLatitude(entry->getDoubleValue("latitude"));
-        ai_ballistic->init();
-        ai_ballistic->bind();
       } 
     }
   }
@@ -109,33 +98,166 @@ void FGAIManager::init() {
 
 
 void FGAIManager::bind() {
+   root = globals->get_props()->getNode("ai/models", true);
+   root->tie("count", SGRawValuePointer<int>(&numObjects));
 }
 
 
 void FGAIManager::unbind() {
-    ai_list_itr = ai_list.begin();
-    while(ai_list_itr != ai_list.end()) {
-        (*ai_list_itr)->unbind();
-        ++ai_list_itr;
-    }
+    root->untie("count");
 }
 
 
 void FGAIManager::update(double dt) {
-#if 0
-       if(!initDone) {
-          init();
-          SG_LOG(SG_ATC, SG_WARN, "Warning - AIManager::update(...) called before AIManager::init()");
-       }
-#endif
        
         ai_list_itr = ai_list.begin();
         while(ai_list_itr != ai_list.end()) {
                 if ((*ai_list_itr)->getDie()) {
-                   ai_list.erase(ai_list_itr, ai_list_itr);
+                   freeID((*ai_list_itr)->getID());
+                   delete (*ai_list_itr);
+                   ai_list.erase(ai_list_itr);
+                   --ai_list_itr;
+                   --numObjects;
                 } else {
+                   fetchUserState();
                    (*ai_list_itr)->update(dt);
                 }
                 ++ai_list_itr;
         }
 }
+
+
+// This function returns the next available ID
+int FGAIManager::assignID() {
+  int maxint = 30000;
+  int x; 
+  bool used;
+  for (x=0; x<maxint; x++) {
+     used = false;
+     id_itr = ids.begin();
+     while( id_itr != ids.end() ) {
+       if ((*id_itr) == x) used = true;
+       ++id_itr;
+     }
+     if (!used) {
+       ids.push_back(x);
+       return x;
+     } 
+  }
+  return -1;  // no available ID's
+}
+
+
+// This function removes an ID from the ID array, making it
+// available for assignment to another AI object
+void FGAIManager::freeID( int ID ) {
+    id_itr = ids.begin();
+    while( id_itr != ids.end() ) {
+      if (*id_itr == ID) {
+        ids.erase( id_itr );
+        return;
+      }
+      ++id_itr;
+    }  
+}
+
+int FGAIManager::createAircraft( string model_class, string path,
+              double latitude, double longitude, double altitude,
+              double heading, double speed, double pitch, double roll ) {
+     
+        FGAIAircraft* ai_plane = new FGAIAircraft(this);
+        ai_list.push_back(ai_plane);
+        ai_plane->setID( assignID() );
+        ++numObjects;
+        if (model_class == "light") {
+          ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::LIGHT]);
+        } else if (model_class == "ww2_fighter") {
+          ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::WW2_FIGHTER]);
+        } else if (model_class ==  "jet_transport") {
+          ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_TRANSPORT]);
+        } else if (model_class == "jet_fighter") {
+          ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_FIGHTER]);
+        }
+        ai_plane->setHeading(heading);
+        ai_plane->setSpeed(speed);
+        ai_plane->setPath(path.c_str());
+        ai_plane->setAltitude(altitude);
+        ai_plane->setLongitude(longitude);
+        ai_plane->setLatitude(latitude);
+        ai_plane->setBank(roll);
+        ai_plane->init();
+        ai_plane->bind();
+        return ai_plane->getID();
+}
+
+
+int FGAIManager::createShip( string path, double latitude, double longitude,
+                             double altitude, double heading, double speed,
+                             double rudder ) {
+
+        FGAIShip* ai_ship = new FGAIShip(this);
+        ai_list.push_back(ai_ship);
+        ai_ship->setID( assignID() );
+        ++numObjects;
+        ai_ship->setHeading(heading);
+        ai_ship->setSpeed(speed);
+        ai_ship->setPath(path.c_str());
+        ai_ship->setAltitude(altitude);
+        ai_ship->setLongitude(longitude);
+        ai_ship->setLatitude(latitude);
+        ai_ship->setBank(rudder);
+        ai_ship->init();
+        ai_ship->bind();
+        return ai_ship->getID();
+}
+
+
+int FGAIManager::createBallistic( string path, double latitude, double longitude,
+                                  double altitude, double azimuth, double elevation,
+                                  double speed ) {
+
+        FGAIBallistic* ai_ballistic = new FGAIBallistic(this);
+        ai_list.push_back(ai_ballistic);
+        ai_ballistic->setID( assignID() );    
+        ++numObjects;
+        ai_ballistic->setAzimuth(azimuth);
+        ai_ballistic->setElevation(elevation);
+        ai_ballistic->setSpeed(speed);
+        ai_ballistic->setPath(path.c_str());
+        ai_ballistic->setAltitude(altitude);
+        ai_ballistic->setLongitude(longitude);
+        ai_ballistic->setLatitude(latitude);
+        ai_ballistic->init();
+        ai_ballistic->bind();
+        return ai_ballistic->getID();
+}
+
+void FGAIManager::destroyObject( int ID ) {
+        ai_list_itr = ai_list.begin();
+        while(ai_list_itr != ai_list.end()) {
+            if ((*ai_list_itr)->getID() == ID) {
+              freeID( ID );
+              delete (*ai_list_itr);
+              ai_list.erase(ai_list_itr);
+              --ai_list_itr;
+              --numObjects;
+              return;
+            }
+            ++ai_list_itr;
+        }
+}
+
+// fetch the user's state every 10 sim cycles
+void FGAIManager::fetchUserState( void ) {
+   ++dt_count;
+   if (dt_count == 10) {
+     user_latitude  = fgGetDouble("/position/latitude-deg");
+     user_longitude = fgGetDouble("/position/longitude-deg");
+     user_altitude  = fgGetDouble("/position/altitude-ft");
+     user_heading   = fgGetDouble("/orientation/heading-deg");
+     user_pitch     = fgGetDouble("/orientation/pitch-deg");
+     user_yaw       = fgGetDouble("/orientation/side-slip-deg");
+     user_speed     = fgGetDouble("/velocities/uBody-fps") * 0.592484;
+     dt_count = 0;
+   }
+}
index 32098fcd7efa8d6822766fec883d450575417a7b..9b668f4ccbfb70a69685733e1d171fd3cbff9f37 100644 (file)
@@ -47,6 +47,11 @@ private:
     ai_list_type ai_list;
     ai_list_iterator ai_list_itr;
 
+    // array of already-assigned ID's
+    typedef vector <int> id_vector_type;
+    id_vector_type ids;                    
+    id_vector_type::iterator id_itr;
+
 public:
 
     enum object_type { otAircraft, otShip, otBallistic, otRocket };
@@ -59,10 +64,61 @@ public:
     void unbind();
     void update(double dt);
 
+    int assignID();
+    void freeID(int ID);
+
+    int createAircraft( string model_class, // see FGAIAircraft.hxx for possible classes
+                        string path,        // path to exterior model
+                        double latitude,    // in degrees -90 to 90
+                        double longitude,   // in degrees -180 to 180
+                        double altitude,    // in feet
+                        double heading,     // true heading in degrees
+                        double speed,       // in knots true airspeed (KTAS)    
+                        double pitch = 0,   // in degrees
+                        double roll = 0 );  // in degrees
+
+    int createShip(     string path,        // path to exterior model
+                        double latitude,    // in degrees -90 to 90
+                        double longitude,   // in degrees -180 to 180
+                        double altitude,    // in feet  (ex. for a lake!)
+                        double heading,     // true heading in degrees
+                        double speed,       // in knots true
+                        double rudder );    // in degrees (between 0 and 5 works best)
+
+
+    int createBallistic( string path,       // path to exterior model
+                         double latitude,   // in degrees -90 to 90
+                         double longitude,  // in degrees -180 to 180
+                         double altitude,   // in feet
+                         double azimuth,    // in degrees (same as heading)
+                         double elevation,  // in degrees (same as pitch)
+                         double speed );    // in feet per second
+
+    void destroyObject( int ID );
+
+    inline double get_user_latitude() { return user_latitude; }
+    inline double get_user_longitude() { return user_longitude; }
+    inline double get_user_altitude() { return user_altitude; }
+    inline double get_user_heading() { return user_heading; }
+    inline double get_user_pitch() { return user_pitch; }
+    inline double get_user_yaw() { return user_yaw; }
+    inline double get_user_speed() {return user_speed; }
 
 private:
 
     bool initDone;
+    int numObjects;
+    SGPropertyNode* root;
+
+    double user_latitude;
+    double user_longitude;
+    double user_altitude;
+    double user_heading;
+    double user_pitch;
+    double user_yaw;
+    double user_speed;
+    int dt_count;
+    void fetchUserState( void );
 
 };
 
index bd9ebb09fbdf177baa998967757e3ba2ae5d0684..d9fc379fe3092e24448ce362578cfe7c5c50c59f 100644 (file)
@@ -27,7 +27,8 @@
 #include "AIShip.hxx"
 
 
-FGAIShip::FGAIShip() {
+FGAIShip::FGAIShip(FGAIManager* mgr) {
+   manager = mgr;
    hdg_lock = false;
    rudder = 0.0;
    _type_str = "ship";
index d4d29f0223340a001eb465898f608f4beccbb791..1fc583ca06321195c8f785a7de56fb75e54dbff2 100644 (file)
 #ifndef _FG_AISHIP_HXX
 #define _FG_AISHIP_HXX
 
-#include "AIManager.hxx"
 #include "AIBase.hxx"
-
+class FGAIManager;
 
 class FGAIShip : public FGAIBase {
        
 public:
        
-       FGAIShip();
+       FGAIShip(FGAIManager* mgr);
        ~FGAIShip();
        
        bool init();