Vivian MEAZZA:
""" "Flight plans" which can start at a given time (gmt) WAITUNTIL tokens which pause the flight plans until a given time (gmt) Submodels can now be attached to any AI objects (except submodels - it can be done, but in my experimental code it's too expensive in frame rate atm) "No-roll" attribute added to Ballistic objects - useful for wakes and the like "Random" attribute added to Ballistic objects (adds =- 5% to the Cd) - useful for smoke, exhausts If the <trigger> tag is not specified the Ballistic object/s will be released at start-up (cannot be stopped) Submodels are not released from AI Objects if the AI Object is more than 15 miles away. """ mf: minor code and formatting fixes; submodels.?xx were FUBAR and are thus astyle formatted; NOTE that <name> tags END, EOF, WAIT, WAITUNTIL are *depreciated*. Don't get too used to them. This will have to be moved from the "name" to regular engries.
This commit is contained in:
parent
caa83238b8
commit
bec023b43c
11 changed files with 1171 additions and 527 deletions
|
@ -3,6 +3,8 @@
|
||||||
// Written by David Culp, started November 2003.
|
// Written by David Culp, started November 2003.
|
||||||
// - davidculp2@comcast.net
|
// - davidculp2@comcast.net
|
||||||
//
|
//
|
||||||
|
// With major additions by Mathias Froehlich & Vivian Meazza 2004-2007
|
||||||
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This program is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU General Public License as
|
// modify it under the terms of the GNU General Public License as
|
||||||
// published by the Free Software Foundation; either version 2 of the
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
@ -22,6 +24,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <simgear/math/point3d.hxx>
|
#include <simgear/math/point3d.hxx>
|
||||||
|
#include <simgear/math/sg_random.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "AIBallistic.hxx"
|
#include "AIBallistic.hxx"
|
||||||
|
@ -57,6 +60,8 @@ void FGAIBallistic::readFromScenario(SGPropertyNode* scFileNode) {
|
||||||
setCd(scFileNode->getDoubleValue("cd", 0.029));
|
setCd(scFileNode->getDoubleValue("cd", 0.029));
|
||||||
setMass(scFileNode->getDoubleValue("mass", 0.007));
|
setMass(scFileNode->getDoubleValue("mass", 0.007));
|
||||||
setStabilisation(scFileNode->getBoolValue("aero_stabilized", false));
|
setStabilisation(scFileNode->getBoolValue("aero_stabilized", false));
|
||||||
|
setNoRoll(scFileNode->getBoolValue("no-roll", false));
|
||||||
|
setRandom(scFileNode->getBoolValue("random", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FGAIBallistic::init(bool search_in_AI_path) {
|
bool FGAIBallistic::init(bool search_in_AI_path) {
|
||||||
|
@ -86,12 +91,10 @@ void FGAIBallistic::update(double dt) {
|
||||||
Transform();
|
Transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FGAIBallistic::setAzimuth(double az) {
|
void FGAIBallistic::setAzimuth(double az) {
|
||||||
hdg = azimuth = az;
|
hdg = azimuth = az;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FGAIBallistic::setElevation(double el) {
|
void FGAIBallistic::setElevation(double el) {
|
||||||
pitch = elevation = el;
|
pitch = elevation = el;
|
||||||
}
|
}
|
||||||
|
@ -104,6 +107,10 @@ void FGAIBallistic::setStabilisation(bool val) {
|
||||||
aero_stabilised = val;
|
aero_stabilised = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGAIBallistic::setNoRoll(bool nr) {
|
||||||
|
no_roll = nr;
|
||||||
|
}
|
||||||
|
|
||||||
void FGAIBallistic::setDragArea(double a) {
|
void FGAIBallistic::setDragArea(double a) {
|
||||||
drag_area = a;
|
drag_area = a;
|
||||||
}
|
}
|
||||||
|
@ -136,8 +143,15 @@ void FGAIBallistic::setMass(double m) {
|
||||||
mass = m;
|
mass = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIBallistic::Run(double dt) {
|
void FGAIBallistic::setRandom(bool r) {
|
||||||
|
random = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIBallistic::setName(const string& n) {
|
||||||
|
name = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIBallistic::Run(double dt) {
|
||||||
life_timer += dt;
|
life_timer += dt;
|
||||||
// cout << "life timer 1" << life_timer << dt << endl;
|
// cout << "life timer 1" << life_timer << dt << endl;
|
||||||
if (life_timer > life) setDie(true);
|
if (life_timer > life) setDie(true);
|
||||||
|
@ -148,14 +162,20 @@ void FGAIBallistic::Run(double dt) {
|
||||||
double wind_speed_from_east_deg_sec;
|
double wind_speed_from_east_deg_sec;
|
||||||
double Cdm; // Cd adjusted by Mach Number
|
double Cdm; // Cd adjusted by Mach Number
|
||||||
|
|
||||||
|
//randomise Cd by +- 5%
|
||||||
|
if (random)
|
||||||
|
Cd = Cd * 0.95 + (0.05 * sg_random());
|
||||||
|
|
||||||
// Adjust Cd by Mach number. The equations are based on curves
|
// Adjust Cd by Mach number. The equations are based on curves
|
||||||
// for a conventional shell/bullet (no boat-tail).
|
// for a conventional shell/bullet (no boat-tail).
|
||||||
if ( Mach < 0.7 ) { Cdm = 0.0125 * Mach + Cd; }
|
if ( Mach < 0.7 )
|
||||||
else if ( 0.7 < Mach && Mach < 1.2 ) {
|
Cdm = 0.0125 * Mach + Cd;
|
||||||
Cdm = 0.3742 * pow ( Mach, 2) - 0.252 * Mach + 0.0021 + Cd; }
|
else if ( 0.7 < Mach && Mach < 1.2 )
|
||||||
else { Cdm = 0.2965 * pow ( Mach, -1.1506 ) + Cd; }
|
Cdm = 0.3742 * pow ( Mach, 2) - 0.252 * Mach + 0.0021 + Cd;
|
||||||
|
else
|
||||||
|
Cdm = 0.2965 * pow ( Mach, -1.1506 ) + Cd;
|
||||||
|
|
||||||
// cout << " Mach , " << Mach << " , Cdm , " << Cdm << endl;
|
//cout << " Mach , " << Mach << " , Cdm , " << Cdm << " ballistic speed kts //"<< speed << endl;
|
||||||
|
|
||||||
// drag = Cd * 0.5 * rho * speed * speed * drag_area;
|
// drag = Cd * 0.5 * rho * speed * speed * drag_area;
|
||||||
// rho is adjusted for altitude in void FGAIBase::update,
|
// rho is adjusted for altitude in void FGAIBase::update,
|
||||||
|
@ -165,11 +185,14 @@ void FGAIBallistic::Run(double dt) {
|
||||||
speed -= (Cdm * 0.5 * rho * speed * speed * drag_area/mass) * dt;
|
speed -= (Cdm * 0.5 * rho * speed * speed * drag_area/mass) * dt;
|
||||||
|
|
||||||
// don't let speed become negative
|
// don't let speed become negative
|
||||||
if ( speed < 0.0 ) speed = 0.0;
|
if ( speed < 0.0 )
|
||||||
|
speed = 0.0;
|
||||||
|
|
||||||
|
double speed_fps = speed * SG_KT_TO_FPS;
|
||||||
|
|
||||||
// calculate vertical and horizontal speed components
|
// calculate vertical and horizontal speed components
|
||||||
vs = sin( pitch * SG_DEGREES_TO_RADIANS ) * speed;
|
vs = sin( pitch * SG_DEGREES_TO_RADIANS ) * speed_fps;
|
||||||
double hs = cos( pitch * SG_DEGREES_TO_RADIANS ) * speed;
|
double hs = cos( pitch * SG_DEGREES_TO_RADIANS ) * speed_fps;
|
||||||
|
|
||||||
// convert horizontal speed (fps) to degrees per second
|
// convert horizontal speed (fps) to degrees per second
|
||||||
speed_north_deg_sec = cos(hdg / SG_RADIANS_TO_DEGREES) * hs / ft_per_deg_lat;
|
speed_north_deg_sec = cos(hdg / SG_RADIANS_TO_DEGREES) * hs / ft_per_deg_lat;
|
||||||
|
@ -186,8 +209,10 @@ void FGAIBallistic::Run(double dt) {
|
||||||
wind_speed_from_east_deg_sec = wind_from_east / ft_per_deg_lon;
|
wind_speed_from_east_deg_sec = wind_from_east / ft_per_deg_lon;
|
||||||
|
|
||||||
// set new position
|
// set new position
|
||||||
pos.setLatitudeDeg( pos.getLatitudeDeg() + (speed_north_deg_sec - wind_speed_from_north_deg_sec) * dt );
|
pos.setLatitudeDeg( pos.getLatitudeDeg()
|
||||||
pos.setLongitudeDeg( pos.getLongitudeDeg() + (speed_east_deg_sec - wind_speed_from_east_deg_sec) * dt );
|
+ (speed_north_deg_sec - wind_speed_from_north_deg_sec) * dt );
|
||||||
|
pos.setLongitudeDeg( pos.getLongitudeDeg()
|
||||||
|
+ (speed_east_deg_sec - wind_speed_from_east_deg_sec) * dt );
|
||||||
|
|
||||||
// adjust vertical speed for acceleration of gravity and buoyancy
|
// adjust vertical speed for acceleration of gravity and buoyancy
|
||||||
vs -= (gravity - buoyancy) * dt;
|
vs -= (gravity - buoyancy) * dt;
|
||||||
|
@ -197,11 +222,14 @@ void FGAIBallistic::Run(double dt) {
|
||||||
pos.setElevationFt(altitude_ft);
|
pos.setElevationFt(altitude_ft);
|
||||||
|
|
||||||
// recalculate pitch (velocity vector) if aerostabilized
|
// recalculate pitch (velocity vector) if aerostabilized
|
||||||
// cout << "aero_stabilised " << aero_stabilised << endl ;
|
/*cout << name << ": " << "aero_stabilised " << aero_stabilised
|
||||||
if (aero_stabilised) pitch = atan2( vs, hs ) * SG_RADIANS_TO_DEGREES;
|
<< " pitch " << pitch <<" vs " << vs <<endl ;*/
|
||||||
|
|
||||||
|
if (aero_stabilised)
|
||||||
|
pitch = atan2( vs, hs ) * SG_RADIANS_TO_DEGREES;
|
||||||
|
|
||||||
// recalculate total speed
|
// recalculate total speed
|
||||||
speed = sqrt( vs * vs + hs * hs);
|
speed = sqrt( vs * vs + hs * hs) / SG_KT_TO_FPS;
|
||||||
|
|
||||||
// set destruction flag if altitude less than sea level -1000
|
// set destruction flag if altitude less than sea level -1000
|
||||||
if (altitude_ft < -1000.0) setDie(true);
|
if (altitude_ft < -1000.0) setDie(true);
|
||||||
|
|
|
@ -36,6 +36,7 @@ public:
|
||||||
bool init(bool search_in_AI_path=false);
|
bool init(bool search_in_AI_path=false);
|
||||||
virtual void bind();
|
virtual void bind();
|
||||||
virtual void unbind();
|
virtual void unbind();
|
||||||
|
|
||||||
void update(double dt);
|
void update(double dt);
|
||||||
|
|
||||||
void setAzimuth( double az );
|
void setAzimuth( double az );
|
||||||
|
@ -50,6 +51,9 @@ public:
|
||||||
void setWind( bool val );
|
void setWind( bool val );
|
||||||
void setCd( double c );
|
void setCd( double c );
|
||||||
void setMass( double m );
|
void setMass( double m );
|
||||||
|
void setNoRoll( bool nr );
|
||||||
|
void setRandom( bool r );
|
||||||
|
void setName(const string&);
|
||||||
|
|
||||||
double _getTime() const;
|
double _getTime() const;
|
||||||
|
|
||||||
|
@ -60,7 +64,7 @@ private:
|
||||||
double azimuth; // degrees true
|
double azimuth; // degrees true
|
||||||
double elevation; // degrees
|
double elevation; // degrees
|
||||||
double rotation; // degrees
|
double rotation; // degrees
|
||||||
bool aero_stabilised; // if true, object will align wit trajectory
|
bool aero_stabilised; // if true, object will align with trajectory
|
||||||
double drag_area; // equivalent drag area in ft2
|
double drag_area; // equivalent drag area in ft2
|
||||||
double life_timer; // seconds
|
double life_timer; // seconds
|
||||||
double gravity; // fps2
|
double gravity; // fps2
|
||||||
|
@ -70,9 +74,10 @@ private:
|
||||||
bool wind; // if true, local wind will be applied to object
|
bool wind; // if true, local wind will be applied to object
|
||||||
double Cd; // drag coefficient
|
double Cd; // drag coefficient
|
||||||
double mass; // slugs
|
double mass; // slugs
|
||||||
|
bool random; // modifier for Cd
|
||||||
|
string name;
|
||||||
|
|
||||||
void Run(double dt);
|
void Run(double dt);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _FG_AIBALLISTIC_HXX
|
#endif // _FG_AIBALLISTIC_HXX
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
// David Luff's FGAIEntity class.
|
// David Luff's FGAIEntity class.
|
||||||
// - davidculp2@comcast.net
|
// - davidculp2@comcast.net
|
||||||
//
|
//
|
||||||
|
// With additions by Mathias Froehlich & Vivian Meazza 2004 -2007
|
||||||
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This program is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU General Public License as
|
// modify it under the terms of the GNU General Public License as
|
||||||
// published by the Free Software Foundation; either version 2 of the
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
@ -76,18 +78,24 @@ FGAIBase::~FGAIBase() {
|
||||||
globals->get_scenery()->unregister_placement_transform(aip.getTransform());
|
globals->get_scenery()->unregister_placement_transform(aip.getTransform());
|
||||||
globals->get_scenery()->get_scene_graph()->removeChild(aip.getSceneGraph());
|
globals->get_scenery()->get_scene_graph()->removeChild(aip.getSceneGraph());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props) {
|
if (props) {
|
||||||
SGPropertyNode* parent = props->getParent();
|
SGPropertyNode* parent = props->getParent();
|
||||||
|
|
||||||
if (parent) {
|
if (parent) {
|
||||||
model_removed->setStringValue(props->getPath());
|
model_removed->setStringValue(props->getPath());
|
||||||
parent->removeChild(props->getName(), props->getIndex(), false);
|
parent->removeChild(props->getName(), props->getIndex(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// so that radar does not have to do extra checks
|
||||||
|
props->setBoolValue("radar/in-range", false);
|
||||||
|
props->removeChild("id", 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
delete fp;
|
delete fp;
|
||||||
fp = 0;
|
fp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FGAIBase::readFromScenario(SGPropertyNode* scFileNode)
|
void FGAIBase::readFromScenario(SGPropertyNode* scFileNode)
|
||||||
{
|
{
|
||||||
if (!scFileNode)
|
if (!scFileNode)
|
||||||
|
@ -101,11 +109,21 @@ void FGAIBase::readFromScenario(SGPropertyNode* scFileNode)
|
||||||
setLongitude(scFileNode->getDoubleValue("longitude", 0.0));
|
setLongitude(scFileNode->getDoubleValue("longitude", 0.0));
|
||||||
setLatitude(scFileNode->getDoubleValue("latitude", 0.0));
|
setLatitude(scFileNode->getDoubleValue("latitude", 0.0));
|
||||||
setBank(scFileNode->getDoubleValue("roll", 0.0));
|
setBank(scFileNode->getDoubleValue("roll", 0.0));
|
||||||
|
|
||||||
|
SGPropertyNode* submodels = scFileNode->getChild("submodels");
|
||||||
|
|
||||||
|
if (submodels) {
|
||||||
|
setServiceable(submodels->getBoolValue("serviceable", false));
|
||||||
|
setSMPath(submodels->getStringValue("path", ""));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIBase::update(double dt) {
|
void FGAIBase::update(double dt) {
|
||||||
|
|
||||||
if (_otype == otStatic)
|
if (_otype == otStatic)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_otype == otBallistic)
|
if (_otype == otBallistic)
|
||||||
CalculateMach();
|
CalculateMach();
|
||||||
|
|
||||||
|
@ -114,19 +132,24 @@ void FGAIBase::update(double dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIBase::Transform() {
|
void FGAIBase::Transform() {
|
||||||
|
|
||||||
if (!invisible) {
|
if (!invisible) {
|
||||||
aip.setPosition(pos);
|
aip.setPosition(pos);
|
||||||
if (no_roll) {
|
|
||||||
|
if (no_roll)
|
||||||
aip.setOrientation(0.0, pitch, hdg);
|
aip.setOrientation(0.0, pitch, hdg);
|
||||||
} else {
|
else
|
||||||
aip.setOrientation(roll, pitch, hdg);
|
aip.setOrientation(roll, pitch, hdg);
|
||||||
}
|
|
||||||
aip.update();
|
aip.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FGAIBase::init(bool search_in_AI_path) {
|
bool FGAIBase::init(bool search_in_AI_path) {
|
||||||
|
|
||||||
if (!model_path.empty()) {
|
if (!model_path.empty()) {
|
||||||
|
|
||||||
if ( (search_in_AI_path)
|
if ( (search_in_AI_path)
|
||||||
&&(model_path.substr(model_path.size() - 4, 4) == ".xml")) {
|
&&(model_path.substr(model_path.size() - 4, 4) == ".xml")) {
|
||||||
SGPath ai_path("AI");
|
SGPath ai_path("AI");
|
||||||
|
@ -137,7 +160,9 @@ bool FGAIBase::init(bool search_in_AI_path) {
|
||||||
} catch (const sg_exception &e) {
|
} catch (const sg_exception &e) {
|
||||||
model = NULL;
|
model = NULL;
|
||||||
}
|
}
|
||||||
} else model = NULL;
|
} else
|
||||||
|
model = NULL;
|
||||||
|
|
||||||
if (!model) {
|
if (!model) {
|
||||||
try {
|
try {
|
||||||
model = load3DModel( globals->get_fg_root(), model_path, props,
|
model = load3DModel( globals->get_fg_root(), model_path, props,
|
||||||
|
@ -145,29 +170,33 @@ bool FGAIBase::init(bool search_in_AI_path) {
|
||||||
} catch (const sg_exception &e) {
|
} catch (const sg_exception &e) {
|
||||||
model = NULL;
|
model = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|
||||||
if (model.get()) {
|
if (model.get()) {
|
||||||
aip.init( model.get() );
|
aip.init( model.get() );
|
||||||
aip.setVisible(true);
|
aip.setVisible(true);
|
||||||
invisible = false;
|
invisible = false;
|
||||||
globals->get_scenery()->get_scene_graph()->addChild(aip.getSceneGraph());
|
globals->get_scenery()->get_scene_graph()->addChild(aip.getSceneGraph());
|
||||||
|
|
||||||
// Register that one at the scenery manager
|
// Register that one at the scenery manager
|
||||||
globals->get_scenery()->register_placement_transform(aip.getTransform());
|
globals->get_scenery()->register_placement_transform(aip.getTransform());
|
||||||
fgSetString("/ai/models/model-added", props->getPath());
|
fgSetString("/ai/models/model-added", props->getPath());
|
||||||
} else {
|
} else {
|
||||||
if (!model_path.empty()) {
|
|
||||||
|
if (!model_path.empty())
|
||||||
SG_LOG(SG_INPUT, SG_WARN, "AIBase: Could not load model " << model_path);
|
SG_LOG(SG_INPUT, SG_WARN, "AIBase: Could not load model " << model_path);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
props->setStringValue("submodels/path", _path.c_str());
|
||||||
setDie(false);
|
setDie(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
osg::Node*
|
osg::Node* FGAIBase::load3DModel(const string& fg_root,
|
||||||
FGAIBase::load3DModel(const string& fg_root,
|
|
||||||
const string &path,
|
const string &path,
|
||||||
SGPropertyNode *prop_root,
|
SGPropertyNode *prop_root,
|
||||||
double sim_time_sec)
|
double sim_time_sec)
|
||||||
|
@ -178,10 +207,11 @@ FGAIBase::load3DModel(const string& fg_root,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FGAIBase::isa( object_type otype ) {
|
bool FGAIBase::isa( object_type otype ) {
|
||||||
if ( otype == _otype )
|
|
||||||
return true;
|
if ( otype == _otype )
|
||||||
else
|
return true;
|
||||||
return false;
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -283,8 +313,7 @@ void FGAIBase::unbind() {
|
||||||
props->untie("controls/lighting/nav-lights");
|
props->untie("controls/lighting/nav-lights");
|
||||||
}
|
}
|
||||||
|
|
||||||
double FGAIBase::UpdateRadar(FGAIManager* manager)
|
double FGAIBase::UpdateRadar(FGAIManager* manager) {
|
||||||
{
|
|
||||||
double radar_range_ft2 = fgGetDouble("/instrumentation/radar/range");
|
double radar_range_ft2 = fgGetDouble("/instrumentation/radar/range");
|
||||||
bool force_on = fgGetBool("/instrumentation/radar/debug-mode", false);
|
bool force_on = fgGetBool("/instrumentation/radar/debug-mode", false);
|
||||||
radar_range_ft2 *= SG_NM_TO_METER * SG_METER_TO_FEET * 1.1; // + 10%
|
radar_range_ft2 *= SG_NM_TO_METER * SG_METER_TO_FEET * 1.1; // + 10%
|
||||||
|
@ -300,8 +329,8 @@ double FGAIBase::UpdateRadar(FGAIManager* manager)
|
||||||
// Test whether the target is within radar range.
|
// Test whether the target is within radar range.
|
||||||
//
|
//
|
||||||
in_range = (range_ft2 && (range_ft2 <= radar_range_ft2));
|
in_range = (range_ft2 && (range_ft2 <= radar_range_ft2));
|
||||||
if ( in_range || force_on )
|
|
||||||
{
|
if ( in_range || force_on ) {
|
||||||
props->setBoolValue("radar/in-range", true);
|
props->setBoolValue("radar/in-range", true);
|
||||||
|
|
||||||
// copy values from the AIManager
|
// copy values from the AIManager
|
||||||
|
@ -382,12 +411,14 @@ double FGAIBase::UpdateRadar(FGAIManager* manager)
|
||||||
return range_ft2;
|
return range_ft2;
|
||||||
}
|
}
|
||||||
|
|
||||||
SGVec3d
|
/*
|
||||||
FGAIBase::getCartPosAt(const SGVec3d& _off) const
|
* Getters and Setters
|
||||||
{
|
*/
|
||||||
// Transform that one to the horizontal local coordinate system.
|
|
||||||
|
|
||||||
|
SGVec3d FGAIBase::getCartPosAt(const SGVec3d& _off) const {
|
||||||
|
// Transform that one to the horizontal local coordinate system.
|
||||||
SGQuatd hlTrans = SGQuatd::fromLonLat(pos);
|
SGQuatd hlTrans = SGQuatd::fromLonLat(pos);
|
||||||
|
|
||||||
// and postrotate the orientation of the AIModel wrt the horizontal
|
// and postrotate the orientation of the AIModel wrt the horizontal
|
||||||
// local frame
|
// local frame
|
||||||
hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
|
hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
|
||||||
|
@ -402,12 +433,10 @@ FGAIBase::getCartPosAt(const SGVec3d& _off) const
|
||||||
return cartPos + off;
|
return cartPos + off;
|
||||||
}
|
}
|
||||||
|
|
||||||
SGVec3d
|
SGVec3d FGAIBase::getCartPos() const {
|
||||||
FGAIBase::getCartPos() const
|
|
||||||
{
|
|
||||||
// Transform that one to the horizontal local coordinate system.
|
// Transform that one to the horizontal local coordinate system.
|
||||||
|
|
||||||
SGQuatd hlTrans = SGQuatd::fromLonLat(pos);
|
SGQuatd hlTrans = SGQuatd::fromLonLat(pos);
|
||||||
|
|
||||||
// and postrotate the orientation of the AIModel wrt the horizontal
|
// and postrotate the orientation of the AIModel wrt the horizontal
|
||||||
// local frame
|
// local frame
|
||||||
hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
|
hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
|
||||||
|
@ -417,33 +446,25 @@ FGAIBase::getCartPos() const
|
||||||
return cartPos;
|
return cartPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double FGAIBase::_getCartPosX() const {
|
||||||
FGAIBase::_getCartPosX() const
|
|
||||||
{
|
|
||||||
SGVec3d cartPos = getCartPos();
|
SGVec3d cartPos = getCartPos();
|
||||||
return cartPos.x();
|
return cartPos.x();
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double FGAIBase::_getCartPosY() const {
|
||||||
FGAIBase::_getCartPosY() const
|
|
||||||
{
|
|
||||||
SGVec3d cartPos = getCartPos();
|
SGVec3d cartPos = getCartPos();
|
||||||
return cartPos.y();
|
return cartPos.y();
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double FGAIBase::_getCartPosZ() const {
|
||||||
FGAIBase::_getCartPosZ() const
|
|
||||||
{
|
|
||||||
SGVec3d cartPos = getCartPos();
|
SGVec3d cartPos = getCartPos();
|
||||||
return cartPos.z();
|
return cartPos.z();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* getters and Setters
|
|
||||||
*/
|
|
||||||
void FGAIBase::_setLongitude( double longitude ) {
|
void FGAIBase::_setLongitude( double longitude ) {
|
||||||
pos.setLongitudeDeg(longitude);
|
pos.setLongitudeDeg(longitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIBase::_setLatitude ( double latitude ) {
|
void FGAIBase::_setLatitude ( double latitude ) {
|
||||||
pos.setLatitudeDeg(latitude);
|
pos.setLatitudeDeg(latitude);
|
||||||
}
|
}
|
||||||
|
@ -451,15 +472,27 @@ void FGAIBase::_setLatitude ( double latitude ) {
|
||||||
double FGAIBase::_getLongitude() const {
|
double FGAIBase::_getLongitude() const {
|
||||||
return pos.getLongitudeDeg();
|
return pos.getLongitudeDeg();
|
||||||
}
|
}
|
||||||
|
|
||||||
double FGAIBase::_getLatitude () const {
|
double FGAIBase::_getLatitude () const {
|
||||||
return pos.getLatitudeDeg();
|
return pos.getLatitudeDeg();
|
||||||
}
|
}
|
||||||
|
|
||||||
double FGAIBase::_getRdot() const {
|
double FGAIBase::_getRdot() const {
|
||||||
return rdot;
|
return rdot;
|
||||||
}
|
}
|
||||||
|
|
||||||
double FGAIBase::_getVS_fps() const {
|
double FGAIBase::_getVS_fps() const {
|
||||||
return vs*60.0;
|
return vs*60.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double FGAIBase::_get_speed_east_fps() const {
|
||||||
|
return speed_east_deg_sec * ft_per_deg_lon;
|
||||||
|
}
|
||||||
|
|
||||||
|
double FGAIBase::_get_speed_north_fps() const {
|
||||||
|
return speed_north_deg_sec * ft_per_deg_lat;
|
||||||
|
}
|
||||||
|
|
||||||
void FGAIBase::_setVS_fps( double _vs ) {
|
void FGAIBase::_setVS_fps( double _vs ) {
|
||||||
vs = _vs/60.0;
|
vs = _vs/60.0;
|
||||||
}
|
}
|
||||||
|
@ -467,6 +500,11 @@ void FGAIBase::_setVS_fps( double _vs ) {
|
||||||
double FGAIBase::_getAltitude() const {
|
double FGAIBase::_getAltitude() const {
|
||||||
return altitude_ft;
|
return altitude_ft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FGAIBase::_getServiceable() const {
|
||||||
|
return serviceable;
|
||||||
|
}
|
||||||
|
|
||||||
void FGAIBase::_setAltitude( double _alt ) {
|
void FGAIBase::_setAltitude( double _alt ) {
|
||||||
setAltitude( _alt );
|
setAltitude( _alt );
|
||||||
}
|
}
|
||||||
|
@ -479,20 +517,37 @@ int FGAIBase::getID() const {
|
||||||
return _refID;
|
return _refID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double FGAIBase::_getSpeed() const {
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
double FGAIBase::_getRoll() const {
|
||||||
|
return roll;
|
||||||
|
}
|
||||||
|
|
||||||
|
double FGAIBase::_getPitch() const {
|
||||||
|
return pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
double FGAIBase::_getHeading() const {
|
||||||
|
return hdg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* FGAIBase::_getPath() {
|
||||||
|
return _path.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
void FGAIBase::CalculateMach() {
|
void FGAIBase::CalculateMach() {
|
||||||
// Calculate rho at altitude, using standard atmosphere
|
// Calculate rho at altitude, using standard atmosphere
|
||||||
// For the temperature T and the pressure p,
|
// For the temperature T and the pressure p,
|
||||||
|
|
||||||
double altitude = altitude_ft;
|
double altitude = altitude_ft;
|
||||||
|
|
||||||
if (altitude < 36152) { // curve fits for the troposphere
|
if (altitude < 36152) { // curve fits for the troposphere
|
||||||
T = 59 - 0.00356 * altitude;
|
T = 59 - 0.00356 * altitude;
|
||||||
p = 2116 * pow( ((T + 459.7) / 518.6) , 5.256);
|
p = 2116 * pow( ((T + 459.7) / 518.6) , 5.256);
|
||||||
|
|
||||||
} else if ( 36152 < altitude && altitude < 82345 ) { // lower stratosphere
|
} else if ( 36152 < altitude && altitude < 82345 ) { // lower stratosphere
|
||||||
T = -70;
|
T = -70;
|
||||||
p = 473.1 * pow( e , 1.73 - (0.000048 * altitude) );
|
p = 473.1 * pow( e , 1.73 - (0.000048 * altitude) );
|
||||||
|
|
||||||
} else { // upper stratosphere
|
} else { // upper stratosphere
|
||||||
T = -205.05 + (0.00164 * altitude);
|
T = -205.05 + (0.00164 * altitude);
|
||||||
p = 51.97 * pow( ((T + 459.7) / 389.98) , -11.388);
|
p = 51.97 * pow( ((T + 459.7) / 389.98) , -11.388);
|
||||||
|
@ -506,20 +561,20 @@ void FGAIBase::CalculateMach() {
|
||||||
// a = speed of sound [ft/s]
|
// a = speed of sound [ft/s]
|
||||||
// g = specific heat ratio, which is usually equal to 1.4
|
// g = specific heat ratio, which is usually equal to 1.4
|
||||||
// R = specific gas constant, which equals 1716 ft-lb/slug/°R
|
// R = specific gas constant, which equals 1716 ft-lb/slug/°R
|
||||||
|
|
||||||
a = sqrt ( 1.4 * 1716 * (T + 459.7));
|
a = sqrt ( 1.4 * 1716 * (T + 459.7));
|
||||||
|
|
||||||
// calculate Mach number
|
// calculate Mach number
|
||||||
|
|
||||||
Mach = speed/a;
|
Mach = speed/a;
|
||||||
|
|
||||||
// cout << "Speed(ft/s) "<< speed <<" Altitude(ft) "<< altitude << " Mach " << Mach;
|
// cout << "Speed(ft/s) "<< speed <<" Altitude(ft) "<< altitude << " Mach " << Mach << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FGAIBase::_newAIModelID() {
|
int FGAIBase::_newAIModelID() {
|
||||||
static int id = 0;
|
static int id = 0;
|
||||||
|
|
||||||
if (!++id)
|
if (!++id)
|
||||||
id++; // id = 0 is not allowed.
|
id++; // id = 0 is not allowed.
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
|
|
||||||
void setManager(FGAIManager* mgr, SGPropertyNode* p);
|
void setManager(FGAIManager* mgr, SGPropertyNode* p);
|
||||||
void setPath( const char* model );
|
void setPath( const char* model );
|
||||||
|
void setSMPath( const string& p );
|
||||||
void setSpeed( double speed_KTAS );
|
void setSpeed( double speed_KTAS );
|
||||||
void setAltitude( double altitude_ft );
|
void setAltitude( double altitude_ft );
|
||||||
void setHeading( double heading );
|
void setHeading( double heading );
|
||||||
|
@ -70,20 +71,23 @@ public:
|
||||||
void setXoffset( double x_offset );
|
void setXoffset( double x_offset );
|
||||||
void setYoffset( double y_offset );
|
void setYoffset( double y_offset );
|
||||||
void setZoffset( double z_offset );
|
void setZoffset( double z_offset );
|
||||||
|
void setServiceable ( bool serviceable );
|
||||||
|
void setDie( bool die );
|
||||||
|
|
||||||
int getID() const;
|
int getID() const;
|
||||||
|
|
||||||
void setDie( bool die );
|
|
||||||
bool getDie();
|
bool getDie();
|
||||||
|
|
||||||
SGVec3d getCartPosAt(const SGVec3d& off) const;
|
SGVec3d getCartPosAt(const SGVec3d& off) const;
|
||||||
SGVec3d getCartPos() const;
|
SGVec3d getCartPos() const;
|
||||||
|
|
||||||
double _getCartPosX() const;
|
double _getCartPosX() const;
|
||||||
double _getCartPosY() const;
|
double _getCartPosY() const;
|
||||||
double _getCartPosZ() const;
|
double _getCartPosZ() const;
|
||||||
|
|
||||||
protected:
|
string _path;
|
||||||
|
|
||||||
|
protected:
|
||||||
SGPropertyNode_ptr props;
|
SGPropertyNode_ptr props;
|
||||||
SGPropertyNode_ptr model_removed; // where to report model removal
|
SGPropertyNode_ptr model_removed; // where to report model removal
|
||||||
FGAIManager* manager;
|
FGAIManager* manager;
|
||||||
|
@ -96,6 +100,8 @@ protected:
|
||||||
double speed; // knots true airspeed
|
double speed; // knots true airspeed
|
||||||
double altitude_ft; // feet above sea level
|
double altitude_ft; // feet above sea level
|
||||||
double vs; // vertical speed, feet per minute
|
double vs; // vertical speed, feet per minute
|
||||||
|
double speed_north_deg_sec;
|
||||||
|
double speed_east_deg_sec;
|
||||||
double turn_radius_ft; // turn radius ft at 15 kts rudder angle 15 degrees
|
double turn_radius_ft; // turn radius ft at 15 kts rudder angle 15 degrees
|
||||||
|
|
||||||
double ft_per_deg_lon;
|
double ft_per_deg_lon;
|
||||||
|
@ -126,10 +132,14 @@ protected:
|
||||||
string model_path; //Path to the 3D model
|
string model_path; //Path to the 3D model
|
||||||
osg::ref_ptr<osg::Node> model; //The 3D model object
|
osg::ref_ptr<osg::Node> model; //The 3D model object
|
||||||
SGModelPlacement aip;
|
SGModelPlacement aip;
|
||||||
|
|
||||||
bool delete_me;
|
bool delete_me;
|
||||||
bool invisible;
|
bool invisible;
|
||||||
bool no_roll;
|
bool no_roll;
|
||||||
|
bool serviceable;
|
||||||
|
|
||||||
double life;
|
double life;
|
||||||
|
|
||||||
FGAIFlightPlan *fp;
|
FGAIFlightPlan *fp;
|
||||||
|
|
||||||
void Transform();
|
void Transform();
|
||||||
|
@ -143,23 +153,21 @@ private:
|
||||||
object_type _otype;
|
object_type _otype;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
object_type getType();
|
object_type getType();
|
||||||
|
|
||||||
virtual const char* getTypeString(void) const { return "null"; }
|
virtual const char* getTypeString(void) const { return "null"; }
|
||||||
|
|
||||||
bool isa( object_type otype );
|
bool isa( object_type otype );
|
||||||
|
|
||||||
double _getVS_fps() const;
|
|
||||||
void _setVS_fps( double _vs );
|
void _setVS_fps( double _vs );
|
||||||
|
|
||||||
double _getAltitude() const;
|
|
||||||
void _setAltitude( double _alt );
|
void _setAltitude( double _alt );
|
||||||
|
|
||||||
void _setLongitude( double longitude );
|
void _setLongitude( double longitude );
|
||||||
void _setLatitude ( double latitude );
|
void _setLatitude ( double latitude );
|
||||||
|
|
||||||
|
double _getVS_fps() const;
|
||||||
|
double _getAltitude() const;
|
||||||
double _getLongitude() const;
|
double _getLongitude() const;
|
||||||
double _getLatitude () const;
|
double _getLatitude () const;
|
||||||
|
|
||||||
double _getBearing() const;
|
double _getBearing() const;
|
||||||
double _getElevation() const;
|
double _getElevation() const;
|
||||||
double _getRdot() const;
|
double _getRdot() const;
|
||||||
|
@ -168,6 +176,19 @@ public:
|
||||||
double _getX_shift() const;
|
double _getX_shift() const;
|
||||||
double _getY_shift() const;
|
double _getY_shift() const;
|
||||||
double _getRotation() const;
|
double _getRotation() const;
|
||||||
|
double _getSpeed() const;
|
||||||
|
double _getRoll() const;
|
||||||
|
double _getPitch() const;
|
||||||
|
double _getHeading() const;
|
||||||
|
double _get_speed_east_fps() const;
|
||||||
|
double _get_speed_north_fps() const;
|
||||||
|
|
||||||
|
bool _getServiceable() const;
|
||||||
|
|
||||||
|
const char* _getPath();
|
||||||
|
const char* _getCallsign();
|
||||||
|
|
||||||
|
// These are used in the Mach number calculations
|
||||||
|
|
||||||
double rho;
|
double rho;
|
||||||
double T; // temperature, degs farenheit
|
double T; // temperature, degs farenheit
|
||||||
|
@ -196,6 +217,15 @@ inline void FGAIBase::setPath(const char* model ) {
|
||||||
model_path.append(model);
|
model_path.append(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void FGAIBase::setSMPath(const string& p) {
|
||||||
|
_path = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void FGAIBase::setServiceable(bool s) {
|
||||||
|
serviceable = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void FGAIBase::setSpeed( double speed_KTAS ) {
|
inline void FGAIBase::setSpeed( double speed_KTAS ) {
|
||||||
speed = tgt_speed = speed_KTAS;
|
speed = tgt_speed = speed_KTAS;
|
||||||
}
|
}
|
||||||
|
@ -230,11 +260,9 @@ inline void FGAIBase::setLatitude ( double latitude ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void FGAIBase::setDie( bool die ) { delete_me = die; }
|
inline void FGAIBase::setDie( bool die ) { delete_me = die; }
|
||||||
|
|
||||||
inline bool FGAIBase::getDie() { return delete_me; }
|
inline bool FGAIBase::getDie() { return delete_me; }
|
||||||
|
|
||||||
inline FGAIBase::object_type FGAIBase::getType() { return _otype; }
|
inline FGAIBase::object_type FGAIBase::getType() { return _otype; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _FG_AIBASE_HXX
|
#endif // _FG_AIBASE_HXX
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,8 @@ FGAIFlightPlan::FGAIFlightPlan(const string& filename)
|
||||||
wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
|
wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
|
||||||
wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
|
wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
|
||||||
wpt->on_ground = wpt_node->getBoolValue("on-ground", false);
|
wpt->on_ground = wpt_node->getBoolValue("on-ground", false);
|
||||||
wpt->wait_time = wpt_node->getDoubleValue("wait-time-sec", 0);
|
wpt->time_sec = wpt_node->getDoubleValue("time-sec", 0);
|
||||||
|
wpt->time = wpt_node->getStringValue("time", "");
|
||||||
|
|
||||||
if (wpt->name == "END") wpt->finished = true;
|
if (wpt->name == "END") wpt->finished = true;
|
||||||
else wpt->finished = false;
|
else wpt->finished = false;
|
||||||
|
|
|
@ -49,7 +49,9 @@ public:
|
||||||
bool flaps_down;
|
bool flaps_down;
|
||||||
bool on_ground;
|
bool on_ground;
|
||||||
int routeIndex; // For AI/ATC purposes;
|
int routeIndex; // For AI/ATC purposes;
|
||||||
double wait_time;
|
double time_sec;
|
||||||
|
string time;
|
||||||
|
|
||||||
} waypoint;
|
} waypoint;
|
||||||
|
|
||||||
FGAIFlightPlan(const string& filename);
|
FGAIFlightPlan(const string& filename);
|
||||||
|
|
|
@ -43,7 +43,7 @@ class FGAIThermal;
|
||||||
class FGAIManager : public SGSubsystem
|
class FGAIManager : public SGSubsystem
|
||||||
{
|
{
|
||||||
|
|
||||||
private:
|
public:
|
||||||
|
|
||||||
// A list of pointers to AI objects
|
// A list of pointers to AI objects
|
||||||
typedef list <SGSharedPtr<FGAIBase> > ai_list_type;
|
typedef list <SGSharedPtr<FGAIBase> > ai_list_type;
|
||||||
|
@ -52,7 +52,7 @@ private:
|
||||||
|
|
||||||
ai_list_type ai_list;
|
ai_list_type ai_list;
|
||||||
|
|
||||||
public:
|
inline const list <SGSharedPtr<FGAIBase> >& get_ai_list() const { return ai_list; }
|
||||||
|
|
||||||
FGAIManager();
|
FGAIManager();
|
||||||
~FGAIManager();
|
~FGAIManager();
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <simgear/math/sg_geodesy.hxx>
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
|
#include <simgear/timing/sg_time.hxx>
|
||||||
#include <simgear/math/sg_random.h>
|
#include <simgear/math/sg_random.h>
|
||||||
|
|
||||||
#include "AIShip.hxx"
|
#include "AIShip.hxx"
|
||||||
|
@ -46,6 +47,7 @@ FGAIShip::~FGAIShip() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIShip::readFromScenario(SGPropertyNode* scFileNode) {
|
void FGAIShip::readFromScenario(SGPropertyNode* scFileNode) {
|
||||||
|
|
||||||
if (!scFileNode)
|
if (!scFileNode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -56,6 +58,7 @@ void FGAIShip::readFromScenario(SGPropertyNode* scFileNode) {
|
||||||
setRadius(scFileNode->getDoubleValue("turn-radius-ft", 2000));
|
setRadius(scFileNode->getDoubleValue("turn-radius-ft", 2000));
|
||||||
std::string flightplan = scFileNode->getStringValue("flightplan");
|
std::string flightplan = scFileNode->getStringValue("flightplan");
|
||||||
setRepeat(scFileNode->getBoolValue("repeat", false));
|
setRepeat(scFileNode->getBoolValue("repeat", false));
|
||||||
|
setStartTime(scFileNode->getStringValue("time", ""));
|
||||||
|
|
||||||
if (!flightplan.empty()) {
|
if (!flightplan.empty()) {
|
||||||
FGAIFlightPlan* fp = new FGAIFlightPlan(flightplan);
|
FGAIFlightPlan* fp = new FGAIFlightPlan(flightplan);
|
||||||
|
@ -69,10 +72,15 @@ bool FGAIShip::init(bool search_in_AI_path) {
|
||||||
curr = 0; // the one ahead
|
curr = 0; // the one ahead
|
||||||
next = 0; // the next plus 1
|
next = 0; // the next plus 1
|
||||||
|
|
||||||
|
_until_time = "";
|
||||||
|
|
||||||
props->setStringValue("name", _name.c_str());
|
props->setStringValue("name", _name.c_str());
|
||||||
props->setStringValue("position/waypoint-name-prev", _prev_name.c_str());
|
props->setStringValue("position/waypoint-name-prev", _prev_name.c_str());
|
||||||
props->setStringValue("position/waypoint-name-curr", _curr_name.c_str());
|
props->setStringValue("position/waypoint-name-curr", _curr_name.c_str());
|
||||||
props->setStringValue("position/waypoint-name-next", _next_name.c_str());
|
props->setStringValue("position/waypoint-name-next", _next_name.c_str());
|
||||||
|
props->setStringValue("submodels/path", _path.c_str());
|
||||||
|
props->setStringValue("position/waypoint-start-time", _start_time.c_str());
|
||||||
|
props->setStringValue("position/waypoint-wait-until-time", _until_time.c_str());
|
||||||
|
|
||||||
_hdg_lock = false;
|
_hdg_lock = false;
|
||||||
_rudder = 0.0;
|
_rudder = 0.0;
|
||||||
|
@ -82,6 +90,7 @@ bool FGAIShip::init(bool search_in_AI_path) {
|
||||||
_roll_constant = 0.001;
|
_roll_constant = 0.001;
|
||||||
_speed_constant = 0.05;
|
_speed_constant = 0.05;
|
||||||
_hdg_constant = 0.01;
|
_hdg_constant = 0.01;
|
||||||
|
_roll_factor = -0.0083335;
|
||||||
|
|
||||||
_rd_turn_radius_ft = _sp_turn_radius_ft = turn_radius_ft;
|
_rd_turn_radius_ft = _sp_turn_radius_ft = turn_radius_ft;
|
||||||
|
|
||||||
|
@ -94,6 +103,9 @@ bool FGAIShip::init(bool search_in_AI_path) {
|
||||||
_wait_count = 0;
|
_wait_count = 0;
|
||||||
_missed_time_sec = 30;
|
_missed_time_sec = 30;
|
||||||
|
|
||||||
|
_day = 86400;
|
||||||
|
|
||||||
|
|
||||||
_wp_range = _old_range = 0;
|
_wp_range = _old_range = 0;
|
||||||
_range_rate = 0;
|
_range_rate = 0;
|
||||||
|
|
||||||
|
@ -117,6 +129,8 @@ void FGAIShip::bind() {
|
||||||
SGRawValuePointer<double>(&tgt_heading));
|
SGRawValuePointer<double>(&tgt_heading));
|
||||||
props->tie("controls/constants/rudder",
|
props->tie("controls/constants/rudder",
|
||||||
SGRawValuePointer<double>(&_rudder_constant));
|
SGRawValuePointer<double>(&_rudder_constant));
|
||||||
|
props->tie("controls/constants/roll-factor",
|
||||||
|
SGRawValuePointer<double>(&_roll_factor));
|
||||||
props->tie("controls/constants/roll",
|
props->tie("controls/constants/roll",
|
||||||
SGRawValuePointer<double>(&_roll_constant));
|
SGRawValuePointer<double>(&_roll_constant));
|
||||||
props->tie("controls/constants/rudder",
|
props->tie("controls/constants/rudder",
|
||||||
|
@ -141,6 +155,8 @@ void FGAIShip::bind() {
|
||||||
SGRawValuePointer<double>(&_wait_count));
|
SGRawValuePointer<double>(&_wait_count));
|
||||||
props->tie("position/waypoint-waiting",
|
props->tie("position/waypoint-waiting",
|
||||||
SGRawValuePointer<bool>(&_waiting));
|
SGRawValuePointer<bool>(&_waiting));
|
||||||
|
props->tie("submodels/serviceable",
|
||||||
|
SGRawValuePointer<bool>(&_serviceable));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIShip::unbind() {
|
void FGAIShip::unbind() {
|
||||||
|
@ -151,6 +167,7 @@ void FGAIShip::unbind() {
|
||||||
props->untie("controls/tgt-heading-degs");
|
props->untie("controls/tgt-heading-degs");
|
||||||
props->untie("controls/constants/roll");
|
props->untie("controls/constants/roll");
|
||||||
props->untie("controls/constants/rudder");
|
props->untie("controls/constants/rudder");
|
||||||
|
props->untie("controls/constants/roll-factor");
|
||||||
props->untie("controls/constants/speed");
|
props->untie("controls/constants/speed");
|
||||||
props->untie("position/waypoint-range-nm");
|
props->untie("position/waypoint-range-nm");
|
||||||
props->untie("position/waypoint-range-old-nm");
|
props->untie("position/waypoint-range-old-nm");
|
||||||
|
@ -160,6 +177,7 @@ void FGAIShip::unbind() {
|
||||||
props->untie("position/waypoint-wait-count");
|
props->untie("position/waypoint-wait-count");
|
||||||
props->untie("position/waypoint-waiting");
|
props->untie("position/waypoint-waiting");
|
||||||
props->untie("position/waypoint-missed-time-sec");
|
props->untie("position/waypoint-missed-time-sec");
|
||||||
|
props->untie("submodels/serviceable");
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIShip::update(double dt) {
|
void FGAIShip::update(double dt) {
|
||||||
|
@ -169,12 +187,12 @@ void FGAIShip::update(double dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIShip::Run(double dt) {
|
void FGAIShip::Run(double dt) {
|
||||||
|
//cout << _name << " init: " << _fp_init << endl;
|
||||||
if (_fp_init)
|
if (_fp_init)
|
||||||
ProcessFlightPlan(dt);
|
ProcessFlightPlan(dt);
|
||||||
|
|
||||||
double speed_north_deg_sec;
|
// double speed_north_deg_sec;
|
||||||
double speed_east_deg_sec;
|
// double speed_east_deg_sec;
|
||||||
double alpha;
|
double alpha;
|
||||||
double rudder_limit;
|
double rudder_limit;
|
||||||
double raw_roll;
|
double raw_roll;
|
||||||
|
@ -189,6 +207,7 @@ void FGAIShip::Run(double dt) {
|
||||||
|
|
||||||
if (speed_diff < 0.0)
|
if (speed_diff < 0.0)
|
||||||
speed -= _speed_constant * dt;
|
speed -= _speed_constant * dt;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not allow unreasonable ship speeds
|
// do not allow unreasonable ship speeds
|
||||||
|
@ -250,8 +269,8 @@ void FGAIShip::Run(double dt) {
|
||||||
if (hdg < 0.0)
|
if (hdg < 0.0)
|
||||||
hdg += 360.0;
|
hdg += 360.0;
|
||||||
|
|
||||||
//adjust roll for _rudder angle and speed. Another bit of voodoo
|
//adjust roll for rudder angle and speed. Another bit of voodoo
|
||||||
raw_roll = -0.0166667 * speed * _rudder;
|
raw_roll = _roll_factor * speed * _rudder;
|
||||||
} else {
|
} else {
|
||||||
// _rudder angle is 0
|
// _rudder angle is 0
|
||||||
raw_roll = 0;
|
raw_roll = 0;
|
||||||
|
@ -292,6 +311,7 @@ void FGAIShip::Run(double dt) {
|
||||||
|
|
||||||
// adjust _rudder angle
|
// adjust _rudder angle
|
||||||
double rudder_diff = _tgt_rudder - _rudder;
|
double rudder_diff = _tgt_rudder - _rudder;
|
||||||
|
|
||||||
// set the _rudder limit by speed
|
// set the _rudder limit by speed
|
||||||
if (speed <= 40)
|
if (speed <= 40)
|
||||||
rudder_limit = (-0.825 * speed) + 35;
|
rudder_limit = (-0.825 * speed) + 35;
|
||||||
|
@ -356,6 +376,15 @@ void FGAIShip::setName(const string& n) {
|
||||||
_name = n;
|
_name = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGAIShip::setStartTime(const string& st) {
|
||||||
|
_start_time = st;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIShip::setUntilTime(const string& ut) {
|
||||||
|
_until_time = ut;
|
||||||
|
props->setStringValue("position/waypoint-wait-until-time", _until_time.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void FGAIShip::setCurrName(const string& c) {
|
void FGAIShip::setCurrName(const string& c) {
|
||||||
_curr_name = c;
|
_curr_name = c;
|
||||||
props->setStringValue("position/waypoint-name-curr", _curr_name.c_str());
|
props->setStringValue("position/waypoint-name-curr", _curr_name.c_str());
|
||||||
|
@ -380,123 +409,6 @@ void FGAIShip::setMissed(bool m) {
|
||||||
props->setBoolValue("position/waypoint-missed", _missed);
|
props->setBoolValue("position/waypoint-missed", _missed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIShip::ProcessFlightPlan(double dt) {
|
|
||||||
|
|
||||||
_missed = false;
|
|
||||||
_dt_count += dt;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Check Execution time (currently once every 1 sec)
|
|
||||||
// Add a bit of randomization to prevent the execution of all flight plans
|
|
||||||
// in synchrony, which can add significant periodic framerate flutter.
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
if (_dt_count < _next_run)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_next_run = 1.0 + (0.5 * sg_random());
|
|
||||||
|
|
||||||
// check to see if we've reached the point for our next turn
|
|
||||||
// if the range to the waypoint is less than the calculated turn
|
|
||||||
// radius we can start the turn to the next leg
|
|
||||||
_wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
|
|
||||||
_range_rate = (_wp_range - _old_range) / _dt_count;
|
|
||||||
double sp_turn_radius_nm = _sp_turn_radius_ft / 6076.1155;
|
|
||||||
|
|
||||||
// we need to try to identify a _missed waypoint
|
|
||||||
|
|
||||||
// calculate the time needed to turn through an arc of 90 degrees, and allow an error of 30 secs
|
|
||||||
if (speed != 0)
|
|
||||||
_missed_time_sec = 30 + ((SGD_PI * sp_turn_radius_nm * 60 * 60) / (2 * fabs(speed)));
|
|
||||||
else
|
|
||||||
_missed_time_sec = 30;
|
|
||||||
|
|
||||||
if ((_range_rate > 0) && (_wp_range < 3 * sp_turn_radius_nm) && !_new_waypoint)
|
|
||||||
_missed_count += _dt_count;
|
|
||||||
|
|
||||||
|
|
||||||
if (_missed_count >= _missed_time_sec) {
|
|
||||||
setMissed(true);
|
|
||||||
} else {
|
|
||||||
setMissed(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_old_range = _wp_range;
|
|
||||||
|
|
||||||
if ((_wp_range < sp_turn_radius_nm) || _missed || _waiting && !_new_waypoint) {
|
|
||||||
|
|
||||||
if (_next_name == "END") {
|
|
||||||
|
|
||||||
if (_repeat) {
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "AIShip: Flightplan restarting ");
|
|
||||||
fp->restart();
|
|
||||||
prev = curr;
|
|
||||||
curr = fp->getCurrentWaypoint();
|
|
||||||
next = fp->getNextWaypoint();
|
|
||||||
setWPNames();
|
|
||||||
_wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
|
|
||||||
_old_range = _wp_range;
|
|
||||||
_range_rate = 0;
|
|
||||||
_new_waypoint = true;
|
|
||||||
_missed_count = 0;
|
|
||||||
AccelTo(prev->speed);
|
|
||||||
} else {
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "AIShip: Flightplan dieing ");
|
|
||||||
setDie(true);
|
|
||||||
_dt_count = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (_next_name == "WAIT") {
|
|
||||||
|
|
||||||
if (_wait_count < next->wait_time) {
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "AIShip: " << _name << " _waiting ");
|
|
||||||
setSpeed(0);
|
|
||||||
_waiting = true;
|
|
||||||
_wait_count += _dt_count;
|
|
||||||
_dt_count = 0;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "AIShip: " << _name << " wait done: getting new waypoints ");
|
|
||||||
prev = curr;
|
|
||||||
fp->IncrementWaypoint(false);
|
|
||||||
fp->IncrementWaypoint(false); // do it twice
|
|
||||||
curr = fp->getCurrentWaypoint();
|
|
||||||
next = fp->getNextWaypoint();
|
|
||||||
_waiting = false;
|
|
||||||
_wait_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//now reorganise the waypoints, so that next becomes current and so on
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "AIShip: " << _name << " getting new waypoints ");
|
|
||||||
fp->IncrementWaypoint(false);
|
|
||||||
prev = fp->getPreviousWaypoint(); //first waypoint
|
|
||||||
curr = fp->getCurrentWaypoint(); //second waypoint
|
|
||||||
next = fp->getNextWaypoint(); //third waypoint (might not exist!)
|
|
||||||
}
|
|
||||||
|
|
||||||
setWPNames();
|
|
||||||
_new_waypoint = true;
|
|
||||||
_missed_count = 0;
|
|
||||||
_range_rate = 0;
|
|
||||||
_wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
|
|
||||||
_old_range = _wp_range;
|
|
||||||
AccelTo(prev->speed);
|
|
||||||
} else {
|
|
||||||
_new_waypoint = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now revise the required course for the next way point
|
|
||||||
double course = getCourse(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
|
|
||||||
|
|
||||||
if (finite(course))
|
|
||||||
TurnTo(course);
|
|
||||||
else
|
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: Bearing or Range is not a finite number");
|
|
||||||
|
|
||||||
_dt_count = 0;
|
|
||||||
} // end Processing FlightPlan
|
|
||||||
|
|
||||||
void FGAIShip::setRudder(float r) {
|
void FGAIShip::setRudder(float r) {
|
||||||
_rudder = r;
|
_rudder = r;
|
||||||
}
|
}
|
||||||
|
@ -505,6 +417,26 @@ void FGAIShip::setRoll(double rl) {
|
||||||
roll = rl;
|
roll = rl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGAIShip::setWPNames() {
|
||||||
|
|
||||||
|
if (prev != 0)
|
||||||
|
setPrevName(prev->name);
|
||||||
|
else
|
||||||
|
setPrevName("");
|
||||||
|
|
||||||
|
setCurrName(curr->name);
|
||||||
|
|
||||||
|
if (next != 0)
|
||||||
|
setNextName(next->name);
|
||||||
|
else
|
||||||
|
setNextName("");
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: prev wp name " << prev->name);
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: current wp name " << curr->name);
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: next wp name " << next->name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
double FGAIShip::getRange(double lat, double lon, double lat2, double lon2) const {
|
double FGAIShip::getRange(double lat, double lon, double lat2, double lon2) const {
|
||||||
|
|
||||||
double course, distance, az2;
|
double course, distance, az2;
|
||||||
|
@ -528,8 +460,175 @@ double FGAIShip::getCourse(double lat, double lon, double lat2, double lon2) con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGAIShip::ProcessFlightPlan(double dt) {
|
||||||
|
|
||||||
|
double time_sec = getDaySeconds();
|
||||||
|
double until_time_sec = 0;
|
||||||
|
|
||||||
|
_missed = false;
|
||||||
|
_dt_count += dt;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check Execution time (currently once every 1 sec)
|
||||||
|
// Add a bit of randomization to prevent the execution of all flight plans
|
||||||
|
// in synchrony, which can add significant periodic framerate flutter.
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//cout << "_start_sec " << _start_sec << " time_sec " << time_sec << endl;
|
||||||
|
if (_dt_count < _next_run && _start_sec < time_sec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_next_run = 1.0 + (0.5 * sg_random());
|
||||||
|
|
||||||
|
// check to see if we've reached the point for our next turn
|
||||||
|
// if the range to the waypoint is less than the calculated turn
|
||||||
|
// radius we can start the turn to the next leg
|
||||||
|
_wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
|
||||||
|
_range_rate = (_wp_range - _old_range) / _dt_count;
|
||||||
|
double sp_turn_radius_nm = _sp_turn_radius_ft / 6076.1155;
|
||||||
|
|
||||||
|
// we need to try to identify a _missed waypoint
|
||||||
|
|
||||||
|
// calculate the time needed to turn through an arc of 90 degrees, and allow an error of 30 secs
|
||||||
|
if (speed != 0)
|
||||||
|
_missed_time_sec = 30 + ((SGD_PI * sp_turn_radius_nm * 60 * 60) / (2 * fabs(speed)));
|
||||||
|
else
|
||||||
|
_missed_time_sec = 30;
|
||||||
|
|
||||||
|
if ((_range_rate > 0) && (_wp_range < 3 * sp_turn_radius_nm) && !_new_waypoint)
|
||||||
|
_missed_count += _dt_count;
|
||||||
|
|
||||||
|
if (_missed_count >= _missed_time_sec) {
|
||||||
|
setMissed(true);
|
||||||
|
} else {
|
||||||
|
setMissed(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_old_range = _wp_range;
|
||||||
|
setWPNames();
|
||||||
|
|
||||||
|
if ((_wp_range < sp_turn_radius_nm) || _missed || _waiting && !_new_waypoint) {
|
||||||
|
|
||||||
|
if (_next_name == "END") {
|
||||||
|
|
||||||
|
if (_repeat) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: Flightplan restarting ");
|
||||||
|
fp->restart();
|
||||||
|
prev = curr;
|
||||||
|
curr = fp->getCurrentWaypoint();
|
||||||
|
next = fp->getNextWaypoint();
|
||||||
|
setWPNames();
|
||||||
|
_wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
|
||||||
|
_old_range = _wp_range;
|
||||||
|
_range_rate = 0;
|
||||||
|
_new_waypoint = true;
|
||||||
|
_missed_count = 0;
|
||||||
|
AccelTo(prev->speed);
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: Flightplan dieing ");
|
||||||
|
setDie(true);
|
||||||
|
_dt_count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (_next_name == "WAIT") {
|
||||||
|
|
||||||
|
if (_wait_count < next->time_sec) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: " << _name << " waiting ");
|
||||||
|
setSpeed(0);
|
||||||
|
_waiting = true;
|
||||||
|
_wait_count += _dt_count;
|
||||||
|
_dt_count = 0;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: " << _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")
|
||||||
|
return;
|
||||||
|
|
||||||
|
prev = curr;
|
||||||
|
fp->IncrementWaypoint(false);
|
||||||
|
curr = fp->getCurrentWaypoint();
|
||||||
|
next = fp->getNextWaypoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (_next_name == "WAITUNTIL") {
|
||||||
|
time_sec = getDaySeconds();
|
||||||
|
until_time_sec = processTimeString(next->time);
|
||||||
|
_until_time = next->time;
|
||||||
|
setUntilTime(next->time);
|
||||||
|
if (until_time_sec > time_sec) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: " << _name << " waiting until: "
|
||||||
|
<< _until_time << " " << until_time_sec << " now " << time_sec );
|
||||||
|
setSpeed(0);
|
||||||
|
_waiting = true;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: "
|
||||||
|
<< _name << " wait until done: getting new waypoints ");
|
||||||
|
setUntilTime("");
|
||||||
|
fp->IncrementWaypoint(false);
|
||||||
|
|
||||||
|
while (next->name == "WAITUNTIL") {
|
||||||
|
fp->IncrementWaypoint(false);
|
||||||
|
next = fp->getNextWaypoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next->name == "WAIT")
|
||||||
|
return;
|
||||||
|
|
||||||
|
prev = curr;
|
||||||
|
fp->IncrementWaypoint(false);
|
||||||
|
curr = fp->getCurrentWaypoint();
|
||||||
|
next = fp->getNextWaypoint();
|
||||||
|
_waiting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//now reorganise the waypoints, so that next becomes current and so on
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: " << _name << " getting new waypoints ");
|
||||||
|
fp->IncrementWaypoint(false);
|
||||||
|
prev = fp->getPreviousWaypoint(); //first waypoint
|
||||||
|
curr = fp->getCurrentWaypoint(); //second waypoint
|
||||||
|
next = fp->getNextWaypoint(); //third waypoint (might not exist!)
|
||||||
|
}
|
||||||
|
|
||||||
|
setWPNames();
|
||||||
|
_new_waypoint = true;
|
||||||
|
_missed_count = 0;
|
||||||
|
_range_rate = 0;
|
||||||
|
_wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
|
||||||
|
_old_range = _wp_range;
|
||||||
|
AccelTo(prev->speed);
|
||||||
|
} else {
|
||||||
|
_new_waypoint = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now revise the required course for the next way point
|
||||||
|
double course = getCourse(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
|
||||||
|
|
||||||
|
if (finite(course))
|
||||||
|
TurnTo(course);
|
||||||
|
else
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: Bearing or Range is not a finite number");
|
||||||
|
|
||||||
|
_dt_count = 0;
|
||||||
|
} // end Processing FlightPlan
|
||||||
|
|
||||||
bool FGAIShip::initFlightPlan() {
|
bool FGAIShip::initFlightPlan() {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " initialising waypoints ");
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: " << _name << " initializing waypoints ");
|
||||||
|
|
||||||
|
bool init = false;
|
||||||
|
|
||||||
|
_start_sec = 0;
|
||||||
|
|
||||||
fp->restart();
|
fp->restart();
|
||||||
fp->IncrementWaypoint(false);
|
fp->IncrementWaypoint(false);
|
||||||
|
|
||||||
|
@ -537,51 +636,222 @@ bool FGAIShip::initFlightPlan() {
|
||||||
curr = fp->getCurrentWaypoint(); //second waypoint
|
curr = fp->getCurrentWaypoint(); //second waypoint
|
||||||
next = fp->getNextWaypoint(); //third waypoint (might not exist!)
|
next = fp->getNextWaypoint(); //third waypoint (might not exist!)
|
||||||
|
|
||||||
if (curr->name == "WAIT") { // don't wait when initialising
|
while (curr->name == "WAIT" || curr->name == "WAITUNTIL") { // don't wait when initialising
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " re-initialising waypoints ");
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: " << _name << " re-initializing waypoints ");
|
||||||
fp->IncrementWaypoint(false);
|
fp->IncrementWaypoint(false);
|
||||||
curr = fp->getCurrentWaypoint();
|
curr = fp->getCurrentWaypoint();
|
||||||
next = fp->getNextWaypoint();
|
next = fp->getNextWaypoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
setWPNames();
|
if (!_start_time.empty()){
|
||||||
|
_start_sec = processTimeString(_start_time);
|
||||||
|
double day_sec = getDaySeconds();
|
||||||
|
|
||||||
|
if (_start_sec < day_sec){
|
||||||
|
//cout << "flight plan has already started " << _start_time << endl;
|
||||||
|
init = advanceFlightPlan(_start_sec, day_sec);
|
||||||
|
|
||||||
|
} else if (_start_sec > day_sec && _repeat) {
|
||||||
|
//cout << "flight plan has not started, " << _start_time;
|
||||||
|
//cout << "offsetting start time by -24 hrs" << endl;
|
||||||
|
_start_sec -= _day;
|
||||||
|
init = advanceFlightPlan(_start_sec, day_sec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init)
|
||||||
|
_start_sec = 0; // set to zero for an immediate start of the Flight Plan
|
||||||
|
else {
|
||||||
|
fp->restart();
|
||||||
|
fp->IncrementWaypoint(false);
|
||||||
|
prev = fp->getPreviousWaypoint();
|
||||||
|
curr = fp->getCurrentWaypoint();
|
||||||
|
next = fp->getNextWaypoint();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
setLatitude(prev->latitude);
|
setLatitude(prev->latitude);
|
||||||
setLongitude(prev->longitude);
|
setLongitude(prev->longitude);
|
||||||
setSpeed(prev->speed);
|
setSpeed(prev->speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
setWPNames();
|
||||||
setHeading(getCourse(prev->latitude, prev->longitude, curr->latitude, curr->longitude));
|
setHeading(getCourse(prev->latitude, prev->longitude, curr->latitude, curr->longitude));
|
||||||
_hdg_lock = true;
|
_wp_range = getRange(prev->latitude, prev->longitude, curr->latitude, curr->longitude);
|
||||||
_wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
|
|
||||||
_old_range = _wp_range;
|
_old_range = _wp_range;
|
||||||
_range_rate = 0;
|
_range_rate = 0;
|
||||||
|
_hdg_lock = true;
|
||||||
_missed = false;
|
_missed = false;
|
||||||
_missed_count = 0;
|
_missed_count = 0;
|
||||||
_new_waypoint = true;
|
_new_waypoint = true;
|
||||||
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "AIShip: " << _name << " done initialising waypoints ");
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: " << _name << " done initialising waypoints ");
|
||||||
|
|
||||||
if (prev)
|
if (prev)
|
||||||
|
init = true;
|
||||||
|
|
||||||
|
if (init)
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
} // end of initialization
|
} // end of initialization
|
||||||
|
|
||||||
void FGAIShip::setWPNames() {
|
|
||||||
|
|
||||||
if (prev != 0)
|
double FGAIShip::processTimeString(const string& theTime) {
|
||||||
setPrevName(prev->name);
|
|
||||||
else
|
|
||||||
setPrevName("");
|
|
||||||
|
|
||||||
setCurrName(curr->name);
|
int Hour;
|
||||||
|
int Minute;
|
||||||
|
int Second;
|
||||||
|
|
||||||
if (next != 0)
|
// first split theTime string into
|
||||||
setNextName(next->name);
|
// hour, minute, second and convert to int;
|
||||||
else
|
Hour = atoi(theTime.substr(0,2).c_str());
|
||||||
setNextName("");
|
Minute = atoi(theTime.substr(3,5).c_str());
|
||||||
|
Second = atoi(theTime.substr(6,8).c_str());
|
||||||
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "AIShip: prev wp name " << prev->name);
|
// offset by a day-sec to allow for starting a day earlier
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "AIShip: current wp name " << curr->name);
|
double time_seconds = Hour * 3600
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "AIShip: next wp name " << next->name);
|
+ Minute * 60
|
||||||
|
+ Second;
|
||||||
|
|
||||||
|
return time_seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
double FGAIShip::getDaySeconds () {
|
||||||
|
// Date and time
|
||||||
|
struct tm *t = globals->get_time_params()->getGmt();
|
||||||
|
|
||||||
|
double day_seconds = t->tm_hour * 3600
|
||||||
|
+ t->tm_min * 60
|
||||||
|
+ t->tm_sec;
|
||||||
|
|
||||||
|
return day_seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FGAIShip::advanceFlightPlan (double start_sec, double day_sec) {
|
||||||
|
|
||||||
|
double elapsed_sec = start_sec;
|
||||||
|
double distance_nm = 0;
|
||||||
|
|
||||||
|
//cout << "advancing flight plan start_sec: " << start_sec << " " << day_sec << endl;
|
||||||
|
|
||||||
|
while ( elapsed_sec < day_sec ) {
|
||||||
|
|
||||||
|
if (next->name == "END") {
|
||||||
|
|
||||||
|
if (_repeat ) {
|
||||||
|
//cout << _name << ": " << "restarting flightplan" << endl;
|
||||||
|
fp->restart();
|
||||||
|
curr = fp->getCurrentWaypoint();
|
||||||
|
next = fp->getNextWaypoint();
|
||||||
|
} else {
|
||||||
|
//cout << _name << ": " << "ending flightplan" << endl;
|
||||||
|
setDie(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (next->name == "WAIT") {
|
||||||
|
//cout << _name << ": begin WAIT: " << prev->name << " ";
|
||||||
|
//cout << curr->name << " " << next->name << endl;
|
||||||
|
|
||||||
|
elapsed_sec += next->time_sec;
|
||||||
|
|
||||||
|
if ( elapsed_sec >= day_sec)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fp->IncrementWaypoint(false);
|
||||||
|
next = fp->getNextWaypoint();
|
||||||
|
|
||||||
|
if (next->name != "WAITUNTIL" && next->name != "WAIT"
|
||||||
|
&& next->name != "END") {
|
||||||
|
prev = curr;
|
||||||
|
fp->IncrementWaypoint(false);
|
||||||
|
curr = fp->getCurrentWaypoint();
|
||||||
|
next = fp->getNextWaypoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (next->name == "WAITUNTIL") {
|
||||||
|
double until_sec = processTimeString(next->time);
|
||||||
|
|
||||||
|
if (until_sec > _start_sec && start_sec < 0)
|
||||||
|
until_sec -= _day;
|
||||||
|
|
||||||
|
if (elapsed_sec < until_sec)
|
||||||
|
elapsed_sec = until_sec;
|
||||||
|
|
||||||
|
if (elapsed_sec >= day_sec )
|
||||||
|
break;
|
||||||
|
|
||||||
|
fp->IncrementWaypoint(false);
|
||||||
|
next = fp->getNextWaypoint();
|
||||||
|
|
||||||
|
if (next->name != "WAITUNTIL" && next->name != "WAIT") {
|
||||||
|
prev = curr;
|
||||||
|
fp->IncrementWaypoint(false);
|
||||||
|
curr = fp->getCurrentWaypoint();
|
||||||
|
next = fp->getNextWaypoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
//cout << _name << ": end WAITUNTIL: ";
|
||||||
|
//cout << prev->name << " " << curr->name << " " << next->name << endl;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
distance_nm = getRange(prev->latitude, prev->longitude, curr->latitude, curr->longitude);
|
||||||
|
elapsed_sec += distance_nm * 60 * 60 / prev->speed;
|
||||||
|
|
||||||
|
if (elapsed_sec >= day_sec)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fp->IncrementWaypoint(false);
|
||||||
|
prev = fp->getPreviousWaypoint();
|
||||||
|
curr = fp->getCurrentWaypoint();
|
||||||
|
next = fp->getNextWaypoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end while
|
||||||
|
|
||||||
|
// the required position lies between the previous and current waypoints
|
||||||
|
// so we will calculate the distance back up the track from the current waypoint
|
||||||
|
// then calculate the lat and lon.
|
||||||
|
/*cout << "advancing flight plan done elapsed_sec: " << elapsed_sec
|
||||||
|
<< " " << day_sec << endl;*/
|
||||||
|
|
||||||
|
double time_diff = elapsed_sec - day_sec;
|
||||||
|
double lat, lon, recip;
|
||||||
|
|
||||||
|
//cout << " time diff " << time_diff << endl;
|
||||||
|
|
||||||
|
if (next->name == "WAIT" ){
|
||||||
|
setSpeed(0);
|
||||||
|
lat = curr->latitude;
|
||||||
|
lon = curr->longitude;
|
||||||
|
_wait_count= time_diff;
|
||||||
|
_waiting = true;
|
||||||
|
} else if (next->name == "WAITUNTIL") {
|
||||||
|
setSpeed(0);
|
||||||
|
lat = curr->latitude;
|
||||||
|
lon = curr->longitude;
|
||||||
|
_waiting = true;
|
||||||
|
} else {
|
||||||
|
setSpeed(prev->speed);
|
||||||
|
distance_nm = speed * time_diff / (60 * 60);
|
||||||
|
double brg = getCourse(curr->latitude, curr->longitude, prev->latitude, prev->longitude);
|
||||||
|
|
||||||
|
//cout << " brg " << brg << " from " << curr->name << " to " << prev->name << " "
|
||||||
|
// << " lat " << curr->latitude << " lon " << curr->longitude
|
||||||
|
// << " distance m " << distance_nm * SG_NM_TO_METER << endl;
|
||||||
|
|
||||||
|
lat = geo_direct_wgs_84 (curr->latitude, curr->longitude, brg,
|
||||||
|
distance_nm * SG_NM_TO_METER, &lat, &lon, &recip );
|
||||||
|
lon = geo_direct_wgs_84 (curr->latitude, curr->longitude, brg,
|
||||||
|
distance_nm * SG_NM_TO_METER, &lat, &lon, &recip );
|
||||||
|
recip = geo_direct_wgs_84 (curr->latitude, curr->longitude, brg,
|
||||||
|
distance_nm * SG_NM_TO_METER, &lat, &lon, &recip );
|
||||||
|
}
|
||||||
|
|
||||||
|
//cout << "Pos " << lat << ", " << lon << " recip " << recip << endl;
|
||||||
|
|
||||||
|
setLatitude(lat);
|
||||||
|
setLongitude(lon);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,12 +56,13 @@ public:
|
||||||
void setPrevName(const string&);
|
void setPrevName(const string&);
|
||||||
|
|
||||||
bool _hdg_lock;
|
bool _hdg_lock;
|
||||||
|
bool _serviceable;
|
||||||
|
|
||||||
virtual const char* getTypeString(void) const { return "ship"; }
|
virtual const char* getTypeString(void) const { return "ship"; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
string _name; // The _name of this ship.
|
string _name; // The name of this ship.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -74,23 +75,35 @@ private:
|
||||||
void setRepeat(bool r);
|
void setRepeat(bool r);
|
||||||
void setMissed(bool m);
|
void setMissed(bool m);
|
||||||
void setWPNames();
|
void setWPNames();
|
||||||
|
void setServiceable(bool s);
|
||||||
void Run(double dt);
|
void Run(double dt);
|
||||||
|
void setStartTime(const string&);
|
||||||
|
void setUntilTime(const string&);
|
||||||
|
|
||||||
|
|
||||||
double getRange(double lat, double lon, double lat2, double lon2) const;
|
double getRange(double lat, double lon, double lat2, double lon2) const;
|
||||||
double getCourse(double lat, double lon, double lat2, double lon2) const;
|
double getCourse(double lat, double lon, double lat2, double lon2) const;
|
||||||
double sign(double x);
|
double sign(double x);
|
||||||
|
double getDaySeconds();
|
||||||
|
double processTimeString(const string& time);
|
||||||
|
|
||||||
bool initFlightPlan();
|
bool initFlightPlan();
|
||||||
|
bool advanceFlightPlan (double elapsed_sec, double day_sec);
|
||||||
|
|
||||||
float _rudder, _tgt_rudder;
|
float _rudder, _tgt_rudder;
|
||||||
|
|
||||||
double _rudder_constant, _roll_constant, _speed_constant, _hdg_constant;
|
double _rudder_constant, _roll_constant, _speed_constant, _hdg_constant, _roll_factor;
|
||||||
double _sp_turn_radius_ft, _rd_turn_radius_ft;
|
double _sp_turn_radius_ft, _rd_turn_radius_ft;
|
||||||
double _wp_range, _old_range, _range_rate;
|
double _wp_range, _old_range, _range_rate;
|
||||||
double _dt_count, _missed_count, _wait_count;
|
double _dt_count, _missed_count, _wait_count;
|
||||||
double _next_run;
|
double _next_run;
|
||||||
double _missed_time_sec;
|
double _missed_time_sec;
|
||||||
|
double _start_sec;
|
||||||
|
double _day;
|
||||||
|
|
||||||
string _prev_name, _curr_name, _next_name;
|
string _prev_name, _curr_name, _next_name;
|
||||||
|
string _path;
|
||||||
|
string _start_time, _until_time;
|
||||||
|
|
||||||
bool _repeat;
|
bool _repeat;
|
||||||
bool _fp_init;
|
bool _fp_init;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// submodel.cxx - models a releasable submodel.
|
// submodel.cxx - models a releasable submodel.
|
||||||
// Written by Dave Culp, started Aug 2004
|
// Written by Dave Culp, started Aug 2004
|
||||||
|
// With major additions by Vivian Meaaza 2004 - 2007
|
||||||
//
|
//
|
||||||
// This file is in the Public Domain and comes with no warranty.
|
// This file is in the Public Domain and comes with no warranty.
|
||||||
|
|
||||||
|
@ -11,38 +12,43 @@
|
||||||
|
|
||||||
#include <simgear/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
|
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/util.hxx>
|
#include <Main/util.hxx>
|
||||||
#include <AIModel/AIManager.hxx>
|
|
||||||
#include <AIModel/AIBallistic.hxx>
|
#include "AIBase.hxx"
|
||||||
|
#include "AIManager.hxx"
|
||||||
|
#include "AIBallistic.hxx"
|
||||||
|
|
||||||
|
|
||||||
const double FGSubmodelMgr::lbs_to_slugs = 0.031080950172;
|
const double FGSubmodelMgr::lbs_to_slugs = 0.031080950172;
|
||||||
|
|
||||||
FGSubmodelMgr::FGSubmodelMgr ()
|
FGSubmodelMgr::FGSubmodelMgr()
|
||||||
{
|
{
|
||||||
|
|
||||||
x_offset = y_offset = 0.0;
|
x_offset = y_offset = 0.0;
|
||||||
z_offset = -4.0;
|
z_offset = -4.0;
|
||||||
pitch_offset = 2.0;
|
pitch_offset = 2.0;
|
||||||
yaw_offset = 0.0;
|
yaw_offset = 0.0;
|
||||||
|
|
||||||
out[0] = out[1] = out[2] = 0;
|
out[0] = out[1] = out[2] = 0;
|
||||||
in[3] = out[3] = 1;
|
in[3] = out[3] = 1;
|
||||||
string contents_node;
|
string contents_node;
|
||||||
contrail_altitude = 30000.0;
|
contrail_altitude = 30000;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGSubmodelMgr::~FGSubmodelMgr ()
|
FGSubmodelMgr::~FGSubmodelMgr()
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void FGSubmodelMgr::init()
|
||||||
FGSubmodelMgr::init ()
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
index = 0;
|
||||||
load();
|
load();
|
||||||
|
|
||||||
_serviceable_node = fgGetNode("/sim/submodels/serviceable", true);
|
_serviceable_node = fgGetNode("/sim/submodels/serviceable", true);
|
||||||
|
_serviceable_node->setBoolValue(true);
|
||||||
|
|
||||||
_user_lat_node = fgGetNode("/position/latitude-deg", true);
|
_user_lat_node = fgGetNode("/position/latitude-deg", true);
|
||||||
_user_lon_node = fgGetNode("/position/longitude-deg", true);
|
_user_lon_node = fgGetNode("/position/longitude-deg", true);
|
||||||
|
@ -56,12 +62,12 @@ FGSubmodelMgr::init ()
|
||||||
|
|
||||||
_user_speed_node = fgGetNode("/velocities/uBody-fps", true);
|
_user_speed_node = fgGetNode("/velocities/uBody-fps", true);
|
||||||
|
|
||||||
_user_wind_from_east_node = fgGetNode("/environment/wind-from-east-fps",true);
|
_user_wind_from_east_node = fgGetNode("/environment/wind-from-east-fps", true);
|
||||||
_user_wind_from_north_node = fgGetNode("/environment/wind-from-north-fps",true);
|
_user_wind_from_north_node = fgGetNode("/environment/wind-from-north-fps", true);
|
||||||
|
|
||||||
_user_speed_down_fps_node = fgGetNode("/velocities/speed-down-fps",true);
|
_user_speed_down_fps_node = fgGetNode("/velocities/speed-down-fps", true);
|
||||||
_user_speed_east_fps_node = fgGetNode("/velocities/speed-east-fps",true);
|
_user_speed_east_fps_node = fgGetNode("/velocities/speed-east-fps", true);
|
||||||
_user_speed_north_fps_node = fgGetNode("/velocities/speed-north-fps",true);
|
_user_speed_north_fps_node = fgGetNode("/velocities/speed-north-fps", true);
|
||||||
|
|
||||||
_contrail_altitude_node = fgGetNode("/environment/params/contrail-altitude", true);
|
_contrail_altitude_node = fgGetNode("/environment/params/contrail-altitude", true);
|
||||||
contrail_altitude = _contrail_altitude_node->getDoubleValue();
|
contrail_altitude = _contrail_altitude_node->getDoubleValue();
|
||||||
|
@ -70,196 +76,307 @@ FGSubmodelMgr::init ()
|
||||||
|
|
||||||
ai = (FGAIManager*)globals->get_subsystem("ai_model");
|
ai = (FGAIManager*)globals->get_subsystem("ai_model");
|
||||||
|
|
||||||
|
loadAI();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void FGSubmodelMgr::bind()
|
||||||
FGSubmodelMgr::bind ()
|
{}
|
||||||
|
|
||||||
|
void FGSubmodelMgr::unbind()
|
||||||
{
|
{
|
||||||
|
submodel_iterator = submodels.begin();
|
||||||
|
|
||||||
|
while (submodel_iterator != submodels.end()) {
|
||||||
|
(*submodel_iterator)->prop->untie("count");
|
||||||
|
++submodel_iterator;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void FGSubmodelMgr::update(double dt)
|
||||||
FGSubmodelMgr::unbind ()
|
|
||||||
{
|
{
|
||||||
submodel_iterator = submodels.begin();
|
|
||||||
while(submodel_iterator != submodels.end()) {
|
if (!(_serviceable_node->getBoolValue()))
|
||||||
(*submodel_iterator)->prop->untie("count");
|
return;
|
||||||
++submodel_iterator;
|
|
||||||
}
|
int i = -1;
|
||||||
|
bool in_range = true;
|
||||||
|
bool trigger = false;
|
||||||
|
|
||||||
|
_contrail_trigger->setBoolValue(_user_alt_node->getDoubleValue() > contrail_altitude);
|
||||||
|
|
||||||
|
submodel_iterator = submodels.begin();
|
||||||
|
while (submodel_iterator != submodels.end()) {
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if ((*submodel_iterator)->trigger_node != 0) {
|
||||||
|
trigger = (*submodel_iterator)->trigger_node->getBoolValue();
|
||||||
|
//cout << (*submodel_iterator)->name << "trigger node found" << trigger << endl;
|
||||||
|
} else {
|
||||||
|
trigger = true;
|
||||||
|
//cout << (*submodel_iterator)->name << "trigger node not found" << trigger << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trigger) {
|
||||||
|
int id = (*submodel_iterator)->id;
|
||||||
|
|
||||||
|
// don't release submodels from AI Objects if they are
|
||||||
|
// too far away to be seen. id 0 is not an AI model,
|
||||||
|
// so we can skip the whole process
|
||||||
|
sm_list_iterator sm_list_itr = sm_list.begin();
|
||||||
|
sm_list_iterator end = sm_list.end();
|
||||||
|
|
||||||
|
while (sm_list_itr != end) {
|
||||||
|
|
||||||
|
if (id == 0) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG,
|
||||||
|
"Submodels: continuing: " << id);
|
||||||
|
++sm_list_itr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parent_id = (*sm_list_itr)->getID();
|
||||||
|
|
||||||
|
if (parent_id == id) {
|
||||||
|
double parent_lat = (*sm_list_itr)->_getLatitude();
|
||||||
|
double parent_lon = (*sm_list_itr)->_getLongitude();
|
||||||
|
double own_lat = _user_lat_node->getDoubleValue();
|
||||||
|
double own_lon = _user_lon_node->getDoubleValue();
|
||||||
|
double range_nm = getRange(parent_lat, parent_lon, own_lat, own_lon);
|
||||||
|
/* cout << "parent " << parent_id << ", "<< parent_lat << ", " << parent_lon << endl;
|
||||||
|
cout << "own " << own_lat << ", " << own_lon << " range " << range_nm << endl;*/
|
||||||
|
|
||||||
|
if (range_nm > 15) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG,
|
||||||
|
"Submodels: skipping release: " << id);
|
||||||
|
in_range = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
++sm_list_itr;
|
||||||
|
} // end while
|
||||||
|
|
||||||
|
if ((*submodel_iterator)->count != 0 && in_range)
|
||||||
|
release((*submodel_iterator), dt);
|
||||||
|
|
||||||
|
} else
|
||||||
|
(*submodel_iterator)->first_time = true;
|
||||||
|
|
||||||
|
++submodel_iterator;
|
||||||
|
} // end while
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool FGSubmodelMgr::release(submodel* sm, double dt)
|
||||||
FGSubmodelMgr::update (double dt)
|
|
||||||
{
|
{
|
||||||
if (!(_serviceable_node->getBoolValue())) return;
|
// only run if first time or repeat is set to true
|
||||||
int i=-1;
|
if (!sm->first_time && !sm->repeat)
|
||||||
|
return false;
|
||||||
|
|
||||||
_contrail_trigger->setBoolValue(_user_alt_node->getDoubleValue() > contrail_altitude);
|
sm->timer += dt;
|
||||||
|
|
||||||
submodel_iterator = submodels.begin();
|
if (sm->timer < sm->delay)
|
||||||
while(submodel_iterator != submodels.end()) {
|
return false;
|
||||||
i++;
|
|
||||||
if ((*submodel_iterator)->trigger->getBoolValue()) {
|
sm->timer = 0.0;
|
||||||
if ((*submodel_iterator)->count != 0) {
|
|
||||||
release( (*submodel_iterator), dt);
|
if (sm->first_time) {
|
||||||
}
|
dt = 0.0;
|
||||||
} else {
|
sm->first_time = false;
|
||||||
(*submodel_iterator)->first_time = true;
|
}
|
||||||
}
|
|
||||||
++submodel_iterator;
|
transform(sm); // calculate submodel's initial conditions in world-coordinates
|
||||||
}
|
|
||||||
|
FGAIBallistic* ballist = new FGAIBallistic;
|
||||||
|
ballist->setPath(sm->model.c_str());
|
||||||
|
ballist->setLatitude(IC.lat);
|
||||||
|
ballist->setLongitude(IC.lon);
|
||||||
|
ballist->setAltitude(IC.alt);
|
||||||
|
ballist->setAzimuth(IC.azimuth);
|
||||||
|
ballist->setElevation(IC.elevation);
|
||||||
|
ballist->setRoll(IC.roll);
|
||||||
|
ballist->setSpeed(IC.speed / SG_KT_TO_FPS);
|
||||||
|
ballist->setWind_from_east(IC.wind_from_east);
|
||||||
|
ballist->setWind_from_north(IC.wind_from_north);
|
||||||
|
ballist->setMass(IC.mass);
|
||||||
|
ballist->setDragArea(sm->drag_area);
|
||||||
|
ballist->setLife(sm->life);
|
||||||
|
ballist->setBuoyancy(sm->buoyancy);
|
||||||
|
ballist->setWind(sm->wind);
|
||||||
|
ballist->setCd(sm->cd);
|
||||||
|
ballist->setStabilisation(sm->aero_stabilised);
|
||||||
|
ballist->setNoRoll(sm->no_roll);
|
||||||
|
ballist->setName(sm->name);
|
||||||
|
ai->attach(ballist);
|
||||||
|
|
||||||
|
if (sm->count > 0)
|
||||||
|
(sm->count)--;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void FGSubmodelMgr::load()
|
||||||
FGSubmodelMgr::release (submodel* sm, double dt)
|
|
||||||
{
|
|
||||||
// only run if first time or repeat is set to true
|
|
||||||
if (!sm->first_time && !sm->repeat) return false;
|
|
||||||
|
|
||||||
sm->timer += dt;
|
|
||||||
if (sm->timer < sm->delay) return false;
|
|
||||||
sm->timer = 0.0;
|
|
||||||
|
|
||||||
if (sm->first_time) {
|
|
||||||
dt = 0.0;
|
|
||||||
sm->first_time = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
transform(sm); // calculate submodel's initial conditions in world-coordinates
|
|
||||||
|
|
||||||
FGAIBallistic* ballist = new FGAIBallistic;
|
|
||||||
ballist->setPath(sm->model.c_str());
|
|
||||||
ballist->setLatitude(IC.lat);
|
|
||||||
ballist->setLongitude(IC.lon);
|
|
||||||
ballist->setAltitude(IC.alt);
|
|
||||||
ballist->setAzimuth(IC.azimuth);
|
|
||||||
ballist->setElevation(IC.elevation);
|
|
||||||
ballist->setRoll(IC.roll);
|
|
||||||
ballist->setSpeed(IC.speed);
|
|
||||||
ballist->setDragArea(sm->drag_area);
|
|
||||||
ballist->setLife(sm->life);
|
|
||||||
ballist->setBuoyancy(sm->buoyancy);
|
|
||||||
ballist->setWind_from_east(IC.wind_from_east);
|
|
||||||
ballist->setWind_from_north(IC.wind_from_north);
|
|
||||||
ballist->setWind(sm->wind);
|
|
||||||
ballist->setCd(sm->cd);
|
|
||||||
ballist->setMass(IC.mass);
|
|
||||||
ballist->setStabilisation(sm->aero_stabilised);
|
|
||||||
ai->attach(ballist);
|
|
||||||
|
|
||||||
if (sm->count > 0) (sm->count)--;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FGSubmodelMgr::load ()
|
|
||||||
{
|
{
|
||||||
SGPropertyNode *path = fgGetNode("/sim/submodels/path");
|
SGPropertyNode *path = fgGetNode("/sim/submodels/path");
|
||||||
SGPropertyNode root;
|
SGPropertyNode root;
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
SGPath config( globals->get_fg_root() );
|
SGPath config(globals->get_fg_root());
|
||||||
config.append( path->getStringValue() );
|
config.append(path->getStringValue());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
readProperties(config.str(), &root);
|
readProperties(config.str(), &root);
|
||||||
} catch (const sg_exception &e) {
|
} catch (const sg_exception &e) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
SG_LOG(SG_GENERAL, SG_INFO,
|
||||||
"Unable to read submodels file: ");
|
"Submodels: unable to read submodels file: " << config.str());
|
||||||
cout << config.str() << endl;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<SGPropertyNode_ptr> children = root.getChildren("submodel");
|
vector<SGPropertyNode_ptr> children = root.getChildren("submodel");
|
||||||
vector<SGPropertyNode_ptr>::iterator it = children.begin();
|
vector<SGPropertyNode_ptr>::iterator it = children.begin();
|
||||||
vector<SGPropertyNode_ptr>::iterator end = children.end();
|
vector<SGPropertyNode_ptr>::iterator end = children.end();
|
||||||
for (int i = 0; it != end; ++it, i++) {
|
|
||||||
|
|
||||||
// cout << "Reading submodel " << (*it)->getPath() << endl;
|
for (int i = 0; it != end; ++it, i++) {
|
||||||
submodel* sm = new submodel;
|
// cout << "Reading submodel " << (*it)->getPath() << endl;
|
||||||
SGPropertyNode * entry_node = *it;
|
submodel* sm = new submodel;
|
||||||
sm->trigger = fgGetNode(entry_node->getStringValue("trigger", "none"), true);
|
SGPropertyNode * entry_node = *it;
|
||||||
sm->name = entry_node->getStringValue("name", "none_defined");
|
sm->name = entry_node->getStringValue("name", "none_defined");
|
||||||
sm->model = entry_node->getStringValue("model", "Models/Geometry/rocket.ac");
|
sm->model = entry_node->getStringValue("model", "Models/Geometry/rocket.ac");
|
||||||
sm->speed = entry_node->getDoubleValue("speed", 2329.4 );
|
sm->speed = entry_node->getDoubleValue("speed", 2329.4);
|
||||||
sm->repeat = entry_node->getBoolValue ("repeat", false);
|
sm->repeat = entry_node->getBoolValue("repeat", false);
|
||||||
sm->delay = entry_node->getDoubleValue("delay", 0.25);
|
sm->delay = entry_node->getDoubleValue("delay", 0.25);
|
||||||
sm->count = entry_node->getIntValue ("count", 1);
|
sm->count = entry_node->getIntValue("count", 1);
|
||||||
sm->slaved = entry_node->getBoolValue ("slaved", false);
|
sm->slaved = entry_node->getBoolValue("slaved", false);
|
||||||
sm->x_offset = entry_node->getDoubleValue("x-offset", 0.0);
|
sm->x_offset = entry_node->getDoubleValue("x-offset", 0.0);
|
||||||
sm->y_offset = entry_node->getDoubleValue("y-offset", 0.0);
|
sm->y_offset = entry_node->getDoubleValue("y-offset", 0.0);
|
||||||
sm->z_offset = entry_node->getDoubleValue("z-offset", 0.0);
|
sm->z_offset = entry_node->getDoubleValue("z-offset", 0.0);
|
||||||
sm->yaw_offset = entry_node->getDoubleValue("yaw-offset", 0.0);
|
sm->yaw_offset = entry_node->getDoubleValue("yaw-offset", 0.0);
|
||||||
sm->pitch_offset = entry_node->getDoubleValue("pitch-offset", 0.0);
|
sm->pitch_offset = entry_node->getDoubleValue("pitch-offset", 0.0);
|
||||||
sm->drag_area = entry_node->getDoubleValue("eda", 0.034);
|
sm->drag_area = entry_node->getDoubleValue("eda", 0.034);
|
||||||
sm->life = entry_node->getDoubleValue("life", 900.0);
|
sm->life = entry_node->getDoubleValue("life", 900.0);
|
||||||
sm->buoyancy = entry_node->getDoubleValue("buoyancy", 0);
|
sm->buoyancy = entry_node->getDoubleValue("buoyancy", 0);
|
||||||
sm->wind = entry_node->getBoolValue ("wind", false);
|
sm->wind = entry_node->getBoolValue("wind", false);
|
||||||
sm->first_time = false;
|
sm->cd = entry_node->getDoubleValue("cd", 0.193);
|
||||||
sm->cd = entry_node->getDoubleValue("cd", 0.193);
|
sm->weight = entry_node->getDoubleValue("weight", 0.25);
|
||||||
sm->weight = entry_node->getDoubleValue("weight", 0.25);
|
sm->aero_stabilised = entry_node->getBoolValue("aero-stabilised", true);
|
||||||
sm->aero_stabilised = entry_node->getBoolValue ("aero-stabilised", true);
|
sm->no_roll = entry_node->getBoolValue("no-roll", false);
|
||||||
sm->contents_node = fgGetNode(entry_node->getStringValue("contents", "none"), true);
|
sm->contents_node = fgGetNode(entry_node->getStringValue("contents", "none"), false);
|
||||||
|
sm->trigger_node = fgGetNode(entry_node->getStringValue("trigger", "none"), false);
|
||||||
|
sm->speed_node = fgGetNode(entry_node->getStringValue("speed-node", "none"), false);
|
||||||
|
|
||||||
sm->trigger->setBoolValue(false);
|
//cout << "sm->contents_node " << sm->contents_node << endl;
|
||||||
sm->timer = sm->delay;
|
if (sm->contents_node != 0)
|
||||||
|
sm->contents = sm->contents_node->getDoubleValue();
|
||||||
sm->contents = sm->contents_node->getDoubleValue();
|
|
||||||
|
|
||||||
sm->prop = fgGetNode("/ai/submodels/submodel", i, true);
|
|
||||||
sm->prop->tie("count", SGRawValuePointer<int>(&(sm->count)));
|
|
||||||
sm->prop->tie("repeat", SGRawValuePointer<bool>(&(sm->repeat)));
|
|
||||||
|
|
||||||
// sm->prop->tie("contents", SGRawValuePointer<double>(&(sm->contents)));
|
//cout << sm->name << " sm->trigger_node " << sm->trigger_node << endl;
|
||||||
// sm->prop->tie("contents path", SGRawValuePointer<const char *>(&(sm->contents_node)));
|
if (sm->trigger_node != 0)
|
||||||
submodels.push_back( sm );
|
sm->trigger_node->setBoolValue(false);
|
||||||
}
|
|
||||||
|
|
||||||
submodel_iterator = submodels.begin();
|
if (sm->speed_node != 0)
|
||||||
|
sm->speed = sm->speed_node->getDoubleValue();
|
||||||
|
|
||||||
|
sm->timer = sm->delay;
|
||||||
|
sm->id = 0;
|
||||||
|
sm->first_time = false;
|
||||||
|
|
||||||
|
sm->prop = fgGetNode("/ai/submodels/submodel", index, true);
|
||||||
|
sm->prop->tie("count", SGRawValuePointer<int>(&(sm->count)));
|
||||||
|
sm->prop->tie("repeat", SGRawValuePointer<bool>(&(sm->repeat)));
|
||||||
|
sm->prop->tie("id", SGRawValuePointer<int>(&(sm->id)));
|
||||||
|
string name = sm->name;
|
||||||
|
sm->prop->setStringValue("name", name.c_str());
|
||||||
|
|
||||||
|
if (sm->contents_node != 0) {
|
||||||
|
sm->prop->tie("contents-lbs", SGRawValuePointer<double>(&(sm->contents)));
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
submodels.push_back(sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
submodel_iterator = submodels.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGSubmodelMgr::transform(submodel* sm)
|
||||||
void
|
|
||||||
FGSubmodelMgr::transform( submodel* sm)
|
|
||||||
{
|
{
|
||||||
|
// get initial conditions
|
||||||
|
if (sm->contents_node != 0) {
|
||||||
|
// get the weight of the contents (lbs) and convert to mass (slugs)
|
||||||
|
sm->contents = sm->contents_node->getDoubleValue();
|
||||||
|
IC.mass = (sm->weight + sm->contents) * lbs_to_slugs;
|
||||||
|
|
||||||
// get initial conditions
|
// set contents to 0 in the parent
|
||||||
|
sm->contents_node->setDoubleValue(0);
|
||||||
// get the weight of the contents (lbs) and convert to mass (slugs)
|
} else
|
||||||
sm->contents = sm->contents_node->getDoubleValue();
|
IC.mass = sm->weight * lbs_to_slugs;
|
||||||
|
|
||||||
IC.mass = (sm->weight + sm->contents) * lbs_to_slugs;;
|
|
||||||
// cout << IC.mass << endl;
|
|
||||||
|
|
||||||
// set contents to 0 in the parent
|
|
||||||
sm->contents_node->setDoubleValue(0);
|
|
||||||
|
|
||||||
IC.lat = _user_lat_node->getDoubleValue();
|
|
||||||
IC.lon = _user_lon_node->getDoubleValue();
|
|
||||||
IC.alt = _user_alt_node->getDoubleValue();
|
|
||||||
IC.roll = _user_roll_node->getDoubleValue(); // rotation about x axis
|
|
||||||
IC.elevation = _user_pitch_node->getDoubleValue(); // rotation about y axis
|
|
||||||
IC.azimuth = _user_heading_node->getDoubleValue(); // rotation about z axis
|
|
||||||
|
|
||||||
IC.speed = _user_speed_node->getDoubleValue();
|
|
||||||
IC.wind_from_east = _user_wind_from_east_node->getDoubleValue();
|
|
||||||
IC.wind_from_north = _user_wind_from_north_node->getDoubleValue();
|
|
||||||
|
|
||||||
IC.speed_down_fps = _user_speed_down_fps_node->getDoubleValue();
|
|
||||||
IC.speed_east_fps = _user_speed_east_fps_node->getDoubleValue();
|
|
||||||
IC.speed_north_fps = _user_speed_north_fps_node->getDoubleValue();
|
|
||||||
|
|
||||||
|
//cout << "mass " << IC.mass << endl;
|
||||||
in[0] = sm->x_offset;
|
|
||||||
in[1] = sm->y_offset;
|
|
||||||
in[2] = sm->z_offset;
|
|
||||||
|
|
||||||
|
|
||||||
// pre-process the trig functions
|
|
||||||
|
|
||||||
|
if (sm->speed_node != 0)
|
||||||
|
sm->speed = sm->speed_node->getDoubleValue();
|
||||||
|
|
||||||
|
int ind = sm->id;
|
||||||
|
|
||||||
|
if (ind == 0) {
|
||||||
|
// set the data for a submodel tied to the main model
|
||||||
|
IC.lat = _user_lat_node->getDoubleValue();
|
||||||
|
IC.lon = _user_lon_node->getDoubleValue();
|
||||||
|
IC.alt = _user_alt_node->getDoubleValue();
|
||||||
|
IC.roll = _user_roll_node->getDoubleValue(); // rotation about x axis
|
||||||
|
IC.elevation = _user_pitch_node->getDoubleValue(); // rotation about y axis
|
||||||
|
IC.azimuth = _user_heading_node->getDoubleValue(); // rotation about z axis
|
||||||
|
IC.speed = _user_speed_node->getDoubleValue();
|
||||||
|
IC.speed_down_fps = _user_speed_down_fps_node->getDoubleValue();
|
||||||
|
IC.speed_east_fps = _user_speed_east_fps_node->getDoubleValue();
|
||||||
|
IC.speed_north_fps = _user_speed_north_fps_node->getDoubleValue();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// set the data for a submodel tied to an AI Object
|
||||||
|
sm_list_iterator sm_list_itr = sm_list.begin();
|
||||||
|
sm_list_iterator end = sm_list.end();
|
||||||
|
|
||||||
|
while (sm_list_itr != end) {
|
||||||
|
int id = (*sm_list_itr)->getID();
|
||||||
|
|
||||||
|
if (ind != id) {
|
||||||
|
++sm_list_itr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cout << "found id " << id << endl;
|
||||||
|
IC.lat = (*sm_list_itr)->_getLatitude();
|
||||||
|
IC.lon = (*sm_list_itr)->_getLongitude();
|
||||||
|
IC.alt = (*sm_list_itr)->_getAltitude();
|
||||||
|
IC.roll = (*sm_list_itr)->_getRoll();
|
||||||
|
IC.elevation = (*sm_list_itr)->_getPitch();
|
||||||
|
IC.azimuth = (*sm_list_itr)->_getHeading();
|
||||||
|
IC.alt = (*sm_list_itr)->_getAltitude();
|
||||||
|
IC.speed = (*sm_list_itr)->_getSpeed() * SG_KT_TO_FPS;
|
||||||
|
IC.speed_down_fps = -(*sm_list_itr)->_getVS_fps();
|
||||||
|
IC.speed_east_fps = (*sm_list_itr)->_get_speed_east_fps();
|
||||||
|
IC.speed_north_fps = (*sm_list_itr)->_get_speed_north_fps();
|
||||||
|
|
||||||
|
++sm_list_itr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*cout << "heading " << IC.azimuth << endl ;
|
||||||
|
cout << "speed down " << IC.speed_down_fps << endl ;
|
||||||
|
cout << "speed east " << IC.speed_east_fps << endl ;
|
||||||
|
cout << "speed north " << IC.speed_north_fps << endl ;
|
||||||
|
cout << "parent speed fps in" << IC.speed << "sm speed in " << sm->speed << endl ;*/
|
||||||
|
|
||||||
|
IC.wind_from_east = _user_wind_from_east_node->getDoubleValue();
|
||||||
|
IC.wind_from_north = _user_wind_from_north_node->getDoubleValue();
|
||||||
|
|
||||||
|
in[0] = sm->x_offset;
|
||||||
|
in[1] = sm->y_offset;
|
||||||
|
in[2] = sm->z_offset;
|
||||||
|
|
||||||
|
// pre-process the trig functions
|
||||||
cosRx = cos(-IC.roll * SG_DEGREES_TO_RADIANS);
|
cosRx = cos(-IC.roll * SG_DEGREES_TO_RADIANS);
|
||||||
sinRx = sin(-IC.roll * SG_DEGREES_TO_RADIANS);
|
sinRx = sin(-IC.roll * SG_DEGREES_TO_RADIANS);
|
||||||
cosRy = cos(-IC.elevation * SG_DEGREES_TO_RADIANS);
|
cosRy = cos(-IC.elevation * SG_DEGREES_TO_RADIANS);
|
||||||
|
@ -267,8 +384,7 @@ FGSubmodelMgr::transform( submodel* sm)
|
||||||
cosRz = cos(IC.azimuth * SG_DEGREES_TO_RADIANS);
|
cosRz = cos(IC.azimuth * SG_DEGREES_TO_RADIANS);
|
||||||
sinRz = sin(IC.azimuth * SG_DEGREES_TO_RADIANS);
|
sinRz = sin(IC.azimuth * SG_DEGREES_TO_RADIANS);
|
||||||
|
|
||||||
// set up the transform matrix
|
// set up the transform matrix
|
||||||
|
|
||||||
trans[0][0] = cosRy * cosRz;
|
trans[0][0] = cosRy * cosRz;
|
||||||
trans[0][1] = -1 * cosRx * sinRz + sinRx * sinRy * cosRz ;
|
trans[0][1] = -1 * cosRx * sinRz + sinRx * sinRy * cosRz ;
|
||||||
trans[0][2] = sinRx * sinRz + cosRx * sinRy * cosRz;
|
trans[0][2] = sinRx * sinRz + cosRx * sinRy * cosRz;
|
||||||
|
@ -282,86 +398,191 @@ FGSubmodelMgr::transform( submodel* sm)
|
||||||
trans[2][2] = cosRx * cosRy;
|
trans[2][2] = cosRx * cosRy;
|
||||||
|
|
||||||
|
|
||||||
// multiply the input and transform matrices
|
// multiply the input and transform matrices
|
||||||
|
out[0] = in[0] * trans[0][0] + in[1] * trans[0][1] + in[2] * trans[0][2];
|
||||||
|
out[1] = in[0] * trans[1][0] + in[1] * trans[1][1] + in[2] * trans[1][2];
|
||||||
|
out[2] = in[0] * trans[2][0] + in[1] * trans[2][1] + in[2] * trans[2][2];
|
||||||
|
|
||||||
out[0] = in[0] * trans[0][0] + in[1] * trans[0][1] + in[2] * trans[0][2];
|
// convert ft to degrees of latitude
|
||||||
out[1] = in[0] * trans[1][0] + in[1] * trans[1][1] + in[2] * trans[1][2];
|
out[0] = out[0] / (366468.96 - 3717.12 * cos(IC.lat * SG_DEGREES_TO_RADIANS));
|
||||||
out[2] = in[0] * trans[2][0] + in[1] * trans[2][1] + in[2] * trans[2][2];
|
|
||||||
|
|
||||||
// convert ft to degrees of latitude
|
// convert ft to degrees of longitude
|
||||||
out[0] = out[0] /(366468.96 - 3717.12 * cos(IC.lat * SG_DEGREES_TO_RADIANS));
|
out[1] = out[1] / (365228.16 * cos(IC.lat * SG_DEGREES_TO_RADIANS));
|
||||||
|
|
||||||
// convert ft to degrees of longitude
|
// set submodel initial position
|
||||||
out[1] = out[1] /(365228.16 * cos(IC.lat * SG_DEGREES_TO_RADIANS));
|
IC.lat += out[0];
|
||||||
|
IC.lon += out[1];
|
||||||
|
IC.alt += out[2];
|
||||||
|
|
||||||
// set submodel initial position
|
// get aircraft velocity vector angles in XZ and XY planes
|
||||||
IC.lat += out[0];
|
|
||||||
IC.lon += out[1];
|
|
||||||
IC.alt += out[2];
|
|
||||||
|
|
||||||
// get aircraft velocity vector angles in XZ and XY planes
|
|
||||||
//double alpha = _user_alpha_node->getDoubleValue();
|
//double alpha = _user_alpha_node->getDoubleValue();
|
||||||
//double velXZ = IC.elevation - alpha * cosRx;
|
//double velXZ = IC.elevation - alpha * cosRx;
|
||||||
//double velXY = IC.azimuth - (IC.elevation - alpha * sinRx);
|
//double velXY = IC.azimuth - (IC.elevation - alpha * sinRx);
|
||||||
|
|
||||||
// Get submodel initial velocity vector angles in XZ and XY planes.
|
|
||||||
// This needs to be fixed. This vector should be added to aircraft's vector.
|
|
||||||
IC.elevation += (sm->yaw_offset * sinRx) + (sm->pitch_offset * cosRx);
|
|
||||||
IC.azimuth += (sm->yaw_offset * cosRx) - (sm->pitch_offset * sinRx);
|
|
||||||
|
|
||||||
// For now assume vector is close to airplane's vector. This needs to be fixed.
|
|
||||||
//IC.speed += ;
|
|
||||||
|
|
||||||
// calcuate the total speed north
|
// Get submodel initial velocity vector angles in XZ and XY planes.
|
||||||
|
// This needs to be fixed. This vector should be added to aircraft's vector.
|
||||||
|
IC.elevation += (sm->yaw_offset * sinRx) + (sm->pitch_offset * cosRx);
|
||||||
|
IC.azimuth += (sm->yaw_offset * cosRx) - (sm->pitch_offset * sinRx);
|
||||||
|
|
||||||
IC.total_speed_north = sm->speed * cos(IC.elevation*SG_DEGREES_TO_RADIANS)*
|
// calcuate the total speed north
|
||||||
cos(IC.azimuth*SG_DEGREES_TO_RADIANS) + IC.speed_north_fps;
|
IC.total_speed_north = sm->speed * cos(IC.elevation * SG_DEGREES_TO_RADIANS)
|
||||||
|
* cos(IC.azimuth * SG_DEGREES_TO_RADIANS) + IC.speed_north_fps;
|
||||||
|
|
||||||
// calculate the total speed east
|
// calculate the total speed east
|
||||||
|
IC.total_speed_east = sm->speed * cos(IC.elevation * SG_DEGREES_TO_RADIANS)
|
||||||
|
* sin(IC.azimuth * SG_DEGREES_TO_RADIANS) + IC.speed_east_fps;
|
||||||
|
|
||||||
IC.total_speed_east = sm->speed * cos(IC.elevation*SG_DEGREES_TO_RADIANS)*
|
// calculate the total speed down
|
||||||
sin(IC.azimuth*SG_DEGREES_TO_RADIANS) + IC.speed_east_fps;
|
IC.total_speed_down = sm->speed * -sin(IC.elevation * SG_DEGREES_TO_RADIANS)
|
||||||
|
+ IC.speed_down_fps;
|
||||||
|
|
||||||
// calculate the total speed down
|
// re-calculate speed, elevation and azimuth
|
||||||
|
IC.speed = sqrt(IC.total_speed_north * IC.total_speed_north
|
||||||
IC.total_speed_down = sm->speed * -sin(IC.elevation*SG_DEGREES_TO_RADIANS) +
|
+ IC.total_speed_east * IC.total_speed_east
|
||||||
IC.speed_down_fps;
|
+ IC.total_speed_down * IC.total_speed_down);
|
||||||
|
|
||||||
// re-calculate speed, elevation and azimuth
|
//cout << " speed fps out" << IC.speed << endl ;
|
||||||
|
IC.azimuth = atan(IC.total_speed_east / IC.total_speed_north) * SG_RADIANS_TO_DEGREES;
|
||||||
|
|
||||||
IC.speed = sqrt( IC.total_speed_north * IC.total_speed_north +
|
// rationalise the output
|
||||||
IC.total_speed_east * IC.total_speed_east +
|
if (IC.total_speed_north <= 0) {
|
||||||
IC.total_speed_down * IC.total_speed_down);
|
IC.azimuth = 180 + IC.azimuth;
|
||||||
|
} else {
|
||||||
|
|
||||||
IC.azimuth = atan(IC.total_speed_east/IC.total_speed_north) * SG_RADIANS_TO_DEGREES;
|
if (IC.total_speed_east <= 0)
|
||||||
|
IC.azimuth = 360 + IC.azimuth;
|
||||||
// rationalise the output
|
|
||||||
|
}
|
||||||
if (IC.total_speed_north <= 0){
|
|
||||||
IC.azimuth = 180 + IC.azimuth;
|
IC.elevation = -atan(IC.total_speed_down / sqrt(IC.total_speed_north
|
||||||
}
|
* IC.total_speed_north + IC.total_speed_east * IC.total_speed_east))
|
||||||
else{
|
* SG_RADIANS_TO_DEGREES;
|
||||||
if(IC.total_speed_east <= 0){
|
|
||||||
IC.azimuth = 360 + IC.azimuth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IC.elevation = -atan(IC.total_speed_down/sqrt(IC.total_speed_north *
|
|
||||||
IC.total_speed_north +
|
|
||||||
IC.total_speed_east * IC.total_speed_east)) * SG_RADIANS_TO_DEGREES;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void FGSubmodelMgr::updatelat(double lat)
|
||||||
FGSubmodelMgr::updatelat(double lat)
|
|
||||||
{
|
{
|
||||||
double latitude = lat;
|
ft_per_deg_latitude = 366468.96 - 3717.12 * cos(lat / SG_RADIANS_TO_DEGREES);
|
||||||
ft_per_deg_latitude = 366468.96 - 3717.12 * cos(latitude / SG_RADIANS_TO_DEGREES);
|
ft_per_deg_longitude = 365228.16 * cos(lat / SG_RADIANS_TO_DEGREES);
|
||||||
ft_per_deg_longitude = 365228.16 * cos(latitude / SG_RADIANS_TO_DEGREES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGSubmodelMgr::loadAI()
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "Submodels: Loading AI submodels ");
|
||||||
|
SGPropertyNode root;
|
||||||
|
sm_list = ai->get_ai_list();
|
||||||
|
|
||||||
|
if (sm_list.empty()) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "Submodels: Unable to read AI submodel list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sm_list_iterator sm_list_itr = sm_list.begin();
|
||||||
|
sm_list_iterator end = sm_list.end();
|
||||||
|
|
||||||
|
while (sm_list_itr != end) {
|
||||||
|
string path = (*sm_list_itr)->_getPath();
|
||||||
|
bool serviceable = (*sm_list_itr)->_getServiceable();
|
||||||
|
if (path.empty()) {
|
||||||
|
++sm_list_itr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cout << " path " << path << " serviceable " << serviceable << endl;
|
||||||
|
|
||||||
|
SGPath config(globals->get_fg_root());
|
||||||
|
config.append(path);
|
||||||
|
int id = (*sm_list_itr)->getID();
|
||||||
|
|
||||||
|
//cout << "id: " << id << endl;
|
||||||
|
|
||||||
|
try {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG,
|
||||||
|
"Submodels: Trying to read AI submodels file: " << config.str());
|
||||||
|
readProperties(config.str(), &root);
|
||||||
|
} catch (const sg_exception &e) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG,
|
||||||
|
"Submodels: Unable to read AI submodels file: " << config.str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<SGPropertyNode_ptr> children = root.getChildren("submodel");
|
||||||
|
vector<SGPropertyNode_ptr>::iterator it = children.begin();
|
||||||
|
vector<SGPropertyNode_ptr>::iterator end = children.end();
|
||||||
|
|
||||||
|
for (int i = 0; it != end; ++it, i++) {
|
||||||
|
//cout << "Reading AI submodel " << (*it)->getPath() << endl;
|
||||||
|
submodel* sm = new submodel;
|
||||||
|
SGPropertyNode * entry_node = *it;
|
||||||
|
sm->name = entry_node->getStringValue("name", "none_defined");
|
||||||
|
sm->model = entry_node->getStringValue("model", "Models/Geometry/rocket.ac");
|
||||||
|
sm->speed = entry_node->getDoubleValue("speed", 2329.4);
|
||||||
|
sm->repeat = entry_node->getBoolValue("repeat", false);
|
||||||
|
sm->delay = entry_node->getDoubleValue("delay", 0.25);
|
||||||
|
sm->count = entry_node->getIntValue("count", 1);
|
||||||
|
sm->slaved = entry_node->getBoolValue("slaved", false);
|
||||||
|
sm->x_offset = entry_node->getDoubleValue("x-offset", 0.0);
|
||||||
|
sm->y_offset = entry_node->getDoubleValue("y-offset", 0.0);
|
||||||
|
sm->z_offset = entry_node->getDoubleValue("z-offset", 0.0);
|
||||||
|
sm->yaw_offset = entry_node->getDoubleValue("yaw-offset", 0.0);
|
||||||
|
sm->pitch_offset = entry_node->getDoubleValue("pitch-offset", 0.0);
|
||||||
|
sm->drag_area = entry_node->getDoubleValue("eda", 0.034);
|
||||||
|
sm->life = entry_node->getDoubleValue("life", 900.0);
|
||||||
|
sm->buoyancy = entry_node->getDoubleValue("buoyancy", 0);
|
||||||
|
sm->wind = entry_node->getBoolValue("wind", false);
|
||||||
|
sm->cd = entry_node->getDoubleValue("cd", 0.193);
|
||||||
|
sm->weight = entry_node->getDoubleValue("weight", 0.25);
|
||||||
|
sm->aero_stabilised = entry_node->getBoolValue("aero-stabilised", true);
|
||||||
|
sm->no_roll = entry_node->getBoolValue("no-roll", false);
|
||||||
|
sm->contents_node = fgGetNode(entry_node->getStringValue("contents", "none"), false);
|
||||||
|
sm->trigger_node = fgGetNode(entry_node->getStringValue("trigger", "none"), false);
|
||||||
|
sm->speed_node = fgGetNode(entry_node->getStringValue("speed-node", "none"), false);
|
||||||
|
|
||||||
|
//cout << "sm->contents_node " << sm->contents_node << endl;
|
||||||
|
if (sm->contents_node != 0)
|
||||||
|
sm->contents = sm->contents_node->getDoubleValue();
|
||||||
|
//cout << "sm->trigger_node " << sm->trigger_node << endl;
|
||||||
|
if (sm->trigger_node != 0)
|
||||||
|
sm->trigger_node->setBoolValue(false);
|
||||||
|
|
||||||
|
if (sm->speed_node != 0)
|
||||||
|
sm->speed = sm->speed_node->getDoubleValue();
|
||||||
|
|
||||||
|
sm->timer = sm->delay;
|
||||||
|
sm->id = id;
|
||||||
|
sm->first_time = false;
|
||||||
|
|
||||||
|
sm->serviceable = (*sm_list_itr)->_getServiceable();
|
||||||
|
|
||||||
|
sm->prop = fgGetNode("/ai/submodels/submodel", index, true);
|
||||||
|
sm->prop->tie("count", SGRawValuePointer<int>(&(sm->count)));
|
||||||
|
sm->prop->tie("repeat", SGRawValuePointer<bool>(&(sm->repeat)));
|
||||||
|
sm->prop->tie("id", SGRawValuePointer<int>(&(sm->id)));
|
||||||
|
sm->prop->tie("serviceable", SGRawValuePointer<bool>(&(sm->serviceable)));
|
||||||
|
string name = sm->name;
|
||||||
|
sm->prop->setStringValue("name", name.c_str());
|
||||||
|
|
||||||
|
if (sm->contents_node != 0)
|
||||||
|
sm->prop->tie("contents-lbs", SGRawValuePointer<double>(&(sm->contents)));
|
||||||
|
|
||||||
|
index++;
|
||||||
|
submodels.push_back(sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
submodel_iterator = submodels.begin();
|
||||||
|
++sm_list_itr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
double FGSubmodelMgr::getRange(double lat, double lon, double lat2, double lon2) const
|
||||||
|
{
|
||||||
|
|
||||||
|
double course, distance, az2;
|
||||||
|
|
||||||
|
//calculate the bearing and range of the second pos from the first
|
||||||
|
geo_inverse_wgs_84(lat, lon, lat2, lon2, &course, &az2, &distance);
|
||||||
|
distance *= SG_METER_TO_NM;
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
// end of submodel.cxx
|
// end of submodel.cxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,72 +19,83 @@
|
||||||
SG_USING_STD(vector);
|
SG_USING_STD(vector);
|
||||||
SG_USING_STD(string);
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
class FGAIBase;
|
||||||
|
|
||||||
class FGSubmodelMgr : public SGSubsystem
|
class FGSubmodelMgr : public SGSubsystem
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SGPropertyNode_ptr trigger_node;
|
||||||
|
SGPropertyNode_ptr prop;
|
||||||
|
SGPropertyNode_ptr contents_node;
|
||||||
|
SGPropertyNode_ptr submodel_node;
|
||||||
|
SGPropertyNode_ptr speed_node;
|
||||||
|
|
||||||
typedef struct {
|
string name;
|
||||||
SGPropertyNode_ptr trigger;
|
string model;
|
||||||
SGPropertyNode_ptr prop;
|
double speed;
|
||||||
SGPropertyNode_ptr contents_node;
|
bool slaved;
|
||||||
|
bool repeat;
|
||||||
string name;
|
double delay;
|
||||||
string model;
|
double timer;
|
||||||
double speed;
|
int count;
|
||||||
bool slaved;
|
double x_offset;
|
||||||
bool repeat;
|
double y_offset;
|
||||||
double delay;
|
double z_offset;
|
||||||
double timer;
|
double yaw_offset;
|
||||||
int count;
|
double pitch_offset;
|
||||||
double x_offset;
|
double drag_area;
|
||||||
double y_offset;
|
double life;
|
||||||
double z_offset;
|
double buoyancy;
|
||||||
double yaw_offset;
|
bool wind;
|
||||||
double pitch_offset;
|
bool first_time;
|
||||||
double drag_area;
|
double cd;
|
||||||
double life;
|
double weight;
|
||||||
double buoyancy;
|
double contents;
|
||||||
bool wind;
|
bool aero_stabilised;
|
||||||
bool first_time;
|
int id;
|
||||||
double cd;
|
bool no_roll;
|
||||||
double weight;
|
bool serviceable;
|
||||||
double contents;
|
}
|
||||||
bool aero_stabilised;
|
submodel;
|
||||||
} submodel;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
double lat;
|
{
|
||||||
double lon;
|
double lat;
|
||||||
double alt;
|
double lon;
|
||||||
double roll;
|
double alt;
|
||||||
double azimuth;
|
double roll;
|
||||||
double elevation;
|
double azimuth;
|
||||||
double speed;
|
double elevation;
|
||||||
double wind_from_east;
|
double speed;
|
||||||
double wind_from_north;
|
double wind_from_east;
|
||||||
double speed_down_fps;
|
double wind_from_north;
|
||||||
double speed_east_fps;
|
double speed_down_fps;
|
||||||
double speed_north_fps;
|
double speed_east_fps;
|
||||||
double total_speed_down;
|
double speed_north_fps;
|
||||||
double total_speed_east;
|
double total_speed_down;
|
||||||
double total_speed_north;
|
double total_speed_east;
|
||||||
double mass;
|
double total_speed_north;
|
||||||
} IC_struct;
|
double mass;
|
||||||
|
int id;
|
||||||
|
bool no_roll;
|
||||||
|
}
|
||||||
|
IC_struct;
|
||||||
|
|
||||||
FGSubmodelMgr ();
|
FGSubmodelMgr();
|
||||||
~FGSubmodelMgr ();
|
~FGSubmodelMgr();
|
||||||
|
|
||||||
void load ();
|
void load();
|
||||||
void init ();
|
void init();
|
||||||
void bind ();
|
void bind();
|
||||||
void unbind ();
|
void unbind();
|
||||||
void update (double dt);
|
void update(double dt);
|
||||||
bool release (submodel* sm, double dt);
|
bool release(submodel* sm, double dt);
|
||||||
void transform (submodel* sm);
|
void transform(submodel* sm);
|
||||||
void updatelat( double lat );
|
void updatelat(double lat);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -106,6 +117,8 @@ private:
|
||||||
float cosRy, sinRy;
|
float cosRy, sinRy;
|
||||||
float cosRz, sinRz;
|
float cosRz, sinRz;
|
||||||
|
|
||||||
|
int index;
|
||||||
|
|
||||||
double ft_per_deg_longitude;
|
double ft_per_deg_longitude;
|
||||||
double ft_per_deg_latitude;
|
double ft_per_deg_latitude;
|
||||||
|
|
||||||
|
@ -137,9 +150,17 @@ private:
|
||||||
FGAIManager* ai;
|
FGAIManager* ai;
|
||||||
IC_struct IC;
|
IC_struct IC;
|
||||||
|
|
||||||
|
// A list of pointers to AI objects
|
||||||
|
typedef list <SGSharedPtr<FGAIBase> > sm_list_type;
|
||||||
|
typedef sm_list_type::iterator sm_list_iterator;
|
||||||
|
typedef sm_list_type::const_iterator sm_list_const_iterator;
|
||||||
|
|
||||||
|
sm_list_type sm_list;
|
||||||
|
|
||||||
|
void loadAI();
|
||||||
|
void loadSubmodels();
|
||||||
|
double getRange(double lat, double lon, double lat2, double lon2) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __SYSTEMS_SUBMODEL_HXX
|
#endif // __SYSTEMS_SUBMODEL_HXX
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue