]> git.mxchange.org Git - flightgear.git/blobdiff - src/AIModel/AIGroundVehicle.cxx
Interpret environment variables and hostname on Windows
[flightgear.git] / src / AIModel / AIGroundVehicle.cxx
index 75f18b9c7844929ac08ccf02e34dcb7f20f439ac..bde684941ef443f1f0e90851e96bcbc8fe14a911 100644 (file)
@@ -37,11 +37,18 @@ FGAIShip(otGroundVehicle),
 _pitch(0),
 _pitch_deg(0),
 _speed_kt(0),
+_selected_ac(0),
 _range_ft(0),
 _relbrg (0),
 _parent_speed(0),
+_dt_count(0),
+_next_run(0),
 _parent_x_offset(0),
-_selected_ac(0)
+_parent_y_offset(0),
+_parent_z_offset(0),
+_parent(""),
+_break_count(0)
+
 {
     invisible = false;
 }
@@ -57,17 +64,20 @@ void FGAIGroundVehicle::readFromScenario(SGPropertyNode* scFileNode) {
     setNoRoll(scFileNode->getBoolValue("no-roll", true));
     setName(scFileNode->getStringValue("name", "groundvehicle"));
     setSMPath(scFileNode->getStringValue("submodel-path", ""));
-    setContactX1offset(scFileNode->getDoubleValue("contact_x1_offset", 0.0));
-    setContactX2offset(scFileNode->getDoubleValue("contact_x2_offset", 0.0));
-    setXOffset(scFileNode->getDoubleValue("hitch-x-offset", 38.55));
+    setContactX1offset(scFileNode->getDoubleValue("contact-x1-offset", 0.0));
+    setContactX2offset(scFileNode->getDoubleValue("contact-x2-offset", 0.0));
+    setXOffset(scFileNode->getDoubleValue("hitch-x-offset", 35.0));
+    setYOffset(scFileNode->getDoubleValue("hitch-y-offset", 0.0));
+    setZOffset(scFileNode->getDoubleValue("hitch-z-offset", 0.0));
     setPitchoffset(scFileNode->getDoubleValue("pitch-offset", 0.0));
     setRolloffset(scFileNode->getDoubleValue("roll-offset", 0.0));
     setYawoffset(scFileNode->getDoubleValue("yaw-offset", 0.0));
-    setPitchCoeff(scFileNode->getDoubleValue("pitch-coefficient", 0.5));
-    setElevCoeff(scFileNode->getDoubleValue("elevation-coefficient", 0.5));
+    setPitchCoeff(scFileNode->getDoubleValue("pitch-coefficient", 0.1));
+    setElevCoeff(scFileNode->getDoubleValue("elevation-coefficient", 0.25));
     setParentName(scFileNode->getStringValue("parent", ""));
-    setTowAngleGain(scFileNode->getDoubleValue("tow-angle-gain", 2.0));
+    setTowAngleGain(scFileNode->getDoubleValue("tow-angle-gain", 1.0));
     setTowAngleLimit(scFileNode->getDoubleValue("tow-angle-limit-deg", 2.0));
+    setInitialTunnel(scFileNode->getBoolValue("tunnel", false));
     //we may need these later for towed vehicles
     //    setSubID(scFileNode->getIntValue("SubID", 0));
     //    setGroundOffset(scFileNode->getDoubleValue("ground-offset", 0.0));
@@ -91,55 +101,45 @@ void FGAIGroundVehicle::bind() {
         SGRawValuePointer<double>(&_range_ft));
     props->tie("hitch/x-offset-ft",
         SGRawValuePointer<double>(&_x_offset));
+    props->tie("hitch/y-offset-ft",
+        SGRawValuePointer<double>(&_y_offset));
+    props->tie("hitch/z-offset-ft",
+        SGRawValuePointer<double>(&_z_offset));
     props->tie("hitch/parent-x-offset-ft",
         SGRawValuePointer<double>(&_parent_x_offset));
+    props->tie("hitch/parent-y-offset-ft",
+        SGRawValuePointer<double>(&_parent_y_offset));
+    props->tie("hitch/parent-z-offset-ft",
+        SGRawValuePointer<double>(&_parent_z_offset));
     props->tie("controls/constants/tow-angle/gain",
         SGRawValuePointer<double>(&_tow_angle_gain));
     props->tie("controls/constants/tow-angle/limit-deg",
         SGRawValuePointer<double>(&_tow_angle_limit));
-
-
-    //we may need these later for towed vehicles
-
-    //    (*this, &FGAIBallistic::getElevHitchToUser));
-    //props->tie("position/x-offset",
-    //    SGRawValueMethods<FGAIBase,double>(*this, &FGAIBase::_getXOffset, &FGAIBase::setXoffset));
-    //props->tie("position/y-offset",
-    //    SGRawValueMethods<FGAIBase,double>(*this, &FGAIBase::_getYOffset, &FGAIBase::setYoffset));
-    //props->tie("position/z-offset",
-    //    SGRawValueMethods<FGAIBase,double>(*this, &FGAIBase::_getZOffset, &FGAIBase::setZoffset));
-    //props->tie("position/tgt-x-offset",
-    //    SGRawValueMethods<FGAIWingman,double>(*this, &FGAIWingman::getTgtXOffset, &FGAIWingman::setTgtXOffset));
-    //props->tie("position/tgt-y-offset",
-    //    SGRawValueMethods<FGAIWingman,double>(*this, &FGAIWingman::getTgtYOffset, &FGAIWingman::setTgtYOffset));
-    //props->tie("position/tgt-z-offset",
-    //    SGRawValueMethods<FGAIWingman,double>(*this, &FGAIWingman::getTgtZOffset, &FGAIWingman::setTgtZOffset));
+    props->tie("controls/contact-x1-offset-ft",
+        SGRawValuePointer<double>(&_contact_x1_offset));
+    props->tie("controls/contact-x2-offset-ft",
+        SGRawValuePointer<double>(&_contact_x2_offset));
 }
 
 void FGAIGroundVehicle::unbind() {
     FGAIShip::unbind();
 
     props->untie("controls/constants/elevation-coeff");
+       props->untie("controls/constants/pitch-coeff");
     props->untie("position/ht-AGL-ft");
-    props->untie("controls/constants/pitch-coeff");
     props->untie("hitch/rel-bearing-deg");
     props->untie("hitch/tow-angle-deg");
     props->untie("hitch/range-ft");
     props->untie("hitch/x-offset-ft");
+    props->untie("hitch/y-offset-ft");
+    props->untie("hitch/z-offset-ft");
     props->untie("hitch/parent-x-offset-ft");
+    props->untie("hitch/parent-y-offset-ft");
+    props->untie("hitch/parent-y-offset-ft");
     props->untie("controls/constants/tow-angle/gain");
     props->untie("controls/constants/tow-angle/limit-deg");
-
-    //we may need these later for towed vehicles
-    //props->untie("load/rel-brg-to-user-deg");
-    //props->untie("load/elev-to-user-deg");
-    //props->untie("velocities/vertical-speed-fps");
-    //props->untie("position/x-offset");
-    //props->untie("position/y-offset");
-    //props->untie("position/z-offset");
-    //props->untie("position/tgt-x-offset");
-    //props->untie("position/tgt-y-offset");
-    //props->untie("position/tgt-z-offset");
+    props->untie("controls/contact-x1-offset-ft");
+    props->untie("controls/contact-x2-offset-ft");
 }
 
 bool FGAIGroundVehicle::init(bool search_in_AI_path) {
@@ -147,7 +147,6 @@ bool FGAIGroundVehicle::init(bool search_in_AI_path) {
         return false;
 
     invisible = false;
-
     _limit = 200;
     no_roll = true;
 
@@ -156,78 +155,9 @@ bool FGAIGroundVehicle::init(bool search_in_AI_path) {
 
 void FGAIGroundVehicle::update(double dt) {
     //    SG_LOG(SG_GENERAL, SG_ALERT, "updating GroundVehicle: " << _name );
-
-    if (getPitch()){
-        setElevation(_elevation, dt, _elevation_coeff);
-        ClimbTo(_elevation_ft);
-        setPitch(_pitch, dt, _pitch_coeff);
-        PitchTo(_pitch_deg);
-    }
-
-    if(_parent !=""){
-        setParent();
-
-        string parent_next_name = _selected_ac->getStringValue("waypoint/name-next");
-        bool parent_waiting = _selected_ac->getBoolValue("waypoint/waiting");
-        _parent_speed = _selected_ac->getDoubleValue("velocities/true-airspeed-kt");
-
-        if (parent_next_name == "END" && fp->getNextWaypoint()->name != "END" ){
-            SG_LOG(SG_GENERAL, SG_DEBUG, "AIGroundVeh1cle: " << _name
-                << " setting END: getting new waypoints ");
-            AdvanceFP();
-            setWPNames();
-        /*} else if (parent_next_name == "WAIT" && fp->getNextWaypoint()->name != "WAIT" ){*/
-        } else if (parent_waiting && !_waiting){
-            SG_LOG(SG_GENERAL, SG_DEBUG, "AIGroundVeh1cle: " << _name
-                << " setting WAIT/WAITUNTIL: getting new waypoints ");
-            AdvanceFP();
-            setWPNames();
-            _waiting = true;
-        } else if (parent_next_name != "WAIT" && fp->getNextWaypoint()->name == "WAIT"){
-            SG_LOG(SG_GENERAL, SG_DEBUG, "AIGroundVeh1cle: " << _name
-                << " wait done: getting new waypoints ");
-            _waiting = false;
-            _wait_count = 0;
-            fp->IncrementWaypoint(false);
-            next = fp->getNextWaypoint();
-
-            if (next->name == "WAITUNTIL" || next->name == "WAIT"
-                || next->name == "END"){
-            } else {
-                prev = curr;
-                fp->IncrementWaypoint(false);
-                curr = fp->getCurrentWaypoint();
-                next = fp->getNextWaypoint();
-            }
-
-            setWPNames();
-        } else if (_range_ft > 1000){
-
-             SG_LOG(SG_GENERAL, SG_INFO, "AIGroundVeh1cle: " << _name
-                << " rescue: reforming train " << _range_ft << " " << _x_offset * 15);
-
-            setTowAngle(0, dt, 1);
-            setSpeed(_parent_speed * 2);
-
-        } else if (_parent_speed > 1){
-
-            setTowSpeed();
-            setTowAngle(_relbrg, dt, 1);
-
-        } else if (_parent_speed < -1){
-
-            setTowSpeed();
-
-            if (_relbrg < 0)
-                setTowAngle(-(180 - (360 + _relbrg)), dt, 1);
-            else
-                setTowAngle(-(180 - _relbrg), dt, 1);
-
-        } else
-            setSpeed(_parent_speed);
-    }
-
     FGAIShip::update(dt);
+
+    RunGroundVehicle(dt);
 }
 
 void FGAIGroundVehicle::setNoRoll(bool nr) {
@@ -246,6 +176,14 @@ void FGAIGroundVehicle::setXOffset(double x) {
     _x_offset = x;
 }
 
+void FGAIGroundVehicle::setYOffset(double y) {
+    _y_offset = y;
+}
+
+void FGAIGroundVehicle::setZOffset(double z) {
+    _z_offset = z;
+}
+
 void FGAIGroundVehicle::setPitchCoeff(double pc) {
     _pitch_coeff = pc;
 }
@@ -278,25 +216,24 @@ void FGAIGroundVehicle::setParentName(const string& p) {
 
 void FGAIGroundVehicle::setTowAngle(double ta, double dt, double coeff){
     ta *= _tow_angle_gain;
-    //_tow_angle = pow(ta,2) * sign(ta);
-    //if (_tow_angle > _tow_angle_limit) _tow_angle = _tow_angle_limit;
-    //if (_tow_angle < -_tow_angle_limit) _tow_angle = -_tow_angle_limit;
-    SG_CLAMP_RANGE(_tow_angle, -_tow_angle_limit, _tow_angle_limit);
+    double factor = -0.0045 * speed + 1;
+    double limit = _tow_angle_limit * factor;
+//     cout << "speed "<< speed << " _factor " << _factor<<" " <<_tow_angle_limit<< endl; 
+     _tow_angle = pow(ta,2) * sign(ta) * factor;
+    SG_CLAMP_RANGE(_tow_angle, -limit, limit);
 }
 
 bool FGAIGroundVehicle::getGroundElev(SGGeod inpos) {
 
-    if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(inpos, 10000),
-        _elevation_m, &_material)){
-            _ht_agl_ft = pos.getElevationFt() - _elevation_m * SG_METER_TO_FEET;
+    double height_m ;
+
+    if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(inpos, 3000), height_m, &_material,0)){
+            _ht_agl_ft = inpos.getElevationFt() - height_m * SG_METER_TO_FEET;
 
             if (_material) {
                 const vector<string>& names = _material->get_names();
 
                 _solid = _material->get_solid();
-                _load_resistance = _material->get_load_resistance();
-                _frictionFactor =_material->get_friction_factor();
-                _elevation = _elevation_m * SG_METER_TO_FEET;
 
                 if (!names.empty())
                     props->setStringValue("material/name", names[0].c_str());
@@ -321,72 +258,107 @@ bool FGAIGroundVehicle::getGroundElev(SGGeod inpos) {
 
 bool FGAIGroundVehicle::getPitch() {
 
-    double vel = props->getDoubleValue("velocities/true-airspeed-kt", 0);
-    double contact_offset_x1_m = _contact_x1_offset * SG_FEET_TO_METER;
-    double contact_offset_x2_m = _contact_x2_offset * SG_FEET_TO_METER;
-
-    SGVec3d front(-contact_offset_x1_m, 0, 0);
-    SGVec3d rear(-contact_offset_x2_m, 0, 0);
-    SGVec3d Front = getCartPosAt(front);
-    SGVec3d Rear = getCartPosAt(rear);
-
-    SGGeod geodFront = SGGeod::fromCart(Front);
-    SGGeod geodRear = SGGeod::fromCart(Rear);
+    if (!_tunnel){
+        double vel = props->getDoubleValue("velocities/true-airspeed-kt", 0);
+        double contact_offset_x1_m = _contact_x1_offset * SG_FEET_TO_METER;
+        double contact_offset_x2_m = _contact_x2_offset * SG_FEET_TO_METER;
+        double _z_offset_m = _parent_z_offset * SG_FEET_TO_METER;
+
+        SGVec3d front(-contact_offset_x1_m, 0, 0);
+        SGVec3d rear(-contact_offset_x2_m, 0, 0);
+        SGVec3d Front = getCartPosAt(front);
+        SGVec3d Rear = getCartPosAt(rear);
+
+        SGGeod geodFront = SGGeod::fromCart(Front);
+        SGGeod geodRear = SGGeod::fromCart(Rear);
+
+        double front_elev_m = 0;
+        double rear_elev_m = 0;
+        double elev_front = 0;
+        double elev_rear = 0;
+        double max_alt = 10000;
+
+        if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(geodFront, 3000),
+            elev_front, &_material, 0)){
+                front_elev_m = elev_front + _z_offset_m;
+        } else
+            return false;
 
-    double front_elev_m = 0;
-    double rear_elev_m = 0;
-    double elev_front = 0;
-    double elev_rear = 0;
+        if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(geodRear, 3000),
+            elev_rear, &_material, 0)){
+                rear_elev_m = elev_rear;
+        } else
+            return false;
 
-    if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(geodFront, 10000),
-        elev_front, &_material)){
+        if (vel >= 0){
+            double diff = front_elev_m - rear_elev_m;
+            _pitch = atan2 (diff,
+                fabs(contact_offset_x1_m) + fabs(contact_offset_x2_m)) * SG_RADIANS_TO_DEGREES;
+            _elevation = (rear_elev_m + diff/2) * SG_METER_TO_FEET;
+        } else {
+            double diff = rear_elev_m - front_elev_m;
+            _pitch = atan2 (diff,
+                fabs(contact_offset_x1_m) + fabs(contact_offset_x2_m)) * SG_RADIANS_TO_DEGREES;
+            _elevation = (front_elev_m + diff/2) * SG_METER_TO_FEET;
+            _pitch = -_pitch;
+        }
 
-            front_elev_m = elev_front;
+    } else {
 
-            //if (_material) {
-            //
-            //}
+        if (prev->altitude == 0 || curr->altitude == 0) return false;
+
+        static double distance;
+        static double d_alt;
+        static double curr_alt;
+        static double prev_alt;
+
+        if (_new_waypoint){
+            //cout << "new waypoint, calculating pitch " << endl;
+            curr_alt = curr->altitude;
+            prev_alt = prev->altitude;
+            cout << "prev_alt" <<prev_alt << endl;
+            d_alt = (curr_alt - prev_alt) * SG_METER_TO_FEET;
+            //_elevation = prev->altitude;
+            distance = SGGeodesy::distanceM(SGGeod::fromDeg(prev->longitude, prev->latitude),
+            SGGeod::fromDeg(curr->longitude, curr->latitude));
+            _pitch = atan2(d_alt, distance * SG_METER_TO_FEET) * SG_RADIANS_TO_DEGREES;
+            //cout << "new waypoint, calculating pitch " <<  _pitch << 
+            //    " " << _pitch_offset << " " << _elevation <<endl;
+        }
 
-    } else
-        return false;
+        double distance_to_go = SGGeodesy::distanceM(SGGeod::fromDeg(pos.getLongitudeDeg(), pos.getLatitudeDeg()),
+            SGGeod::fromDeg(curr->longitude, curr->latitude));
 
-    if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(geodRear, 10000),
-        elev_rear, &_material)){
-            rear_elev_m = elev_rear;
-            //if (_material) {
-            //    rear_elev_m = elev_rear;
-            //}
+        /*cout << "tunnel " << _tunnel
+             << " distance prev & curr " << prev->name << " " << curr->name << " " << distance * SG_METER_TO_FEET
+             << " distance to go " << distance_to_go * SG_METER_TO_FEET
+             << " d_alt ft " << d_alt
+             << endl;*/
 
-    } else
-        return false;
+        if (distance_to_go > distance)
+            _elevation = prev_alt;
+        else
+            _elevation = curr_alt - (tan(_pitch * SG_DEGREES_TO_RADIANS) * distance_to_go * SG_METER_TO_FEET);
 
-    if (vel >= 0){
-        double diff = front_elev_m - rear_elev_m;
-        _pitch = atan2 (diff,
-            fabs(contact_offset_x1_m) + fabs(contact_offset_x2_m)) * SG_RADIANS_TO_DEGREES;
-        _elevation = (rear_elev_m + diff/2) * SG_METER_TO_FEET;
-    } else {
-        double diff = rear_elev_m - front_elev_m;
-        _pitch = atan2 (diff,
-            fabs(contact_offset_x1_m) + fabs(contact_offset_x2_m)) * SG_RADIANS_TO_DEGREES;
-        _elevation = (front_elev_m + diff/2) * SG_METER_TO_FEET;
-        _pitch = -_pitch;
     }
 
+    getGroundElev(pos);
+
     return true;
 }
 
 void FGAIGroundVehicle::setParent() {
 
-    const SGPropertyNode *ai = fgGetNode("/ai/models", true);
+    const SGPropertyNode_ptr ai = fgGetNode("/ai/models", true);
 
     for (int i = ai->nChildren() - 1; i >= -1; i--) {
-        const SGPropertyNode *model;
+        SGPropertyNode_ptr model;
 
         if (i < 0) { // last iteration: selected model
             model = _selected_ac;
         } else {
             model = ai->getChild(i);
+            string path = ai->getPath();
             const string name = model->getStringValue("name");
 
             if (!model->nChildren()){
@@ -408,12 +380,24 @@ void FGAIGroundVehicle::setParent() {
         double lat = _selected_ac->getDoubleValue("position/latitude-deg");
         double lon = _selected_ac->getDoubleValue("position/longitude-deg");
         double elevation = _selected_ac->getDoubleValue("position/altitude-ft");
-        double hitch_offset_m = _x_offset * SG_FEET_TO_METER;
+        double hitch_x_offset_m = _selected_ac->getDoubleValue("hitch/x-offset-ft")
+            * SG_FEET_TO_METER;
+        double hitch_y_offset_m = _selected_ac->getDoubleValue("hitch/y-offset-ft")
+            * SG_FEET_TO_METER;
+        double hitch_z_offset_m = _selected_ac->getDoubleValue("hitch/z-offset-ft")
+            * SG_FEET_TO_METER;
+        
         _selectedpos.setLatitudeDeg(lat);
         _selectedpos.setLongitudeDeg(lon);
         _selectedpos.setElevationFt(elevation);
 
-        SGVec3d rear_hitch(-hitch_offset_m, 0, 0);
+        _parent_x_offset = _selected_ac->getDoubleValue("hitch/x-offset-ft");
+        _parent_y_offset = _selected_ac->getDoubleValue("hitch/y-offset-ft");
+        _parent_z_offset = _selected_ac->getDoubleValue("hitch/z-offset-ft");
+
+        _parent_speed    = _selected_ac->getDoubleValue("velocities/true-airspeed-kt");
+
+        SGVec3d rear_hitch(-hitch_x_offset_m, hitch_y_offset_m, 0);
         SGVec3d RearHitch = getCartHitchPosAt(rear_hitch);
 
         SGGeod rearpos = SGGeod::fromCart(RearHitch);
@@ -441,15 +425,13 @@ void FGAIGroundVehicle::calcRangeBearing(double lat, double lon, double lat2, do
     // calculate the bearing and range of the second pos from the first
     double az2, distance;
     geo_inverse_wgs_84(lat, lon, lat2, lon2, &bearing, &az2, &distance);
-    range = distance *= SG_METER_TO_NM;
+    range = distance * SG_METER_TO_NM;
 }
 
 double FGAIGroundVehicle::calcRelBearingDeg(double bearing, double heading)
 {
     double angle = bearing - heading;
-
     SG_NORMALIZE_RANGE(angle, -180.0, 180.0);
-
     return angle;
 }
 
@@ -535,9 +517,7 @@ void FGAIGroundVehicle::AdvanceFP(){
 
 void FGAIGroundVehicle::setTowSpeed(){
 
-    _parent_x_offset = _selected_ac->getDoubleValue("hitch/x-offset-ft");
-
-    // double diff = _range_ft - _parent_x_offset;
+    double diff = _range_ft - _x_offset;
     double  x = 0;
 
     if (_range_ft > _x_offset * 3) x = 50;
@@ -545,11 +525,11 @@ void FGAIGroundVehicle::setTowSpeed(){
     if (_relbrg < -90 || _relbrg > 90){
         setSpeed(_parent_speed - 5 - x);
         //cout << _name << " case 1r _relbrg spd - 5 " << _relbrg << " " << diff << endl;
-    }else if (_range_ft > _parent_x_offset + 0.25 && _relbrg >= -90 && _relbrg <= 90){
+    }else if (_range_ft > _x_offset + 0.25 && _relbrg >= -90 && _relbrg <= 90){
         setSpeed(_parent_speed + 1 + x);
         //cout << _name << " case 2r _relbrg spd + 1 " << _relbrg << " "
         //    << diff << " range " << _range_ft << endl;
-    } else if (_range_ft < _parent_x_offset - 0.25 && _relbrg >= -90 && _relbrg <= 90){
+    } else if (_range_ft < _x_offset - 0.25 && _relbrg >= -90 && _relbrg <= 90){
         setSpeed(_parent_speed - 1 - x);
         //cout << _name << " case 3r _relbrg spd - 2 " << _relbrg << " "
         //    << diff << " " << _range_ft << endl;
@@ -559,4 +539,104 @@ void FGAIGroundVehicle::setTowSpeed(){
     }
 
 }
+
+void FGAIGroundVehicle::RunGroundVehicle(double dt){
+
+    _dt_count += dt;
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Check execution time (currently once every 0.05 sec or 20 fps)
+    // Add a bit of randomization to prevent the execution of all flight plans
+    // in synchrony, which can add significant periodic framerate flutter.
+    // Randomization removed to get better appearance
+    ///////////////////////////////////////////////////////////////////////////
+
+    //cout << "_start_sec " << _start_sec << " time_sec " << time_sec << endl;
+    if (_dt_count < _next_run)
+        return;
+
+    _next_run = 0.05 /*+ (0.015 * sg_random())*/;
+
+    if (getPitch()){
+        setElevation(_elevation, _dt_count, _elevation_coeff);
+        ClimbTo(_elevation_ft);
+        setPitch(_pitch, _dt_count, _pitch_coeff);
+        PitchTo(_pitch_deg);
+    }
+
+    if(_parent == ""){
+        AccelTo(prev->speed);
+        _dt_count = 0;
+        return;
+    }
+
+    setParent();
+
+    string parent_next_name = _selected_ac->getStringValue("waypoint/name-next");
+    bool parent_waiting = _selected_ac->getBoolValue("waypoint/waiting");
+    bool parent_restart = _selected_ac->getBoolValue("controls/restart"); 
+
+    if (parent_next_name == "END" && fp->getNextWaypoint()->name != "END" ){
+        SG_LOG(SG_GENERAL, SG_DEBUG, "AIGroundVeh1cle: " << _name
+            << " setting END: getting new waypoints ");
+        AdvanceFP();
+        setWPNames();
+        setTunnel(_initial_tunnel);
+        if(_restart) _missed_count = 200;
+        /*} else if (parent_next_name == "WAIT" && fp->getNextWaypoint()->name != "WAIT" ){*/
+    } else if (parent_waiting && !_waiting){
+        SG_LOG(SG_GENERAL, SG_DEBUG, "AIGroundVeh1cle: " << _name
+            << " setting WAIT/WAITUNTIL: getting new waypoints ");
+        AdvanceFP();
+        setWPNames();
+        _waiting = true;
+    } else if (parent_next_name != "WAIT" && fp->getNextWaypoint()->name == "WAIT"){
+        SG_LOG(SG_GENERAL, SG_DEBUG, "AIGroundVeh1cle: " << _name
+            << " wait done: getting new waypoints ");
+        _waiting = false;
+        _wait_count = 0;
+        fp->IncrementWaypoint(false);
+        next = fp->getNextWaypoint();
+
+        if (next->name == "WAITUNTIL" || next->name == "WAIT"
+            || next->name == "END"){
+        } else {
+            prev = curr;
+            fp->IncrementWaypoint(false);
+            curr = fp->getCurrentWaypoint();
+            next = fp->getNextWaypoint();
+        }
+
+        setWPNames();
+    } else if (_range_ft > (_x_offset +_parent_x_offset)* 4
+        ){
+        SG_LOG(SG_GENERAL, SG_ALERT, "AIGroundVeh1cle: " << _name
+            << " rescue: reforming train " << _range_ft 
+            );
+
+        setTowAngle(0, dt, 1);
+        setSpeed(_parent_speed + (10 * sign(_parent_speed)));
+
+    } else if (_parent_speed > 1){
+
+        setTowSpeed();
+        setTowAngle(_relbrg, dt, 1);
+
+    } else if (_parent_speed < -1){
+
+        setTowSpeed();
+
+        if (_relbrg < 0)
+            setTowAngle(-(180 - (360 + _relbrg)), dt, 1);
+        else
+            setTowAngle(-(180 - _relbrg), dt, 1);
+
+    } else
+        setSpeed(_parent_speed);
+
+//    FGAIShip::update(_dt_count);
+    _dt_count = 0;
+
+}
+
 // end AIGroundvehicle