#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include <Airports/dynamics.hxx>
-#include <Airports/simple.hxx>
+#include <Airports/airport.hxx>
+#include <Main/util.hxx>
+
+#include <simgear/structure/exception.hxx>
#include <string>
-#include <math.h>
-#include <time.h>
-
-#ifdef _MSC_VER
-# include <float.h>
-# define finite _finite
-#elif defined(__sun) || defined(sgi)
-# include <ieeefp.h>
-#endif
+#include <cmath>
+#include <ctime>
+// defined in AIShip.cxx
+extern double fgIsFinite(double x);
#include "AIAircraft.hxx"
#include "performancedata.hxx"
headingError = 0;
minBearing = 360;
speedFraction =1.0;
+ prev_dist_to_go = 0.0;
holdPos = false;
needsTaxiClearance = false;
takeOffStatus = 0;
trackCache.remainingLength = 0;
+ trackCache.startWptName = "-";
}
void FGAIAircraft::bind() {
FGAIBase::bind();
- tie("controls/gear/gear-down",
- SGRawValueMethods<FGAIAircraft,bool>(*this,
- &FGAIAircraft::_getGearDown));
tie("transponder-id",
SGRawValueMethods<FGAIAircraft,const char*>(*this,
&FGAIAircraft::_getTransponderCode));
handleATCRequests(); // ATC also has a word to say
updateSecondaryTargetValues(); // target roll, vertical speed, pitch
- updateActualState();
- // We currently have one situation in which an AIAircraft object is used that is not attached to the
+ updateActualState();
+#if 0
+ // 25/11/12 - added but disabled, since setting properties isn't
+ // affecting the AI-model as expected.
+ updateModelProperties(dt);
+#endif
+
+ // We currently have one situation in which an AIAircraft object is used that is not attached to the
// AI manager. In this particular case, the AIAircraft is used to shadow the user's aircraft's behavior in the AI world.
// Since we perhaps don't want a radar entry of our own aircraft, the following conditional should probably be adequate
// enough
- if (manager)
+ if (manager){
UpdateRadar(manager);
- checkVisibility();
+ invisible = !manager->isVisible(pos);
+ }
}
-void FGAIAircraft::checkVisibility()
-{
- double visibility_meters = fgGetDouble("/environment/visibility-m");
- invisible = (SGGeodesy::distanceM(globals->get_view_position(), pos) > visibility_meters);
-}
-
-
void FGAIAircraft::AccelTo(double speed) {
tgt_speed = speed;
}
-void FGAIAircraft::setFlightPlan(const std::string& flightplan, bool repeat) {
- if (!flightplan.empty()) {
- FGAIFlightPlan* fp = new FGAIFlightPlan(flightplan);
+void FGAIAircraft::setFlightPlan(const std::string& flightplan, bool repeat)
+{
+ if (flightplan.empty()) {
+ // this is the case for Nasal-scripted aircraft
+ return;
+ }
+
+ FGAIFlightPlan* fp = new FGAIFlightPlan(flightplan);
+ if (fp->isValidPlan()) {
fp->setRepeat(repeat);
SetFlightPlan(fp);
+ } else {
+ SG_LOG(SG_AI, SG_WARN, "setFlightPlan: invalid flightplan specified:" << flightplan);
+ delete fp;
}
}
-void FGAIAircraft::SetFlightPlan(FGAIFlightPlan *f) {
+void FGAIAircraft::SetFlightPlan(FGAIFlightPlan *f)
+{
delete fp;
fp = f;
}
void FGAIAircraft::initializeFlightPlan() {
}
-
-bool FGAIAircraft::_getGearDown() const {
- return _performance->gearExtensible(this);
-}
-
-
const char * FGAIAircraft::_getTransponderCode() const {
return transponderCode.c_str();
}
void FGAIAircraft::announcePositionToController() {
- if (trafficRef) {
- int leg = fp->getLeg();
-
- // 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
- // NOTE: As of July, 30, 2011, the post-creation leg updating is no longer happening.
- // Leg numbers are updated only once the aircraft passes the last waypoint created for that legm so I should probably just use
- // the original leg numbers here!
- switch (leg) {
- case 1: // Startup and Push back
- if (trafficRef->getDepartureAirport()->getDynamics())
- controller = trafficRef->getDepartureAirport()->getDynamics()->getStartupController();
- break;
- case 2: // Taxiing to runway
- if (trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork()->exists())
- controller = trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork();
- break;
- case 3: //Take off tower controller
- if (trafficRef->getDepartureAirport()->getDynamics()) {
- controller = trafficRef->getDepartureAirport()->getDynamics()->getTowerController();
- towerController = 0;
- } else {
- cerr << "Error: Could not find Dynamics at airport : " << trafficRef->getDepartureAirport()->getId() << endl;
- }
- break;
- case 6:
- if (trafficRef->getDepartureAirport()->getDynamics()) {
- controller = trafficRef->getArrivalAirport()->getDynamics()->getApproachController();
- }
- break;
- case 8: // Taxiing for parking
- if (trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork()->exists())
- controller = trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork();
- break;
- default:
- controller = 0;
- break;
+ if (!trafficRef) {
+ return;
+ }
+
+ int leg = fp->getLeg();
+ if (!fp->getCurrentWaypoint()) {
+ // http://code.google.com/p/flightgear-bugs/issues/detail?id=1153
+ // throw an exception so this aircraft gets killed by the AIManager.
+ throw sg_exception("bad AI flight plan");
+ }
+
+ // 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
+ // NOTE: As of July, 30, 2011, the post-creation leg updating is no longer happening.
+ // Leg numbers are updated only once the aircraft passes the last waypoint created for that legm so I should probably just use
+ // the original leg numbers here!
+ switch (leg) {
+ case 1: // Startup and Push back
+ if (trafficRef->getDepartureAirport()->getDynamics())
+ controller = trafficRef->getDepartureAirport()->getDynamics()->getStartupController();
+ break;
+ case 2: // Taxiing to runway
+ if (trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork()->exists())
+ controller = trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork();
+ break;
+ case 3: //Take off tower controller
+ if (trafficRef->getDepartureAirport()->getDynamics()) {
+ controller = trafficRef->getDepartureAirport()->getDynamics()->getTowerController();
+ towerController = 0;
+ } else {
+ cerr << "Error: Could not find Dynamics at airport : " << trafficRef->getDepartureAirport()->getId() << endl;
}
+ break;
+ case 6:
+ if (trafficRef->getDepartureAirport()->getDynamics()) {
+ controller = trafficRef->getArrivalAirport()->getDynamics()->getApproachController();
+ }
+ break;
+ case 8: // Taxiing for parking
+ if (trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork()->exists())
+ controller = trafficRef->getArrivalAirport()->getDynamics()->getGroundNetwork();
+ break;
+ default:
+ controller = 0;
+ break;
+ }
- if ((controller != prevController) && (prevController != 0)) {
- prevController->signOff(getID());
- }
- prevController = controller;
- if (controller) {
- controller->announcePosition(getID(), fp, fp->getCurrentWaypoint()->getRouteIndex(),
- _getLatitude(), _getLongitude(), hdg, speed, altitude_ft,
- trafficRef->getRadius(), leg, this);
- }
+ if ((controller != prevController) && (prevController != 0)) {
+ prevController->signOff(getID());
+ }
+ prevController = controller;
+ if (controller) {
+ controller->announcePosition(getID(), fp, fp->getCurrentWaypoint()->getRouteIndex(),
+ _getLatitude(), _getLongitude(), hdg, speed, altitude_ft,
+ trafficRef->getRadius(), leg, this);
}
}
// Process ATC instructions and report back
-void FGAIAircraft::processATC(FGATCInstruction instruction) {
+void FGAIAircraft::processATC(const FGATCInstruction& instruction) {
if (instruction.getCheckForCircularWait()) {
// This is not exactly an elegant solution,
// but at least it gives me a chance to check
SG_NORMALIZE_RANGE(calc_bearing, 0.0, 360.0);
}
- if (finite(calc_bearing)) {
+ if (fgIsFinite(calc_bearing)) {
double hdg_error = calc_bearing - tgt_heading;
if (fabs(hdg_error) > 0.01) {
TurnTo( calc_bearing );
}
}
}
- if (trafficRef)
- //cerr << trafficRef->getCallSign() << " Heading "
- // << hdg << ". Target " << tgt_heading << ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << "Heading change rate : " << headingChangeRate << " bacnk sence " << bank_sense << endl;
- hdg += headingChangeRate * dt * sqrt(fabs(speed) / 15);
+
+ hdg += headingChangeRate * dt * sqrt(fabs(speed) / 15);
headingError = headingDiff;
if (fabs(headingError) < 1.0) {
hdg = tgt_heading;
}
return (ete - secondsToGo); // Positive when we're too slow...
}
+
+double limitRateOfChange(double cur, double target, double maxDeltaSec, double dt)
+{
+ double delta = target - cur;
+ double maxDelta = maxDeltaSec * dt;
+
+// if delta is > maxDelta, use maxDelta, but with the sign of delta.
+ return (fabs(delta) < maxDelta) ? delta : copysign(maxDelta, delta);
+}
+
+// drive various properties in a semi-realistic fashion.
+void FGAIAircraft::updateModelProperties(double dt)
+{
+ if (!props) {
+ return;
+ }
+
+ SGPropertyNode* gear = props->getChild("gear", 0, true);
+ double targetGearPos = fp->getCurrentWaypoint()->getGear_down() ? 1.0 : 0.0;
+ if (!gear->hasValue("gear/position-norm")) {
+ gear->setDoubleValue("gear/position-norm", targetGearPos);
+ }
+
+ double gearPosNorm = gear->getDoubleValue("gear/position-norm");
+ if (gearPosNorm != targetGearPos) {
+ gearPosNorm += limitRateOfChange(gearPosNorm, targetGearPos, 0.1, dt);
+ if (gearPosNorm < 0.001) {
+ gearPosNorm = 0.0;
+ } else if (gearPosNorm > 0.999) {
+ gearPosNorm = 1.0;
+ }
+
+ for (int i=0; i<6; ++i) {
+ SGPropertyNode* g = gear->getChild("gear", i, true);
+ g->setDoubleValue("position-norm", gearPosNorm);
+ } // of gear setting loop
+ } // of gear in-transit
+
+// double flapPosNorm = props->getDoubleValue();
+}
+