_pos.setelev(_cruise_alt);
// initially set waypoint as airport location
_wp = _destPos;
- _hdg = GetHeadingFromTo(_pos, _wp);
+ //_hdg = GetHeadingFromTo(_pos, _wp);
+ SetTrack(GetHeadingFromTo(_pos, _wp));
_roll = 0.0;
_pitch = 0.0;
slope = 0.0;
_straightIn = true;
_incoming = true;
_wp = GetPatternApproachPos();
- _hdg = GetHeadingFromTo(_pos, _wp); // TODO - turn properly!
+ //_hdg = GetHeadingFromTo(_pos, _wp); // TODO - turn properly!
+ SetTrack(GetHeadingFromTo(_pos, _wp));
slope = atan((_wp.elev() - _pos.elev()) / dclGetHorizontalSeparation(_wp, _pos)) * DCL_RADIANS_TO_DEGREES;
double thesh_offset = 0.0;
Point3D opos = ortho.ConvertToLocal(_pos);
_downwindEntry = true;
_incoming = true;
_wp = GetPatternApproachPos();
- _hdg = GetHeadingFromTo(_pos, _wp); // TODO - turn properly!
+ SetTrack(GetHeadingFromTo(_pos, _wp));
slope = atan((_wp.elev() - _pos.elev()) / dclGetHorizontalSeparation(_wp, _pos)) * DCL_RADIANS_TO_DEGREES;
//cout << "slope = " << slope << '\n';
pending_transmission = "Report ";
if(_straightIn) {
//cout << "A " << flush;
if(fabs(orthopos.x()) < 10.0 && !_established) {
- _hdg = rwy.hdg; // MEGA MEGA HACK - FIXME!!!!!!!
+ SetTrack(rwy.hdg);
_established = true;
//cout << "Established at " << orthopos << '\n';
}
if(_entering) {
//cout << "C" << flush;
if(_turning) {
- double tgt_hdg = rwy.hdg + 180.0;
- while((tgt_hdg - _hdg) > 180.0) _hdg += 360.0;
- while((_hdg - tgt_hdg) > 180.0) _hdg -= 360.0;
- double turn_time = 60.0;
- _hdg += (360.0 / turn_time) * dt * (tgt_hdg > _hdg ? 1.0 : -1.0);
- Bank(25.0 * (tgt_hdg > _hdg ? 1.0 : -1.0));
- if(fabs(_hdg - tgt_hdg) < 2.0) {
+ if(fabs(_hdg - (rwy.hdg + 180)) < 2.0) { // TODO - use track instead of _hdg?
//cout << "Going Local...\n";
- _hdg = rwy.hdg + 180.0; // TODO - FIX THIS UGLY HACK!!!!!!!
leg = DOWNWIND;
_local = true;
_aip.setVisible(true); // HACK
if(fabs(orthopos.x() - (patternDirection == 1 ? 1000 : -1000)) < (_e45 ? 175 : 550)) { // Caution - hardwired turn clearances.
//cout << "_turning...\n";
_turning = true;
+ SetTrack(rwy.hdg + 180.0);
} // TODO - need to check for other traffic in the pattern and enter much more integilently than that!!!
} else {
//cout << "D" << flush;
slope = 0.0;
ConditionalTransmit(30);
if(_e45) {
- _hdg = (patternDirection == 1 ? rwy.hdg - 135.0 : rwy.hdg + 135.0);
+ SetTrack(patternDirection == 1 ? rwy.hdg - 135.0 : rwy.hdg + 135.0);
} else {
- _hdg = (patternDirection == 1 ? rwy.hdg + 90.0 : rwy.hdg - 90.0);
+ SetTrack(patternDirection == 1 ? rwy.hdg + 90.0 : rwy.hdg - 90.0);
}
- if(_hdg < 0.0) _hdg += 360.0;
+ //if(_hdg < 0.0) _hdg += 360.0;
_entering = true;
+ } else {
+ SetTrack(GetHeadingFromTo(_pos, _wp));
}
}
}
slope = 0.0;
}
// FIXME - lots of hackery in the next six lines!!!!
- double track = _hdg;
- double crab = 0.0;
+ //double track = _hdg;
+ double crab = 0.0; // This is a placeholder for when we take wind into account.
_hdg = track + crab;
double vel = _cruise_ias;
double dist = vel * 0.514444 * dt;
// 3/ At and appropriate point on non-circuit side of rwy at take-off end for perpendicular entry to circuit overflying end-of-rwy.
Point3D FGAIGAVFRTraffic::GetPatternApproachPos() {
//cout << "\n\n";
- //cout << "PPPPPPPPPPPPPPPPPPPPPPPppppppppppppppp\n";
//cout << "Calculating pattern approach pos for " << plane.callsign << '\n';
Point3D orthopos = ortho.ConvertToLocal(_pos);
Point3D tmp;
//cout << "GetRwyDetails called" << endl;
rwy.rwyID = tower->GetActiveRunway();
+ //cout << "id = " << id << '\n';
+ //cout << "Returned id is " << tower->get_ident() << '\n';
+ //cout << "Returned name is " << tower->get_name() << '\n';
+ //cout << "rwy.rwyID = " << rwy.rwyID << '\n';
// Now we need to get the threshold position and rwy heading
rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
} else {
- SG_LOG(SG_ATC, SG_ALERT, "Help - can't get good runway in FGAILocalTraffic!!\n");
+ SG_LOG(SG_ATC, SG_ALERT, "Help - can't get good runway at airport " << id << " in FGAILocalTraffic!!");
}
}
leg = DOWNWIND;
elevInitGood = false;
inAir = true;
- track = rwy.hdg - (180 * patternDirection); //should tend to bring track back into the 0->360 range
+ SetTrack(rwy.hdg - (180 * patternDirection));
slope = 0.0;
_pitch = 0.0;
_roll = 0.0;
leg = DOWNWIND;
elevInitGood = false;
inAir = true;
- track = rwy.hdg - (180 * patternDirection); //should tend to bring track back into the 0->360 range
+ SetTrack(rwy.hdg - (180 * patternDirection));
slope = 0.0;
_pitch = 0.0;
_roll = 0.0;
leg = FINAL;
elevInitGood = false;
inAir = true;
- track = rwy.hdg;
+ SetTrack(rwy.hdg);
transmitted = true; // TODO - fix this hack.
// TODO - set up the next 5 properly for a descent!
slope = -5.5;
//fgSetDouble("/AI/Local1/ortho-y", (ortho.ConvertToLocal(_pos)).y());
//fgSetDouble("/AI/Local1/elev", _pos.elev() * SG_METER_TO_FEET);
- // And finally, call parent for transmission rendering
+ // And finally, call parent.
FGAIPlane::Update(dt);
}
IAS = vel + (cos((_hdg - wind_from) * DCL_DEGREES_TO_RADIANS) * wind_speed);
if(IAS >= 70) {
leg = CLIMBOUT;
+ SetTrack(rwy.hdg); // Hands over control of turning to AIPlane
_pitch = 10.0;
IAS = best_rate_of_climb_speed;
//slope = 7.0;
}
break;
case CLIMBOUT:
- track = rwy.hdg;
// Turn to crosswind if above 700ft AND if other traffic allows
// (decided in FGTower and accessed through GetCrosswindConstraint(...)).
// According to AIM, traffic should climb to within 300ft of pattern altitude before commencing crosswind turn.
}
break;
case TURN1:
- track += (360.0 / turn_time) * dt * patternDirection;
- Bank(25.0 * patternDirection);
+ SetTrack(rwy.hdg + (90.0 * patternDirection));
if((track < (rwy.hdg - 89.0)) || (track > (rwy.hdg + 89.0))) {
leg = CROSSWIND;
}
break;
case CROSSWIND:
goAround = false;
- LevelWings();
- track = rwy.hdg + (90.0 * patternDirection);
if((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 1000) {
slope = 0.0;
_pitch = 0.0;
}
break;
case TURN2:
- track += (360.0 / turn_time) * dt * patternDirection;
- Bank(25.0 * patternDirection);
+ SetTrack(rwy.hdg - (180 * patternDirection));
// just in case we didn't make height on crosswind
if((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 1000) {
slope = 0.0;
if((track < (rwy.hdg - 179.0)) || (track > (rwy.hdg + 179.0))) {
leg = DOWNWIND;
transmitted = false;
- //roll = 0.0;
}
break;
case DOWNWIND:
- LevelWings();
- track = rwy.hdg - (180 * patternDirection); //should tend to bring track back into the 0->360 range
// just in case we didn't make height on crosswind
if(((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 995) && ((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET < 1015)) {
slope = 0.0;
}
break;
case TURN3:
- track += (360.0 / turn_time) * dt * patternDirection;
- Bank(25.0 * patternDirection);
+ SetTrack(rwy.hdg - (90 * patternDirection));
if(fabs(rwy.hdg - track) < 91.0) {
leg = BASE;
}
break;
case BASE:
- LevelWings();
if(!transmitted) {
// Base report should only be transmitted at uncontrolled airport - not towered.
if(!_controlled) TransmitPatternPositionReport();
IAS = 70.0;
}
- track = rwy.hdg - (90 * patternDirection);
-
// Try and arrange to turn nicely onto final
turn_circumference = IAS * 0.514444 * turn_time;
//Hmmm - this is an interesting one - ground vs airspeed in relation to turn radius
}
break;
case TURN4:
- track += (360.0 / turn_time) * dt * patternDirection;
- Bank(25.0 * patternDirection);
+ SetTrack(rwy.hdg);
if(fabs(track - rwy.hdg) < 0.6) {
leg = FINAL;
vel = nominal_final_speed;
}
}
// Try and track the extended centreline
- track = rwy.hdg - (0.2 * orthopos.x());
+ SetTrack(rwy.hdg - (0.2 * orthopos.x()));
//cout << "orthopos.x() = " << orthopos.x() << " hdg = " << hdg << '\n';
if(_pos.elev() < (rwy.threshold_pos.elev()+20.0+wheelOffset)) {
DoGroundElev(); // Need to call it here expicitly on final since it's only called
_pitch = 0.0;
leg = LANDING_ROLL;
inAir = false;
+ LevelWings();
+ ClearTrack(); // Take over explicit track handling since AIPlane currently always banks when changing course
}
} // else need a fallback position based on arpt elev in case ground elev determination fails?
} else {
playing = false;
voiceOK = false;
vPtr = NULL;
+ _tgtTrack = 0.0;
+ _trackSet = false;
+ _tgtRoll = 0.0;
+ _rollSuspended = false;
}
FGAIPlane::~FGAIPlane() {
}
_counter += dt;
}
-}
-
-void FGAIPlane::Bank(double angle) {
- // This *should* bank us smoothly to any angle
- if(fabs(_roll - angle) > 0.6) {
- _roll -= ((_roll - angle)/fabs(_roll - angle));
+
+ // Fly the plane if necessary
+ if(_trackSet) {
+ while((_tgtTrack - track) > 180.0) track += 360.0;
+ while((track - _tgtTrack) > 180.0) track -= 360.0;
+ double turn_time = 60.0;
+ track += (360.0 / turn_time) * dt * (_tgtTrack > track ? 1.0 : -1.0);
+ Bank(25.0 * (_tgtTrack > track ? 1.0 : -1.0));
+ if(fabs(track - _tgtTrack) < 2.0) { // TODO - might need to optimise the delta there - it's on the large (safe) side atm.
+ track = _tgtTrack;
+ LevelWings();
+ }
}
-}
-
-// Duplication of Bank(0.0) really - should I cut this?
-void FGAIPlane::LevelWings(void) {
- // bring the plane back to level smoothly (this should work to come out of either bank)
- if(fabs(_roll) > 0.6) {
- _roll -= (_roll/fabs(_roll));
+
+ if(!_rollSuspended) {
+ if(fabs(_roll - _tgtRoll) > 0.6) {
+ // This *should* bank us smoothly to any angle
+ _roll -= ((_roll - _tgtRoll)/fabs(_roll - _tgtRoll));
+ } else {
+ _roll = _tgtRoll;
+ }
}
}
// Transmit regardless of other dialog on the channel eg emergency
void ImmediateTransmit(int callback_code = 0);
+
+ inline void SetTrack(double t) { _tgtTrack = t; _trackSet = true; }
+ inline void ClearTrack() { _trackSet = false; }
- void Bank(double angle);
- void LevelWings(void);
+ inline void Bank(double r) { _tgtRoll = r; }
+ inline void LevelWings(void) { _tgtRoll = 0.0; }
virtual void ProcessCallback(int code);
bool playing; // Indicates a message in progress
bool voiceOK; // Flag - true if at least one voice has loaded OK
FGATCVoice* vPtr;
+
+ // Navigation
+ double _tgtTrack; // Track to be following if _trackSet is true
+ bool _trackSet; // Set true if tgtTrack is to be followed
+ double _tgtRoll;
+ bool _rollSuspended; // Set true when a derived class has suspended AIPlane's roll control
};
#endif // _FG_AI_PLANE_HXX