Thomas Foerster: Prepare for the inclusion of aircraft specific performance
data for AI traffic. Default performance classes are still available as a backup. This database will allow the calculation of aircraft-specific take-off speed and estimate runway lenght requirements. Further added rudimentary support for take-off and landing rotation of AIAircraft.
This commit is contained in:
parent
0b84cddee7
commit
1613d7e63e
7 changed files with 448 additions and 214 deletions
|
@ -43,28 +43,15 @@
|
|||
SG_USING_STD(string);
|
||||
|
||||
#include "AIAircraft.hxx"
|
||||
#include "performancedata.hxx"
|
||||
#include "performancedb.hxx"
|
||||
|
||||
//#include <Airports/trafficcontroller.hxx>
|
||||
|
||||
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}
|
||||
};
|
||||
class AI_OutOfSight{};
|
||||
class FP_Inactive{};
|
||||
|
||||
FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) {
|
||||
trafficRef = ref;
|
||||
|
@ -92,6 +79,8 @@ FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) {
|
|||
headingChangeRate = 0.0;
|
||||
|
||||
holdPos = false;
|
||||
|
||||
_performance = 0; //TODO initialize to JET_TRANSPORT from PerformanceDB
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,62 +127,36 @@ 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) {
|
||||
void FGAIAircraft::Run(double dt) {
|
||||
FGAIAircraft::dt = dt;
|
||||
|
||||
FGAIAircraft::dt = dt;
|
||||
if (!updateTargetValues())
|
||||
return;
|
||||
try {
|
||||
updatePrimaryTargetValues(); // target hdg, alt, speed
|
||||
}
|
||||
catch (AI_OutOfSight) {
|
||||
return;
|
||||
}
|
||||
catch (FP_Inactive) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (controller) {
|
||||
controller->update(getID(),
|
||||
pos.getLatitudeDeg(),
|
||||
pos.getLongitudeDeg(),
|
||||
hdg,
|
||||
speed,
|
||||
altitude_ft, dt);
|
||||
processATC(controller->getInstruction(getID()));
|
||||
}
|
||||
handleATCRequests(); // ATC also has a word to say
|
||||
updateSecondaryTargetValues(); // target roll, vertical speed, pitch
|
||||
updateActualState();
|
||||
UpdateRadar(manager);
|
||||
}
|
||||
|
||||
if (no_roll) {
|
||||
adjustSpeed(groundTargetSpeed);
|
||||
} else {
|
||||
adjustSpeed(tgt_speed);
|
||||
}
|
||||
|
||||
updatePosition();
|
||||
updateHeading();
|
||||
updateBankAngles();
|
||||
updateAltitudes();
|
||||
updateVerticalSpeed();
|
||||
matchPitchAngle();
|
||||
UpdateRadar(manager);
|
||||
}
|
||||
|
||||
|
||||
void FGAIAircraft::AccelTo(double speed) {
|
||||
|
@ -352,9 +315,7 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -403,8 +364,8 @@ void FGAIAircraft::getGroundElev(double dt) {
|
|||
// to prevent all IA 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) {
|
||||
|
@ -511,6 +472,17 @@ void FGAIAircraft::announcePositionToController() {
|
|||
|
||||
|
||||
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 ()) {}
|
||||
|
||||
|
@ -755,7 +727,7 @@ 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() {
|
||||
if (fp) // AI object has a flightplan
|
||||
{
|
||||
//TODO make this a function of AIBase
|
||||
|
@ -767,13 +739,13 @@ bool FGAIAircraft::updateTargetValues() {
|
|||
// 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) {
|
||||
if (onGround()) {
|
||||
Transform(); // make sure aip is initialized.
|
||||
if (trafficRef) {
|
||||
//cerr << trafficRef->getRegistration() << " Setting altitude to " << altitude_ft;
|
||||
if (! aiTrafficVisible()) {
|
||||
setDie(true);
|
||||
return false;
|
||||
throw AI_OutOfSight();
|
||||
}
|
||||
getGroundElev(dt);
|
||||
doGroundAltitude();
|
||||
|
@ -781,7 +753,7 @@ bool FGAIAircraft::updateTargetValues() {
|
|||
pos.setElevationFt(altitude_ft);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
throw FP_Inactive();
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -813,39 +785,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,7 +812,7 @@ 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);
|
||||
|
||||
if (headingDiff > 180)
|
||||
|
@ -922,7 +863,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 +879,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 +921,64 @@ 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;
|
||||
|
||||
if (vs > tgt_vs)
|
||||
vs = tgt_vs;
|
||||
} else {
|
||||
vs -= (performance->descent_rate / 3.0) * dt;
|
||||
|
||||
if (vs < tgt_vs)
|
||||
vs = tgt_vs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FGAIAircraft::matchPitchAngle() {
|
||||
//TODO pitch angle on approach and landing
|
||||
|
||||
// match pitch angle to vertical speed
|
||||
if (vs > 0) {
|
||||
pitch = vs * 0.005;
|
||||
else if (tgt_vs > 0) {
|
||||
tgt_pitch = tgt_vs * 0.005;
|
||||
} else {
|
||||
pitch = vs * 0.002;
|
||||
tgt_pitch = tgt_vs * 0.002;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -30,33 +30,11 @@
|
|||
#include <string>
|
||||
SG_USING_STD(string);
|
||||
|
||||
class PerformanceData;
|
||||
|
||||
class FGAIAircraft : public FGAIBase {
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
double accel;
|
||||
double decel;
|
||||
double climb_rate;
|
||||
double descent_rate;
|
||||
double takeoff_speed;
|
||||
double climb_speed;
|
||||
double cruise_speed;
|
||||
double descent_speed;
|
||||
double land_speed;
|
||||
} PERF_STRUCT;
|
||||
|
||||
public:
|
||||
enum aircraft_e {
|
||||
LIGHT = 0,
|
||||
WW2_FIGHTER,
|
||||
JET_TRANSPORT,
|
||||
JET_FIGHTER,
|
||||
TANKER,
|
||||
UFO
|
||||
};
|
||||
static const PERF_STRUCT settings[];
|
||||
|
||||
FGAIAircraft(FGAISchedule *ref=0);
|
||||
~FGAIAircraft();
|
||||
|
||||
|
@ -68,32 +46,45 @@ public:
|
|||
virtual void update(double dt);
|
||||
|
||||
void setPerformance(const std::string& perfString);
|
||||
void SetPerformance(const PERF_STRUCT *ps);
|
||||
void setPerformance(PerformanceData *ps);
|
||||
|
||||
void setFlightPlan(const std::string& fp, bool repat = false);
|
||||
void SetFlightPlan(FGAIFlightPlan *f);
|
||||
void initializeFlightPlan();
|
||||
FGAIFlightPlan* GetFlightPlan() const { return fp; };
|
||||
void ProcessFlightPlan( double dt, time_t now );
|
||||
|
||||
void AccelTo(double speed);
|
||||
void PitchTo(double angle);
|
||||
void RollTo(double angle);
|
||||
void YawTo(double angle);
|
||||
void ClimbTo(double altitude);
|
||||
void TurnTo(double heading);
|
||||
void ProcessFlightPlan( double dt, time_t now );
|
||||
|
||||
void setCallSign(const string& );
|
||||
|
||||
void getGroundElev(double dt);
|
||||
void getGroundElev(double dt); //TODO these 3 really need to be public?
|
||||
void doGroundAltitude();
|
||||
void loadNextLeg ();
|
||||
|
||||
void setAcType(const string& ac) { acType = ac; };
|
||||
void setCompany(const string& comp) { company = comp;};
|
||||
|
||||
void announcePositionToController();
|
||||
void announcePositionToController(); //TODO have to be public?
|
||||
void processATC(FGATCInstruction instruction);
|
||||
|
||||
virtual const char* getTypeString(void) const { return "aircraft"; }
|
||||
|
||||
// included as performance data needs them, who else?
|
||||
inline bool onGround() const { return no_roll; };
|
||||
inline double getSpeed() const { return speed; };
|
||||
inline double getRoll() const { return roll; };
|
||||
inline double getPitch() const { return pitch; };
|
||||
inline double getAltitude() const { return altitude_ft; };
|
||||
inline double getVerticalSpeed() const { return vs; };
|
||||
inline double altitudeAGL() const { return props->getFloatValue("position/altitude-agl-ft");};
|
||||
inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");};
|
||||
|
||||
protected:
|
||||
void Run(double dt);
|
||||
|
||||
|
@ -110,11 +101,12 @@ private:
|
|||
double groundOffset;
|
||||
double dt;
|
||||
|
||||
const PERF_STRUCT *performance;
|
||||
bool use_perf_vs;
|
||||
SGPropertyNode_ptr refuel_node;
|
||||
|
||||
// helpers for Run
|
||||
//TODO sort out which ones are better protected virtuals to allow
|
||||
//subclasses to override specific behaviour
|
||||
bool fpExecutable(time_t now);
|
||||
void handleFirstWaypoint(void);
|
||||
bool leadPointReached(FGAIFlightPlan::waypoint* curr);
|
||||
|
@ -122,16 +114,17 @@ private:
|
|||
bool aiTrafficVisible(void);
|
||||
void controlHeading(FGAIFlightPlan::waypoint* curr);
|
||||
void controlSpeed(FGAIFlightPlan::waypoint* curr,
|
||||
FGAIFlightPlan::waypoint* next);
|
||||
bool updateTargetValues();
|
||||
void adjustSpeed(double tgt_speed);
|
||||
FGAIFlightPlan::waypoint* next);
|
||||
void updatePrimaryTargetValues();
|
||||
void updateSecondaryTargetValues();
|
||||
void updatePosition();
|
||||
void updateHeading();
|
||||
void updateBankAngles();
|
||||
void updateAltitudes();
|
||||
void updateVerticalSpeed();
|
||||
void matchPitchAngle();
|
||||
|
||||
void updateBankAngleTarget();
|
||||
void updateVerticalSpeedTarget();
|
||||
void updatePitchAngleTarget();
|
||||
void updateActualState();
|
||||
void handleATCRequests();
|
||||
|
||||
double sign(double x);
|
||||
|
||||
string acType;
|
||||
|
@ -146,6 +139,8 @@ private:
|
|||
bool _getGearDown() const;
|
||||
bool reachedWaypoint;
|
||||
string callsign; // The callsign of this tanker.
|
||||
|
||||
PerformanceData* _performance; // the performance data for this aircraft
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
noinst_LIBRARIES = libAIModel.a
|
||||
|
||||
libAIModel_a_SOURCES = submodel.cxx submodel.hxx \
|
||||
AIManager.hxx AIManager.cxx \
|
||||
AIBase.hxx AIBase.cxx \
|
||||
AIAircraft.hxx AIAircraft.cxx AIMultiplayer.hxx \
|
||||
AIMultiplayer.cxx \
|
||||
AIShip.hxx AIShip.cxx \
|
||||
AIBallistic.hxx AIBallistic.cxx \
|
||||
AIStorm.hxx AIStorm.cxx \
|
||||
AIThermal.hxx AIThermal.cxx \
|
||||
AIFlightPlan.hxx AIFlightPlan.cxx \
|
||||
AIFlightPlanCreate.cxx \
|
||||
AIFlightPlanCreateCruise.cxx \
|
||||
AICarrier.hxx AICarrier.cxx \
|
||||
AIStatic.hxx AIStatic.cxx \
|
||||
AITanker.cxx AITanker.hxx
|
||||
libAIModel_a_SOURCES = submodel.cxx submodel.hxx \
|
||||
AIManager.hxx AIManager.cxx \
|
||||
AIBase.hxx AIBase.cxx \
|
||||
AIAircraft.hxx AIAircraft.cxx \
|
||||
AIMultiplayer.hxx AIMultiplayer.cxx \
|
||||
AIShip.hxx AIShip.cxx \
|
||||
AIBallistic.hxx AIBallistic.cxx \
|
||||
AIStorm.hxx AIStorm.cxx \
|
||||
AIThermal.hxx AIThermal.cxx \
|
||||
AIFlightPlan.hxx AIFlightPlan.cxx \
|
||||
AIFlightPlanCreate.cxx AIFlightPlanCreateCruise.cxx \
|
||||
AICarrier.hxx AICarrier.cxx \
|
||||
AIStatic.hxx AIStatic.cxx \
|
||||
AITanker.cxx AITanker.hxx \
|
||||
performancedata.cxx performancedata.hxx \
|
||||
performancedb.cxx performancedb.hxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||
|
|
148
src/AIModel/performancedata.cxx
Normal file
148
src/AIModel/performancedata.cxx
Normal file
|
@ -0,0 +1,148 @@
|
|||
#include "performancedata.hxx"
|
||||
#include "AIAircraft.hxx"
|
||||
|
||||
PerformanceData::PerformanceData(double acceleration,
|
||||
double deceleration,
|
||||
double climbRate,
|
||||
double descentRate,
|
||||
double vRotate,
|
||||
double vTakeOff,
|
||||
double vClimb,
|
||||
double vCruise,
|
||||
double vDescent,
|
||||
double vApproach,
|
||||
double vTouchdown,
|
||||
double vTaxi) :
|
||||
_acceleration(acceleration),
|
||||
_deceleration(deceleration),
|
||||
_climbRate(climbRate),
|
||||
_descentRate(descentRate),
|
||||
_vRotate(vRotate),
|
||||
_vTakeOff(vTakeOff),
|
||||
_vClimb(vClimb),
|
||||
_vCruise(vCruise),
|
||||
_vDescent(vDescent),
|
||||
_vApproach(vApproach),
|
||||
_vTouchdown(vTouchdown),
|
||||
_vTaxi(vTaxi)
|
||||
{
|
||||
_rollrate = 9.0; // degrees per second
|
||||
_maxbank = 30.0; // passenger friendly bank angle
|
||||
}
|
||||
|
||||
// read perf data from file
|
||||
PerformanceData::PerformanceData( const std::string& filename)
|
||||
{}
|
||||
|
||||
PerformanceData::~PerformanceData()
|
||||
{}
|
||||
|
||||
double PerformanceData::actualSpeed(FGAIAircraft* ac, double tgt_speed, double dt) {
|
||||
// if (tgt_speed > _vTaxi & ac->onGround()) // maximum taxi speed on ground
|
||||
// tgt_speed = _vTaxi;
|
||||
// bad idea for a take off roll :-)
|
||||
|
||||
double speed = ac->getSpeed();
|
||||
double speed_diff = tgt_speed - speed;
|
||||
|
||||
if (speed_diff > 0.0) // need to accelerate
|
||||
{
|
||||
speed += _acceleration * dt;
|
||||
if ( speed > tgt_speed )
|
||||
speed = tgt_speed;
|
||||
|
||||
} else if (speed_diff < 0.0) { // decelerate
|
||||
if (ac->onGround()) {
|
||||
// deceleration performance is better due to wheel brakes.
|
||||
speed -= 3 * _deceleration * dt;
|
||||
} else {
|
||||
speed -= _deceleration * dt;
|
||||
}
|
||||
|
||||
if ( speed < tgt_speed )
|
||||
speed = tgt_speed;
|
||||
|
||||
}
|
||||
|
||||
return speed;
|
||||
}
|
||||
|
||||
double PerformanceData::actualBankAngle(FGAIAircraft* ac, double tgt_roll, double dt) {
|
||||
// check maximum bank angle
|
||||
if (fabs(tgt_roll) > _maxbank)
|
||||
tgt_roll = _maxbank * tgt_roll/fabs(tgt_roll);
|
||||
|
||||
double roll = ac->getRoll();
|
||||
double bank_diff = tgt_roll - roll;
|
||||
|
||||
if (fabs(bank_diff) > 0.2) {
|
||||
if (bank_diff > 0.0) {
|
||||
roll += _rollrate * dt;
|
||||
if (roll > tgt_roll)
|
||||
roll = tgt_roll;
|
||||
}
|
||||
else if (bank_diff < 0.0) {
|
||||
roll -= _rollrate * dt;
|
||||
|
||||
if (roll < tgt_roll)
|
||||
roll = tgt_roll;
|
||||
}
|
||||
//while (roll > 180) roll -= 360;
|
||||
//while (roll < 180) roll += 360;
|
||||
}
|
||||
|
||||
return roll;
|
||||
}
|
||||
|
||||
double PerformanceData::actualPitch(FGAIAircraft* ac, double tgt_pitch, double dt) {
|
||||
double pitch = ac->getPitch();
|
||||
double pdiff = tgt_pitch - pitch;
|
||||
|
||||
if (pdiff > 0.0) { // nose up
|
||||
pitch += 0.005*_climbRate * dt / 3.0; //TODO avoid hardcoded 3 secs
|
||||
|
||||
if (pitch > tgt_pitch)
|
||||
pitch = tgt_pitch;
|
||||
|
||||
} else if (pdiff < 0.0) { // nose down
|
||||
pitch -= 0.002*_descentRate * dt / 3.0;
|
||||
|
||||
if (pitch < tgt_pitch)
|
||||
pitch = tgt_pitch;
|
||||
}
|
||||
|
||||
return pitch;
|
||||
}
|
||||
|
||||
double PerformanceData::actualAltitude(FGAIAircraft* ac, double tgt_altitude, double dt) {
|
||||
if (ac->onGround()) {
|
||||
} else
|
||||
return ac->getAltitude() + ac->getVerticalSpeed()*dt/60.0;
|
||||
}
|
||||
|
||||
double PerformanceData::actualVerticalSpeed(FGAIAircraft* ac, double tgt_vs, double dt) {
|
||||
double vs = ac->getVerticalSpeed();
|
||||
double vs_diff = tgt_vs - vs;
|
||||
|
||||
if (fabs(vs_diff) > 10.0) {
|
||||
if (vs_diff > 0.0) {
|
||||
vs += _climbRate * dt / 3.0; //TODO avoid hardcoded 3 secs to attain climb rate from level flight
|
||||
|
||||
if (vs > tgt_vs)
|
||||
vs = tgt_vs;
|
||||
|
||||
} else if (vs_diff < 0.0) {
|
||||
vs -= _descentRate * dt / 3.0;
|
||||
|
||||
if (vs < tgt_vs)
|
||||
vs = tgt_vs;
|
||||
}
|
||||
}
|
||||
|
||||
return vs;
|
||||
}
|
||||
|
||||
bool PerformanceData::gearExtensible(const FGAIAircraft* ac) {
|
||||
return (ac->altitudeAGL() < 900.0)
|
||||
&& (ac->airspeed() < _vTouchdown * 1.25);
|
||||
}
|
64
src/AIModel/performancedata.hxx
Normal file
64
src/AIModel/performancedata.hxx
Normal file
|
@ -0,0 +1,64 @@
|
|||
#ifndef PERFORMANCEDATA_HXX
|
||||
#define PERFORMANCEDATA_HXX
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
class FGAIAircraft;
|
||||
|
||||
/**
|
||||
Data storage for aircraft performance data. This is used to properly simulate the flight of AIAircrafts.
|
||||
|
||||
@author Thomas Förster <t.foerster@biologie.hu-berlin.de>
|
||||
*/
|
||||
class PerformanceData
|
||||
{
|
||||
public:
|
||||
PerformanceData(double acceleration,
|
||||
double deceleration,
|
||||
double climbRate,
|
||||
double descentRate,
|
||||
double vRotate,
|
||||
double vTakeOff,
|
||||
double vClimb,
|
||||
double vCruise,
|
||||
double vDescent,
|
||||
double vApproach,
|
||||
double vTouchdown,
|
||||
double vTaxi);
|
||||
PerformanceData(const std::string& filename);
|
||||
~PerformanceData();
|
||||
|
||||
double actualSpeed(FGAIAircraft* ac, double tgt_speed, double dt);
|
||||
double actualBankAngle(FGAIAircraft* ac, double tgt_roll, double dt);
|
||||
double actualPitch(FGAIAircraft* ac, double tgt_pitch, double dt);
|
||||
double actualHeading(FGAIAircraft* ac, double tgt_heading, double dt);
|
||||
double actualAltitude(FGAIAircraft* ac, double tgt_altitude, double dt);
|
||||
double actualVerticalSpeed(FGAIAircraft* ac, double tgt_vs, double dt);
|
||||
|
||||
bool gearExtensible(const FGAIAircraft* ac);
|
||||
|
||||
inline double climbRate() { return _climbRate; };
|
||||
inline double descentRate() { return _descentRate; };
|
||||
inline double vRotate() { return _vRotate; };
|
||||
inline double maximumBankAngle() { return _maxbank; };
|
||||
|
||||
private:
|
||||
double _acceleration;
|
||||
double _deceleration;
|
||||
double _climbRate;
|
||||
double _descentRate;
|
||||
double _vRotate;
|
||||
double _vTakeOff;
|
||||
double _vClimb;
|
||||
double _vCruise;
|
||||
double _vDescent;
|
||||
double _vApproach;
|
||||
double _vTouchdown;
|
||||
double _vTaxi;
|
||||
|
||||
double _rollrate;
|
||||
double _maxbank;
|
||||
};
|
||||
|
||||
#endif
|
40
src/AIModel/performancedb.cxx
Normal file
40
src/AIModel/performancedb.cxx
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "performancedb.hxx"
|
||||
|
||||
PerformanceDB::PerformanceDB()
|
||||
{
|
||||
// these are the 6 classes originally defined in the PERFSTRUCT
|
||||
registerPerformanceData("light", new PerformanceData(
|
||||
2.0, 2.0, 450.0, 1000.0, 70.0, 70.0, 80.0, 100.0, 80.0, 70.0, 60.0, 15.0));
|
||||
registerPerformanceData("ww2_fighter", new PerformanceData(
|
||||
4.0, 2.0, 3000.0, 1500.0, 110.0, 110.0, 180.0, 250.0, 200.0, 130.0, 100.0, 15.0));
|
||||
registerPerformanceData("jet_fighter", new PerformanceData(
|
||||
7.0, 3.0, 4000.0, 2000.0, 120.0, 150.0, 350.0, 500.0, 350.0, 170.0, 150.0, 15.0));
|
||||
registerPerformanceData("jet_transport", new PerformanceData(
|
||||
5.0, 2.0, 3000.0, 1500.0, 100.0, 140.0, 300.0, 430.0, 300.0, 170.0, 130.0, 15.0));
|
||||
registerPerformanceData("tanker", new PerformanceData(
|
||||
5.0, 2.0, 3000.0, 1500.0, 100.0, 140.0, 300.0, 430.0, 300.0, 170.0, 130.0, 15.0));
|
||||
registerPerformanceData("ufo", new PerformanceData(
|
||||
30.0, 30.0, 6000.0, 6000.0, 150.0, 150.0, 300.0, 430.0, 300.0, 170.0, 130.0, 15.0));
|
||||
|
||||
}
|
||||
|
||||
|
||||
PerformanceDB::~PerformanceDB()
|
||||
{}
|
||||
|
||||
void PerformanceDB::registerPerformanceData(const std::string& id, PerformanceData* data) {
|
||||
//TODO if key exists already replace data "inplace", i.e. copy to existing PerfData instance
|
||||
// this updates all aircraft currently using the PerfData instance.
|
||||
_db[id] = data;
|
||||
}
|
||||
|
||||
void PerformanceDB::registerPerformanceData(const std::string& id, const std::string& filename) {
|
||||
registerPerformanceData(id, new PerformanceData(filename));
|
||||
}
|
||||
|
||||
PerformanceData* PerformanceDB::getDataFor(const std::string& id) {
|
||||
if (_db.find(id) == _db.end()) // id not found -> return jet_transport data
|
||||
return _db["jet_transport"];
|
||||
|
||||
return _db[id];
|
||||
}
|
33
src/AIModel/performancedb.hxx
Normal file
33
src/AIModel/performancedb.hxx
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef PERFORMANCEDB_HXX
|
||||
#define PERFORMANCEDB_HXX
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "performancedata.hxx"
|
||||
|
||||
/**
|
||||
* Registry for performance data.
|
||||
*
|
||||
* Allows to store performance data for later reuse/retrieval. Just
|
||||
* a simple map for now.
|
||||
*
|
||||
* @author Thomas Förster <t.foerster@biologie.hu-berlin.de>
|
||||
*/
|
||||
//TODO provide std::map interface?
|
||||
class PerformanceDB
|
||||
{
|
||||
public:
|
||||
PerformanceDB();
|
||||
~PerformanceDB();
|
||||
|
||||
void registerPerformanceData(const std::string& id, PerformanceData* data);
|
||||
void registerPerformanceData(const std::string& id, const std::string& filename);
|
||||
|
||||
PerformanceData* getDataFor(const std::string& id);
|
||||
|
||||
private:
|
||||
std::map<std::string, PerformanceData*> _db;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue