#include "AIBallistic.hxx"
#include <Main/util.hxx>
+#include <Environment/gravity.hxx>
using namespace simgear;
const double FGAIBallistic::slugs_to_lbs = 32.1740485564;
FGAIBallistic::FGAIBallistic(object_type ot) :
-FGAIBase(ot),
+FGAIBase(ot, false),
_height(0.0),
+_speed(0),
_ht_agl_ft(0.0),
_azimuth(0.0),
_elevation(0.0),
_rotation(0.0),
-_formate_to_ac(false),
+hs(0),
+_elapsed_time(0),
_aero_stabilised(false),
_drag_area(0.007),
_life_timer(0.0),
-_gravity(32.1740485564),
_buoyancy(0),
_wind(true),
_mass(0),
_slave_load_to_ac(false),
_contents_lb(0),
_report_collision(false),
-_report_expiry(false),
_report_impact(false),
_external_force(false),
+_report_expiry(false),
_impact_report_node(fgGetNode("/ai/models/model-impact", true)),
-_old_height(0),
-_elapsed_time(0),
-hs(0)
+_old_height(0)
{
no_roll = false;
setSlaved(scFileNode->getBoolValue("slaved", false));
setSlavedLoad(scFileNode->getBoolValue("slaved-load", false));
setContentsPath(scFileNode->getStringValue("contents"));
+ setParentName(scFileNode->getStringValue("parent"));
}
bool FGAIBallistic::init(bool search_in_AI_path) {
_elapsed_time += (sg_random() * 100);
+ _life_timer = 0;
+
props->setStringValue("material/name", "");
props->setStringValue("name", _name.c_str());
props->setStringValue("submodels/path", _path.c_str());
props->setStringValue("contents/path", _contents_path.c_str());
}
+ //cout << "init: name " << _name.c_str() << " _life_timer " << _life_timer
+ // << endl;
+
+ //if(_parent != ""){
+ // setParentNode();
+ //}
+
+ //setParentNodes(_selected_ac);
+
//props->setStringValue("vector/path", _vector_path.c_str());
// start with high value so that animations don't trigger yet
Transform();
- //cout << _name << " speed init: " << speed << endl;
+ if(_parent != ""){
+ setParentNode();
+ }
+
+ setParentNodes(_selected_ac);
return true;
}
props->tie("sim/time/elapsed-sec",
SGRawValueMethods<FGAIBallistic,double>(*this,
- &FGAIBallistic::_getTime));
+ &FGAIBallistic::_getTime, &FGAIBallistic::setTime));
//props->tie("mass-slug",
// SGRawValueMethods<FGAIBallistic,double>(*this,
// &FGAIBallistic::getMass));
(*this, &FGAIBallistic::getLoadOffset, &FGAIBallistic::setLoadOffset));
props->tie("load/distance-to-hitch-ft",
SGRawValueMethods<FGAIBallistic,double>
- (*this, &FGAIBallistic::getDistanceLoadToHitch));
+ (*this, &FGAIBallistic::getDistanceToHitch));
props->tie("load/elevation-to-hitch-deg",
SGRawValueMethods<FGAIBallistic,double>
- (*this, &FGAIBallistic::getElevLoadToHitch));
+ (*this, &FGAIBallistic::getElevToHitch));
props->tie("load/bearing-to-hitch-deg",
SGRawValueMethods<FGAIBallistic,double>
- (*this, &FGAIBallistic::getBearingLoadToHitch));
+ (*this, &FGAIBallistic::getBearingToHitch));
props->tie("material/load-resistance",
SGRawValuePointer<double>(&_load_resistance));
}
FGAIBase::update(dt);
_setUserPos();
- if (_formate_to_ac){
- formateToAC(dt);
- Transform();
- } else if (_slave_to_ac){
+ if (_slave_to_ac){
slaveToAC(dt);
Transform();
} else if (!invisible){
if (_random){
life = seconds * _randomness + (seconds * (1 -_randomness) * sg_random());
- //cout << "life " << life << endl;
+ //cout << " set life " << life << endl;
} else
life = seconds;
}
_impact_report_node = fgGetNode(path.c_str(), true);
}
-void FGAIBallistic::setName(const string& n) {
- _name = n;
-}
-
void FGAIBallistic::setSMPath(const string& s) {
_path = s;
//cout << "submodel path " << _path << endl;
_slave_to_ac = s;
}
-void FGAIBallistic::setFormate(bool f) {
- _formate_to_ac = f;
-}
-
void FGAIBallistic::setContentsPath(const string& path) {
_contents_path = path;
}
}
-void FGAIBallistic::setParentNode(SGPropertyNode_ptr node) {
+void FGAIBallistic::setParentNodes(SGPropertyNode_ptr node) {
+
if (node != 0) {
_pnode = node;
_p_pos_node = _pnode->getChild("position", 0, true);
_p_lat_node = _p_pos_node->getChild("latitude-deg", 0, true);
_p_lon_node = _p_pos_node->getChild("longitude-deg", 0, true);
_p_alt_node = _p_pos_node->getChild("altitude-ft", 0, true);
+ _p_agl_node = _p_pos_node->getChild("altitude-agl-ft", 0, true);
+
_p_ori_node = _pnode->getChild("orientation", 0, true);
_p_pch_node = _p_ori_node->getChild("pitch-deg", 0, true);
_p_vel_node = _pnode->getChild("velocities", 0, true);
_p_spd_node = _p_vel_node->getChild("true-airspeed-kt", 0, true);
-
}
+
}
void FGAIBallistic::setParentPos() {
- if (_pnode != 0) {
+
+ if (_pnode != 0) {
+ //cout << "set parent pos" << endl;
+
double lat = _p_lat_node->getDoubleValue();
double lon = _p_lon_node->getDoubleValue();
double alt = _p_alt_node->getDoubleValue();
_parentpos.setElevationFt(alt);
}
+
}
bool FGAIBallistic::getSlaved() const {
return _slave_to_ac;
}
-bool FGAIBallistic::getFormate() const {
- return _formate_to_ac;
-}
-
double FGAIBallistic::getMass() const {
return _mass;
}
roll = (r * c) + (roll * (1 - c));
}
+void FGAIBallistic::setSpd(double s, double dt, double coeff){
+ double c = dt / (coeff + dt);
+ _speed = (s * c) + (_speed * (1 - c));
+}
+
void FGAIBallistic::setHt(double h, double dt, double coeff){
double c = dt / (coeff + dt);
_height = (h * c) + (_height * (1 - c));
}
-void FGAIBallistic::setHdg(double az, double dt, double coeff){
+int FGAIBallistic::setHdg(double tgt_hdg, double dt, double coeff){
double recip = getRecip(hdg);
double c = dt / (coeff + dt);
+ //cout << "set heading " << tgt_hdg << endl;
//we need to ensure that we turn the short way to the new hdg
- if (az < recip && az < hdg && hdg > 180) {
- hdg = ((az + 360) * c) + (hdg * (1 - c));
- } else if (az > recip && az > hdg && hdg <= 180){
- hdg = ((az - 360) * c) + (hdg * (1 - c));
+ if (tgt_hdg < recip && tgt_hdg < hdg && hdg > 180) {
+ hdg = ((tgt_hdg + 360) * c) + (hdg * (1 - c));
+// cout << "case 1: right turn" << endl;
+ } else if (tgt_hdg > recip && tgt_hdg > hdg && hdg <= 180){
+ hdg = ((tgt_hdg - 360) * c) + (hdg * (1 - c));
+// cout << "case 2: left turn" << endl;
} else {
- hdg = (az * c) + (hdg * (1 - c));
+ hdg = (tgt_hdg * c) + (hdg * (1 - c));
+// cout << "case 4: left turn" << endl;
}
+ return -1;
}
double FGAIBallistic::getTgtXOffset() const {
void FGAIBallistic::slaveToAC(double dt){
- double hdg, pch, rll = 0;
+ if (invisible)
+ return;
+
+ double hdg, pch, rll, agl = 0;
if (_pnode != 0) {
setParentPos();
hdg = _p_hdg_node->getDoubleValue();
pch = _p_pch_node->getDoubleValue();
rll = _p_rll_node->getDoubleValue();
+ agl = _p_agl_node->getDoubleValue();
setOffsetPos(_parentpos, hdg, pch, rll);
setSpeed(_p_spd_node->getDoubleValue());
}else {
hdg = manager->get_user_heading();
pch = manager->get_user_pitch();
rll = manager->get_user_roll();
+ agl = manager->get_user_agl();
setOffsetPos(userpos, hdg, pch, rll);
setSpeed(manager->get_user_speed());
}
setPitch(pch + _pitch_offset);
setBank(rll + _roll_offset);
setOffsetVelocity(dt, pos);
+ setTime(0);
//update the mass (slugs)
_mass = (_weight_lb + getContents()) / slugs_to_lbs;
void FGAIBallistic::Run(double dt) {
_life_timer += dt;
+
+ //_pass += 1;
+ //cout<<"AIBallistic run: name " << _name.c_str()
+ // << " dt " << dt << " _life_timer " << _life_timer << " pass " << _pass << endl;
// if life = -1 the object does not die
if (_life_timer > life && life != -1){
if (_report_expiry && !_expiry_reported && !_impact_reported && !_collision_reported){
- //cout<<"AIBallistic: expiry"<< endl;
+ //cout<<"AIBallistic run: name " << _name.c_str() << " expiry "
+ //<< " _life_timer " << _life_timer<< endl;
handle_expiry();
- } else
+ } else{
+ //cout<<"AIBallistic run: name " << _name.c_str()
+ // << " die " << " _life_timer " << _life_timer << endl;
setDie(true);
+ }
+ setTime(0);
}
//set the contents in the appropriate tank or other property in the parent to zero
if ( speed < 0.0 )
speed = 0.0;
- double speed_fps = speed * SG_KT_TO_FPS;
- //double hs;
+// double speed_fps = speed * SG_KT_TO_FPS;
// calculate vertical and horizontal speed components
- if (speed == 0.0) {
- hs = vs = 0.0;
- } else {
- vs = sin( _elevation * SG_DEGREES_TO_RADIANS ) * speed_fps;
- hs = cos( _elevation * SG_DEGREES_TO_RADIANS ) * speed_fps;
- }
+ calcVSHS();
//resolve horizontal speed into north and east components:
- double speed_north_fps = cos(_azimuth / SG_RADIANS_TO_DEGREES) * hs;
- double speed_east_fps = sin(_azimuth / SG_RADIANS_TO_DEGREES) * hs;
-
- // convert horizontal speed (fps) to degrees per second
- double speed_north_deg_sec = speed_north_fps / ft_per_deg_lat;
- double speed_east_deg_sec = speed_east_fps / ft_per_deg_lon;
+ //and convert horizontal speed (fps) to degrees per second
+ calcNE();
// if wind not required, set to zero
if (!_wind) {
double friction_force_speed_north_deg_sec = 0;
double friction_force_speed_east_deg_sec = 0;
double force_elevation_deg = 0;
+ double force_azimuth_deg = 0;
+ double force_lbs = 0;
if (_external_force) {
- //cout << _name << " external force" << endl;
+ //cout << _name << " external force " << hdg << " az " << _azimuth << endl;
SGPropertyNode *n = fgGetNode(_force_path.c_str(), true);
- double force_lbs = n->getChild("force-lb", 0, true)->getDoubleValue();
- force_elevation_deg = n->getChild("force-elevation-deg", 0, true)->getDoubleValue();
- double force_azimuth_deg = n->getChild("force-azimuth-deg", 0, true)->getDoubleValue();
+ force_lbs = n->getChild("force-lb", 0, true)->getDoubleValue();
+ force_elevation_deg = n->getChild("force-elevation-deg", 0, true)->getDoubleValue();
+ force_azimuth_deg = n->getChild("force-azimuth-deg", 0, true)->getDoubleValue();
//resolve force into vertical and horizontal components:
double v_force_lbs = force_lbs * sin( force_elevation_deg * SG_DEGREES_TO_RADIANS );
h_force_lbs = force_lbs * cos( force_elevation_deg * SG_DEGREES_TO_RADIANS );
//ground interaction
+ //we don't do this if impacts are calculated
+ if(!_report_impact){
- if (getHtAGL(10000)){
- double deadzone = 0.1;
+ if (getHtAGL(10000)){
+ double deadzone = 0.1;
- if (_ht_agl_ft <= (0 + _ground_offset + deadzone) && _solid){
- normal_force_lbs = (_mass * slugs_to_lbs) - v_force_lbs;
+ if (_ht_agl_ft <= (0 + _ground_offset + deadzone) && _solid){
+ normal_force_lbs = (_mass * slugs_to_lbs) - v_force_lbs;
- if ( normal_force_lbs < 0 )
- normal_force_lbs = 0;
+ if ( normal_force_lbs < 0 )
+ normal_force_lbs = 0;
- pos.setElevationFt(0 + _ground_offset);
- if (vs < 0)
- vs = -vs * 0.5;
+ pos.setElevationFt(0 + _ground_offset);
+ if (vs < 0)
+ vs = -vs * 0.5;
+
+ // calculate friction
+ // we assume a static Coefficient of Friction (mu) of 0.62 (wood on concrete)
+ double mu = 0.62;
- // calculate friction
- // we assume a static Coefficient of Friction (mu) of 0.62 (wood on concrete)
- double mu = 0.62;
+ static_friction_force_lbs = mu * normal_force_lbs * _frictionFactor;
- static_friction_force_lbs = mu * normal_force_lbs * _frictionFactor;
+ //adjust horizontal force. We assume that a speed of <= 5 fps is static
+ if (h_force_lbs <= static_friction_force_lbs && hs <= 5){
+ h_force_lbs = hs = 0;
+ _speed_north_fps = _speed_east_fps = 0;
+ } else
+ dynamic_friction_force_lbs = (static_friction_force_lbs * 0.95);
- //adjust horizontal force. We assume that a speed of <= 5 fps is static
- if (h_force_lbs <= static_friction_force_lbs && hs <= 5){
- h_force_lbs = hs = 0;
- speed_north_fps = speed_east_fps = 0;
- } else
- dynamic_friction_force_lbs = (static_friction_force_lbs * 0.95);
+ //ignore wind when on the ground for now
+ //TODO fix this
+ _wind_from_north = 0;
+ _wind_from_east = 0;
- //ignore wind when on the ground for now
- //TODO fix this
- _wind_from_north = 0;
- _wind_from_east = 0;
+ }
}
- }
+ } //endif
//acceleration = (force(lbsf)/mass(slugs))
v_force_acc_fpss = v_force_lbs/_mass;
double wind_speed_from_east_deg_sec = _wind_from_east / ft_per_deg_lon;
//recombine the horizontal velocity components
- hs = sqrt(((speed_north_fps + force_speed_north_fps + friction_force_speed_north_fps)
- * (speed_north_fps + force_speed_north_fps + friction_force_speed_north_fps))
- + ((speed_east_fps + force_speed_east_fps + friction_force_speed_east_fps)
- * (speed_east_fps + force_speed_east_fps + friction_force_speed_east_fps)));
+ hs = sqrt(((_speed_north_fps + force_speed_north_fps + friction_force_speed_north_fps)
+ * (_speed_north_fps + force_speed_north_fps + friction_force_speed_north_fps))
+ + ((_speed_east_fps + force_speed_east_fps + friction_force_speed_east_fps)
+ * (_speed_east_fps + force_speed_east_fps + friction_force_speed_east_fps)));
if (hs <= 0.00001)
hs = 0;
// adjust vertical speed for acceleration of gravity, buoyancy, and vertical force
- vs -= (_gravity - _buoyancy - v_force_acc_fpss - normal_force_fpss) * dt;
+ double gravity = SG_METER_TO_FEET * (Environment::Gravity::instance()->getGravity(pos));
+ vs -= (gravity - _buoyancy - v_force_acc_fpss - normal_force_fpss) * dt;
if (vs <= 0.00001 && vs >= -0.00001)
vs = 0;
// recalculate elevation and azimuth (velocity vectors)
_elevation = atan2( vs, hs ) * SG_RADIANS_TO_DEGREES;
- _azimuth = atan2((speed_east_fps + force_speed_east_fps + friction_force_speed_east_fps),
- (speed_north_fps + force_speed_north_fps + friction_force_speed_north_fps))
+ _azimuth = atan2((_speed_east_fps + force_speed_east_fps + friction_force_speed_east_fps),
+ (_speed_north_fps + force_speed_north_fps + friction_force_speed_north_fps))
* SG_RADIANS_TO_DEGREES;
// rationalise azimuth
_azimuth += 360;
if (_aero_stabilised) { // we simulate rotational moment of inertia by using a filter
- //cout<< "_aero_stabilised "<< endl;
+ //cout<< "_aero_stabilised " << hdg << " az " << _azimuth << endl;
const double coeff = 0.9;
// we assume a symetrical MI about the pitch and yaw axis
return _life_timer;
}
+void FGAIBallistic::setTime(double s){
+ _life_timer = s;
+}
+
void FGAIBallistic::handle_impact() {
// try terrain intersection
- double start = pos.getElevationM() + 10;
+ double start = pos.getElevationM() + 100;
if(!getHtAGL(start))
return;
if (_ht_agl_ft <= 0) {
- SG_LOG(SG_GENERAL, SG_DEBUG, "AIBallistic: terrain impact");
+ SG_LOG(SG_AI, SG_DEBUG, "AIBallistic: terrain impact material" << _mat_name);
report_impact(_elevation_m);
_impact_reported = true;
void FGAIBallistic::handle_expiry() {
- SG_LOG(SG_GENERAL, SG_DEBUG, "AIBallistic: handle_expiry " << pos.getElevationM());
+ //SG_LOG(SG_AI, SG_DEBUG, "AIBallistic: handle_expiry " << pos.getElevationM());
report_impact(pos.getElevationM());
_expiry_reported = true;
else
n->setStringValue("type", "terrain");
- SG_LOG(SG_GENERAL, SG_DEBUG, "AIBallistic: object impact" << _name << " lon " <<_impact_lon);
+ SG_LOG(SG_AI, SG_DEBUG, "AIBallistic: object impact " << _name
+ << " lon " <<_impact_lon << " lat " <<_impact_lat << " sec " << _life_timer);
n->setDoubleValue("longitude-deg", _impact_lon);
n->setDoubleValue("latitude-deg", _impact_lat);
}
-double FGAIBallistic::getDistanceLoadToHitch() const {
+double FGAIBallistic::getDistanceToHitch() const {
//calculate the distance load to hitch
SGVec3d carthitchPos = getCartHitchPos();
SGVec3d cartPos = getCartPos();
return distance * SG_METER_TO_FEET;
}
-
-double FGAIBallistic::getElevLoadToHitch() const {
+double FGAIBallistic::getElevToHitch() const {
// now the angle, positive angles are upwards
- double distance = getDistanceLoadToHitch() * SG_FEET_TO_METER;
+ double distance = getDistanceToHitch() * SG_FEET_TO_METER;
double angle = 0;
double daltM = _offsetpos.getElevationM() - pos.getElevationM();
return angle;
}
-double FGAIBallistic::getBearingLoadToHitch() const {
+double FGAIBallistic::getBearingToHitch() const {
//calculate the bearing and range of the second pos from the first
- double az1, az2, distance;
+ double distance = getDistanceToHitch() * SG_FEET_TO_METER;
+ double az1, az2;
geo_inverse_wgs_84(pos, _offsetpos, &az1, &az2, &distance);
double rel_brg = az1 - hdg;
- if (rel_brg > 180)
- rel_brg -= 360;
+ SG_NORMALIZE_RANGE(rel_brg, -180.0, 180.0);
return rel_brg;
}
_z_offset = (_tgt_z_offset * c) + (_z_offset * (1 - c));
}
-void FGAIBallistic::formateToAC(double dt){
-
- setTgtOffsets(dt, 25);
- setOffsetPos(userpos,
- manager->get_user_heading(),
- manager->get_user_pitch(),
- manager->get_user_roll()
- );
-
- // elapsed time has a random initialisation so that each
- // wingman moves differently
- _elapsed_time += dt;
-
- // we derive a sine based factor to give us smoothly
- // varying error between -1 and 1
- double factor = sin(SGMiscd::deg2rad(_elapsed_time * 10));
- double r_angle = 5 * factor;
- double p_angle = 2.5 * factor;
- double h_angle = 5 * factor;
- double h_feet = 3 * factor;
-
- pos.setLatitudeDeg(_offsetpos.getLatitudeDeg());
- pos.setLongitudeDeg(_offsetpos.getLongitudeDeg());
-
- if (getHtAGL(10000)){
-
- if(_ht_agl_ft <= 10) {
- _height = userpos.getElevationFt();
- } else if (_ht_agl_ft > 10 && _ht_agl_ft <= 150 ) {
- setHt(userpos.getElevationFt(), dt, 1.0);
- } else if (_ht_agl_ft > 150 && _ht_agl_ft <= 250) {
- setHt(_offsetpos.getElevationFt()+ h_feet, dt, 0.75);
- } else
- setHt(_offsetpos.getElevationFt()+ h_feet, dt, 0.5);
-
- pos.setElevationFt(_height);
- }
- // these calculations are unreliable at slow speeds
- if(speed >= 10) {
- setHdg(_azimuth + h_angle, dt, 0.9);
- setPch(_elevation + p_angle + _pitch_offset, dt, 0.9);
-
- if (roll <= 115 && roll >= -115)
- setBnk(manager->get_user_roll() + r_angle + _roll_offset, dt, 0.5);
- else
- roll = manager->get_user_roll() + r_angle + _roll_offset;
-
- } else {
- setHdg(manager->get_user_heading(), dt, 0.9);
- setPch(manager->get_user_pitch() + _pitch_offset, dt, 0.9);
- setBnk(manager->get_user_roll() + _roll_offset, dt, 0.9);
- }
-
- setOffsetVelocity(dt, pos);
-}
void FGAIBallistic::calcVSHS(){
// calculate vertical and horizontal speed components
double speed_fps = speed * SG_KT_TO_FPS;
-_z_offset * SG_FEET_TO_METER);
// Transform the user position to the horizontal local coordinate system.
- SGQuatd hlTrans = SGQuatd::fromLonLat(userpos);
+ SGQuatd hlTrans = SGQuatd::fromLonLat(inpos);
// and postrotate the orientation of the user model wrt the horizontal
// local frame
calcVSHS();
//calculate the bearing of the new offset position from the old
- double az1, az2, dist;
- geo_inverse_wgs_84(_oldoffsetpos, offsetpos, &az1, &az2, &dist);
- _azimuth = az1;
+ //don't do this if speed is low
+ //cout << "speed " << speed << endl;
+ if (speed > 0.1){
+ double az1, az2, dist;
+ geo_inverse_wgs_84(_oldoffsetpos, offsetpos, &az1, &az2, &dist);
+ _azimuth = az1;
+ //cout << "offset az " << _azimuth << endl;
+ } else {
+ _azimuth = hdg;
+ //cout << " slow offset az " << _azimuth << endl;
+ }
//resolve horizontal speed into north and east components:
calcNE();