Merge branch 'vivian/trainz'
This commit is contained in:
commit
c1bb4aec97
15 changed files with 892 additions and 145 deletions
|
@ -2735,6 +2735,13 @@
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\AIModel\AICarrier.hxx">
|
RelativePath="..\..\src\AIModel\AICarrier.hxx">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\AIModel\AIEscort.cxx">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\AIModel\AIEscort.hxx">
|
||||||
|
</File>
|
||||||
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\AIModel\AIFlightPlan.cxx">
|
RelativePath="..\..\src\AIModel\AIFlightPlan.cxx">
|
||||||
</File>
|
</File>
|
||||||
|
|
|
@ -3909,6 +3909,14 @@
|
||||||
RelativePath="..\..\..\src\AIModel\AICarrier.hxx"
|
RelativePath="..\..\..\src\AIModel\AICarrier.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\AIModel\AIEscort.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\AIModel\AIEscort.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\AIModel\AIFlightPlan.cxx"
|
RelativePath="..\..\..\src\AIModel\AIFlightPlan.cxx"
|
||||||
>
|
>
|
||||||
|
|
|
@ -45,7 +45,7 @@ class FGAIBase : public osg::Referenced {
|
||||||
public:
|
public:
|
||||||
enum object_type { otNull = 0, otAircraft, otShip, otCarrier, otBallistic,
|
enum object_type { otNull = 0, otAircraft, otShip, otCarrier, otBallistic,
|
||||||
otRocket, otStorm, otThermal, otStatic, otWingman, otGroundVehicle,
|
otRocket, otStorm, otThermal, otStatic, otWingman, otGroundVehicle,
|
||||||
otMultiplayer,
|
otEscort, otMultiplayer,
|
||||||
MAX_OBJECTS }; // Needs to be last!!!
|
MAX_OBJECTS }; // Needs to be last!!!
|
||||||
|
|
||||||
FGAIBase(object_type ot);
|
FGAIBase(object_type ot);
|
||||||
|
|
|
@ -127,8 +127,8 @@ void FGAICarrier::update(double dt) {
|
||||||
FGAIShip::update(dt);
|
FGAIShip::update(dt);
|
||||||
|
|
||||||
//automatic turn into wind with a target wind of 25 kts otd
|
//automatic turn into wind with a target wind of 25 kts otd
|
||||||
//SG_LOG(SG_GENERAL, SG_ALERT, "AICarrier: MPControl " << MPControl );
|
//SG_LOG(SG_GENERAL, SG_ALERT, "AICarrier: MPControl " << MPControl << " AIControl " << AIControl);
|
||||||
if (!MPControl){
|
if (!MPControl && AIControl){
|
||||||
|
|
||||||
if(turn_to_launch_hdg){
|
if(turn_to_launch_hdg){
|
||||||
TurnToLaunch();
|
TurnToLaunch();
|
||||||
|
@ -260,8 +260,8 @@ void FGAICarrier::bind() {
|
||||||
SGRawValueMethods<SGGeod,double>(pos, &SGGeod::getLongitudeDeg));
|
SGRawValueMethods<SGGeod,double>(pos, &SGGeod::getLongitudeDeg));
|
||||||
props->tie("controls/mp-control",
|
props->tie("controls/mp-control",
|
||||||
SGRawValuePointer<bool>(&MPControl));
|
SGRawValuePointer<bool>(&MPControl));
|
||||||
props->tie("velocities/speed-kts",
|
props->tie("controls/ai-control",
|
||||||
SGRawValuePointer<double>(&speed));
|
SGRawValuePointer<bool>(&AIControl));
|
||||||
props->tie("environment/surface-wind-speed-true-kts",
|
props->tie("environment/surface-wind-speed-true-kts",
|
||||||
SGRawValuePointer<double>(&wind_speed_kts));
|
SGRawValuePointer<double>(&wind_speed_kts));
|
||||||
props->tie("environment/surface-wind-from-true-degs",
|
props->tie("environment/surface-wind-from-true-degs",
|
||||||
|
@ -317,7 +317,6 @@ void FGAICarrier::unbind() {
|
||||||
props->untie("controls/flols/distance-m");
|
props->untie("controls/flols/distance-m");
|
||||||
props->untie("controls/flols/angle-degs");
|
props->untie("controls/flols/angle-degs");
|
||||||
props->untie("controls/turn-to-launch-hdg");
|
props->untie("controls/turn-to-launch-hdg");
|
||||||
props->untie("velocities/speed-kts");
|
|
||||||
props->untie("environment/wind-speed-true-kts");
|
props->untie("environment/wind-speed-true-kts");
|
||||||
props->untie("environment/wind-from-true-degs");
|
props->untie("environment/wind-from-true-degs");
|
||||||
props->untie("environment/rel-wind-from-degs");
|
props->untie("environment/rel-wind-from-degs");
|
||||||
|
@ -333,6 +332,7 @@ void FGAICarrier::unbind() {
|
||||||
props->untie("controls/constants/jbd/trans-time-s");
|
props->untie("controls/constants/jbd/trans-time-s");
|
||||||
props->untie("controls/jbd-time-constant");
|
props->untie("controls/jbd-time-constant");
|
||||||
props->untie("controls/mp-control");
|
props->untie("controls/mp-control");
|
||||||
|
props->untie("controls/ai-control");
|
||||||
props->untie("controls/turn-to-recovery-hdg");
|
props->untie("controls/turn-to-recovery-hdg");
|
||||||
props->untie("controls/turn-to-base-course");
|
props->untie("controls/turn-to-base-course");
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ private:
|
||||||
bool turn_to_base_course;
|
bool turn_to_base_course;
|
||||||
bool returning; // set if the carrier is returning to an operating box
|
bool returning; // set if the carrier is returning to an operating box
|
||||||
bool InToWind(); // set if the carrier is in to wind
|
bool InToWind(); // set if the carrier is in to wind
|
||||||
bool MPControl;
|
bool MPControl, AIControl;
|
||||||
|
|
||||||
|
|
||||||
SGPropertyNode_ptr _longitude_node;
|
SGPropertyNode_ptr _longitude_node;
|
||||||
|
|
443
src/AIModel/AIEscort.cxx
Normal file
443
src/AIModel/AIEscort.cxx
Normal file
|
@ -0,0 +1,443 @@
|
||||||
|
// FGAIEscort - FGAIShip-derived class creates an AI Ground Vehicle
|
||||||
|
// by adding a ground following utility
|
||||||
|
//
|
||||||
|
// Written by Vivian Meazza, started August 2009.
|
||||||
|
// - vivian.meazza at lineone.net
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <simgear/sg_inlines.h>
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <Main/util.hxx>
|
||||||
|
#include <Main/viewer.hxx>
|
||||||
|
|
||||||
|
#include <Scenery/scenery.hxx>
|
||||||
|
#include <Scenery/tilemgr.hxx>
|
||||||
|
|
||||||
|
#include "AIEscort.hxx"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
FGAIEscort::FGAIEscort() :
|
||||||
|
FGAIShip(otEscort),
|
||||||
|
|
||||||
|
_selected_ac(0),
|
||||||
|
_relbrg (0),
|
||||||
|
_stn_truebrg(0),
|
||||||
|
_parent_speed(0),
|
||||||
|
_stn_limit(0),
|
||||||
|
_stn_angle_limit(0),
|
||||||
|
_stn_speed(0),
|
||||||
|
_stn_height(0),
|
||||||
|
_max_speed(0),
|
||||||
|
_interval(0),
|
||||||
|
_MPControl(false),
|
||||||
|
_patrol(false),
|
||||||
|
_stn_deg_true(false),
|
||||||
|
_parent("")
|
||||||
|
|
||||||
|
{
|
||||||
|
invisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FGAIEscort::~FGAIEscort() {}
|
||||||
|
|
||||||
|
void FGAIEscort::readFromScenario(SGPropertyNode* scFileNode) {
|
||||||
|
if (!scFileNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FGAIShip::readFromScenario(scFileNode);
|
||||||
|
|
||||||
|
setName(scFileNode->getStringValue("name", "Escort"));
|
||||||
|
setSMPath(scFileNode->getStringValue("submodel-path", ""));
|
||||||
|
setStnRange(scFileNode->getDoubleValue("station/range-nm", 1));
|
||||||
|
setStnBrg(scFileNode->getDoubleValue("station/brg-deg", 0.0));
|
||||||
|
setStnLimit(scFileNode->getDoubleValue("station/range-limit-nm", 0.2));
|
||||||
|
setStnAngleLimit(scFileNode->getDoubleValue("station/angle-limit-deg", 15.0));
|
||||||
|
setStnSpeed(scFileNode->getDoubleValue("station/speed-kts", 2.5));
|
||||||
|
setStnPatrol(scFileNode->getBoolValue("station/patrol", false));
|
||||||
|
setStnHtFt(scFileNode->getDoubleValue("station/height-ft", 0.0));
|
||||||
|
setStnDegTrue(scFileNode->getBoolValue("station/deg-true", false));
|
||||||
|
setParentName(scFileNode->getStringValue("station/parent", ""));
|
||||||
|
setMaxSpeed(scFileNode->getDoubleValue("max-speed-kts", 30.0));
|
||||||
|
setUpdateInterval(scFileNode->getDoubleValue("update-interval-sec", 10.0));
|
||||||
|
setCallSign(scFileNode->getStringValue("callsign", ""));
|
||||||
|
|
||||||
|
if(_patrol)
|
||||||
|
sg_srandom_time();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::bind() {
|
||||||
|
FGAIShip::bind();
|
||||||
|
|
||||||
|
props->tie("station/rel-bearing-deg",
|
||||||
|
SGRawValuePointer<double>(&_stn_relbrg));
|
||||||
|
props->tie("station/true-bearing-deg",
|
||||||
|
SGRawValuePointer<double>(&_stn_truebrg));
|
||||||
|
props->tie("station/range-nm",
|
||||||
|
SGRawValuePointer<double>(&_stn_range));
|
||||||
|
props->tie("station/range-limit-nm",
|
||||||
|
SGRawValuePointer<double>(&_stn_limit));
|
||||||
|
props->tie("station/angle-limit-deg",
|
||||||
|
SGRawValuePointer<double>(&_stn_angle_limit));
|
||||||
|
props->tie("station/speed-kts",
|
||||||
|
SGRawValuePointer<double>(&_stn_speed));
|
||||||
|
props->tie("station/height-ft",
|
||||||
|
SGRawValuePointer<double>(&_stn_height));
|
||||||
|
props->tie("controls/update-interval-sec",
|
||||||
|
SGRawValuePointer<double>(&_interval));
|
||||||
|
props->tie("controls/parent-mp-control",
|
||||||
|
SGRawValuePointer<bool>(&_MPControl));
|
||||||
|
props->tie("station/target-range-nm",
|
||||||
|
SGRawValuePointer<double>(&_tgtrange));
|
||||||
|
props->tie("station/target-brg-deg-t",
|
||||||
|
SGRawValuePointer<double>(&_tgtbrg));
|
||||||
|
props->tie("station/patrol",
|
||||||
|
SGRawValuePointer<bool>(&_patrol));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::unbind() {
|
||||||
|
FGAIShip::unbind();
|
||||||
|
|
||||||
|
props->untie("station/rel-bearing-deg");
|
||||||
|
props->untie("station/true-bearing-deg");
|
||||||
|
props->untie("station/range-nm");
|
||||||
|
props->untie("station/range-limit-nm");
|
||||||
|
props->untie("station/angle-limit-deg");
|
||||||
|
props->untie("station/speed-kts");
|
||||||
|
props->untie("station/height-ft");
|
||||||
|
props->untie("controls/update-interval-sec");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FGAIEscort::init(bool search_in_AI_path) {
|
||||||
|
if (!FGAIShip::init(search_in_AI_path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
invisible = false;
|
||||||
|
no_roll = false;
|
||||||
|
|
||||||
|
props->setStringValue("controls/parent-name", _parent.c_str());
|
||||||
|
setParent();
|
||||||
|
pos = _tgtpos;
|
||||||
|
speed = _parent_speed;
|
||||||
|
hdg = _parent_hdg;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::update(double dt) {
|
||||||
|
FGAIShip::update(dt);
|
||||||
|
|
||||||
|
RunEscort(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setStnRange(double r) {
|
||||||
|
_stn_range = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setStnBrg(double b) {
|
||||||
|
_stn_brg = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setStnLimit(double l) {
|
||||||
|
_stn_limit = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setStnAngleLimit(double al) {
|
||||||
|
_stn_angle_limit = al;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setStnSpeed(double s) {
|
||||||
|
_stn_speed = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setStnHtFt(double h) {
|
||||||
|
_stn_height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setStnDegTrue(bool t) {
|
||||||
|
_stn_deg_true = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setMaxSpeed(double m) {
|
||||||
|
_max_speed = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setUpdateInterval(double i) {
|
||||||
|
_interval = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setStnPatrol(bool p) {
|
||||||
|
_patrol = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setParentName(const string& p) {
|
||||||
|
_parent = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FGAIEscort::getGroundElev(SGGeod inpos) {
|
||||||
|
|
||||||
|
double height_m ;
|
||||||
|
|
||||||
|
if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(inpos, 3000), height_m, &_material,0)){
|
||||||
|
_ht_agl_ft = inpos.getElevationFt() - height_m * SG_METER_TO_FEET;
|
||||||
|
|
||||||
|
if (_material) {
|
||||||
|
const vector<string>& names = _material->get_names();
|
||||||
|
|
||||||
|
_solid = _material->get_solid();
|
||||||
|
|
||||||
|
if (!names.empty())
|
||||||
|
props->setStringValue("material/name", names[0].c_str());
|
||||||
|
else
|
||||||
|
props->setStringValue("material/name", "");
|
||||||
|
|
||||||
|
//cout << "material " << names[0].c_str()
|
||||||
|
// << " _elevation_m " << _elevation_m
|
||||||
|
// << " solid " << _solid
|
||||||
|
// << " load " << _load_resistance
|
||||||
|
// << " frictionFactor " << _frictionFactor
|
||||||
|
// << endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::setParent() {
|
||||||
|
|
||||||
|
const SGPropertyNode *ai = fgGetNode("/ai/models", true);
|
||||||
|
|
||||||
|
for (int i = ai->nChildren() - 1; i >= -1; i--) {
|
||||||
|
const SGPropertyNode *model;
|
||||||
|
|
||||||
|
if (i < 0) { // last iteration: selected model
|
||||||
|
model = _selected_ac;
|
||||||
|
} else {
|
||||||
|
model = ai->getChild(i);
|
||||||
|
string path = ai->getPath();
|
||||||
|
const string name = model->getStringValue("name");
|
||||||
|
|
||||||
|
if (!model->nChildren()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (name == _parent) {
|
||||||
|
_selected_ac = model; // save selected model for last iteration
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!model)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}// end for loop
|
||||||
|
|
||||||
|
if (_selected_ac != 0){
|
||||||
|
const string name = _selected_ac->getStringValue("name");
|
||||||
|
double lat = _selected_ac->getDoubleValue("position/latitude-deg");
|
||||||
|
double lon = _selected_ac->getDoubleValue("position/longitude-deg");
|
||||||
|
double elevation = _selected_ac->getDoubleValue("position/altitude-ft");
|
||||||
|
_MPControl = _selected_ac->getBoolValue("controls/mp-control");
|
||||||
|
|
||||||
|
_selectedpos.setLatitudeDeg(lat);
|
||||||
|
_selectedpos.setLongitudeDeg(lon);
|
||||||
|
_selectedpos.setElevationFt(elevation);
|
||||||
|
|
||||||
|
_parent_speed = _selected_ac->getDoubleValue("velocities/speed-kts");
|
||||||
|
_parent_hdg = _selected_ac->getDoubleValue("orientation/true-heading-deg");
|
||||||
|
|
||||||
|
if(!_stn_deg_true){
|
||||||
|
_stn_truebrg = calcTrueBearingDeg(_stn_brg, _parent_hdg);
|
||||||
|
_stn_relbrg = _stn_brg;
|
||||||
|
//cout << _name <<" set rel"<<endl;
|
||||||
|
} else {
|
||||||
|
_stn_truebrg = _stn_brg;
|
||||||
|
_stn_relbrg = calcRelBearingDeg(_stn_brg, _parent_hdg);
|
||||||
|
//cout << _name << " set true"<<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
double course2;
|
||||||
|
|
||||||
|
SGGeodesy::direct( _selectedpos, _stn_truebrg, _stn_range * SG_NM_TO_METER,
|
||||||
|
_tgtpos, course2);
|
||||||
|
|
||||||
|
_tgtpos.setElevationFt(_stn_height);
|
||||||
|
|
||||||
|
calcRangeBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(),
|
||||||
|
_tgtpos.getLatitudeDeg(), _tgtpos.getLongitudeDeg(), _tgtrange, _tgtbrg);
|
||||||
|
|
||||||
|
_relbrg = calcRelBearingDeg(_tgtbrg, hdg);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "AIEscort: " << _name
|
||||||
|
<< " parent not found: dying ");
|
||||||
|
setDie(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::calcRangeBearing(double lat, double lon, double lat2, double lon2,
|
||||||
|
double &range, double &bearing) const
|
||||||
|
{
|
||||||
|
// calculate the bearing and range of the second pos from the first
|
||||||
|
double az2, distance;
|
||||||
|
geo_inverse_wgs_84(lat, lon, lat2, lon2, &bearing, &az2, &distance);
|
||||||
|
range = distance * SG_METER_TO_NM;
|
||||||
|
}
|
||||||
|
|
||||||
|
double FGAIEscort::calcRelBearingDeg(double bearing, double heading)
|
||||||
|
{
|
||||||
|
double angle = bearing - heading;
|
||||||
|
SG_NORMALIZE_RANGE(angle, -180.0, 180.0);
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
double FGAIEscort::calcTrueBearingDeg(double bearing, double heading)
|
||||||
|
{
|
||||||
|
double angle = bearing + heading;
|
||||||
|
SG_NORMALIZE_RANGE(angle, 0.0, 360.0);
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
double FGAIEscort::calcRecipBearingDeg(double bearing)
|
||||||
|
{
|
||||||
|
double angle = bearing - 180;
|
||||||
|
SG_NORMALIZE_RANGE(angle, 0.0, 360.0);
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGVec3d FGAIEscort::getCartHitchPosAt(const SGVec3d& _off) const {
|
||||||
|
double hdg = _selected_ac->getDoubleValue("orientation/true-heading-deg");
|
||||||
|
double pitch = _selected_ac->getDoubleValue("orientation/pitch-deg");
|
||||||
|
double roll = _selected_ac->getDoubleValue("orientation/roll-deg");
|
||||||
|
|
||||||
|
// Transform that one to the horizontal local coordinate system.
|
||||||
|
SGQuatd hlTrans = SGQuatd::fromLonLat(_selectedpos);
|
||||||
|
|
||||||
|
// and postrotate the orientation of the AIModel wrt the horizontal
|
||||||
|
// local frame
|
||||||
|
hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
|
||||||
|
|
||||||
|
// The offset converted to the usual body fixed coordinate system
|
||||||
|
// rotated to the earth fiexed coordinates axis
|
||||||
|
SGVec3d off = hlTrans.backTransform(_off);
|
||||||
|
|
||||||
|
// Add the position offset of the AIModel to gain the earth centered position
|
||||||
|
SGVec3d cartPos = SGVec3d::fromGeod(_selectedpos);
|
||||||
|
|
||||||
|
return cartPos + off;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FGAIEscort::setStationSpeed(){
|
||||||
|
|
||||||
|
double speed = 0;
|
||||||
|
double angle = 0;
|
||||||
|
|
||||||
|
// these are the AI rules for the manoeuvring of escorts
|
||||||
|
|
||||||
|
if (_MPControl && _tgtrange > 4 * _stn_limit){
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "AIEscort: " << _name
|
||||||
|
<< " re-aligning to MP pos");
|
||||||
|
pos = _tgtpos;
|
||||||
|
speed = 0;
|
||||||
|
angle = 0;
|
||||||
|
}else if ((_relbrg < -90 || _relbrg > 90) && _tgtrange > _stn_limit ){
|
||||||
|
angle =_relbrg;
|
||||||
|
|
||||||
|
if(_tgtrange > 4 * _stn_limit)
|
||||||
|
speed = 4 * -_stn_speed;
|
||||||
|
else
|
||||||
|
speed = -_stn_speed;
|
||||||
|
|
||||||
|
}else if ((_relbrg >= -90 || _relbrg <= 90) && _tgtrange > _stn_limit){
|
||||||
|
angle = _relbrg;
|
||||||
|
|
||||||
|
if(_tgtrange > 4 * _stn_limit)
|
||||||
|
speed = 4 * _stn_speed;
|
||||||
|
else
|
||||||
|
speed = _stn_speed;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if(_patrol){
|
||||||
|
angle = 15 * sg_random();
|
||||||
|
speed = 5 * sg_random();
|
||||||
|
} else {
|
||||||
|
angle = 0;
|
||||||
|
speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
double station_speed = _parent_speed + speed;
|
||||||
|
|
||||||
|
SG_CLAMP_RANGE(station_speed, 5.0, _max_speed);
|
||||||
|
SG_CLAMP_RANGE(angle, -_stn_angle_limit, _stn_angle_limit);
|
||||||
|
|
||||||
|
AccelTo(station_speed);
|
||||||
|
TurnTo(_parent_hdg + angle);
|
||||||
|
ClimbTo(_stn_height);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIEscort::RunEscort(double dt){
|
||||||
|
|
||||||
|
_dt_count += dt;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Check execution time (currently once every 0.05 sec or 20 fps)
|
||||||
|
// Add a bit of randomization to prevent the execution of all flight plans
|
||||||
|
// in synchrony, which can add significant periodic framerate flutter.
|
||||||
|
// Randomization removed to get better appearance
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//cout << "_start_sec " << _start_sec << " time_sec " << time_sec << endl;
|
||||||
|
if (_dt_count < _next_run)
|
||||||
|
return;
|
||||||
|
_next_run = _interval /*+ (0.015 * sg_random())*/;
|
||||||
|
|
||||||
|
if(_parent == ""){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setParent();
|
||||||
|
setStationSpeed();
|
||||||
|
//getGroundElev(pos);
|
||||||
|
|
||||||
|
_dt_count = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// end AIGroundvehicle
|
106
src/AIModel/AIEscort.hxx
Normal file
106
src/AIModel/AIEscort.hxx
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
// FGAIGroundVehicle - FGAIShip-derived class creates an AI Ground Vehicle
|
||||||
|
// by adding a ground following utility
|
||||||
|
//
|
||||||
|
// Written by Vivian Meazza, started August 2009.
|
||||||
|
// - vivian.meazza at lineone.net
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
#ifndef _FG_AIESCORT_HXX
|
||||||
|
#define _FG_AIESCORT_HXX
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include "AIBase.hxx"
|
||||||
|
|
||||||
|
#include "AIShip.hxx"
|
||||||
|
|
||||||
|
#include "AIManager.hxx"
|
||||||
|
#include "AIBase.hxx"
|
||||||
|
|
||||||
|
class FGAIEscort : public FGAIShip {
|
||||||
|
public:
|
||||||
|
FGAIEscort();
|
||||||
|
virtual ~FGAIEscort();
|
||||||
|
|
||||||
|
virtual void readFromScenario(SGPropertyNode* scFileNode);
|
||||||
|
virtual void bind();
|
||||||
|
virtual void unbind();
|
||||||
|
virtual const char* getTypeString(void) const { return "escort"; }
|
||||||
|
|
||||||
|
bool init(bool search_in_AI_path=false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
virtual void reinit() { init(); }
|
||||||
|
virtual void update (double dt);
|
||||||
|
|
||||||
|
void setParentName(const std::string& p);
|
||||||
|
void setParent();
|
||||||
|
void setStnRange(double r);
|
||||||
|
void setStnBrg(double y);
|
||||||
|
void setStationSpeed();
|
||||||
|
void setStnLimit(double l);
|
||||||
|
void setStnAngleLimit(double l);
|
||||||
|
void setStnSpeed(double s);
|
||||||
|
void setStnHtFt(double h);
|
||||||
|
void setStnPatrol(bool p);
|
||||||
|
void setStnDegTrue(bool t);
|
||||||
|
|
||||||
|
void setMaxSpeed(double m);
|
||||||
|
void setUpdateInterval(double i);
|
||||||
|
|
||||||
|
void RunEscort(double dt);
|
||||||
|
|
||||||
|
bool getGroundElev(SGGeod inpos);
|
||||||
|
|
||||||
|
SGVec3d getCartHitchPosAt(const SGVec3d& off) const;
|
||||||
|
|
||||||
|
void calcRangeBearing(double lat, double lon, double lat2, double lon2,
|
||||||
|
double &range, double &bearing) const;
|
||||||
|
double calcRelBearingDeg(double bearing, double heading);
|
||||||
|
double calcTrueBearingDeg(double bearing, double heading);
|
||||||
|
double calcRecipBearingDeg(double bearing);
|
||||||
|
|
||||||
|
SGGeod _selectedpos;
|
||||||
|
SGGeod _tgtpos;
|
||||||
|
|
||||||
|
bool _solid; // if true ground is solid for FDMs
|
||||||
|
double _load_resistance; // ground load resistanc N/m^2
|
||||||
|
double _frictionFactor; // dimensionless modifier for Coefficient of Friction
|
||||||
|
double _tgtrange, _tgtbrg;
|
||||||
|
double _ht_agl_ft;
|
||||||
|
double _relbrg, _truebrg;
|
||||||
|
double _parent_speed, _parent_hdg;
|
||||||
|
double _interval;
|
||||||
|
|
||||||
|
double _stn_relbrg, _stn_truebrg, _stn_brg, _stn_range, _stn_height;
|
||||||
|
double _stn_speed, _stn_angle_limit, _stn_limit;
|
||||||
|
|
||||||
|
double _max_speed;
|
||||||
|
|
||||||
|
const SGMaterial* _material;
|
||||||
|
const SGPropertyNode *_selected_ac;
|
||||||
|
|
||||||
|
bool _MPControl, _patrol, _stn_deg_true;
|
||||||
|
|
||||||
|
std::string _parent;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FG_AIGROUNDVEHICLE_HXX
|
|
@ -45,7 +45,9 @@ _dt_count(0),
|
||||||
_next_run(0),
|
_next_run(0),
|
||||||
_parent_x_offset(0),
|
_parent_x_offset(0),
|
||||||
_parent_y_offset(0),
|
_parent_y_offset(0),
|
||||||
_parent("")
|
_parent_z_offset(0),
|
||||||
|
_parent(""),
|
||||||
|
_break_count(0)
|
||||||
|
|
||||||
{
|
{
|
||||||
invisible = false;
|
invisible = false;
|
||||||
|
@ -64,16 +66,18 @@ void FGAIGroundVehicle::readFromScenario(SGPropertyNode* scFileNode) {
|
||||||
setSMPath(scFileNode->getStringValue("submodel-path", ""));
|
setSMPath(scFileNode->getStringValue("submodel-path", ""));
|
||||||
setContactX1offset(scFileNode->getDoubleValue("contact-x1-offset", 0.0));
|
setContactX1offset(scFileNode->getDoubleValue("contact-x1-offset", 0.0));
|
||||||
setContactX2offset(scFileNode->getDoubleValue("contact-x2-offset", 0.0));
|
setContactX2offset(scFileNode->getDoubleValue("contact-x2-offset", 0.0));
|
||||||
setXOffset(scFileNode->getDoubleValue("hitch-x-offset", 38.55));
|
setXOffset(scFileNode->getDoubleValue("hitch-x-offset", 35.0));
|
||||||
setYOffset(scFileNode->getDoubleValue("hitch-y-offset", 0.0));
|
setYOffset(scFileNode->getDoubleValue("hitch-y-offset", 0.0));
|
||||||
|
setZOffset(scFileNode->getDoubleValue("hitch-z-offset", 0.0));
|
||||||
setPitchoffset(scFileNode->getDoubleValue("pitch-offset", 0.0));
|
setPitchoffset(scFileNode->getDoubleValue("pitch-offset", 0.0));
|
||||||
setRolloffset(scFileNode->getDoubleValue("roll-offset", 0.0));
|
setRolloffset(scFileNode->getDoubleValue("roll-offset", 0.0));
|
||||||
setYawoffset(scFileNode->getDoubleValue("yaw-offset", 0.0));
|
setYawoffset(scFileNode->getDoubleValue("yaw-offset", 0.0));
|
||||||
setPitchCoeff(scFileNode->getDoubleValue("pitch-coefficient", 0.1));
|
setPitchCoeff(scFileNode->getDoubleValue("pitch-coefficient", 0.1));
|
||||||
setElevCoeff(scFileNode->getDoubleValue("elevation-coefficient", 0.25));
|
setElevCoeff(scFileNode->getDoubleValue("elevation-coefficient", 0.25));
|
||||||
setParentName(scFileNode->getStringValue("parent", ""));
|
setParentName(scFileNode->getStringValue("parent", ""));
|
||||||
setTowAngleGain(scFileNode->getDoubleValue("tow-angle-gain", 2.0));
|
setTowAngleGain(scFileNode->getDoubleValue("tow-angle-gain", 1.0));
|
||||||
setTowAngleLimit(scFileNode->getDoubleValue("tow-angle-limit-deg", 2.0));
|
setTowAngleLimit(scFileNode->getDoubleValue("tow-angle-limit-deg", 2.0));
|
||||||
|
setInitialTunnel(scFileNode->getBoolValue("tunnel", false));
|
||||||
//we may need these later for towed vehicles
|
//we may need these later for towed vehicles
|
||||||
// setSubID(scFileNode->getIntValue("SubID", 0));
|
// setSubID(scFileNode->getIntValue("SubID", 0));
|
||||||
// setGroundOffset(scFileNode->getDoubleValue("ground-offset", 0.0));
|
// setGroundOffset(scFileNode->getDoubleValue("ground-offset", 0.0));
|
||||||
|
@ -99,10 +103,14 @@ void FGAIGroundVehicle::bind() {
|
||||||
SGRawValuePointer<double>(&_x_offset));
|
SGRawValuePointer<double>(&_x_offset));
|
||||||
props->tie("hitch/y-offset-ft",
|
props->tie("hitch/y-offset-ft",
|
||||||
SGRawValuePointer<double>(&_y_offset));
|
SGRawValuePointer<double>(&_y_offset));
|
||||||
|
props->tie("hitch/z-offset-ft",
|
||||||
|
SGRawValuePointer<double>(&_z_offset));
|
||||||
props->tie("hitch/parent-x-offset-ft",
|
props->tie("hitch/parent-x-offset-ft",
|
||||||
SGRawValuePointer<double>(&_parent_x_offset));
|
SGRawValuePointer<double>(&_parent_x_offset));
|
||||||
props->tie("hitch/parent-y-offset-ft",
|
props->tie("hitch/parent-y-offset-ft",
|
||||||
SGRawValuePointer<double>(&_parent_y_offset));
|
SGRawValuePointer<double>(&_parent_y_offset));
|
||||||
|
props->tie("hitch/parent-z-offset-ft",
|
||||||
|
SGRawValuePointer<double>(&_parent_z_offset));
|
||||||
props->tie("controls/constants/tow-angle/gain",
|
props->tie("controls/constants/tow-angle/gain",
|
||||||
SGRawValuePointer<double>(&_tow_angle_gain));
|
SGRawValuePointer<double>(&_tow_angle_gain));
|
||||||
props->tie("controls/constants/tow-angle/limit-deg",
|
props->tie("controls/constants/tow-angle/limit-deg",
|
||||||
|
@ -117,15 +125,17 @@ void FGAIGroundVehicle::unbind() {
|
||||||
FGAIShip::unbind();
|
FGAIShip::unbind();
|
||||||
|
|
||||||
props->untie("controls/constants/elevation-coeff");
|
props->untie("controls/constants/elevation-coeff");
|
||||||
props->untie("position/ht-AGL-ft");
|
|
||||||
props->untie("controls/constants/pitch-coeff");
|
props->untie("controls/constants/pitch-coeff");
|
||||||
|
props->untie("position/ht-AGL-ft");
|
||||||
props->untie("hitch/rel-bearing-deg");
|
props->untie("hitch/rel-bearing-deg");
|
||||||
props->untie("hitch/tow-angle-deg");
|
props->untie("hitch/tow-angle-deg");
|
||||||
props->untie("hitch/range-ft");
|
props->untie("hitch/range-ft");
|
||||||
props->untie("hitch/x-offset-ft");
|
props->untie("hitch/x-offset-ft");
|
||||||
props->untie("hitch/y-offset-ft");
|
props->untie("hitch/y-offset-ft");
|
||||||
|
props->untie("hitch/z-offset-ft");
|
||||||
props->untie("hitch/parent-x-offset-ft");
|
props->untie("hitch/parent-x-offset-ft");
|
||||||
props->untie("hitch/parent-y-offset-ft");
|
props->untie("hitch/parent-y-offset-ft");
|
||||||
|
props->untie("hitch/parent-y-offset-ft");
|
||||||
props->untie("controls/constants/tow-angle/gain");
|
props->untie("controls/constants/tow-angle/gain");
|
||||||
props->untie("controls/constants/tow-angle/limit-deg");
|
props->untie("controls/constants/tow-angle/limit-deg");
|
||||||
props->untie("controls/contact-x1-offset-ft");
|
props->untie("controls/contact-x1-offset-ft");
|
||||||
|
@ -145,9 +155,9 @@ bool FGAIGroundVehicle::init(bool search_in_AI_path) {
|
||||||
|
|
||||||
void FGAIGroundVehicle::update(double dt) {
|
void FGAIGroundVehicle::update(double dt) {
|
||||||
// SG_LOG(SG_GENERAL, SG_ALERT, "updating GroundVehicle: " << _name );
|
// SG_LOG(SG_GENERAL, SG_ALERT, "updating GroundVehicle: " << _name );
|
||||||
|
FGAIShip::update(dt);
|
||||||
|
|
||||||
RunGroundVehicle(dt);
|
RunGroundVehicle(dt);
|
||||||
// FGAIShip::update(dt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIGroundVehicle::setNoRoll(bool nr) {
|
void FGAIGroundVehicle::setNoRoll(bool nr) {
|
||||||
|
@ -170,6 +180,10 @@ void FGAIGroundVehicle::setYOffset(double y) {
|
||||||
_y_offset = y;
|
_y_offset = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGAIGroundVehicle::setZOffset(double z) {
|
||||||
|
_z_offset = z;
|
||||||
|
}
|
||||||
|
|
||||||
void FGAIGroundVehicle::setPitchCoeff(double pc) {
|
void FGAIGroundVehicle::setPitchCoeff(double pc) {
|
||||||
_pitch_coeff = pc;
|
_pitch_coeff = pc;
|
||||||
}
|
}
|
||||||
|
@ -201,9 +215,12 @@ void FGAIGroundVehicle::setParentName(const string& p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIGroundVehicle::setTowAngle(double ta, double dt, double coeff){
|
void FGAIGroundVehicle::setTowAngle(double ta, double dt, double coeff){
|
||||||
//_tow_angle = ta * _tow_angle_gain;
|
ta *= _tow_angle_gain;
|
||||||
_tow_angle = pow(ta,2) * sign(ta);
|
double factor = -0.0045 * speed + 1;
|
||||||
SG_CLAMP_RANGE(_tow_angle, -_tow_angle_limit, _tow_angle_limit);
|
double limit = _tow_angle_limit * factor;
|
||||||
|
// cout << "speed "<< speed << " _factor " << _factor<<" " <<_tow_angle_limit<< endl;
|
||||||
|
_tow_angle = pow(ta,2) * sign(ta) * factor;
|
||||||
|
SG_CLAMP_RANGE(_tow_angle, -limit, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FGAIGroundVehicle::getGroundElev(SGGeod inpos) {
|
bool FGAIGroundVehicle::getGroundElev(SGGeod inpos) {
|
||||||
|
@ -242,10 +259,10 @@ bool FGAIGroundVehicle::getGroundElev(SGGeod inpos) {
|
||||||
bool FGAIGroundVehicle::getPitch() {
|
bool FGAIGroundVehicle::getPitch() {
|
||||||
|
|
||||||
if (!_tunnel){
|
if (!_tunnel){
|
||||||
|
|
||||||
double vel = props->getDoubleValue("velocities/true-airspeed-kt", 0);
|
double vel = props->getDoubleValue("velocities/true-airspeed-kt", 0);
|
||||||
double contact_offset_x1_m = _contact_x1_offset * SG_FEET_TO_METER;
|
double contact_offset_x1_m = _contact_x1_offset * SG_FEET_TO_METER;
|
||||||
double contact_offset_x2_m = _contact_x2_offset * SG_FEET_TO_METER;
|
double contact_offset_x2_m = _contact_x2_offset * SG_FEET_TO_METER;
|
||||||
|
double _z_offset_m = _parent_z_offset * SG_FEET_TO_METER;
|
||||||
|
|
||||||
SGVec3d front(-contact_offset_x1_m, 0, 0);
|
SGVec3d front(-contact_offset_x1_m, 0, 0);
|
||||||
SGVec3d rear(-contact_offset_x2_m, 0, 0);
|
SGVec3d rear(-contact_offset_x2_m, 0, 0);
|
||||||
|
@ -261,9 +278,9 @@ bool FGAIGroundVehicle::getPitch() {
|
||||||
double elev_rear = 0;
|
double elev_rear = 0;
|
||||||
double max_alt = 10000;
|
double max_alt = 10000;
|
||||||
|
|
||||||
if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(geodFront, 3000), elev_front,
|
if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(geodFront, 3000),
|
||||||
&_material, 0)){
|
elev_front, &_material, 0)){
|
||||||
front_elev_m = elev_front;
|
front_elev_m = elev_front + _z_offset_m;
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -296,27 +313,27 @@ bool FGAIGroundVehicle::getPitch() {
|
||||||
static double prev_alt;
|
static double prev_alt;
|
||||||
|
|
||||||
if (_new_waypoint){
|
if (_new_waypoint){
|
||||||
cout << "new waypoint, calculating pitch " << endl;
|
//cout << "new waypoint, calculating pitch " << endl;
|
||||||
curr_alt = curr->altitude * SG_METER_TO_FEET;
|
curr_alt = curr->altitude;
|
||||||
prev_alt = prev->altitude * SG_METER_TO_FEET;
|
prev_alt = prev->altitude;
|
||||||
d_alt = curr_alt - prev_alt;
|
cout << "prev_alt" <<prev_alt << endl;
|
||||||
|
d_alt = (curr_alt - prev_alt) * SG_METER_TO_FEET;
|
||||||
|
//_elevation = prev->altitude;
|
||||||
distance = SGGeodesy::distanceM(SGGeod::fromDeg(prev->longitude, prev->latitude),
|
distance = SGGeodesy::distanceM(SGGeod::fromDeg(prev->longitude, prev->latitude),
|
||||||
SGGeod::fromDeg(curr->longitude, curr->latitude));
|
SGGeod::fromDeg(curr->longitude, curr->latitude));
|
||||||
|
|
||||||
_pitch = atan2(d_alt, distance * SG_METER_TO_FEET) * SG_RADIANS_TO_DEGREES;
|
_pitch = atan2(d_alt, distance * SG_METER_TO_FEET) * SG_RADIANS_TO_DEGREES;
|
||||||
// cout << "new waypoint, calculating pitch " << _pitch << endl;
|
//cout << "new waypoint, calculating pitch " << _pitch <<
|
||||||
|
// " " << _pitch_offset << " " << _elevation <<endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double distance_to_go = SGGeodesy::distanceM(SGGeod::fromDeg(pos.getLongitudeDeg(), pos.getLatitudeDeg()),
|
double distance_to_go = SGGeodesy::distanceM(SGGeod::fromDeg(pos.getLongitudeDeg(), pos.getLatitudeDeg()),
|
||||||
SGGeod::fromDeg(curr->longitude, curr->latitude));
|
SGGeod::fromDeg(curr->longitude, curr->latitude));
|
||||||
|
|
||||||
//cout << "tunnel " << _tunnel
|
/*cout << "tunnel " << _tunnel
|
||||||
// << " distance curr & prev " << prev->name << " " << curr->name << " " << distance * SG_METER_TO_FEET
|
<< " distance prev & curr " << prev->name << " " << curr->name << " " << distance * SG_METER_TO_FEET
|
||||||
// << " distance to go " << distance_to_go * SG_METER_TO_FEET
|
<< " distance to go " << distance_to_go * SG_METER_TO_FEET
|
||||||
// << " d_alt ft " << d_alt
|
<< " d_alt ft " << d_alt
|
||||||
// << endl;
|
<< endl;*/
|
||||||
|
|
||||||
if (distance_to_go > distance)
|
if (distance_to_go > distance)
|
||||||
_elevation = prev_alt;
|
_elevation = prev_alt;
|
||||||
|
@ -367,6 +384,8 @@ void FGAIGroundVehicle::setParent() {
|
||||||
* SG_FEET_TO_METER;
|
* SG_FEET_TO_METER;
|
||||||
double hitch_y_offset_m = _selected_ac->getDoubleValue("hitch/y-offset-ft")
|
double hitch_y_offset_m = _selected_ac->getDoubleValue("hitch/y-offset-ft")
|
||||||
* SG_FEET_TO_METER;
|
* SG_FEET_TO_METER;
|
||||||
|
double hitch_z_offset_m = _selected_ac->getDoubleValue("hitch/z-offset-ft")
|
||||||
|
* SG_FEET_TO_METER;
|
||||||
|
|
||||||
_selectedpos.setLatitudeDeg(lat);
|
_selectedpos.setLatitudeDeg(lat);
|
||||||
_selectedpos.setLongitudeDeg(lon);
|
_selectedpos.setLongitudeDeg(lon);
|
||||||
|
@ -374,6 +393,8 @@ void FGAIGroundVehicle::setParent() {
|
||||||
|
|
||||||
_parent_x_offset = _selected_ac->getDoubleValue("hitch/x-offset-ft");
|
_parent_x_offset = _selected_ac->getDoubleValue("hitch/x-offset-ft");
|
||||||
_parent_y_offset = _selected_ac->getDoubleValue("hitch/y-offset-ft");
|
_parent_y_offset = _selected_ac->getDoubleValue("hitch/y-offset-ft");
|
||||||
|
_parent_z_offset = _selected_ac->getDoubleValue("hitch/z-offset-ft");
|
||||||
|
|
||||||
_parent_speed = _selected_ac->getDoubleValue("velocities/true-airspeed-kt");
|
_parent_speed = _selected_ac->getDoubleValue("velocities/true-airspeed-kt");
|
||||||
|
|
||||||
SGVec3d rear_hitch(-hitch_x_offset_m, hitch_y_offset_m, 0);
|
SGVec3d rear_hitch(-hitch_x_offset_m, hitch_y_offset_m, 0);
|
||||||
|
@ -534,7 +555,7 @@ void FGAIGroundVehicle::RunGroundVehicle(double dt){
|
||||||
if (_dt_count < _next_run)
|
if (_dt_count < _next_run)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_next_run = 0.055 /*+ (0.015 * sg_random())*/;
|
_next_run = 0.05 /*+ (0.015 * sg_random())*/;
|
||||||
|
|
||||||
if (getPitch()){
|
if (getPitch()){
|
||||||
setElevation(_elevation, _dt_count, _elevation_coeff);
|
setElevation(_elevation, _dt_count, _elevation_coeff);
|
||||||
|
@ -545,7 +566,6 @@ void FGAIGroundVehicle::RunGroundVehicle(double dt){
|
||||||
|
|
||||||
if(_parent == ""){
|
if(_parent == ""){
|
||||||
AccelTo(prev->speed);
|
AccelTo(prev->speed);
|
||||||
FGAIShip::update(_dt_count);
|
|
||||||
_dt_count = 0;
|
_dt_count = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -554,12 +574,15 @@ void FGAIGroundVehicle::RunGroundVehicle(double dt){
|
||||||
|
|
||||||
string parent_next_name = _selected_ac->getStringValue("waypoint/name-next");
|
string parent_next_name = _selected_ac->getStringValue("waypoint/name-next");
|
||||||
bool parent_waiting = _selected_ac->getBoolValue("waypoint/waiting");
|
bool parent_waiting = _selected_ac->getBoolValue("waypoint/waiting");
|
||||||
|
bool parent_restart = _selected_ac->getBoolValue("controls/restart");
|
||||||
|
|
||||||
if (parent_next_name == "END" && fp->getNextWaypoint()->name != "END" ){
|
if (parent_next_name == "END" && fp->getNextWaypoint()->name != "END" ){
|
||||||
SG_LOG(SG_GENERAL, SG_DEBUG, "AIGroundVeh1cle: " << _name
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIGroundVeh1cle: " << _name
|
||||||
<< " setting END: getting new waypoints ");
|
<< " setting END: getting new waypoints ");
|
||||||
AdvanceFP();
|
AdvanceFP();
|
||||||
setWPNames();
|
setWPNames();
|
||||||
|
setTunnel(_initial_tunnel);
|
||||||
|
if(_restart) _missed_count = 200;
|
||||||
/*} else if (parent_next_name == "WAIT" && fp->getNextWaypoint()->name != "WAIT" ){*/
|
/*} else if (parent_next_name == "WAIT" && fp->getNextWaypoint()->name != "WAIT" ){*/
|
||||||
} else if (parent_waiting && !_waiting){
|
} else if (parent_waiting && !_waiting){
|
||||||
SG_LOG(SG_GENERAL, SG_DEBUG, "AIGroundVeh1cle: " << _name
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AIGroundVeh1cle: " << _name
|
||||||
|
@ -585,12 +608,14 @@ void FGAIGroundVehicle::RunGroundVehicle(double dt){
|
||||||
}
|
}
|
||||||
|
|
||||||
setWPNames();
|
setWPNames();
|
||||||
} else if (_range_ft > _parent_x_offset * 4){
|
} else if (_range_ft > (_x_offset +_parent_x_offset)* 4
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "AIGroundVeh1cle: " << _name
|
){
|
||||||
<< " rescue: reforming train " << _range_ft << " " << _x_offset * 15);
|
SG_LOG(SG_GENERAL, SG_ALERT, "AIGroundVeh1cle: " << _name
|
||||||
|
<< " rescue: reforming train " << _range_ft
|
||||||
|
);
|
||||||
|
|
||||||
setTowAngle(0, dt, 1);
|
setTowAngle(0, dt, 1);
|
||||||
setSpeed(_parent_speed * 2);
|
setSpeed(_parent_speed + (10 * sign(_parent_speed)));
|
||||||
|
|
||||||
} else if (_parent_speed > 1){
|
} else if (_parent_speed > 1){
|
||||||
|
|
||||||
|
@ -609,7 +634,7 @@ void FGAIGroundVehicle::RunGroundVehicle(double dt){
|
||||||
} else
|
} else
|
||||||
setSpeed(_parent_speed);
|
setSpeed(_parent_speed);
|
||||||
|
|
||||||
FGAIShip::update(_dt_count);
|
// FGAIShip::update(_dt_count);
|
||||||
_dt_count = 0;
|
_dt_count = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ private:
|
||||||
void setContactX2offset(double x2);
|
void setContactX2offset(double x2);
|
||||||
void setXOffset(double x);
|
void setXOffset(double x);
|
||||||
void setYOffset(double y);
|
void setYOffset(double y);
|
||||||
|
void setZOffset(double z);
|
||||||
|
|
||||||
void setPitchCoeff(double pc);
|
void setPitchCoeff(double pc);
|
||||||
void setElevCoeff(double ec);
|
void setElevCoeff(double ec);
|
||||||
|
@ -91,8 +92,8 @@ private:
|
||||||
double _x_offset, _y_offset;
|
double _x_offset, _y_offset;
|
||||||
double _range_ft;
|
double _range_ft;
|
||||||
double _relbrg;
|
double _relbrg;
|
||||||
double _parent_speed, _parent_x_offset, _parent_y_offset;
|
double _parent_speed, _parent_x_offset, _parent_y_offset, _parent_z_offset;
|
||||||
double _dt_count, _next_run;
|
double _dt_count, _next_run, _break_count;
|
||||||
|
|
||||||
const SGMaterial* _material;
|
const SGMaterial* _material;
|
||||||
const SGPropertyNode *_selected_ac;
|
const SGPropertyNode *_selected_ac;
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "AITanker.hxx"
|
#include "AITanker.hxx"
|
||||||
#include "AIWingman.hxx"
|
#include "AIWingman.hxx"
|
||||||
#include "AIGroundVehicle.hxx"
|
#include "AIGroundVehicle.hxx"
|
||||||
|
#include "AIEscort.hxx"
|
||||||
|
|
||||||
FGAIManager::FGAIManager() {
|
FGAIManager::FGAIManager() {
|
||||||
_dt = 0.0;
|
_dt = 0.0;
|
||||||
|
@ -311,6 +312,11 @@ FGAIManager::processScenario( const string &filename ) {
|
||||||
groundvehicle->readFromScenario(scEntry);
|
groundvehicle->readFromScenario(scEntry);
|
||||||
attach(groundvehicle);
|
attach(groundvehicle);
|
||||||
|
|
||||||
|
} else if (type == "escort") {
|
||||||
|
FGAIEscort* escort = new FGAIEscort;
|
||||||
|
escort->readFromScenario(scEntry);
|
||||||
|
attach(escort);
|
||||||
|
|
||||||
} else if (type == "thunderstorm") {
|
} else if (type == "thunderstorm") {
|
||||||
FGAIStorm* storm = new FGAIStorm;
|
FGAIStorm* storm = new FGAIStorm;
|
||||||
storm->readFromScenario(scEntry);
|
storm->readFromScenario(scEntry);
|
||||||
|
@ -395,8 +401,8 @@ const FGAIBase *
|
||||||
FGAIManager::calcCollision(double alt, double lat, double lon, double fuse_range)
|
FGAIManager::calcCollision(double alt, double lat, double lon, double fuse_range)
|
||||||
{
|
{
|
||||||
// we specify tgt extent (ft) according to the AIObject type
|
// we specify tgt extent (ft) according to the AIObject type
|
||||||
double tgt_ht[] = {0, 50 ,100, 250, 0, 100, 0, 0, 50, 50, 50};
|
double tgt_ht[] = {0, 50, 100, 250, 0, 100, 0, 0, 50, 50, 20, 100, 50};
|
||||||
double tgt_length[] = {0, 100, 200, 750, 0, 50, 0, 0, 200, 100, 100};
|
double tgt_length[] = {0, 100, 200, 750, 0, 50, 0, 0, 200, 100, 40, 200, 100};
|
||||||
ai_list_iterator ai_list_itr = ai_list.begin();
|
ai_list_iterator ai_list_itr = ai_list.begin();
|
||||||
ai_list_iterator end = ai_list.end();
|
ai_list_iterator end = ai_list.end();
|
||||||
|
|
||||||
|
@ -407,11 +413,11 @@ FGAIManager::calcCollision(double alt, double lat, double lon, double fuse_range
|
||||||
|
|
||||||
if (fabs(tgt_alt - alt) > tgt_ht[type] || type == FGAIBase::otBallistic
|
if (fabs(tgt_alt - alt) > tgt_ht[type] || type == FGAIBase::otBallistic
|
||||||
|| type == FGAIBase::otStorm || type == FGAIBase::otThermal ) {
|
|| type == FGAIBase::otStorm || type == FGAIBase::otThermal ) {
|
||||||
SG_LOG(SG_GENERAL, SG_DEBUG, "AIManager: skipping "
|
//SG_LOG(SG_GENERAL, SG_DEBUG, "AIManager: skipping "
|
||||||
<< fabs(tgt_alt - alt)
|
// << fabs(tgt_alt - alt)
|
||||||
<< " "
|
// << " "
|
||||||
<< type
|
// << type
|
||||||
);
|
// );
|
||||||
++ai_list_itr;
|
++ai_list_itr;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -422,14 +428,14 @@ FGAIManager::calcCollision(double alt, double lat, double lon, double fuse_range
|
||||||
|
|
||||||
double range = calcRange(lat, lon, tgt_lat, tgt_lon);
|
double range = calcRange(lat, lon, tgt_lat, tgt_lon);
|
||||||
|
|
||||||
SG_LOG(SG_GENERAL, SG_DEBUG, "AIManager: AI list size "
|
//SG_LOG(SG_GENERAL, SG_DEBUG, "AIManager: AI list size "
|
||||||
<< ai_list.size()
|
// << ai_list.size()
|
||||||
<< " type " << type
|
// << " type " << type
|
||||||
<< " ID " << id
|
// << " ID " << id
|
||||||
<< " range " << range
|
// << " range " << range
|
||||||
//<< " bearing " << bearing
|
// //<< " bearing " << bearing
|
||||||
<< " alt " << tgt_alt
|
// << " alt " << tgt_alt
|
||||||
);
|
// );
|
||||||
|
|
||||||
tgt_length[type] += fuse_range;
|
tgt_length[type] += fuse_range;
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
FGAIShip::FGAIShip(object_type ot) :
|
FGAIShip::FGAIShip(object_type ot) :
|
||||||
FGAIBase(ot),
|
FGAIBase(ot),
|
||||||
_limit(40),
|
_limit(100),
|
||||||
_elevation_m(0),
|
_elevation_m(0),
|
||||||
_elevation_ft(0),
|
_elevation_ft(0),
|
||||||
_tow_angle(0),
|
_tow_angle(0),
|
||||||
|
@ -68,7 +68,8 @@ _old_range(0),
|
||||||
_range_rate(0),
|
_range_rate(0),
|
||||||
_roll_constant(0.001),
|
_roll_constant(0.001),
|
||||||
_hdg_constant(0.01),
|
_hdg_constant(0.01),
|
||||||
_roll_factor(-0.0083335)
|
_roll_factor(-0.0083335),
|
||||||
|
_restart(false)
|
||||||
|
|
||||||
{
|
{
|
||||||
invisible = false;
|
invisible = false;
|
||||||
|
@ -89,6 +90,7 @@ void FGAIShip::readFromScenario(SGPropertyNode* scFileNode) {
|
||||||
setRadius(scFileNode->getDoubleValue("turn-radius-ft", 2000));
|
setRadius(scFileNode->getDoubleValue("turn-radius-ft", 2000));
|
||||||
std::string flightplan = scFileNode->getStringValue("flightplan");
|
std::string flightplan = scFileNode->getStringValue("flightplan");
|
||||||
setRepeat(scFileNode->getBoolValue("repeat", false));
|
setRepeat(scFileNode->getBoolValue("repeat", false));
|
||||||
|
setRestart(scFileNode->getBoolValue("restart", false));
|
||||||
setStartTime(scFileNode->getStringValue("time", ""));
|
setStartTime(scFileNode->getStringValue("time", ""));
|
||||||
setLeadAngleGain(scFileNode->getDoubleValue("lead-angle-gain", 1.5));
|
setLeadAngleGain(scFileNode->getDoubleValue("lead-angle-gain", 1.5));
|
||||||
setLeadAngleLimit(scFileNode->getDoubleValue("lead-angle-limit-deg", 15));
|
setLeadAngleLimit(scFileNode->getDoubleValue("lead-angle-limit-deg", 15));
|
||||||
|
@ -196,6 +198,10 @@ void FGAIShip::bind() {
|
||||||
SGRawValuePointer<double>(&_proportion));
|
SGRawValuePointer<double>(&_proportion));
|
||||||
props->tie("controls/fixed-turn-radius-ft",
|
props->tie("controls/fixed-turn-radius-ft",
|
||||||
SGRawValuePointer<double>(&_fixed_turn_radius));
|
SGRawValuePointer<double>(&_fixed_turn_radius));
|
||||||
|
props->tie("controls/restart",
|
||||||
|
SGRawValuePointer<bool>(&_restart));
|
||||||
|
props->tie("velocities/speed-kts",
|
||||||
|
SGRawValuePointer<double>(&speed));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIShip::unbind() {
|
void FGAIShip::unbind() {
|
||||||
|
@ -231,6 +237,8 @@ void FGAIShip::unbind() {
|
||||||
props->untie("controls/constants/lead-angle/proportion");
|
props->untie("controls/constants/lead-angle/proportion");
|
||||||
props->untie("controls/fixed-turn-radius-ft");
|
props->untie("controls/fixed-turn-radius-ft");
|
||||||
props->untie("controls/constants/speed");
|
props->untie("controls/constants/speed");
|
||||||
|
props->untie("controls/restart");
|
||||||
|
props->untie("velocities/speed-kts");
|
||||||
|
|
||||||
}
|
}
|
||||||
void FGAIShip::update(double dt) {
|
void FGAIShip::update(double dt) {
|
||||||
|
@ -304,8 +312,7 @@ void FGAIShip::Run(double dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not allow unreasonable speeds
|
// do not allow unreasonable speeds
|
||||||
if (speed > _limit)
|
SG_CLAMP_RANGE(speed, -_limit * 0.75, _limit);
|
||||||
speed = _limit;
|
|
||||||
|
|
||||||
// convert speed to degrees per second
|
// convert speed to degrees per second
|
||||||
speed_north_deg_sec = cos(hdg / SGD_RADIANS_TO_DEGREES)
|
speed_north_deg_sec = cos(hdg / SGD_RADIANS_TO_DEGREES)
|
||||||
|
@ -332,18 +339,27 @@ void FGAIShip::Run(double dt) {
|
||||||
|
|
||||||
|
|
||||||
//we assume that at slow speed ships will manoeuvre using engines/bow thruster
|
//we assume that at slow speed ships will manoeuvre using engines/bow thruster
|
||||||
|
if(type == "ship" || type == "carrier" || type == "escort"){
|
||||||
|
|
||||||
if (fabs(speed)<=5)
|
if (fabs(speed)<=5)
|
||||||
_sp_turn_radius_ft = _fixed_turn_radius;
|
_sp_turn_radius_ft = _fixed_turn_radius;
|
||||||
else {
|
else {
|
||||||
// adjust turn radius for speed. The equation is very approximate.
|
// adjust turn radius for speed. The equation is very approximate.
|
||||||
// we need to allow for negative speeds
|
// we need to allow for negative speeds
|
||||||
if (type == "ship")
|
|
||||||
_sp_turn_radius_ft = 10 * pow ((fabs(speed) - 15), 2) + turn_radius_ft;
|
_sp_turn_radius_ft = 10 * pow ((fabs(speed) - 15), 2) + turn_radius_ft;
|
||||||
else
|
|
||||||
_sp_turn_radius_ft = turn_radius_ft;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (fabs(speed) <= 40)
|
||||||
|
_sp_turn_radius_ft = _fixed_turn_radius;
|
||||||
|
else {
|
||||||
|
// adjust turn radius for speed.
|
||||||
|
_sp_turn_radius_ft = turn_radius_ft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (_rudder <= -0.25 || _rudder >= 0.25) {
|
if (_rudder <= -0.25 || _rudder >= 0.25) {
|
||||||
// adjust turn radius for _rudder angle. The equation is even more approximate.
|
// adjust turn radius for _rudder angle. The equation is even more approximate.
|
||||||
float a = 19;
|
float a = 19;
|
||||||
|
@ -404,7 +420,7 @@ void FGAIShip::Run(double dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the _rudder limit by speed
|
// set the _rudder limit by speed
|
||||||
if (type == "ship"){
|
if (type == "ship" || type == "carrier" || type == "escort"){
|
||||||
|
|
||||||
if (speed <= 40)
|
if (speed <= 40)
|
||||||
rudder_limit = (-0.825 * speed) + 35;
|
rudder_limit = (-0.825 * speed) + 35;
|
||||||
|
@ -456,13 +472,6 @@ void FGAIShip::ClimbTo(double altitude) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIShip::TurnTo(double heading) {
|
void FGAIShip::TurnTo(double heading) {
|
||||||
//double relbrg_corr = _relbrg;
|
|
||||||
|
|
||||||
//if ( relbrg_corr > 5)
|
|
||||||
// relbrg_corr = 5;
|
|
||||||
//else if( relbrg_corr < -5)
|
|
||||||
// relbrg_corr = -5;
|
|
||||||
|
|
||||||
tgt_heading = heading - _lead_angle + _tow_angle;
|
tgt_heading = heading - _lead_angle + _tow_angle;
|
||||||
SG_NORMALIZE_RANGE(tgt_heading, 0.0, 360.0);
|
SG_NORMALIZE_RANGE(tgt_heading, 0.0, 360.0);
|
||||||
_hdg_lock = true;
|
_hdg_lock = true;
|
||||||
|
@ -511,6 +520,10 @@ void FGAIShip::setRepeat(bool r) {
|
||||||
_repeat = r;
|
_repeat = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGAIShip::setRestart(bool r) {
|
||||||
|
_restart = r;
|
||||||
|
}
|
||||||
|
|
||||||
void FGAIShip::setMissed(bool m) {
|
void FGAIShip::setMissed(bool m) {
|
||||||
_missed = m;
|
_missed = m;
|
||||||
props->setBoolValue("waypoint/missed", _missed);
|
props->setBoolValue("waypoint/missed", _missed);
|
||||||
|
@ -548,6 +561,15 @@ void FGAIShip::setFixedTurnRadius(double ftr) {
|
||||||
_fixed_turn_radius = ftr;
|
_fixed_turn_radius = ftr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGAIShip::setInitialTunnel(bool t) {
|
||||||
|
_initial_tunnel = t;
|
||||||
|
setTunnel(_initial_tunnel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIShip::setTunnel(bool t) {
|
||||||
|
_tunnel = t;
|
||||||
|
}
|
||||||
|
|
||||||
void FGAIShip::setWPNames() {
|
void FGAIShip::setWPNames() {
|
||||||
|
|
||||||
if (prev != 0)
|
if (prev != 0)
|
||||||
|
@ -614,7 +636,7 @@ void FGAIShip::ProcessFlightPlan(double dt) {
|
||||||
if (_dt_count < _next_run && _start_sec < time_sec)
|
if (_dt_count < _next_run && _start_sec < time_sec)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_next_run = 1.0 + (0.5 * sg_random());
|
_next_run = 0.05 + (0.025 * sg_random());
|
||||||
|
|
||||||
double until_time_sec = 0;
|
double until_time_sec = 0;
|
||||||
_missed = false;
|
_missed = false;
|
||||||
|
@ -657,7 +679,7 @@ void FGAIShip::ProcessFlightPlan(double dt) {
|
||||||
if (_next_name == "TUNNEL"){
|
if (_next_name == "TUNNEL"){
|
||||||
_tunnel = !_tunnel;
|
_tunnel = !_tunnel;
|
||||||
|
|
||||||
//SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " TUNNEL ");
|
SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " " << sp_turn_radius_nm );
|
||||||
|
|
||||||
fp->IncrementWaypoint(false);
|
fp->IncrementWaypoint(false);
|
||||||
next = fp->getNextWaypoint();
|
next = fp->getNextWaypoint();
|
||||||
|
@ -674,7 +696,7 @@ void FGAIShip::ProcessFlightPlan(double dt) {
|
||||||
}else if(_next_name == "END" || fp->getNextWaypoint() == 0) {
|
}else if(_next_name == "END" || fp->getNextWaypoint() == 0) {
|
||||||
|
|
||||||
if (_repeat) {
|
if (_repeat) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: "<< _name << "Flightplan restarting ");
|
SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: "<< _name << " Flightplan repeating ");
|
||||||
fp->restart();
|
fp->restart();
|
||||||
prev = curr;
|
prev = curr;
|
||||||
curr = fp->getCurrentWaypoint();
|
curr = fp->getCurrentWaypoint();
|
||||||
|
@ -687,6 +709,10 @@ void FGAIShip::ProcessFlightPlan(double dt) {
|
||||||
_missed_count = 0;
|
_missed_count = 0;
|
||||||
_lead_angle = 0;
|
_lead_angle = 0;
|
||||||
AccelTo(prev->speed);
|
AccelTo(prev->speed);
|
||||||
|
} else if (_restart){
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " Flightplan restarting ");
|
||||||
|
_missed_count = 0;
|
||||||
|
initFlightPlan();
|
||||||
} else {
|
} else {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " Flightplan dying ");
|
SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " Flightplan dying ");
|
||||||
setDie(true);
|
setDie(true);
|
||||||
|
@ -802,6 +828,7 @@ bool FGAIShip::initFlightPlan() {
|
||||||
|
|
||||||
bool init = false;
|
bool init = false;
|
||||||
_start_sec = 0;
|
_start_sec = 0;
|
||||||
|
_tunnel = _initial_tunnel;
|
||||||
|
|
||||||
fp->restart();
|
fp->restart();
|
||||||
fp->IncrementWaypoint(false);
|
fp->IncrementWaypoint(false);
|
||||||
|
@ -859,7 +886,7 @@ bool FGAIShip::initFlightPlan() {
|
||||||
_missed_count = 0;
|
_missed_count = 0;
|
||||||
_new_waypoint = true;
|
_new_waypoint = true;
|
||||||
|
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " done initialising waypoints ");
|
SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " done initialising waypoints " << _tunnel);
|
||||||
if (prev)
|
if (prev)
|
||||||
init = true;
|
init = true;
|
||||||
|
|
||||||
|
@ -1068,15 +1095,17 @@ void FGAIShip::setXTrackError() {
|
||||||
double brg = getCourse(pos.getLatitudeDeg(), pos.getLongitudeDeg(),
|
double brg = getCourse(pos.getLatitudeDeg(), pos.getLongitudeDeg(),
|
||||||
curr->latitude, curr->longitude);
|
curr->latitude, curr->longitude);
|
||||||
double xtrack_error_nm = sin((course - brg)* SG_DEGREES_TO_RADIANS) * _wp_range;
|
double xtrack_error_nm = sin((course - brg)* SG_DEGREES_TO_RADIANS) * _wp_range;
|
||||||
|
double factor = -0.0045 * speed + 1;
|
||||||
|
double limit = _lead_angle_limit * factor;
|
||||||
|
|
||||||
if (_wp_range > 0){
|
if (_wp_range > 0){
|
||||||
_lead_angle = atan2(xtrack_error_nm,(_wp_range * _proportion)) * SG_RADIANS_TO_DEGREES;
|
_lead_angle = atan2(xtrack_error_nm,(_wp_range * _proportion)) * SG_RADIANS_TO_DEGREES;
|
||||||
} else
|
} else
|
||||||
_lead_angle = 0;
|
_lead_angle = 0;
|
||||||
|
|
||||||
_lead_angle *= _lead_angle_gain;
|
_lead_angle *= _lead_angle_gain * factor;
|
||||||
_xtrack_error = xtrack_error_nm * 6076.1155;
|
_xtrack_error = xtrack_error_nm * 6076.1155;
|
||||||
|
|
||||||
SG_CLAMP_RANGE(_lead_angle, -_lead_angle_limit, _lead_angle_limit);
|
SG_CLAMP_RANGE(_lead_angle, -limit, limit);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,9 @@ public:
|
||||||
void setRudderConstant(double rc);
|
void setRudderConstant(double rc);
|
||||||
void setSpeedConstant(double sc);
|
void setSpeedConstant(double sc);
|
||||||
void setFixedTurnRadius(double ft);
|
void setFixedTurnRadius(double ft);
|
||||||
|
void setTunnel(bool t);
|
||||||
|
void setInitialTunnel(bool t);
|
||||||
|
|
||||||
void setWPNames();
|
void setWPNames();
|
||||||
void setWPPos();
|
void setWPPos();
|
||||||
double sign(double x);
|
double sign(double x);
|
||||||
|
@ -69,13 +72,14 @@ public:
|
||||||
bool _serviceable;
|
bool _serviceable;
|
||||||
bool _waiting;
|
bool _waiting;
|
||||||
bool _new_waypoint;
|
bool _new_waypoint;
|
||||||
bool _tunnel;
|
bool _tunnel, _initial_tunnel;
|
||||||
|
bool _restart;
|
||||||
|
|
||||||
virtual const char* getTypeString(void) const { return "ship"; }
|
virtual const char* getTypeString(void) const { return "ship"; }
|
||||||
double _rudder_constant, _speed_constant, _hdg_constant, _limit ;
|
double _rudder_constant, _speed_constant, _hdg_constant, _limit ;
|
||||||
double _elevation_m, _elevation_ft;
|
double _elevation_m, _elevation_ft;
|
||||||
double _missed_range, _tow_angle, _wait_count, _wp_range;
|
double _missed_range, _tow_angle, _wait_count, _missed_count,_wp_range;
|
||||||
|
double _dt_count, _next_run;
|
||||||
|
|
||||||
FGAIFlightPlan::waypoint* prev; // the one behind you
|
FGAIFlightPlan::waypoint* prev; // the one behind you
|
||||||
FGAIFlightPlan::waypoint* curr; // the one ahead
|
FGAIFlightPlan::waypoint* curr; // the one ahead
|
||||||
|
@ -92,6 +96,7 @@ private:
|
||||||
virtual void reinit() { init(); }
|
virtual void reinit() { init(); }
|
||||||
|
|
||||||
void setRepeat(bool r);
|
void setRepeat(bool r);
|
||||||
|
void setRestart(bool r);
|
||||||
void setMissed(bool m);
|
void setMissed(bool m);
|
||||||
|
|
||||||
void setServiceable(bool s);
|
void setServiceable(bool s);
|
||||||
|
@ -119,8 +124,6 @@ private:
|
||||||
double _roll_constant, _roll_factor;
|
double _roll_constant, _roll_factor;
|
||||||
double _sp_turn_radius_ft, _rd_turn_radius_ft, _fixed_turn_radius;
|
double _sp_turn_radius_ft, _rd_turn_radius_ft, _fixed_turn_radius;
|
||||||
double _old_range, _range_rate;
|
double _old_range, _range_rate;
|
||||||
double _dt_count, _missed_count;
|
|
||||||
double _next_run;
|
|
||||||
double _missed_time_sec;
|
double _missed_time_sec;
|
||||||
double _start_sec;
|
double _start_sec;
|
||||||
double _day;
|
double _day;
|
||||||
|
@ -138,6 +141,7 @@ private:
|
||||||
bool _fp_init;
|
bool _fp_init;
|
||||||
bool _missed;
|
bool _missed;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _FG_AISHIP_HXX
|
#endif // _FG_AISHIP_HXX
|
||||||
|
|
|
@ -18,6 +18,7 @@ libAIModel_a_SOURCES = submodel.cxx submodel.hxx \
|
||||||
AITanker.cxx AITanker.hxx \
|
AITanker.cxx AITanker.hxx \
|
||||||
AIWingman.cxx AIWingman.hxx\
|
AIWingman.cxx AIWingman.hxx\
|
||||||
AIGroundVehicle.cxx AIGroundVehicle.hxx \
|
AIGroundVehicle.cxx AIGroundVehicle.hxx \
|
||||||
|
AIEscort.cxx AIEscort.hxx \
|
||||||
performancedata.cxx performancedata.hxx \
|
performancedata.cxx performancedata.hxx \
|
||||||
performancedb.cxx performancedb.hxx
|
performancedb.cxx performancedb.hxx
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,10 @@ using std::setfill;
|
||||||
#include "od_gauge.hxx"
|
#include "od_gauge.hxx"
|
||||||
#include "wxradar.hxx"
|
#include "wxradar.hxx"
|
||||||
|
|
||||||
|
#include <iostream> // for cout, endl
|
||||||
|
|
||||||
|
using std::cout;
|
||||||
|
using std::endl;
|
||||||
|
|
||||||
static const float UNIT = 1.0f / 8.0f; // 8 symbols in a row/column in the texture
|
static const float UNIT = 1.0f / 8.0f; // 8 symbols in a row/column in the texture
|
||||||
static const char *DEFAULT_FONT = "typewriter.txf";
|
static const char *DEFAULT_FONT = "typewriter.txf";
|
||||||
|
@ -72,11 +75,12 @@ static const char *DEFAULT_FONT = "typewriter.txf";
|
||||||
wxRadarBg::wxRadarBg(SGPropertyNode *node) :
|
wxRadarBg::wxRadarBg(SGPropertyNode *node) :
|
||||||
_name(node->getStringValue("name", "radar")),
|
_name(node->getStringValue("name", "radar")),
|
||||||
_num(node->getIntValue("number", 0)),
|
_num(node->getIntValue("number", 0)),
|
||||||
_interval(node->getDoubleValue("update-interval-sec", 1.0)),
|
|
||||||
_time(0.0),
|
_time(0.0),
|
||||||
|
_interval(node->getDoubleValue("update-interval-sec", 1.0)),
|
||||||
_sim_init_done(false),
|
_sim_init_done(false),
|
||||||
_odg(0),
|
_odg(0),
|
||||||
_last_switchKnob("off"),
|
_last_switchKnob("off"),
|
||||||
|
_antenna_ht(node->getDoubleValue("antenna-ht-ft", 0.0)),
|
||||||
_resultTexture(0),
|
_resultTexture(0),
|
||||||
_wxEcho(0)
|
_wxEcho(0)
|
||||||
{
|
{
|
||||||
|
@ -281,8 +285,11 @@ wxRadarBg::update (double delta_time_sec)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_time += delta_time_sec;
|
_time += delta_time_sec;
|
||||||
if (_time < _interval)
|
if (_time < _interval){
|
||||||
|
// cout << "WXradar update too soon " << _time << endl;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
// cout << "WXradar updating" << _time<< endl;
|
||||||
|
|
||||||
_time = 0.0;
|
_time = 0.0;
|
||||||
|
|
||||||
|
@ -293,7 +300,9 @@ wxRadarBg::update (double delta_time_sec)
|
||||||
center_map();
|
center_map();
|
||||||
}
|
}
|
||||||
} else if (mode == "plan") {
|
} else if (mode == "plan") {
|
||||||
_display_mode = PLAN;
|
_display_mode = PLAN;}
|
||||||
|
else if (mode == "bscan") {
|
||||||
|
_display_mode = BSCAN;
|
||||||
} else {
|
} else {
|
||||||
_display_mode = ARC;
|
_display_mode = ARC;
|
||||||
}
|
}
|
||||||
|
@ -358,6 +367,8 @@ wxRadarBg::update (double delta_time_sec)
|
||||||
if (_radar_rotate_node->getBoolValue()) {
|
if (_radar_rotate_node->getBoolValue()) {
|
||||||
_angle_offset = -_view_heading;
|
_angle_offset = -_view_heading;
|
||||||
}
|
}
|
||||||
|
} else if (_display_mode == BSCAN) {
|
||||||
|
_angle_offset = -_view_heading;
|
||||||
} else {
|
} else {
|
||||||
// rose
|
// rose
|
||||||
}
|
}
|
||||||
|
@ -458,7 +469,7 @@ wxRadarBg::update (double delta_time_sec)
|
||||||
void
|
void
|
||||||
wxRadarBg::update_weather()
|
wxRadarBg::update_weather()
|
||||||
{
|
{
|
||||||
string modeButton = _Instrument->getStringValue("mode", "wx");
|
string modeButton = _Instrument->getStringValue("mode", "WX");
|
||||||
_radarEchoBuffer = *sgEnviro.get_radar_echo();
|
_radarEchoBuffer = *sgEnviro.get_radar_echo();
|
||||||
|
|
||||||
// pretend we have a scan angle bigger then the FOV
|
// pretend we have a scan angle bigger then the FOV
|
||||||
|
@ -586,6 +597,75 @@ wxRadarBg::update_data(const SGPropertyNode *ac, double altitude, double heading
|
||||||
void
|
void
|
||||||
wxRadarBg::update_aircraft()
|
wxRadarBg::update_aircraft()
|
||||||
{
|
{
|
||||||
|
double diff;
|
||||||
|
double age_factor = 1.0;
|
||||||
|
double test_rng;
|
||||||
|
double test_brg;
|
||||||
|
double range;
|
||||||
|
double bearing;
|
||||||
|
float echo_radius;
|
||||||
|
double angle;
|
||||||
|
|
||||||
|
if (!ground_echoes.empty()){
|
||||||
|
ground_echoes_iterator = ground_echoes.begin();
|
||||||
|
|
||||||
|
while(ground_echoes_iterator != ground_echoes.end()) {
|
||||||
|
diff = _elapsed_time - (*ground_echoes_iterator)->elapsed_time;
|
||||||
|
|
||||||
|
if( diff > _persistance) {
|
||||||
|
ground_echoes.erase(ground_echoes_iterator);
|
||||||
|
} else {
|
||||||
|
// double test_brg = (*ground_echoes_iterator)->bearing;
|
||||||
|
// double bearing = test_brg * SG_DEGREES_TO_RADIANS;
|
||||||
|
// float angle = calcRelBearing(bearing, _view_heading);
|
||||||
|
double bumpinessFactor = (*ground_echoes_iterator)->bumpiness;
|
||||||
|
float heading = get_heading();
|
||||||
|
if ( _display_mode == BSCAN ){
|
||||||
|
test_rng = (*ground_echoes_iterator)->elevation * 6;
|
||||||
|
test_brg = (*ground_echoes_iterator)->bearing;
|
||||||
|
angle = calcRelBearingDeg(test_brg, heading) * 6;
|
||||||
|
range = sqrt(test_rng * test_rng + angle * angle);
|
||||||
|
bearing = atan2(angle, test_rng);
|
||||||
|
//cout << "angle " << angle <<" bearing "
|
||||||
|
// << bearing / SG_DEGREES_TO_RADIANS << endl;
|
||||||
|
echo_radius = (0.1 + (1.9 * bumpinessFactor)) * 240 * age_factor;
|
||||||
|
} else {
|
||||||
|
test_rng = (*ground_echoes_iterator)->range;
|
||||||
|
range = test_rng * SG_METER_TO_NM;
|
||||||
|
test_brg = (*ground_echoes_iterator)->bearing;
|
||||||
|
bearing = test_brg * SG_DEGREES_TO_RADIANS;
|
||||||
|
echo_radius = (0.1 + (1.9 * bumpinessFactor)) * 120 * age_factor;
|
||||||
|
bearing += _angle_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
float radius = range * _scale;
|
||||||
|
//double heading = 90 * SG_DEGREES_TO_RADIANS;
|
||||||
|
//heading += _angle_offset;
|
||||||
|
|
||||||
|
age_factor = 1;
|
||||||
|
|
||||||
|
if (diff != 0)
|
||||||
|
age_factor = 1 - (0.5 * diff/_persistance);
|
||||||
|
|
||||||
|
float size = echo_radius * UNIT;
|
||||||
|
|
||||||
|
const osg::Vec2f texBase(3 * UNIT, 3 * UNIT);
|
||||||
|
osg::Matrixf m(osg::Matrixf::scale(size, size, 1.0f)
|
||||||
|
* osg::Matrixf::translate(0.0f, radius, 0.0f)
|
||||||
|
* wxRotate(bearing) * _centerTrans);
|
||||||
|
addQuad(_vertices, _texCoords, m, texBase);
|
||||||
|
|
||||||
|
++ground_echoes_iterator;
|
||||||
|
|
||||||
|
//cout << "test bearing " << test_brg
|
||||||
|
//<< " test_rng " << test_rng * SG_METER_TO_NM
|
||||||
|
//<< " persistance " << _persistance
|
||||||
|
//<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
if (!_ai_enabled_node->getBoolValue())
|
if (!_ai_enabled_node->getBoolValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -630,11 +710,13 @@ wxRadarBg::update_aircraft()
|
||||||
|
|
||||||
double echo_radius, sigma;
|
double echo_radius, sigma;
|
||||||
const string name = model->getName();
|
const string name = model->getName();
|
||||||
|
|
||||||
|
//cout << "name "<<name << endl;
|
||||||
if (name == "aircraft" || name == "tanker")
|
if (name == "aircraft" || name == "tanker")
|
||||||
echo_radius = 1, sigma = 1;
|
echo_radius = 1, sigma = 1;
|
||||||
else if (name == "multiplayer" || name == "wingman" || name == "static")
|
else if (name == "multiplayer" || name == "wingman" || name == "static")
|
||||||
echo_radius = 1.5, sigma = 1;
|
echo_radius = 1.5, sigma = 1;
|
||||||
else if (name == "ship" || name == "carrier" || name == "storm")
|
else if (name == "ship" || name == "carrier" || name == "escort" ||name == "storm")
|
||||||
echo_radius = 1.5, sigma = 100;
|
echo_radius = 1.5, sigma = 100;
|
||||||
else if (name == "thermal")
|
else if (name == "thermal")
|
||||||
echo_radius = 2, sigma = 100;
|
echo_radius = 2, sigma = 100;
|
||||||
|
@ -652,7 +734,7 @@ wxRadarBg::update_aircraft()
|
||||||
|
|
||||||
double range, bearing;
|
double range, bearing;
|
||||||
calcRangeBearing(user_lat, user_lon, lat, lon, range, bearing);
|
calcRangeBearing(user_lat, user_lon, lat, lon, range, bearing);
|
||||||
|
//cout << _antenna_ht << _interval<< endl;
|
||||||
bool isVisible = withinRadarHorizon(user_alt, alt, range);
|
bool isVisible = withinRadarHorizon(user_alt, alt, range);
|
||||||
|
|
||||||
if (!isVisible)
|
if (!isVisible)
|
||||||
|
@ -785,15 +867,17 @@ wxRadarBg::withinRadarHorizon(double user_alt, double alt, double range_nm)
|
||||||
{
|
{
|
||||||
// Radar Horizon = 1.23(ht^1/2 + hr^1/2),
|
// Radar Horizon = 1.23(ht^1/2 + hr^1/2),
|
||||||
//don't allow negative altitudes (an approximation - yes altitudes can be negative)
|
//don't allow negative altitudes (an approximation - yes altitudes can be negative)
|
||||||
|
// Allow antenna ht to be set, but only on ground
|
||||||
|
_antenna_ht = _Instrument->getDoubleValue("antenna-ht-ft");
|
||||||
|
|
||||||
if (user_alt < 0)
|
if (user_alt <= 0)
|
||||||
user_alt = 0;
|
user_alt = _antenna_ht;
|
||||||
|
|
||||||
if (alt < 0)
|
if (alt <= 0)
|
||||||
alt = 0;
|
alt = 0; // to allow some vertical extent of target
|
||||||
|
|
||||||
double radarhorizon = 1.23 * (sqrt(alt) + sqrt(user_alt));
|
double radarhorizon = 1.23 * (sqrt(alt) + sqrt(user_alt));
|
||||||
//SG_LOG(SG_GENERAL, SG_DEBUG, "Radar: horizon " << radarhorizon);
|
// SG_LOG(SG_GENERAL, SG_ALERT, "Radar: radar horizon " << radarhorizon);
|
||||||
return radarhorizon >= range_nm;
|
return radarhorizon >= range_nm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -851,6 +935,20 @@ wxRadarBg::calcRelBearing(float bearing, float heading)
|
||||||
return angle;
|
return angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
wxRadarBg::calcRelBearingDeg(float bearing, float heading)
|
||||||
|
{
|
||||||
|
float angle = bearing - heading;
|
||||||
|
|
||||||
|
if (angle >= 180)
|
||||||
|
return angle -= 360;
|
||||||
|
|
||||||
|
if (angle < -180)
|
||||||
|
return angle += 360;
|
||||||
|
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
wxRadarBg::updateFont()
|
wxRadarBg::updateFont()
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
@ -53,8 +54,10 @@ public:
|
||||||
protected:
|
protected:
|
||||||
string _name;
|
string _name;
|
||||||
int _num;
|
int _num;
|
||||||
double _interval;
|
|
||||||
double _time;
|
double _time;
|
||||||
|
double _interval;
|
||||||
|
double _elapsed_time;
|
||||||
|
double _persistance;
|
||||||
bool _sim_init_done;
|
bool _sim_init_done;
|
||||||
|
|
||||||
SGPropertyNode_ptr _serviceable_node;
|
SGPropertyNode_ptr _serviceable_node;
|
||||||
|
@ -68,6 +71,20 @@ protected:
|
||||||
|
|
||||||
FGODGauge *_odg;
|
FGODGauge *_odg;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double bearing;
|
||||||
|
double range;
|
||||||
|
double elevation;
|
||||||
|
double bumpiness;
|
||||||
|
double elapsed_time;
|
||||||
|
}ground_echo;
|
||||||
|
|
||||||
|
typedef vector <ground_echo*> ground_echo_vector_type;
|
||||||
|
typedef ground_echo_vector_type::iterator ground_echo_vector_iterator;
|
||||||
|
|
||||||
|
ground_echo_vector_type ground_echoes;
|
||||||
|
ground_echo_vector_iterator ground_echoes_iterator;
|
||||||
|
|
||||||
// Convenience function for creating a property node with a
|
// Convenience function for creating a property node with a
|
||||||
// default value
|
// default value
|
||||||
template<typename DefaultType>
|
template<typename DefaultType>
|
||||||
|
@ -76,7 +93,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
string _texture_path;
|
string _texture_path;
|
||||||
|
|
||||||
typedef enum { ARC, MAP, PLAN, ROSE } DisplayMode;
|
typedef enum { ARC, MAP, PLAN, ROSE, BSCAN} DisplayMode;
|
||||||
DisplayMode _display_mode;
|
DisplayMode _display_mode;
|
||||||
|
|
||||||
string _last_switchKnob;
|
string _last_switchKnob;
|
||||||
|
@ -89,6 +106,7 @@ private:
|
||||||
|
|
||||||
double _radar_ref_rng;
|
double _radar_ref_rng;
|
||||||
double _lat, _lon;
|
double _lat, _lon;
|
||||||
|
double _antenna_ht;
|
||||||
|
|
||||||
SGPropertyNode_ptr _Tacan;
|
SGPropertyNode_ptr _Tacan;
|
||||||
SGPropertyNode_ptr _Radar_controls;
|
SGPropertyNode_ptr _Radar_controls;
|
||||||
|
@ -147,6 +165,7 @@ private:
|
||||||
bool inRadarRange(double sigma, double range);
|
bool inRadarRange(double sigma, double range);
|
||||||
|
|
||||||
float calcRelBearing(float bearing, float heading);
|
float calcRelBearing(float bearing, float heading);
|
||||||
|
float calcRelBearingDeg(float bearing, float heading);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue