// Written by David Culp, started November 2003.
// - davidculp2@comcast.net
//
+// With major additions by Mathias Froehlich & Vivian Meazza 2004-2007
+//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
#endif
#include <simgear/math/point3d.hxx>
+#include <simgear/math/sg_random.h>
#include <math.h>
#include "AIBallistic.hxx"
setCd(scFileNode->getDoubleValue("cd", 0.029));
setMass(scFileNode->getDoubleValue("mass", 0.007));
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) {
Transform();
}
-
void FGAIBallistic::setAzimuth(double az) {
hdg = azimuth = az;
}
-
void FGAIBallistic::setElevation(double el) {
pitch = elevation = el;
}
aero_stabilised = val;
}
+void FGAIBallistic::setNoRoll(bool nr) {
+ no_roll = nr;
+}
+
void FGAIBallistic::setDragArea(double a) {
drag_area = a;
}
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;
// cout << "life timer 1" << life_timer << dt << endl;
if (life_timer > life) setDie(true);
double wind_speed_from_east_deg_sec;
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
// for a conventional shell/bullet (no boat-tail).
- if ( Mach < 0.7 ) { Cdm = 0.0125 * Mach + Cd; }
- else if ( 0.7 < Mach && Mach < 1.2 ) {
- 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;
+ if ( Mach < 0.7 )
+ Cdm = 0.0125 * Mach + Cd;
+ else if ( 0.7 < Mach && Mach < 1.2 )
+ 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 << " ballistic speed kts //"<< speed << endl;
// drag = Cd * 0.5 * rho * speed * speed * drag_area;
// rho is adjusted for altitude in void FGAIBase::update,
speed -= (Cdm * 0.5 * rho * speed * speed * drag_area/mass) * dt;
// 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
- vs = sin( pitch * SG_DEGREES_TO_RADIANS ) * speed;
- double hs = cos( pitch * SG_DEGREES_TO_RADIANS ) * speed;
+ vs = sin( pitch * SG_DEGREES_TO_RADIANS ) * speed_fps;
+ double hs = cos( pitch * SG_DEGREES_TO_RADIANS ) * speed_fps;
// convert horizontal speed (fps) to degrees per second
speed_north_deg_sec = cos(hdg / SG_RADIANS_TO_DEGREES) * hs / ft_per_deg_lat;
wind_speed_from_east_deg_sec = wind_from_east / ft_per_deg_lon;
// set new position
- pos.setLatitudeDeg( pos.getLatitudeDeg() + (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 );
+ pos.setLatitudeDeg( pos.getLatitudeDeg()
+ + (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
vs -= (gravity - buoyancy) * dt;
pos.setElevationFt(altitude_ft);
// recalculate pitch (velocity vector) if aerostabilized
- // cout << "aero_stabilised " << aero_stabilised << endl ;
- if (aero_stabilised) pitch = atan2( vs, hs ) * SG_RADIANS_TO_DEGREES;
+ /*cout << name << ": " << "aero_stabilised " << aero_stabilised
+ << " pitch " << pitch <<" vs " << vs <<endl ;*/
+
+ if (aero_stabilised)
+ pitch = atan2( vs, hs ) * SG_RADIANS_TO_DEGREES;
// 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
if (altitude_ft < -1000.0) setDie(true);
bool init(bool search_in_AI_path=false);
virtual void bind();
virtual void unbind();
+
void update(double dt);
void setAzimuth( double az );
void setWind( bool val );
void setCd( double c );
void setMass( double m );
+ void setNoRoll( bool nr );
+ void setRandom( bool r );
+ void setName(const string&);
double _getTime() const;
double azimuth; // degrees true
double elevation; // 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 life_timer; // seconds
double gravity; // fps2
bool wind; // if true, local wind will be applied to object
double Cd; // drag coefficient
double mass; // slugs
+ bool random; // modifier for Cd
+ string name;
void Run(double dt);
};
#endif // _FG_AIBALLISTIC_HXX
-
// David Luff's FGAIEntity class.
// - davidculp2@comcast.net
//
+// With additions by Mathias Froehlich & Vivian Meazza 2004 -2007
+//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
globals->get_scenery()->unregister_placement_transform(aip.getTransform());
globals->get_scenery()->get_scene_graph()->removeChild(aip.getSceneGraph());
}
+
if (props) {
SGPropertyNode* parent = props->getParent();
+
if (parent) {
model_removed->setStringValue(props->getPath());
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;
fp = 0;
}
-
void FGAIBase::readFromScenario(SGPropertyNode* scFileNode)
{
if (!scFileNode)
setLongitude(scFileNode->getDoubleValue("longitude", 0.0));
setLatitude(scFileNode->getDoubleValue("latitude", 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) {
+
if (_otype == otStatic)
return;
+
if (_otype == otBallistic)
CalculateMach();
}
void FGAIBase::Transform() {
+
if (!invisible) {
aip.setPosition(pos);
- if (no_roll) {
+
+ if (no_roll)
aip.setOrientation(0.0, pitch, hdg);
- } else {
+ else
aip.setOrientation(roll, pitch, hdg);
- }
+
aip.update();
}
+
}
bool FGAIBase::init(bool search_in_AI_path) {
+
if (!model_path.empty()) {
+
if ( (search_in_AI_path)
&&(model_path.substr(model_path.size() - 4, 4) == ".xml")) {
SGPath ai_path("AI");
} catch (const sg_exception &e) {
model = NULL;
}
- } else model = NULL;
+ } else
+ model = NULL;
+
if (!model) {
try {
model = load3DModel( globals->get_fg_root(), model_path, props,
} catch (const sg_exception &e) {
model = NULL;
}
- }
- }
+ }
+
+ }
+
if (model.get()) {
aip.init( model.get() );
aip.setVisible(true);
invisible = false;
globals->get_scenery()->get_scene_graph()->addChild(aip.getSceneGraph());
+
// Register that one at the scenery manager
globals->get_scenery()->register_placement_transform(aip.getTransform());
fgSetString("/ai/models/model-added", props->getPath());
} else {
- if (!model_path.empty()) {
+
+ if (!model_path.empty())
SG_LOG(SG_INPUT, SG_WARN, "AIBase: Could not load model " << model_path);
- }
+
}
+ props->setStringValue("submodels/path", _path.c_str());
setDie(false);
return true;
}
-osg::Node*
-FGAIBase::load3DModel(const string& fg_root,
+osg::Node* FGAIBase::load3DModel(const string& fg_root,
const string &path,
SGPropertyNode *prop_root,
double sim_time_sec)
}
bool FGAIBase::isa( object_type otype ) {
- if ( otype == _otype )
- return true;
- else
- return false;
+
+ if ( otype == _otype )
+ return true;
+ else
+ return false;
}
props->untie("controls/lighting/nav-lights");
}
-double FGAIBase::UpdateRadar(FGAIManager* manager)
-{
+double FGAIBase::UpdateRadar(FGAIManager* manager) {
double radar_range_ft2 = fgGetDouble("/instrumentation/radar/range");
bool force_on = fgGetBool("/instrumentation/radar/debug-mode", false);
radar_range_ft2 *= SG_NM_TO_METER * SG_METER_TO_FEET * 1.1; // + 10%
// Test whether the target is within radar range.
//
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);
// copy values from the AIManager
return range_ft2;
}
-SGVec3d
-FGAIBase::getCartPosAt(const SGVec3d& _off) const
-{
- // Transform that one to the horizontal local coordinate system.
+/*
+* Getters and Setters
+*/
+SGVec3d FGAIBase::getCartPosAt(const SGVec3d& _off) const {
+ // Transform that one to the horizontal local coordinate system.
SGQuatd hlTrans = SGQuatd::fromLonLat(pos);
+
// and postrotate the orientation of the AIModel wrt the horizontal
// local frame
hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
return cartPos + off;
}
-SGVec3d
-FGAIBase::getCartPos() const
-{
+SGVec3d FGAIBase::getCartPos() const {
// Transform that one to the horizontal local coordinate system.
-
SGQuatd hlTrans = SGQuatd::fromLonLat(pos);
+
// and postrotate the orientation of the AIModel wrt the horizontal
// local frame
hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
return cartPos;
}
-double
-FGAIBase::_getCartPosX() const
-{
+double FGAIBase::_getCartPosX() const {
SGVec3d cartPos = getCartPos();
return cartPos.x();
}
-double
-FGAIBase::_getCartPosY() const
-{
+double FGAIBase::_getCartPosY() const {
SGVec3d cartPos = getCartPos();
return cartPos.y();
}
-double
-FGAIBase::_getCartPosZ() const
-{
+double FGAIBase::_getCartPosZ() const {
SGVec3d cartPos = getCartPos();
return cartPos.z();
}
-/*
- * getters and Setters
- */
void FGAIBase::_setLongitude( double longitude ) {
pos.setLongitudeDeg(longitude);
}
+
void FGAIBase::_setLatitude ( double latitude ) {
pos.setLatitudeDeg(latitude);
}
double FGAIBase::_getLongitude() const {
return pos.getLongitudeDeg();
}
+
double FGAIBase::_getLatitude () const {
return pos.getLatitudeDeg();
}
+
double FGAIBase::_getRdot() const {
return rdot;
}
+
double FGAIBase::_getVS_fps() const {
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 ) {
vs = _vs/60.0;
}
double FGAIBase::_getAltitude() const {
return altitude_ft;
}
+
+bool FGAIBase::_getServiceable() const {
+ return serviceable;
+}
+
void FGAIBase::_setAltitude( double _alt ) {
setAltitude( _alt );
}
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() {
// Calculate rho at altitude, using standard atmosphere
// For the temperature T and the pressure p,
-
double altitude = altitude_ft;
if (altitude < 36152) { // curve fits for the troposphere
T = 59 - 0.00356 * altitude;
p = 2116 * pow( ((T + 459.7) / 518.6) , 5.256);
-
} else if ( 36152 < altitude && altitude < 82345 ) { // lower stratosphere
T = -70;
p = 473.1 * pow( e , 1.73 - (0.000048 * altitude) );
-
} else { // upper stratosphere
T = -205.05 + (0.00164 * altitude);
p = 51.97 * pow( ((T + 459.7) / 389.98) , -11.388);
// a = speed of sound [ft/s]
// g = specific heat ratio, which is usually equal to 1.4
// R = specific gas constant, which equals 1716 ft-lb/slug/°R
-
a = sqrt ( 1.4 * 1716 * (T + 459.7));
// calculate Mach number
-
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() {
static int id = 0;
+
if (!++id)
id++; // id = 0 is not allowed.
+
return id;
}
void setManager(FGAIManager* mgr, SGPropertyNode* p);
void setPath( const char* model );
+ void setSMPath( const string& p );
void setSpeed( double speed_KTAS );
void setAltitude( double altitude_ft );
void setHeading( double heading );
void setXoffset( double x_offset );
void setYoffset( double y_offset );
void setZoffset( double z_offset );
+ void setServiceable ( bool serviceable );
+ void setDie( bool die );
int getID() const;
- void setDie( bool die );
bool getDie();
SGVec3d getCartPosAt(const SGVec3d& off) const;
SGVec3d getCartPos() const;
+
double _getCartPosX() const;
double _getCartPosY() const;
double _getCartPosZ() const;
-protected:
+ string _path;
+protected:
SGPropertyNode_ptr props;
SGPropertyNode_ptr model_removed; // where to report model removal
FGAIManager* manager;
double speed; // knots true airspeed
double altitude_ft; // feet above sea level
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 ft_per_deg_lon;
string model_path; //Path to the 3D model
osg::ref_ptr<osg::Node> model; //The 3D model object
SGModelPlacement aip;
+
bool delete_me;
bool invisible;
bool no_roll;
+ bool serviceable;
+
double life;
+
FGAIFlightPlan *fp;
void Transform();
object_type _otype;
public:
-
object_type getType();
+
virtual const char* getTypeString(void) const { return "null"; }
+
bool isa( object_type otype );
- double _getVS_fps() const;
void _setVS_fps( double _vs );
-
- double _getAltitude() const;
void _setAltitude( double _alt );
-
void _setLongitude( double longitude );
void _setLatitude ( double latitude );
+ double _getVS_fps() const;
+ double _getAltitude() const;
double _getLongitude() const;
double _getLatitude () const;
-
double _getBearing() const;
double _getElevation() const;
double _getRdot() const;
double _getX_shift() const;
double _getY_shift() 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 T; // temperature, degs farenheit
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 ) {
speed = tgt_speed = speed_KTAS;
}
}
inline void FGAIBase::setDie( bool die ) { delete_me = die; }
+
inline bool FGAIBase::getDie() { return delete_me; }
inline FGAIBase::object_type FGAIBase::getType() { return _otype; }
-
-
#endif // _FG_AIBASE_HXX
-
wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
wpt->flaps_down= wpt_node->getBoolValue("flaps-down", 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;
else wpt->finished = false;
bool flaps_down;
bool on_ground;
int routeIndex; // For AI/ATC purposes;
- double wait_time;
+ double time_sec;
+ string time;
+
} waypoint;
FGAIFlightPlan(const string& filename);
class FGAIManager : public SGSubsystem
{
-private:
+public:
// A list of pointers to AI objects
typedef list <SGSharedPtr<FGAIBase> > ai_list_type;
ai_list_type ai_list;
-public:
+ inline const list <SGSharedPtr<FGAIBase> >& get_ai_list() const { return ai_list; }
FGAIManager();
~FGAIManager();
#include <math.h>
#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/timing/sg_time.hxx>
#include <simgear/math/sg_random.h>
#include "AIShip.hxx"
}
void FGAIShip::readFromScenario(SGPropertyNode* scFileNode) {
+
if (!scFileNode)
return;
setRadius(scFileNode->getDoubleValue("turn-radius-ft", 2000));
std::string flightplan = scFileNode->getStringValue("flightplan");
setRepeat(scFileNode->getBoolValue("repeat", false));
+ setStartTime(scFileNode->getStringValue("time", ""));
if (!flightplan.empty()) {
FGAIFlightPlan* fp = new FGAIFlightPlan(flightplan);
curr = 0; // the one ahead
next = 0; // the next plus 1
+ _until_time = "";
+
props->setStringValue("name", _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-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;
_rudder = 0.0;
_roll_constant = 0.001;
_speed_constant = 0.05;
_hdg_constant = 0.01;
+ _roll_factor = -0.0083335;
_rd_turn_radius_ft = _sp_turn_radius_ft = turn_radius_ft;
_wait_count = 0;
_missed_time_sec = 30;
+ _day = 86400;
+
+
_wp_range = _old_range = 0;
_range_rate = 0;
SGRawValuePointer<double>(&tgt_heading));
props->tie("controls/constants/rudder",
SGRawValuePointer<double>(&_rudder_constant));
+ props->tie("controls/constants/roll-factor",
+ SGRawValuePointer<double>(&_roll_factor));
props->tie("controls/constants/roll",
SGRawValuePointer<double>(&_roll_constant));
props->tie("controls/constants/rudder",
SGRawValuePointer<double>(&_wait_count));
props->tie("position/waypoint-waiting",
SGRawValuePointer<bool>(&_waiting));
+ props->tie("submodels/serviceable",
+ SGRawValuePointer<bool>(&_serviceable));
}
void FGAIShip::unbind() {
props->untie("controls/tgt-heading-degs");
props->untie("controls/constants/roll");
props->untie("controls/constants/rudder");
+ props->untie("controls/constants/roll-factor");
props->untie("controls/constants/speed");
props->untie("position/waypoint-range-nm");
props->untie("position/waypoint-range-old-nm");
props->untie("position/waypoint-wait-count");
props->untie("position/waypoint-waiting");
props->untie("position/waypoint-missed-time-sec");
+ props->untie("submodels/serviceable");
}
void FGAIShip::update(double dt) {
}
void FGAIShip::Run(double dt) {
-
+ //cout << _name << " init: " << _fp_init << endl;
if (_fp_init)
ProcessFlightPlan(dt);
- double speed_north_deg_sec;
- double speed_east_deg_sec;
+ // double speed_north_deg_sec;
+ // double speed_east_deg_sec;
double alpha;
double rudder_limit;
double raw_roll;
if (speed_diff < 0.0)
speed -= _speed_constant * dt;
+
}
// do not allow unreasonable ship speeds
if (hdg < 0.0)
hdg += 360.0;
- //adjust roll for _rudder angle and speed. Another bit of voodoo
- raw_roll = -0.0166667 * speed * _rudder;
+ //adjust roll for rudder angle and speed. Another bit of voodoo
+ raw_roll = _roll_factor * speed * _rudder;
} else {
// _rudder angle is 0
raw_roll = 0;
// adjust _rudder angle
double rudder_diff = _tgt_rudder - _rudder;
+
// set the _rudder limit by speed
if (speed <= 40)
rudder_limit = (-0.825 * speed) + 35;
_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) {
_curr_name = c;
props->setStringValue("position/waypoint-name-curr", _curr_name.c_str());
props->setBoolValue("position/waypoint-missed", _missed);
}
+void FGAIShip::setRudder(float r) {
+ _rudder = r;
+}
+
+void FGAIShip::setRoll(double 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 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;
+}
+
+double FGAIShip::getCourse(double lat, double lon, double lat2, double lon2) const {
+
+ double course, distance, recip;
+
+ //calculate the bearing and range of the second pos from the first
+ geo_inverse_wgs_84(lat, lon, lat2, lon2, &course, &recip, &distance);
+ if (tgt_speed >= 0) {
+ return course;
+ } else {
+ return recip;
+ }
+}
+
void FGAIShip::ProcessFlightPlan(double dt) {
+ double time_sec = getDaySeconds();
+ double until_time_sec = 0;
+
_missed = false;
_dt_count += dt;
// 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)
+
+ //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());
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 {
}
_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_INFO, "AIShip: Flightplan restarting ");
+ SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: Flightplan restarting ");
fp->restart();
prev = curr;
curr = fp->getCurrentWaypoint();
_missed_count = 0;
AccelTo(prev->speed);
} else {
- SG_LOG(SG_GENERAL, SG_INFO, "AIShip: Flightplan dieing ");
+ SG_LOG(SG_GENERAL, SG_DEBUG, "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 ");
+ 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_INFO, "AIShip: " << _name << " wait done: getting new waypoints ");
+ 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);
- 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 ");
+ SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: " << _name << " getting new waypoints ");
fp->IncrementWaypoint(false);
prev = fp->getPreviousWaypoint(); //first waypoint
curr = fp->getCurrentWaypoint(); //second waypoint
if (finite(course))
TurnTo(course);
else
- SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: Bearing or Range is not a finite number");
+ SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: Bearing or Range is not a finite number");
_dt_count = 0;
} // end Processing FlightPlan
-void FGAIShip::setRudder(float r) {
- _rudder = r;
-}
-
-void FGAIShip::setRoll(double rl) {
- roll = rl;
-}
-
-double FGAIShip::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;
-}
+bool FGAIShip::initFlightPlan() {
-double FGAIShip::getCourse(double lat, double lon, double lat2, double lon2) const {
+ SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: " << _name << " initializing waypoints ");
- double course, distance, recip;
+ bool init = false;
- //calculate the bearing and range of the second pos from the first
- geo_inverse_wgs_84(lat, lon, lat2, lon2, &course, &recip, &distance);
- if (tgt_speed >= 0) {
- return course;
- } else {
- return recip;
- }
-}
+ _start_sec = 0;
-bool FGAIShip::initFlightPlan() {
- SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " initialising waypoints ");
fp->restart();
fp->IncrementWaypoint(false);
curr = fp->getCurrentWaypoint(); //second waypoint
next = fp->getNextWaypoint(); //third waypoint (might not exist!)
- if (curr->name == "WAIT") { // don't wait when initialising
- SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " re-initialising waypoints ");
+ while (curr->name == "WAIT" || curr->name == "WAITUNTIL") { // don't wait when initialising
+ SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: " << _name << " re-initializing waypoints ");
fp->IncrementWaypoint(false);
curr = fp->getCurrentWaypoint();
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);
setLongitude(prev->longitude);
setSpeed(prev->speed);
+ }
+
+ setWPNames();
setHeading(getCourse(prev->latitude, prev->longitude, curr->latitude, curr->longitude));
- _hdg_lock = true;
- _wp_range = getRange(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr->latitude, curr->longitude);
+ _wp_range = getRange(prev->latitude, prev->longitude, curr->latitude, curr->longitude);
_old_range = _wp_range;
_range_rate = 0;
+ _hdg_lock = true;
_missed = false;
_missed_count = 0;
_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)
+ init = true;
+
+ if (init)
return true;
else
return false;
} // end of initialization
-void FGAIShip::setWPNames() {
- if (prev != 0)
- setPrevName(prev->name);
- else
- setPrevName("");
+double FGAIShip::processTimeString(const string& theTime) {
- setCurrName(curr->name);
+ int Hour;
+ int Minute;
+ int Second;
- if (next != 0)
- setNextName(next->name);
- else
- setNextName("");
+ // first split theTime string into
+ // hour, minute, second and convert to int;
+ Hour = atoi(theTime.substr(0,2).c_str());
+ Minute = atoi(theTime.substr(3,5).c_str());
+ Second = atoi(theTime.substr(6,8).c_str());
+
+ // offset by a day-sec to allow for starting a day earlier
+ double time_seconds = Hour * 3600
+ + 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 );
+ }
- SG_LOG(SG_GENERAL, SG_INFO, "AIShip: prev wp name " << prev->name);
- SG_LOG(SG_GENERAL, SG_INFO, "AIShip: current wp name " << curr->name);
- SG_LOG(SG_GENERAL, SG_INFO, "AIShip: next wp name " << next->name);
+ //cout << "Pos " << lat << ", " << lon << " recip " << recip << endl;
+ setLatitude(lat);
+ setLongitude(lon);
+ return true;
}
void setPrevName(const string&);
bool _hdg_lock;
+ bool _serviceable;
virtual const char* getTypeString(void) const { return "ship"; }
protected:
- string _name; // The _name of this ship.
+ string _name; // The name of this ship.
private:
void setRepeat(bool r);
void setMissed(bool m);
void setWPNames();
+ void setServiceable(bool s);
void Run(double dt);
+ void setStartTime(const string&);
+ void setUntilTime(const string&);
+
+
double getRange(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 getDaySeconds();
+ double processTimeString(const string& time);
bool initFlightPlan();
+ bool advanceFlightPlan (double elapsed_sec, double day_sec);
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 _wp_range, _old_range, _range_rate;
double _dt_count, _missed_count, _wait_count;
double _next_run;
double _missed_time_sec;
+ double _start_sec;
+ double _day;
string _prev_name, _curr_name, _next_name;
+ string _path;
+ string _start_time, _until_time;
bool _repeat;
bool _fp_init;
// submodel.cxx - models a releasable submodel.
// 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.
#include <simgear/structure/exception.hxx>
#include <simgear/misc/sg_path.hxx>
+#include <simgear/math/sg_geodesy.hxx>
#include <Main/fg_props.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;
-FGSubmodelMgr::FGSubmodelMgr ()
+FGSubmodelMgr::FGSubmodelMgr()
{
-
- x_offset = y_offset = 0.0;
- z_offset = -4.0;
- pitch_offset = 2.0;
- yaw_offset = 0.0;
-
- out[0] = out[1] = out[2] = 0;
- in[3] = out[3] = 1;
- string contents_node;
- contrail_altitude = 30000.0;
-}
-FGSubmodelMgr::~FGSubmodelMgr ()
-{
+ x_offset = y_offset = 0.0;
+ z_offset = -4.0;
+ pitch_offset = 2.0;
+ yaw_offset = 0.0;
+
+ out[0] = out[1] = out[2] = 0;
+ in[3] = out[3] = 1;
+ string contents_node;
+ contrail_altitude = 30000;
}
-void
-FGSubmodelMgr::init ()
+FGSubmodelMgr::~FGSubmodelMgr()
+{}
+
+void FGSubmodelMgr::init()
{
+
+ index = 0;
load();
+
_serviceable_node = fgGetNode("/sim/submodels/serviceable", true);
+ _serviceable_node->setBoolValue(true);
_user_lat_node = fgGetNode("/position/latitude-deg", true);
_user_lon_node = fgGetNode("/position/longitude-deg", true);
_user_speed_node = fgGetNode("/velocities/uBody-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_east_node = fgGetNode("/environment/wind-from-east-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_east_fps_node = fgGetNode("/velocities/speed-east-fps",true);
- _user_speed_north_fps_node = fgGetNode("/velocities/speed-north-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_north_fps_node = fgGetNode("/velocities/speed-north-fps", true);
_contrail_altitude_node = fgGetNode("/environment/params/contrail-altitude", true);
contrail_altitude = _contrail_altitude_node->getDoubleValue();
ai = (FGAIManager*)globals->get_subsystem("ai_model");
+ loadAI();
}
-void
-FGSubmodelMgr::bind ()
-{
-}
+void FGSubmodelMgr::bind()
+{}
-void
-FGSubmodelMgr::unbind ()
+void FGSubmodelMgr::unbind()
{
- submodel_iterator = submodels.begin();
- while(submodel_iterator != submodels.end()) {
- (*submodel_iterator)->prop->untie("count");
- ++submodel_iterator;
- }
+ submodel_iterator = submodels.begin();
+
+ while (submodel_iterator != submodels.end()) {
+ (*submodel_iterator)->prop->untie("count");
+ ++submodel_iterator;
+ }
+
}
-void
-FGSubmodelMgr::update (double dt)
+void FGSubmodelMgr::update(double dt)
{
- if (!(_serviceable_node->getBoolValue())) return;
- int i=-1;
-
- _contrail_trigger->setBoolValue(_user_alt_node->getDoubleValue() > contrail_altitude);
-
- submodel_iterator = submodels.begin();
- while(submodel_iterator != submodels.end()) {
- i++;
- if ((*submodel_iterator)->trigger->getBoolValue()) {
- if ((*submodel_iterator)->count != 0) {
- release( (*submodel_iterator), dt);
- }
- } else {
- (*submodel_iterator)->first_time = true;
- }
- ++submodel_iterator;
- }
-
+
+ if (!(_serviceable_node->getBoolValue()))
+ return;
+
+ 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
+
}
-bool
-FGSubmodelMgr::release (submodel* sm, double dt)
+bool 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;
+ // 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 / 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;
}
-void
-FGSubmodelMgr::load ()
+void FGSubmodelMgr::load()
{
SGPropertyNode *path = fgGetNode("/sim/submodels/path");
SGPropertyNode root;
if (path) {
- SGPath config( globals->get_fg_root() );
- config.append( path->getStringValue() );
-
- try {
- readProperties(config.str(), &root);
- } catch (const sg_exception &e) {
- SG_LOG(SG_GENERAL, SG_ALERT,
- "Unable to read submodels file: ");
- cout << config.str() << endl;
- return;
- }
+ SGPath config(globals->get_fg_root());
+ config.append(path->getStringValue());
+
+ try {
+ readProperties(config.str(), &root);
+ } catch (const sg_exception &e) {
+ SG_LOG(SG_GENERAL, SG_INFO,
+ "Submodels: unable to read 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 submodel " << (*it)->getPath() << endl;
- submodel* sm = new submodel;
- SGPropertyNode * entry_node = *it;
- sm->trigger = fgGetNode(entry_node->getStringValue("trigger", "none"), true);
- 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->first_time = 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->contents_node = fgGetNode(entry_node->getStringValue("contents", "none"), true);
-
- sm->trigger->setBoolValue(false);
- sm->timer = sm->delay;
-
- 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)));
-// sm->prop->tie("contents path", SGRawValuePointer<const char *>(&(sm->contents_node)));
- submodels.push_back( sm );
- }
-
- submodel_iterator = submodels.begin();
-
-}
+ 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 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->name << " 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 = 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;
+
+ // set contents to 0 in the parent
+ sm->contents_node->setDoubleValue(0);
+ } else
+ IC.mass = sm->weight * lbs_to_slugs;
+
+ //cout << "mass " << IC.mass << endl;
+
+ 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 ;*/
-// get initial conditions
-
-// 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;;
-// 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();
-
-
- in[0] = sm->x_offset;
- in[1] = sm->y_offset;
- in[2] = sm->z_offset;
-
-
-// pre-process the trig functions
+ 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);
sinRx = sin(-IC.roll * SG_DEGREES_TO_RADIANS);
cosRy = cos(-IC.elevation * SG_DEGREES_TO_RADIANS);
cosRz = cos(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][1] = -1 * cosRx * sinRz + sinRx * sinRy * cosRz ;
trans[0][2] = sinRx * sinRz + cosRx * sinRy * cosRz;
trans[2][2] = cosRx * cosRy;
-// 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];
+ // 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];
- // convert ft to degrees of latitude
- out[0] = out[0] /(366468.96 - 3717.12 * cos(IC.lat * SG_DEGREES_TO_RADIANS));
+ // convert ft to degrees of latitude
+ out[0] = out[0] / (366468.96 - 3717.12 * cos(IC.lat * SG_DEGREES_TO_RADIANS));
- // convert ft to degrees of longitude
- out[1] = out[1] /(365228.16 * cos(IC.lat * SG_DEGREES_TO_RADIANS));
+ // convert ft to degrees of longitude
+ out[1] = out[1] / (365228.16 * cos(IC.lat * SG_DEGREES_TO_RADIANS));
- // set submodel initial position
- IC.lat += out[0];
- IC.lon += out[1];
- IC.alt += out[2];
+ // set submodel initial position
+ IC.lat += out[0];
+ IC.lon += out[1];
+ IC.alt += out[2];
- // get aircraft velocity vector angles in XZ and XY planes
+ // get aircraft velocity vector angles in XZ and XY planes
//double alpha = _user_alpha_node->getDoubleValue();
//double velXZ = IC.elevation - alpha * cosRx;
//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
-
- 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
-
- IC.total_speed_east = sm->speed * cos(IC.elevation*SG_DEGREES_TO_RADIANS)*
- sin(IC.azimuth*SG_DEGREES_TO_RADIANS) + IC.speed_east_fps;
-
- // calculate the total speed down
-
- IC.total_speed_down = sm->speed * -sin(IC.elevation*SG_DEGREES_TO_RADIANS) +
- IC.speed_down_fps;
-
- // re-calculate speed, elevation and azimuth
-
- IC.speed = sqrt( IC.total_speed_north * IC.total_speed_north +
- IC.total_speed_east * IC.total_speed_east +
- IC.total_speed_down * IC.total_speed_down);
-
- IC.azimuth = atan(IC.total_speed_east/IC.total_speed_north) * SG_RADIANS_TO_DEGREES;
-
- // rationalise the output
-
- if (IC.total_speed_north <= 0){
- IC.azimuth = 180 + IC.azimuth;
- }
- else{
- 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;
+
+ // 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);
+
+ // calcuate the total speed north
+ 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
+ IC.total_speed_east = sm->speed * cos(IC.elevation * SG_DEGREES_TO_RADIANS)
+ * sin(IC.azimuth * SG_DEGREES_TO_RADIANS) + IC.speed_east_fps;
+
+ // calculate the total speed down
+ IC.total_speed_down = sm->speed * -sin(IC.elevation * SG_DEGREES_TO_RADIANS)
+ + IC.speed_down_fps;
+
+ // re-calculate speed, elevation and azimuth
+ IC.speed = sqrt(IC.total_speed_north * IC.total_speed_north
+ + IC.total_speed_east * IC.total_speed_east
+ + IC.total_speed_down * IC.total_speed_down);
+
+ //cout << " speed fps out" << IC.speed << endl ;
+ IC.azimuth = atan(IC.total_speed_east / IC.total_speed_north) * SG_RADIANS_TO_DEGREES;
+
+ // rationalise the output
+ if (IC.total_speed_north <= 0) {
+ IC.azimuth = 180 + IC.azimuth;
+ } else {
+
+ 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
-FGSubmodelMgr::updatelat(double lat)
+void FGSubmodelMgr::updatelat(double lat)
{
- double latitude = lat;
- ft_per_deg_latitude = 366468.96 - 3717.12 * cos(latitude / SG_RADIANS_TO_DEGREES);
- ft_per_deg_longitude = 365228.16 * cos(latitude / SG_RADIANS_TO_DEGREES);
+ ft_per_deg_latitude = 366468.96 - 3717.12 * cos(lat / SG_RADIANS_TO_DEGREES);
+ ft_per_deg_longitude = 365228.16 * cos(lat / SG_RADIANS_TO_DEGREES);
}
-// end of submodel.cxx
+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
SG_USING_STD(vector);
SG_USING_STD(string);
+class FGAIBase;
class FGSubmodelMgr : public SGSubsystem
{
public:
-
- typedef struct {
- SGPropertyNode_ptr trigger;
- SGPropertyNode_ptr prop;
- SGPropertyNode_ptr contents_node;
-
- string name;
- string model;
- double speed;
- bool slaved;
- bool repeat;
- double delay;
- double timer;
- int count;
- double x_offset;
- double y_offset;
- double z_offset;
- double yaw_offset;
- double pitch_offset;
- double drag_area;
- double life;
- double buoyancy;
- bool wind;
- bool first_time;
- double cd;
- double weight;
- double contents;
- bool aero_stabilised;
- } submodel;
-
- typedef struct {
- double lat;
- double lon;
- double alt;
- double roll;
- double azimuth;
- double elevation;
- double speed;
- double wind_from_east;
- double wind_from_north;
- double speed_down_fps;
- double speed_east_fps;
- double speed_north_fps;
- double total_speed_down;
- double total_speed_east;
- double total_speed_north;
- double mass;
- } IC_struct;
-
- FGSubmodelMgr ();
- ~FGSubmodelMgr ();
-
- void load ();
- void init ();
- void bind ();
- void unbind ();
- void update (double dt);
- bool release (submodel* sm, double dt);
- void transform (submodel* sm);
- void updatelat( double lat );
+ typedef struct
+ {
+ SGPropertyNode_ptr trigger_node;
+ SGPropertyNode_ptr prop;
+ SGPropertyNode_ptr contents_node;
+ SGPropertyNode_ptr submodel_node;
+ SGPropertyNode_ptr speed_node;
+
+ string name;
+ string model;
+ double speed;
+ bool slaved;
+ bool repeat;
+ double delay;
+ double timer;
+ int count;
+ double x_offset;
+ double y_offset;
+ double z_offset;
+ double yaw_offset;
+ double pitch_offset;
+ double drag_area;
+ double life;
+ double buoyancy;
+ bool wind;
+ bool first_time;
+ double cd;
+ double weight;
+ double contents;
+ bool aero_stabilised;
+ int id;
+ bool no_roll;
+ bool serviceable;
+ }
+ submodel;
+
+ typedef struct
+ {
+ double lat;
+ double lon;
+ double alt;
+ double roll;
+ double azimuth;
+ double elevation;
+ double speed;
+ double wind_from_east;
+ double wind_from_north;
+ double speed_down_fps;
+ double speed_east_fps;
+ double speed_north_fps;
+ double total_speed_down;
+ double total_speed_east;
+ double total_speed_north;
+ double mass;
+ int id;
+ bool no_roll;
+ }
+ IC_struct;
+
+ FGSubmodelMgr();
+ ~FGSubmodelMgr();
+
+ void load();
+ void init();
+ void bind();
+ void unbind();
+ void update(double dt);
+ bool release(submodel* sm, double dt);
+ void transform(submodel* sm);
+ void updatelat(double lat);
private:
float cosRy, sinRy;
float cosRz, sinRz;
+ int index;
+
double ft_per_deg_longitude;
double ft_per_deg_latitude;
FGAIManager* ai;
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;
-#endif // __SYSTEMS_SUBMODEL_HXX
+ sm_list_type sm_list;
+ void loadAI();
+ void loadSubmodels();
+ double getRange(double lat, double lon, double lat2, double lon2) const;
+};
+#endif // __SYSTEMS_SUBMODEL_HXX