X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=sidebyside;f=src%2FAIModel%2FAIAircraft.cxx;h=2bf71b3b18b96b35a66462bce9f0fe2c9e282e97;hb=d35b8db13f7aceee46d63b061cd20e6d3968f92a;hp=ea0637bf235e4d4c1b4f02ebefe496aa8dacfa2d;hpb=514acc9f5fa8aa9bdb2b64b36c905d9b695a05ef;p=flightgear.git diff --git a/src/AIModel/AIAircraft.cxx b/src/AIModel/AIAircraft.cxx index ea0637bf2..2bf71b3b1 100644 --- a/src/AIModel/AIAircraft.cxx +++ b/src/AIModel/AIAircraft.cxx @@ -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. // @@ -22,17 +22,18 @@ # include #endif -#include #include #include
#include
#include
#include #include +#include #include #include #include + #ifdef _MSC_VER # include # define finite _finite @@ -40,36 +41,22 @@ # include #endif -SG_USING_STD(string); +using std::string; #include "AIAircraft.hxx" +#include "performancedata.hxx" +#include "performancedb.hxx" + //#include static string tempReg; -// -// accel, decel, climb_rate, descent_rate, takeoff_speed, climb_speed, -// cruise_speed, descent_speed, land_speed -// - -const FGAIAircraft::PERF_STRUCT FGAIAircraft::settings[] = { - // light aircraft - {2.0, 2.0, 450.0, 1000.0, 70.0, 80.0, 100.0, 80.0, 60.0}, - // ww2_fighter - {4.0, 2.0, 3000.0, 1500.0, 110.0, 180.0, 250.0, 200.0, 100.0}, - // jet_transport - {5.0, 2.0, 3000.0, 1500.0, 140.0, 300.0, 430.0, 300.0, 130.0}, - // jet_fighter - {7.0, 3.0, 4000.0, 2000.0, 150.0, 350.0, 500.0, 350.0, 150.0}, - // tanker - {5.0, 2.0, 3000.0, 1500.0, 140.0, 300.0, 430.0, 300.0, 130.0}, - // ufo (extreme accel/decel) - {30.0, 30.0, 6000.0, 6000.0, 150.0, 300.0, 430.0, 300.0, 130.0} - }; FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) { trafficRef = ref; - if (trafficRef) + if (trafficRef) { groundOffset = trafficRef->getGroundOffset(); + setCallSign(trafficRef->getCallSign()); + } else groundOffset = 0; @@ -90,8 +77,12 @@ FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) { alt_lock = false; roll = 0; headingChangeRate = 0.0; + headingError = 0; holdPos = false; + + _performance = 0; //TODO initialize to JET_TRANSPORT from PerformanceDB + dt = 0; } @@ -121,7 +112,9 @@ void FGAIAircraft::bind() { props->tie("controls/gear/gear-down", SGRawValueMethods(*this, &FGAIAircraft::_getGearDown)); - props->setStringValue("callsign", callsign.c_str()); + props->tie("transponder-id", + SGRawValueMethods(*this, + &FGAIAircraft::_getTransponderCode)); } @@ -129,6 +122,7 @@ void FGAIAircraft::unbind() { FGAIBase::unbind(); props->untie("controls/gear/gear-down"); + props->untie("transponder-id"); } @@ -138,63 +132,47 @@ void FGAIAircraft::update(double dt) { Transform(); } - void FGAIAircraft::setPerformance(const std::string& acclass) { - if (acclass == "light") { - SetPerformance(&FGAIAircraft::settings[FGAIAircraft::LIGHT]); - } else if (acclass == "ww2_fighter") { - SetPerformance(&FGAIAircraft::settings[FGAIAircraft::WW2_FIGHTER]); - } else if (acclass == "jet_transport") { - SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_TRANSPORT]); - } else if (acclass == "jet_fighter") { - SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_FIGHTER]); - } else if (acclass == "tanker") { - SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_TRANSPORT]); - } else if (acclass == "ufo") { - SetPerformance(&FGAIAircraft::settings[FGAIAircraft::UFO]); - } else { - SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_TRANSPORT]); - } -} - + static PerformanceDB perfdb; //TODO make it a global service + setPerformance(perfdb.getDataFor(acclass)); + } -void FGAIAircraft::SetPerformance(const PERF_STRUCT *ps) { - - performance = ps; -} + void FGAIAircraft::setPerformance(PerformanceData *ps) { + _performance = ps; + } -void FGAIAircraft::Run(double dt) { - FGAIAircraft::dt = dt; - if (!updateTargetValues()) + void FGAIAircraft::Run(double dt) { + FGAIAircraft::dt = dt; + + bool outOfSight = false, + flightplanActive = true; + updatePrimaryTargetValues(flightplanActive, outOfSight); // target hdg, alt, speed + if (outOfSight) { return; - - if (controller) { - controller->update(getID(), - pos.getLatitudeDeg(), - pos.getLongitudeDeg(), - hdg, - speed, - altitude_ft, dt); - processATC(controller->getInstruction(getID())); - } - - if (no_roll) { - adjustSpeed(groundTargetSpeed); - } else { - adjustSpeed(tgt_speed); - } - - updatePosition(); - updateHeading(); - updateBankAngles(); - updateAltitudes(); - updateVerticalSpeed(); - matchPitchAngle(); + } + + if (!flightplanActive) { + 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(); + invisible = (SGGeodesy::distanceM(vw->getPosition(), pos) > visibility_meters); } + void FGAIAircraft::AccelTo(double speed) { tgt_speed = speed; } @@ -254,9 +232,6 @@ void FGAIAircraft::SetFlightPlan(FGAIFlightPlan *f) { void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) { - //if (! fpExecutable(now)) - // return; - // the one behind you FGAIFlightPlan::waypoint* prev = 0; // the one ahead @@ -277,7 +252,8 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) { handleFirstWaypoint(); return; } // end of initialization - + if (! fpExecutable(now)) + return; dt_count = 0; if (! leadPointReached(curr)) { @@ -300,9 +276,12 @@ 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(); + fp->IncrementWaypoint( trafficRef != 0 ); + if (!(fp->getNextWaypoint()) && trafficRef != 0) + if (!loadNextLeg()) { + setDie(true); + return; + } prev = fp->getPreviousWaypoint(); curr = fp->getCurrentWaypoint(); @@ -326,7 +305,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 @@ -353,17 +332,23 @@ void FGAIAircraft::initializeFlightPlan() { bool FGAIAircraft::_getGearDown() const { - return ((props->getFloatValue("position/altitude-agl-ft") < 900.0) - && (props->getFloatValue("velocities/airspeed-kt") - < performance->land_speed*1.25)); + return _performance->gearExtensible(this); } -void FGAIAircraft::loadNextLeg() { +const char * FGAIAircraft::_getTransponderCode() const { + return transponderCode.c_str(); +} + + +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); } @@ -376,10 +361,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(), @@ -388,7 +374,9 @@ void FGAIAircraft::loadNextLeg() { trafficRef->getFlightType(), acType, company); + //cerr << "created leg " << leg << " for " << trafficRef->getCallSign() << endl; } + return true; } @@ -401,47 +389,34 @@ 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; - else - dt_elev_count = 0; + + dt_elev_count = 0; // Only do the proper hitlist stuff if we are within visible range of the viewer. if (!invisible) { 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); + + if (SGGeodesy::distanceM(vw->getPosition(), pos) > visibility_meters) { return; } - // FIXME: make sure the pos.lat/pos.lon values are in degrees ... double range = 500.0; - if (!globals->get_tile_mgr()->scenery_available(pos.getLatitudeDeg(), pos.getLongitudeDeg(), range)) { + if (!globals->get_tile_mgr()->scenery_available(pos, range)) { // Try to shedule tiles for that position. - globals->get_tile_mgr()->update( aip.getSGLocation(), range ); + globals->get_tile_mgr()->update( pos, range ); } - // FIXME: make sure the pos.lat/pos.lon values are in degrees ... double alt; - if (globals->get_scenery()->get_elevation_m(pos.getLatitudeDeg(), pos.getLongitudeDeg(), 20000.0, alt, 0)) + if (getGroundElevationM(SGGeod::fromGeodM(pos, 20000), alt, 0)) tgt_altitude_ft = alt * SG_METER_TO_FEET; } } -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); @@ -454,10 +429,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(); @@ -465,13 +444,6 @@ void FGAIAircraft::announcePositionToController() { case 4: //Take off tower controller 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; - // 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; } @@ -487,31 +459,30 @@ 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()) { + // This is not exactly an elegant solution, + // but at least it gives me a chance to check + // if circular waits are resolved. + // For now, just take the offending aircraft + // out of the scene + setDie(true); + // a more proper way should be - of course - to + // let an offending aircraft take an evasive action + // for instance taxi back a little bit. + } //cerr << "Processing ATC instruction (not Implimented yet)" << endl; if (instruction.getHoldPattern ()) {} @@ -524,7 +495,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 @@ -552,6 +523,7 @@ void FGAIAircraft::processATC(FGATCInstruction instruction) { void FGAIAircraft::handleFirstWaypoint() { bool eraseWaypoints; //TODO YAGNI + headingError = 0; if (trafficRef) { eraseWaypoints = true; } else { @@ -568,7 +540,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 @@ -639,31 +614,30 @@ 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)) { - //don't skip over the waypoint - lead_dist = fabs(2*speed); - //cerr << "Extending lead distance to " << lead_dist << endl; + //don't skip over the waypoint + lead_dist = fabs(2*speed); + //cerr << "Extending lead distance to " << lead_dist << endl; } //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; } bool FGAIAircraft::aiTrafficVisible() { - double userLatitude = fgGetDouble("/position/latitude-deg"); - double userLongitude = fgGetDouble("/position/longitude-deg"); - double course, distance; - - SGWayPoint current(pos.getLongitudeDeg(), pos.getLatitudeDeg(), 0); - SGWayPoint user (userLongitude, userLatitude, 0); - - user.CourseAndDistance(current, &course, &distance); - - return ((distance * SG_METER_TO_NM) <= TRAFFICTOAIDIST); + SGGeod userPos(SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"), + fgGetDouble("/position/latitude-deg"))); + + return (SGGeodesy::distanceNm(userPos, pos) <= TRAFFICTOAIDISTTODIE); } @@ -686,8 +660,13 @@ 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 // so, the schedule should update and wait for the next departure time. @@ -697,7 +676,7 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIFlightPlan::waypoint* prev, time_t if (nextDeparture < (now+1200)) { nextDeparture = now + 1200; } - fp->setTime(nextDeparture); + fp->setTime(nextDeparture); // should be "next departure" } return true; @@ -720,7 +699,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 ); } @@ -747,7 +726,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); + } } } @@ -755,36 +736,38 @@ void FGAIAircraft::controlSpeed(FGAIFlightPlan::waypoint* curr, FGAIFlightPlan:: /** * Update target values (heading, alt, speed) depending on flight plan or control properties */ -bool FGAIAircraft::updateTargetValues() { +void FGAIAircraft::updatePrimaryTargetValues(bool& flightplanActive, bool& aiOutOfSight) { if (fp) // AI object has a flightplan { //TODO make this a function of AIBase 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 (no_roll) { + + // 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); - return false; - } - 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; + aiOutOfSight = !aiTrafficVisible(); + if (aiOutOfSight) { + setDie(true); + //cerr << trafficRef->getRegistration() << " is set to die " << endl; + aiOutOfSight = true; + return; } - return false; } - } - else { + timeElapsed = now - fp->getStartTime(); + flightplanActive = fp->isActive(now); + } 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 @@ -813,39 +796,8 @@ bool FGAIAircraft::updateTargetValues() { AccelTo( props->getDoubleValue("controls/flight/target-spd" ) ); } - return true; } - -/** - * Adjust the speed (accelerate/decelerate) to tgt_speed. - */ -void FGAIAircraft::adjustSpeed(double tgt_speed) { - double speed_diff = tgt_speed - speed; - speed_diff = groundTargetSpeed - speed; - - if (speed_diff > 0.0) // need to accelerate - { - speed += performance->accel * dt; - if ( speed > tgt_speed ) - speed = tgt_speed; - - } else if (speed_diff < 0.0) { - if (no_roll) { - // on ground (aircraft can't roll) - // deceleration performance is better due to wheel brakes. - speed -= performance->decel * dt * 3; - } else { - speed -= performance->decel * dt; - } - - if ( speed < tgt_speed ) - speed = tgt_speed; - - } -} - - void FGAIAircraft::updatePosition() { // convert speed to degrees per second double speed_north_deg_sec = cos( hdg * SGD_DEGREES_TO_RADIANS ) @@ -871,32 +823,65 @@ void FGAIAircraft::updateHeading() { //else // turnConstant = 0.088362; // If on ground, calculate heading change directly - if (no_roll) { + 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 @@ -922,7 +907,7 @@ void FGAIAircraft::updateHeading() { } -void FGAIAircraft::updateBankAngles() { +void FGAIAircraft::updateBankAngleTarget() { // adjust target bank angle if heading lock engaged if (hdg_lock) { double bank_sense = 0.0; @@ -938,55 +923,37 @@ void FGAIAircraft::updateBankAngles() { } else { bank_sense = -1.0; // left turn } - if (diff < 30) { + if (diff < _performance->maximumBankAngle()) { tgt_roll = diff * bank_sense; } else { - tgt_roll = 30.0 * bank_sense; + tgt_roll = _performance->maximumBankAngle() * bank_sense; } - if ((fabs((double) spinCounter) > 1) && (diff > 30)) { + if ((fabs((double) spinCounter) > 1) && (diff > _performance->maximumBankAngle())) { tgt_speed *= 0.999; // Ugly hack: If aircraft get stuck, they will continually spin around. // The only way to resolve this is to make them slow down. } } - - // adjust bank angle, use 9 degrees per second - double bank_diff = tgt_roll - roll; - if (fabs(bank_diff) > 0.2) { - if (bank_diff > 0.0) - roll += 9.0 * dt; - - if (bank_diff < 0.0) - roll -= 9.0 * dt; - //while (roll > 180) roll -= 360; - //while (roll < 180) roll += 360; - } } -void FGAIAircraft::updateAltitudes() { - // adjust altitude (meters) based on current vertical speed (fpm) - altitude_ft += vs / 60.0 * dt; - pos.setElevationFt(altitude_ft); - +void FGAIAircraft::updateVerticalSpeedTarget() { // adjust target Altitude, based on ground elevation when on ground - if (no_roll) { + if (onGround()) { getGroundElev(dt); doGroundAltitude(); - } else { - // find target vertical speed if altitude lock engaged - if (alt_lock && use_perf_vs) { + } else if (alt_lock) { + // find target vertical speed + if (use_perf_vs) { if (altitude_ft < tgt_altitude_ft) { tgt_vs = tgt_altitude_ft - altitude_ft; - if (tgt_vs > performance->climb_rate) - tgt_vs = performance->climb_rate; + if (tgt_vs > _performance->climbRate()) + tgt_vs = _performance->climbRate(); } else { tgt_vs = tgt_altitude_ft - altitude_ft; - if (tgt_vs < (-performance->descent_rate)) - tgt_vs = -performance->descent_rate; + if (tgt_vs < (-_performance->descentRate())) + tgt_vs = -_performance->descentRate(); } - } - - if (alt_lock && !use_perf_vs) { + } else { double max_vs = 4*(tgt_altitude_ft - altitude_ft); double min_vs = 100; if (tgt_altitude_ft < altitude_ft) @@ -998,34 +965,78 @@ void FGAIAircraft::updateAltitudes() { if (fabs(tgt_vs) < fabs(min_vs)) tgt_vs = min_vs; } - } + } //else + // tgt_vs = 0.0; } +void FGAIAircraft::updatePitchAngleTarget() { + // if on ground and above vRotate -> initial rotation + if (onGround() && (speed > _performance->vRotate())) + tgt_pitch = 8.0; // some rough B737 value -void FGAIAircraft::updateVerticalSpeed() { - // adjust vertical speed - double vs_diff = tgt_vs - vs; - if (fabs(vs_diff) > 10.0) { - if (vs_diff > 0.0) { - vs += (performance->climb_rate / 3.0) * dt; + //TODO pitch angle on approach and landing + + // match pitch angle to vertical speed + else if (tgt_vs > 0) { + tgt_pitch = tgt_vs * 0.005; + } else { + tgt_pitch = tgt_vs * 0.002; + } +} - if (vs > tgt_vs) - vs = tgt_vs; - } else { - vs -= (performance->descent_rate / 3.0) * dt; +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; +} - if (vs < tgt_vs) - vs = tgt_vs; - } +void FGAIAircraft::handleATCRequests() { + //TODO implement NullController for having no ATC to save the conditionals + if (controller) { + controller->update(getID(), + pos.getLatitudeDeg(), + pos.getLongitudeDeg(), + hdg, + speed, + altitude_ft, dt); + processATC(controller->getInstruction(getID())); } } +void FGAIAircraft::updateActualState() { + //update current state + //TODO have a single tgt_speed and check speed limit on ground on setting tgt_speed + updatePosition(); -void FGAIAircraft::matchPitchAngle() { - // match pitch angle to vertical speed - if (vs > 0) { - pitch = vs * 0.005; - } else { - pitch = vs * 0.002; - } + if (onGround()) + speed = _performance->actualSpeed(this, groundTargetSpeed, dt); + else + speed = _performance->actualSpeed(this, tgt_speed, dt); + + updateHeading(); + roll = _performance->actualBankAngle(this, tgt_roll, dt); + + // adjust altitude (meters) based on current vertical speed (fpm) + altitude_ft += vs / 60.0 * dt; + pos.setElevationFt(altitude_ft); + + vs = _performance->actualVerticalSpeed(this, tgt_vs, dt); + pitch = _performance->actualPitch(this, tgt_pitch, dt); +} + +void FGAIAircraft::updateSecondaryTargetValues() { + // derived target state values + updateBankAngleTarget(); + updateVerticalSpeedTarget(); + updatePitchAngleTarget(); + + //TODO calculate wind correction angle (tgt_yaw) }