From 6310fdd9c5a9594282561f311faf5efa78befe3c Mon Sep 17 00:00:00 2001 From: Vivian Meazza Date: Fri, 16 Jul 2010 23:05:05 +0100 Subject: [PATCH 1/5] Remove range criteria, add sub-submodels to any depth, and add expiry criteria Signed-off-by: Vivian Meazza --- src/AIModel/AIBallistic.cxx | 30 +++++++++- src/AIModel/AIBallistic.hxx | 3 + src/AIModel/AIBase.cxx | 4 ++ src/AIModel/AIBase.hxx | 2 + src/AIModel/submodel.cxx | 110 ++++++++++++++---------------------- src/AIModel/submodel.hxx | 3 + 6 files changed, 83 insertions(+), 69 deletions(-) diff --git a/src/AIModel/AIBallistic.cxx b/src/AIModel/AIBallistic.cxx index 5e3b15509..68a388e75 100644 --- a/src/AIModel/AIBallistic.cxx +++ b/src/AIModel/AIBallistic.cxx @@ -61,6 +61,7 @@ FGAIBallistic::FGAIBallistic(object_type ot) : _slave_load_to_ac(false), _contents_lb(0), _report_collision(false), + _report_expiry(false), _report_impact(false), _external_force(false), _impact_report_node(fgGetNode("/ai/models/model-impact", true)), @@ -321,6 +322,7 @@ void FGAIBallistic::setMass(double m) { void FGAIBallistic::setWeight(double w) { _weight_lb = w; } + void FGAIBallistic::setRandom(bool r) { _random = r; } @@ -333,6 +335,11 @@ void FGAIBallistic::setCollision(bool c) { _report_collision = c; } +void FGAIBallistic::setExpiry(bool e) { + _report_expiry = e; +// cout << "_report_expiry " << _report_expiry << endl; +} + void FGAIBallistic::setExternalForce(bool f) { _external_force = f; } @@ -536,8 +543,14 @@ void FGAIBallistic::Run(double dt) { _life_timer += dt; // if life = -1 the object does not die - if (_life_timer > life && life != -1) - setDie(true); + if (_life_timer > life && life != -1){ + + if (_report_expiry && !_expiry_reported){ + handle_expiry(); + } else + setDie(true); + + } //set the contents in the appropriate tank or other property in the parent to zero setContents(0); @@ -809,6 +822,19 @@ void FGAIBallistic::handle_impact() { } } +void FGAIBallistic::handle_expiry() { + + report_impact(pos.getElevationM()); + _expiry_reported = true; + + SG_LOG(SG_GENERAL, SG_ALERT, "AIBallistic: expiry"); + //if (life == -1){ + // invisible = true; + //} else if (_subID == 0) // kill the AIObject if there is no subsubmodel + // setDie(true); + +} + void FGAIBallistic::handle_collision() { const FGAIBase *object = manager->calcCollision(pos.getElevationFt(), diff --git a/src/AIModel/AIBallistic.hxx b/src/AIModel/AIBallistic.hxx index 859bcd109..29b51fffd 100644 --- a/src/AIModel/AIBallistic.hxx +++ b/src/AIModel/AIBallistic.hxx @@ -70,6 +70,7 @@ public: void setRandom( bool r ); void setName(const string&); void setCollision(bool c); + void setExpiry(bool e); void setImpact(bool i); void setImpactReportNode(const string&); void setContentsNode(const string&); @@ -164,6 +165,7 @@ private: bool _report_collision; // if true a collision point with AI Objects is calculated bool _report_impact; // if true an impact point on the terrain is calculated bool _external_force; // if true then apply external force + bool _report_expiry; SGPropertyNode_ptr _impact_report_node; // report node for impact and collision SGPropertyNode_ptr _contents_node; // report node for impact and collision @@ -181,6 +183,7 @@ private: const SGMaterial* _material; void handle_collision(); + void handle_expiry(); void handle_impact(); void report_impact(double elevation, const FGAIBase *target = 0); void slaveToAC(double dt); diff --git a/src/AIModel/AIBase.cxx b/src/AIModel/AIBase.cxx index de107a682..f4d002563 100644 --- a/src/AIModel/AIBase.cxx +++ b/src/AIModel/AIBase.cxx @@ -579,6 +579,10 @@ bool FGAIBase::_getCollisionData() { return _collision_reported; } +bool FGAIBase::_getExpiryData() { + return _expiry_reported; +} + bool FGAIBase::_getImpactData() { return _impact_reported; } diff --git a/src/AIModel/AIBase.hxx b/src/AIModel/AIBase.hxx index ee6a70a34..e47f778d0 100644 --- a/src/AIModel/AIBase.hxx +++ b/src/AIModel/AIBase.hxx @@ -177,6 +177,7 @@ protected: bool _impact_reported; bool _collision_reported; + bool _expiry_reported; double _impact_lat; double _impact_lon; @@ -246,6 +247,7 @@ public: bool _getImpact(); bool _getImpactData(); bool _getCollisionData(); + bool _getExpiryData(); SGPropertyNode* _getProps() const; diff --git a/src/AIModel/submodel.cxx b/src/AIModel/submodel.cxx index 7b946f0b8..c810c5ccf 100644 --- a/src/AIModel/submodel.cxx +++ b/src/AIModel/submodel.cxx @@ -37,6 +37,7 @@ FGSubmodelMgr::FGSubmodelMgr() string contents_node; contrail_altitude = 30000; _count = 0; + _found_sub = true; } FGSubmodelMgr::~FGSubmodelMgr() @@ -82,7 +83,9 @@ void FGSubmodelMgr::init() void FGSubmodelMgr::postinit() { // postinit, so that the AI list is populated loadAI(); - loadSubmodels(); + + while (_found_sub) + loadSubmodels(); //TODO reload submodels if an MP ac joins } @@ -106,6 +109,7 @@ void FGSubmodelMgr::update(double dt) _impact = false; _hit = false; + _expiry = false; // check if the submodel hit an object or terrain sm_list = ai->get_ai_list(); @@ -115,13 +119,14 @@ void FGSubmodelMgr::update(double dt) for (; sm_list_itr != end; ++sm_list_itr) { _impact = (*sm_list_itr)->_getImpactData(); _hit = (*sm_list_itr)->_getCollisionData(); + _expiry = (*sm_list_itr)->_getExpiryData(); int parent_subID = (*sm_list_itr)->_getSubID(); //SG_LOG(SG_GENERAL, SG_DEBUG, "Submodel: Impact " << _impact << " hit! " // << _hit <<" parent_subID " << parent_subID); if ( parent_subID == 0) // this entry in the list has no associated submodel continue; // so we can continue - if (_impact || _hit) { + if (_impact || _hit || _expiry) { //SG_LOG(SG_GENERAL, SG_DEBUG, "Submodel: Impact " << _impact << " hit! " << _hit ); submodel_iterator = submodels.begin(); @@ -175,58 +180,19 @@ void FGSubmodelMgr::update(double dt) //cout << (*submodel_iterator)->name << "trigger node not found " << trigger << endl; } - if (trigger) { - int id = (*submodel_iterator)->id; - string name = (*submodel_iterator)->name; - // 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(); + if (trigger && (*submodel_iterator)->count != 0) { - while (sm_list_itr != end) { - in_range = true; + //int id = (*submodel_iterator)->id; + //string name = (*submodel_iterator)->name; + /*SG_LOG(SG_GENERAL, SG_DEBUG, + "Submodels end: " << (*submodel_iterator)->id + << " name " << (*submodel_iterator)->name + << " count " << (*submodel_iterator)->count + << " in range " << in_range);*/ - if (id == 0) { - //SG_LOG(SG_GENERAL, SG_DEBUG, - // "Submodels: continuing: " << id << " name " << name ); - ++sm_list_itr; - continue; - } - - int parent_id = (*submodel_iterator)->id; - - if (parent_id == id) { - double parent_lat = (*sm_list_itr)->_getLatitude(); - double parent_lon = (*sm_list_itr)->_getLongitude(); - string parent_name = (*sm_list_itr)->_getName(); - 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 name " << parent_name << ", "<< parent_id << ", "<< parent_lat << ", " << parent_lon << endl; - //cout << "own name " << own_lat << ", " << own_lon << " range " << range_nm << endl; - - if (range_nm > 15) { - //SG_LOG(SG_GENERAL, SG_DEBUG, - // "Submodels: skipping release, out of range: " << id); - in_range = false; - } - } - - ++sm_list_itr; - } // end while - - /*SG_LOG(SG_GENERAL, SG_DEBUG, - "Submodels end: " << (*submodel_iterator)->id - << " name " << (*submodel_iterator)->name - << " count " << (*submodel_iterator)->count - << " in range " << in_range);*/ - - if ((*submodel_iterator)->count != 0 && in_range) - release(*submodel_iterator, dt); - - } else - (*submodel_iterator)->first_time = true; + release(*submodel_iterator, dt); + } else + (*submodel_iterator)->first_time = true; ++submodel_iterator; } // end while @@ -281,6 +247,7 @@ bool FGSubmodelMgr::release(submodel *sm, double dt) ballist->setNoRoll(sm->no_roll); ballist->setName(sm->name); ballist->setCollision(sm->collision); + ballist->setExpiry(sm->expiry); ballist->setImpact(sm->impact); ballist->setImpactReportNode(sm->impact_report); ballist->setFuseRange(sm->fuse_range); @@ -595,6 +562,7 @@ void FGSubmodelMgr::setData(int id, string& path, bool serviceable) sm->aero_stabilised = entry_node->getBoolValue("aero-stabilised", true); sm->no_roll = entry_node->getBoolValue("no-roll", false); sm->collision = entry_node->getBoolValue("collision", false); + sm->expiry = entry_node->getBoolValue("expiry", false); sm->impact = entry_node->getBoolValue("impact", false); sm->impact_report = entry_node->getStringValue("impact-reports"); sm->fuse_range = entry_node->getDoubleValue("fuse-range", 0.0); @@ -698,6 +666,7 @@ void FGSubmodelMgr::setSubData(int id, string& path, bool serviceable) sm->aero_stabilised = entry_node->getBoolValue("aero-stabilised", true); sm->no_roll = entry_node->getBoolValue("no-roll", false); sm->collision = entry_node->getBoolValue("collision", false); + sm->expiry = entry_node->getBoolValue("expiry", false); sm->impact = entry_node->getBoolValue("impact", false); sm->impact_report = entry_node->getStringValue("impact-reports"); sm->fuse_range = entry_node->getDoubleValue("fuse-range", 0.0); @@ -757,31 +726,38 @@ void FGSubmodelMgr::loadSubmodels() { SG_LOG(SG_GENERAL, SG_DEBUG, "Submodels: Loading sub submodels"); + _found_sub = false; + submodel_iterator = submodels.begin(); - while (submodel_iterator != submodels.end()) { - string submodel = (*submodel_iterator)->submodel; - if (!submodel.empty()) { - //int id = (*submodel_iterator)->id; - bool serviceable = true; - //SG_LOG(SG_GENERAL, SG_DEBUG, "found path sub sub " - // << submodel - // << " index " << index - // << "name " << (*submodel_iterator)->name); + while (submodel_iterator != submodels.end()) { + string submodel = (*submodel_iterator)->submodel; + if (!submodel.empty()) { + //int id = (*submodel_iterator)->id; + bool serviceable = true; + //SG_LOG(SG_GENERAL, SG_DEBUG, "found path sub sub " + // << submodel + // << " index " << index + // << "name " << (*submodel_iterator)->name); - (*submodel_iterator)->sub_id = index; - setSubData(index, submodel, serviceable); - } + if ((*submodel_iterator)->sub_id == 0){ + (*submodel_iterator)->sub_id = index; + _found_sub = true; + setSubData(index, submodel, serviceable); + } + } - ++submodel_iterator; - } + ++submodel_iterator; + } // end while subsubmodel_iterator = subsubmodels.begin(); while (subsubmodel_iterator != subsubmodels.end()) { submodels.push_back(*subsubmodel_iterator); ++subsubmodel_iterator; - } + } // end while + + subsubmodels.clear(); //submodel_iterator = submodels.begin(); diff --git a/src/AIModel/submodel.hxx b/src/AIModel/submodel.hxx index 9709bb375..bcf7363e8 100644 --- a/src/AIModel/submodel.hxx +++ b/src/AIModel/submodel.hxx @@ -63,6 +63,7 @@ public: bool no_roll; bool serviceable; bool collision; + bool expiry; bool impact; string impact_report; double fuse_range; @@ -148,6 +149,8 @@ private: bool _impact; bool _hit; + bool _expiry; + bool _found_sub; SGPropertyNode_ptr _serviceable_node; SGPropertyNode_ptr _user_lat_node; From adf17287ab5122a28faba707d8242e140cab0d0c Mon Sep 17 00:00:00 2001 From: Vivian Meazza Date: Wed, 28 Jul 2010 22:20:50 +0100 Subject: [PATCH 2/5] Add "expiry" parameter and other changes to implement persistent contrails using Ballistic objects Signed-off-by: Vivian Meazza --- src/AIModel/AIBallistic.cxx | 130 ++++++++++++++++++----------- src/AIModel/AIBallistic.hxx | 6 +- src/AIModel/AIBase.cxx | 2 + src/AIModel/submodel.cxx | 161 ++++++++++++++++++++++++------------ src/AIModel/submodel.hxx | 12 ++- 5 files changed, 211 insertions(+), 100 deletions(-) diff --git a/src/AIModel/AIBallistic.cxx b/src/AIModel/AIBallistic.cxx index 68a388e75..63409b81a 100644 --- a/src/AIModel/AIBallistic.cxx +++ b/src/AIModel/AIBallistic.cxx @@ -65,7 +65,8 @@ FGAIBallistic::FGAIBallistic(object_type ot) : _report_impact(false), _external_force(false), _impact_report_node(fgGetNode("/ai/models/model-impact", true)), - _old_height(0) + _old_height(0), + _elapsed_time(0) { no_roll = false; @@ -81,7 +82,8 @@ void FGAIBallistic::readFromScenario(SGPropertyNode* scFileNode) { FGAIBase::readFromScenario(scFileNode); - //setPath(scFileNode->getStringValue("model", "Models/Geometry/rocket.ac")); + //setPath(scFileNode->getStringValue("model", "Models/Geometry/rocket.ac")); + setRandom(scFileNode->getBoolValue("random", false)); setAzimuth(scFileNode->getDoubleValue("azimuth", 0.0)); setElevation(scFileNode->getDoubleValue("elevation", 0)); setDragArea(scFileNode->getDoubleValue("eda", 0.007)); @@ -94,10 +96,11 @@ void FGAIBallistic::readFromScenario(SGPropertyNode* scFileNode) { setCd(scFileNode->getDoubleValue("cd", 0.029)); //setMass(scFileNode->getDoubleValue("mass", 0.007)); setWeight(scFileNode->getDoubleValue("weight", 0.25)); - setStabilisation(scFileNode->getBoolValue("aero-stabilized", false)); + setStabilisation(scFileNode->getBoolValue("aero-stabilised", false)); setNoRoll(scFileNode->getBoolValue("no-roll", false)); - setRandom(scFileNode->getBoolValue("random", false)); setImpact(scFileNode->getBoolValue("impact", false)); + setExpiry(scFileNode->getBoolValue("expiry", false)); + setCollision(scFileNode->getBoolValue("collision", false)); setImpactReportNode(scFileNode->getStringValue("impact-reports")); setName(scFileNode->getStringValue("name", "Rocket")); setFuseRange(scFileNode->getDoubleValue("fuse-range", 0.0)); @@ -105,7 +108,7 @@ void FGAIBallistic::readFromScenario(SGPropertyNode* scFileNode) { setSubID(scFileNode->getIntValue("SubID", 0)); setExternalForce(scFileNode->getBoolValue("external-force", false)); setForcePath(scFileNode->getStringValue("force-path", "")); - setForceStabilisation(scFileNode->getBoolValue("force-stabilized", false)); + setForceStabilisation(scFileNode->getBoolValue("force-stabilised", false)); setXoffset(scFileNode->getDoubleValue("x-offset", 0.0)); setYoffset(scFileNode->getDoubleValue("y-offset", 0.0)); setZoffset(scFileNode->getDoubleValue("z-offset", 0.0)); @@ -117,7 +120,6 @@ void FGAIBallistic::readFromScenario(SGPropertyNode* scFileNode) { setSlaved(scFileNode->getBoolValue("slaved", false)); setSlavedLoad(scFileNode->getBoolValue("slaved-load", false)); setContentsNode(scFileNode->getStringValue("contents")); - setRandom(scFileNode->getBoolValue("random", false)); } bool FGAIBallistic::init(bool search_in_AI_path) { @@ -125,6 +127,16 @@ bool FGAIBallistic::init(bool search_in_AI_path) { _impact_reported = false; _collision_reported = false; + _expiry_reported = false; + + _impact_lat = 0; + _impact_lon = 0; + _impact_elev = 0; + _impact_hdg = 0; + _impact_pitch = 0; + _impact_roll = 0; + _impact_speed = 0; + invisible = false; _elapsed_time += (sg_random() * 100); @@ -132,6 +144,8 @@ bool FGAIBallistic::init(bool search_in_AI_path) { props->setStringValue("material/name", ""); props->setStringValue("name", _name.c_str()); props->setStringValue("submodels/path", _submodel.c_str()); + props->setStringValue("force/path", _force_path.c_str()); + //props->setStringValue("vector/path", _vector_path.c_str()); // start with high value so that animations don't trigger yet _ht_agl_ft = 1e10; @@ -264,7 +278,14 @@ void FGAIBallistic::update(double dt) { } void FGAIBallistic::setAzimuth(double az) { - hdg = _azimuth = az; + + + if (_random) + hdg = _azimuth = (az - 5 ) + (10 * sg_random()); + else + hdg = _azimuth = az; + + //cout << _name << " init hdg " << hdg << " random " << _random << endl; } void FGAIBallistic::setElevation(double el) { @@ -292,7 +313,12 @@ void FGAIBallistic::setDragArea(double a) { } void FGAIBallistic::setLife(double seconds) { - life = seconds; + + if (_random){ + life = seconds * _randomness + (seconds * (1 -_randomness) * sg_random()); + //cout << "life " << life << endl; + } else + life = seconds; } void FGAIBallistic::setBuoyancy(double fpss) { @@ -323,6 +349,10 @@ void FGAIBallistic::setWeight(double w) { _weight_lb = w; } +void FGAIBallistic::setRandomness(double r) { + _randomness = r; +} + void FGAIBallistic::setRandom(bool r) { _random = r; } @@ -335,9 +365,9 @@ void FGAIBallistic::setCollision(bool c) { _report_collision = c; } -void FGAIBallistic::setExpiry(bool e) { - _report_expiry = e; -// cout << "_report_expiry " << _report_expiry << endl; +void FGAIBallistic::setExpiry(bool e) { + _report_expiry = e; + //cout << "_report_expiry " << _report_expiry << endl; } void FGAIBallistic::setExternalForce(bool f) { @@ -486,17 +516,17 @@ void FGAIBallistic::setHt(double h, double dt, double coeff){ } void FGAIBallistic::setHdg(double az, double dt, double coeff){ - double recip = getRecip(hdg); - double c = dt / (coeff + dt); - //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)); - } else { - hdg = (az * c) + (hdg * (1 - c)); - } - } + double recip = getRecip(hdg); + double c = dt / (coeff + dt); + //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)); + } else { + hdg = (az * c) + (hdg * (1 - c)); + } +} double FGAIBallistic::getTgtXOffset() const { return _tgt_x_offset; @@ -543,21 +573,22 @@ void FGAIBallistic::Run(double dt) { _life_timer += dt; // if life = -1 the object does not die - if (_life_timer > life && life != -1){ - - if (_report_expiry && !_expiry_reported){ - handle_expiry(); - } else - setDie(true); - + if (_life_timer > life && life != -1){ + + if (_report_expiry && !_expiry_reported){ + //cout<<"AIBallistic: expiry"<< endl; + handle_expiry(); + } else + setDie(true); + } //set the contents in the appropriate tank or other property in the parent to zero setContents(0); - //randomise Cd by +- 5% + //randomise Cd by +- 10% if (_random) - _Cd = _Cd * 0.95 + (0.05 * sg_random()); + _Cd = _Cd * 0.90 + (0.10 * sg_random()); // Adjust Cd by Mach number. The equations are based on curves // for a conventional shell/bullet (no boat-tail). @@ -630,12 +661,13 @@ void FGAIBallistic::Run(double dt) { double friction_force_speed_east_deg_sec = 0; double force_elevation_deg = 0; - if (_external_force) { + if (_external_force) { + 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(); - + //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 ); @@ -764,14 +796,19 @@ void FGAIBallistic::Run(double dt) { if (_azimuth < 0) _azimuth += 360; + //cout << "_azimuth " << _azimuth << " hdg "<< hdg << endl; + if (_aero_stabilised) { // we simulate rotational moment of inertia by using a filter + cout<< "_aero_stabilised "<< endl; const double coeff = 0.9; // we assume a symetrical MI about the pitch and yaw axis setPch(_elevation, dt, coeff); setHdg(_azimuth, dt, coeff); } else if (_force_stabilised) { // we simulate rotational moment of inertia by using a filter - const double coeff = 0.9; + //cout<< "_force_stabilised "<< endl; + + const double coeff = 0.9; double ratio = h_force_lbs/(_mass * slugs_to_lbs); if (ratio > 1) ratio = 1; @@ -822,17 +859,18 @@ void FGAIBallistic::handle_impact() { } } -void FGAIBallistic::handle_expiry() { - - report_impact(pos.getElevationM()); - _expiry_reported = true; - - SG_LOG(SG_GENERAL, SG_ALERT, "AIBallistic: expiry"); - //if (life == -1){ - // invisible = true; - //} else if (_subID == 0) // kill the AIObject if there is no subsubmodel - // setDie(true); - +void FGAIBallistic::handle_expiry() { + + SG_LOG(SG_GENERAL, SG_DEBUG, "AIBallistic: handle_expiry " << pos.getElevationM()); + + report_impact(pos.getElevationM()); + _expiry_reported = true; + + //if (life == -1){ + // invisible = true; + //} else if (_subID == 0) // kill the AIObject if there is no subsubmodel + // setDie(true); + } void FGAIBallistic::handle_collision() @@ -883,7 +921,7 @@ SGVec3d FGAIBallistic::getCartHitchPos() const{ // convert geodetic positions to geocentered SGVec3d cartuserPos = getCartUserPos(); - SGVec3d cartPos = getCartPos(); + //SGVec3d cartPos = getCartPos(); // Transform to the right coordinate frame, configuration is done in // the x-forward, y-right, z-up coordinates (feet), computation diff --git a/src/AIModel/AIBallistic.hxx b/src/AIModel/AIBallistic.hxx index 29b51fffd..84fcc8ee7 100644 --- a/src/AIModel/AIBallistic.hxx +++ b/src/AIModel/AIBallistic.hxx @@ -68,6 +68,7 @@ public: void setWeight( double w ); void setNoRoll( bool nr ); void setRandom( bool r ); + void setRandomness( double r ); void setName(const string&); void setCollision(bool c); void setExpiry(bool e); @@ -151,7 +152,8 @@ private: bool _wind; // if true, local wind will be applied to object double _Cd; // drag coefficient double _mass; // slugs - bool _random; // modifier for Cd + bool _random; // modifier for Cd, life, az + double _randomness; // dimension for _random double _load_resistance; // ground load resistanc N/m^2 double _frictionFactor; // dimensionless modifier for Coefficient of Friction bool _solid; // if true ground is solid for FDMs @@ -195,13 +197,13 @@ private: double getDistanceLoadToHitch() const; double getElevLoadToHitch() const; double getBearingLoadToHitch() const; + double getRecip(double az); double getMass() const; double hs; double _ground_offset; double _load_offset; - double _force; double _old_height; SGVec3d _oldcarthitchPos; diff --git a/src/AIModel/AIBase.cxx b/src/AIModel/AIBase.cxx index f4d002563..d143296a1 100644 --- a/src/AIModel/AIBase.cxx +++ b/src/AIModel/AIBase.cxx @@ -81,6 +81,8 @@ FGAIBase::FGAIBase(object_type ot) : delete_me = false; _impact_reported = false; _collision_reported = false; + _expiry_reported = false; + _subID = 0; _x_offset = 0; diff --git a/src/AIModel/submodel.cxx b/src/AIModel/submodel.cxx index c810c5ccf..f5cc1f816 100644 --- a/src/AIModel/submodel.cxx +++ b/src/AIModel/submodel.cxx @@ -127,7 +127,8 @@ void FGSubmodelMgr::update(double dt) continue; // so we can continue if (_impact || _hit || _expiry) { - //SG_LOG(SG_GENERAL, SG_DEBUG, "Submodel: Impact " << _impact << " hit! " << _hit ); + // SG_LOG(SG_GENERAL, SG_ALERT, "Submodel: Impact " << _impact << " hit! " << _hit + //<< " exipiry :-( " << _expiry ); submodel_iterator = submodels.begin(); @@ -144,9 +145,11 @@ void FGSubmodelMgr::update(double dt) _parent_roll = (*sm_list_itr)->_getImpactRoll(); _parent_speed = (*sm_list_itr)->_getImpactSpeed(); (*submodel_iterator)->first_time = true; + //cout << "Impact: parent SubID = child_ID elev " << _parent_elev << endl; - if (release(*submodel_iterator, dt)) + if (release(*submodel_iterator, dt)) (*sm_list_itr)->setDie(true); + } ++submodel_iterator; @@ -174,7 +177,7 @@ void FGSubmodelMgr::update(double dt) if ((*submodel_iterator)->trigger_node != 0) { _trigger_node = (*submodel_iterator)->trigger_node; trigger = _trigger_node->getBoolValue(); - //cout << "trigger node found " << trigger << endl; + //cout << (*submodel_iterator)->name << "trigger node found " << trigger << endl; } else { trigger = true; //cout << (*submodel_iterator)->name << "trigger node not found " << trigger << endl; @@ -182,8 +185,8 @@ void FGSubmodelMgr::update(double dt) if (trigger && (*submodel_iterator)->count != 0) { - //int id = (*submodel_iterator)->id; - //string name = (*submodel_iterator)->name; + int id = (*submodel_iterator)->id; + string name = (*submodel_iterator)->name; /*SG_LOG(SG_GENERAL, SG_DEBUG, "Submodels end: " << (*submodel_iterator)->id << " name " << (*submodel_iterator)->name @@ -213,9 +216,11 @@ bool FGSubmodelMgr::release(submodel *sm, double dt) sm->timer += dt; if (sm->timer < sm->delay) { - //cout << "not yet: timer" << sm->timer << " delay " << sm->delay<< endl; + //cout << "not yet: timer " << sm->timer << " delay " << sm->delay << endl; return false; } + + //cout << "released timer: " << sm->timer << " delay " << sm->delay << endl; sm->timer = 0.0; @@ -228,9 +233,12 @@ bool FGSubmodelMgr::release(submodel *sm, double dt) FGAIBallistic* ballist = new FGAIBallistic; ballist->setPath(sm->model.c_str()); - ballist->setLatitude(IC.lat); - ballist->setLongitude(IC.lon); - ballist->setAltitude(IC.alt); + ballist->setName(sm->name); + ballist->setRandom(sm->random); + ballist->setRandomness(sm->randomness); + ballist->setLatitude(offsetpos.getLatitudeDeg()); + ballist->setLongitude(offsetpos.getLongitudeDeg()); + ballist->setAltitude(offsetpos.getElevationFt()); ballist->setAzimuth(IC.azimuth); ballist->setElevation(IC.elevation); ballist->setRoll(IC.roll); @@ -245,7 +253,6 @@ bool FGSubmodelMgr::release(submodel *sm, double dt) ballist->setCd(sm->cd); ballist->setStabilisation(sm->aero_stabilised); ballist->setNoRoll(sm->no_roll); - ballist->setName(sm->name); ballist->setCollision(sm->collision); ballist->setExpiry(sm->expiry); ballist->setImpact(sm->impact); @@ -260,7 +267,6 @@ bool FGSubmodelMgr::release(submodel *sm, double dt) if (sm->count > 0) sm->count--; - return true; } @@ -305,7 +311,9 @@ void FGSubmodelMgr::transform(submodel *sm) //cout << " name " << name << " id " << id << " sub id" << sub_id << endl; - if (_impact || _hit) { + // set the Initial Conditions for the types of submodel parent + + if (_impact || _hit || _expiry) { // set the data for a submodel tied to a submodel _count++; //cout << "Submodels: release sub sub " << _count<< endl; @@ -380,12 +388,22 @@ void FGSubmodelMgr::transform(submodel *sm) cout << "speed north " << IC.speed_north_fps << endl ; cout << "parent speed fps in" << IC.speed << "sm speed in " << sm->speed << endl ;*/ + // Set the Initial Conditions that are common to all types of parent 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; + userpos.setLatitudeDeg(IC.lat); + userpos.setLongitudeDeg(IC.lon); + userpos.setElevationFt(IC.alt); + + _x_offset = sm->x_offset; + _y_offset = sm->y_offset; + _z_offset = sm->z_offset; + + setOffsetPos(); + + //IC.elevation += sm->pitch_offset; + //IC.azimuth += sm->yaw_offset ; // pre-process the trig functions cosRx = cos(-IC.roll * SG_DEGREES_TO_RADIANS); @@ -395,35 +413,35 @@ void FGSubmodelMgr::transform(submodel *sm) cosRz = cos(IC.azimuth * SG_DEGREES_TO_RADIANS); sinRz = sin(IC.azimuth * SG_DEGREES_TO_RADIANS); - // 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; + //// 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[1][0] = cosRy * sinRz; - trans[1][1] = cosRx * cosRz + sinRx * sinRy * sinRz; - trans[1][2] = -1 * sinRx * cosRx + cosRx * sinRy * sinRz; + //trans[1][0] = cosRy * sinRz; + //trans[1][1] = cosRx * cosRz + sinRx * sinRy * sinRz; + //trans[1][2] = -1 * sinRx * cosRx + cosRx * sinRy * sinRz; - trans[2][0] = -1 * sinRy; - trans[2][1] = sinRx * cosRy; - trans[2][2] = cosRx * cosRy; + //trans[2][0] = -1 * sinRy; + //trans[2][1] = sinRx * cosRy; + //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 //double alpha = _user_alpha_node->getDoubleValue(); @@ -431,7 +449,7 @@ void FGSubmodelMgr::transform(submodel *sm) //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. + // 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); @@ -454,7 +472,7 @@ void FGSubmodelMgr::transform(submodel *sm) // if speeds are low this calculation can become unreliable if (IC.speed > 1) { - IC.azimuth = atan2(IC.total_speed_east , IC.total_speed_north) * SG_RADIANS_TO_DEGREES; + //IC.azimuth = atan2(IC.total_speed_east, IC.total_speed_north) * SG_RADIANS_TO_DEGREES; // cout << "azimuth1 " << IC.azimuth<force_stabilised= entry_node->getBoolValue("force-stabilised", false); sm->ext_force = entry_node->getBoolValue("external-force", false); sm->force_path = entry_node->getStringValue("force-path", ""); + sm->random = entry_node->getBoolValue("random", false); + sm->randomness = entry_node->getDoubleValue("randomness", 0.5); + + //cout << "sm->contents_node " << sm->contents_node << endl; if (sm->contents_node != 0) sm->contents = sm->contents_node->getDoubleValue(); @@ -594,11 +607,13 @@ void FGSubmodelMgr::setData(int id, string& path, bool serviceable) sm->sub_id = 0; sm->prop = fgGetNode("/ai/submodels/submodel", index, true); + sm->prop->tie("delay", SGRawValuePointer(&(sm->delay))); sm->prop->tie("count", SGRawValuePointer(&(sm->count))); sm->prop->tie("repeat", SGRawValuePointer(&(sm->repeat))); sm->prop->tie("id", SGRawValuePointer(&(sm->id))); sm->prop->tie("sub-id", SGRawValuePointer(&(sm->sub_id))); sm->prop->tie("serviceable", SGRawValuePointer(&(sm->serviceable))); + sm->prop->tie("random", SGRawValuePointer(&(sm->random))); string name = sm->name; sm->prop->setStringValue("name", name.c_str()); @@ -608,7 +623,7 @@ void FGSubmodelMgr::setData(int id, string& path, bool serviceable) string force_path = sm->force_path; sm->prop->setStringValue("force_path", force_path.c_str()); - //cout << "set force_path " << force_path << endl; + //cout << "set force_path Sub " << force_path << endl; if (sm->contents_node != 0) sm->prop->tie("contents-lbs", SGRawValuePointer(&(sm->contents))); @@ -673,8 +688,11 @@ void FGSubmodelMgr::setSubData(int id, string& path, bool serviceable) sm->contents_node = fgGetNode(entry_node->getStringValue("contents", "none"), false); sm->speed_node = fgGetNode(entry_node->getStringValue("speed-node", "none"), false); sm->submodel = entry_node->getStringValue("submodel-path", ""); + sm->force_stabilised= entry_node->getBoolValue("force-stabilised", false); sm->ext_force = entry_node->getBoolValue("external-force", false); sm->force_path = entry_node->getStringValue("force-path", ""); + sm->random = entry_node->getBoolValue("random", false); + sm->randomness = entry_node->getDoubleValue("randomness", 0.5); //cout << "sm->contents_node " << sm->contents_node << endl; if (sm->contents_node != 0) @@ -703,16 +721,17 @@ void FGSubmodelMgr::setSubData(int id, string& path, bool serviceable) sm->prop->tie("id", SGRawValuePointer(&(sm->id))); sm->prop->tie("sub-id", SGRawValuePointer(&(sm->sub_id))); sm->prop->tie("serviceable", SGRawValuePointer(&(sm->serviceable))); + sm->prop->tie("random", SGRawValuePointer(&(sm->random))); string name = sm->name; sm->prop->setStringValue("name", name.c_str()); string submodel = sm->submodel; sm->prop->setStringValue("submodel", submodel.c_str()); - // cout << " set submodel path " << submodel<< endl; + // cout << " set submodel path AI" << submodel<< endl; string force_path = sm->force_path; sm->prop->setStringValue("force_path", force_path.c_str()); - //cout << "set force_path " << force_path << endl; + cout << "set force_path AI" << force_path << endl; if (sm->contents_node != 0) sm->prop->tie("contents-lbs", SGRawValuePointer(&(sm->contents))); @@ -772,4 +791,44 @@ void FGSubmodelMgr::loadSubmodels() //} } +SGVec3d FGSubmodelMgr::getCartOffsetPos() const{ + + // convert geodetic positions to geocentered + SGVec3d cartuserPos = SGVec3d::fromGeod(userpos); + + // Transform to the right coordinate frame, configuration is done in + // the x-forward, y-right, z-up coordinates (feet), computation + // in the simulation usual body x-forward, y-right, z-down coordinates + // (meters) ) + + SGVec3d _off(_x_offset * SG_FEET_TO_METER, + _y_offset * SG_FEET_TO_METER, + -_z_offset * SG_FEET_TO_METER); + + // Transform the user position to the horizontal local coordinate system. + SGQuatd hlTrans = SGQuatd::fromLonLat(userpos); + + // and postrotate the orientation of the user model wrt the horizontal + // local frame + hlTrans *= SGQuatd::fromYawPitchRollDeg( + IC.azimuth, + IC.elevation, + IC.roll); + + // The offset converted to the usual body fixed coordinate system + // rotated to the earth-fixed coordinates axis + SGVec3d off = hlTrans.backTransform(_off); + + // Add the position offset of the user model to get the geocentered position + SGVec3d offsetPos = cartuserPos + off; + + return offsetPos; +} + +void FGSubmodelMgr::setOffsetPos(){ + // convert the offset geocentered position to geodetic + SGVec3d cartoffsetPos = getCartOffsetPos(); + + SGGeodesy::SGCartToGeod(cartoffsetPos, offsetpos); +} // end of submodel.cxx diff --git a/src/AIModel/submodel.hxx b/src/AIModel/submodel.hxx index bcf7363e8..cd645f64e 100644 --- a/src/AIModel/submodel.hxx +++ b/src/AIModel/submodel.hxx @@ -53,6 +53,7 @@ public: double drag_area; double life; double buoyancy; + double randomness; bool wind; bool first_time; double cd; @@ -62,6 +63,7 @@ public: int id; bool no_roll; bool serviceable; + bool random; bool collision; bool expiry; bool impact; @@ -142,6 +144,10 @@ private: double _parent_pitch; double _parent_roll; double _parent_speed; + double _x_offset; + double _y_offset; + double _z_offset; + static const double lbs_to_slugs; //conversion factor @@ -193,9 +199,13 @@ private: bool release(submodel *, double dt); - double getRange(double lat, double lon, double lat2, double lon2) const; int _count; + + SGGeod userpos; + SGGeod offsetpos; + SGVec3d getCartOffsetPos() const; + void setOffsetPos(); }; From da8251d1a4a597d11d2c1f3f7332d81ba8a73223 Mon Sep 17 00:00:00 2001 From: Vivian Meazza Date: Wed, 28 Jul 2010 22:22:04 +0100 Subject: [PATCH 3/5] Experimental bugfix for particle wind Signed-off-by: Vivian Meazza --- src/Environment/environment_mgr.cxx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Environment/environment_mgr.cxx b/src/Environment/environment_mgr.cxx index 15268f93e..07e834772 100644 --- a/src/Environment/environment_mgr.cxx +++ b/src/Environment/environment_mgr.cxx @@ -292,10 +292,20 @@ FGEnvironmentMgr::update (double dt) _environment->set_elevation_ft(fgGetDouble("/position/altitude-ft")); _environment->set_local_weather_lift_fps(fgGetDouble("/local-weather/current/thermal-lift")); - osg::Vec3 windVec(-_environment->get_wind_from_north_fps(), - -_environment->get_wind_from_east_fps(), - _environment->get_wind_from_down_fps()); + osg::Vec3 windVec(_environment->get_wind_from_north_fps(), + -_environment->get_wind_from_east_fps(), + 0); + // SG_LOG(SG_GENERAL, SG_ALERT, "-_environment->get_wind_from_north_mps() " << + //_environment->get_wind_from_north_fps() * SG_FEET_TO_METER + //<< " -_environment->get_wind_from_east_mps() " + //<< -_environment->get_wind_from_east_fps() * SG_FEET_TO_METER + //); + simgear::Particles::setWindVector(windVec * SG_FEET_TO_METER); + //double wind_true_deg = _environment->get_wind_from_heading_deg(); + //simgear::Particles::setWindFrom( wind_true_deg, + // _environment->get_wind_speed_kt() ); + } FGEnvironment From 6a7ec168e5628b471ccd439ff8391d9aef1a4252 Mon Sep 17 00:00:00 2001 From: Vivian Meazza Date: Sun, 1 Aug 2010 10:47:40 +0100 Subject: [PATCH 4/5] Tidy up for commit Signed-off-by: Vivian Meazza --- src/AIModel/AIBallistic.cxx | 2 +- src/AIModel/AIBallistic.hxx | 2 +- src/AIModel/submodel.cxx | 51 ++++--------------------------------- 3 files changed, 7 insertions(+), 48 deletions(-) diff --git a/src/AIModel/AIBallistic.cxx b/src/AIModel/AIBallistic.cxx index 63409b81a..15693f398 100644 --- a/src/AIModel/AIBallistic.cxx +++ b/src/AIModel/AIBallistic.cxx @@ -799,7 +799,7 @@ void FGAIBallistic::Run(double dt) { //cout << "_azimuth " << _azimuth << " hdg "<< hdg << endl; if (_aero_stabilised) { // we simulate rotational moment of inertia by using a filter - cout<< "_aero_stabilised "<< endl; + //cout<< "_aero_stabilised "<< endl; const double coeff = 0.9; // we assume a symetrical MI about the pitch and yaw axis diff --git a/src/AIModel/AIBallistic.hxx b/src/AIModel/AIBallistic.hxx index 84fcc8ee7..09efbd6e1 100644 --- a/src/AIModel/AIBallistic.hxx +++ b/src/AIModel/AIBallistic.hxx @@ -153,7 +153,7 @@ private: double _Cd; // drag coefficient double _mass; // slugs bool _random; // modifier for Cd, life, az - double _randomness; // dimension for _random + double _randomness; // dimension for _random, only applies to life at present double _load_resistance; // ground load resistanc N/m^2 double _frictionFactor; // dimensionless modifier for Coefficient of Friction bool _solid; // if true ground is solid for FDMs diff --git a/src/AIModel/submodel.cxx b/src/AIModel/submodel.cxx index f5cc1f816..0958923c1 100644 --- a/src/AIModel/submodel.cxx +++ b/src/AIModel/submodel.cxx @@ -121,8 +121,10 @@ void FGSubmodelMgr::update(double dt) _hit = (*sm_list_itr)->_getCollisionData(); _expiry = (*sm_list_itr)->_getExpiryData(); int parent_subID = (*sm_list_itr)->_getSubID(); + //SG_LOG(SG_GENERAL, SG_DEBUG, "Submodel: Impact " << _impact << " hit! " // << _hit <<" parent_subID " << parent_subID); + if ( parent_subID == 0) // this entry in the list has no associated submodel continue; // so we can continue @@ -187,6 +189,7 @@ void FGSubmodelMgr::update(double dt) int id = (*submodel_iterator)->id; string name = (*submodel_iterator)->name; + /*SG_LOG(SG_GENERAL, SG_DEBUG, "Submodels end: " << (*submodel_iterator)->id << " name " << (*submodel_iterator)->name @@ -316,13 +319,6 @@ void FGSubmodelMgr::transform(submodel *sm) if (_impact || _hit || _expiry) { // set the data for a submodel tied to a submodel _count++; - //cout << "Submodels: release sub sub " << _count<< endl; - //cout << " id " << sm->id - // << " lat " << _parent_lat - // << " lon " << _parent_lon - // << " elev " << _parent_elev - // << " name " << sm->name - // << endl; IC.lat = _parent_lat; IC.lon = _parent_lon; @@ -337,10 +333,7 @@ void FGSubmodelMgr::transform(submodel *sm) } else if (id == 0) { //set the data for a submodel tied to the main model - /*cout << "Submodels: release main sub " << endl; - cout << " name " << sm->name - << " id" << sm->id - << endl;*/ + IC.lat = _user_lat_node->getDoubleValue(); IC.lon = _user_lon_node->getDoubleValue(); IC.alt = _user_alt_node->getDoubleValue(); @@ -413,40 +406,6 @@ void FGSubmodelMgr::transform(submodel *sm) cosRz = cos(IC.azimuth * SG_DEGREES_TO_RADIANS); sinRz = sin(IC.azimuth * SG_DEGREES_TO_RADIANS); - //// 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[1][0] = cosRy * sinRz; - //trans[1][1] = cosRx * cosRz + sinRx * sinRy * sinRz; - //trans[1][2] = -1 * sinRx * cosRx + cosRx * sinRy * sinRz; - - //trans[2][0] = -1 * sinRy; - //trans[2][1] = sinRx * cosRy; - //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]; - - //// 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)); - - //// 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 - //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 vector should be added to aircraft's vector. @@ -731,7 +690,7 @@ void FGSubmodelMgr::setSubData(int id, string& path, bool serviceable) string force_path = sm->force_path; sm->prop->setStringValue("force_path", force_path.c_str()); - cout << "set force_path AI" << force_path << endl; + //cout << "set force_path AI" << force_path << endl; if (sm->contents_node != 0) sm->prop->tie("contents-lbs", SGRawValuePointer(&(sm->contents))); From d31742825771a25990f484e8138fe157729b9403 Mon Sep 17 00:00:00 2001 From: Vivian Meazza Date: Sun, 1 Aug 2010 14:50:03 +0100 Subject: [PATCH 5/5] More tidying Signed-off-by: Vivian Meazza --- src/AIModel/AIBallistic.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AIModel/AIBallistic.cxx b/src/AIModel/AIBallistic.cxx index 15693f398..76e412c0c 100644 --- a/src/AIModel/AIBallistic.cxx +++ b/src/AIModel/AIBallistic.cxx @@ -279,7 +279,6 @@ void FGAIBallistic::update(double dt) { void FGAIBallistic::setAzimuth(double az) { - if (_random) hdg = _azimuth = (az - 5 ) + (10 * sg_random()); else