2004-10-28 08:33:55 +00:00
|
|
|
// FGAICarrier - FGAIShip-derived class creates an AI aircraft carrier
|
|
|
|
//
|
|
|
|
// Written by David Culp, started October 2004.
|
|
|
|
// - davidculp2@comcast.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
|
2006-02-21 01:16:04 +00:00
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2004-10-28 08:33:55 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
#include <algorithm>
|
2004-11-26 10:24:48 +00:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2009-03-01 16:22:04 +00:00
|
|
|
#include <osg/Geode>
|
|
|
|
#include <osg/Drawable>
|
|
|
|
#include <osg/Transform>
|
2006-10-29 19:30:21 +00:00
|
|
|
#include <osg/NodeVisitor>
|
2009-03-01 16:22:04 +00:00
|
|
|
#include <osg/TemplatePrimitiveFunctor>
|
2006-10-29 19:30:21 +00:00
|
|
|
|
2009-01-14 11:18:06 +00:00
|
|
|
#include <simgear/sg_inlines.h>
|
2006-02-19 17:28:31 +00:00
|
|
|
#include <simgear/math/SGMath.hxx>
|
2004-11-30 12:34:11 +00:00
|
|
|
#include <simgear/math/sg_geodesy.hxx>
|
2006-10-29 19:30:21 +00:00
|
|
|
#include <simgear/scene/util/SGNodeMasks.hxx>
|
2009-03-01 16:22:04 +00:00
|
|
|
#include <simgear/scene/util/SGSceneUserData.hxx>
|
|
|
|
#include <simgear/scene/bvh/BVHGroup.hxx>
|
|
|
|
#include <simgear/scene/bvh/BVHLineGeometry.hxx>
|
2006-10-29 19:30:21 +00:00
|
|
|
|
2004-11-30 12:34:11 +00:00
|
|
|
#include <math.h>
|
|
|
|
#include <Main/util.hxx>
|
|
|
|
#include <Main/viewer.hxx>
|
|
|
|
|
2004-10-28 08:33:55 +00:00
|
|
|
#include "AICarrier.hxx"
|
|
|
|
|
2009-03-01 16:22:04 +00:00
|
|
|
/// Hmm: move that kind of configuration into the model file???
|
|
|
|
class LineCollector : public osg::NodeVisitor {
|
|
|
|
struct LinePrimitiveFunctor {
|
|
|
|
LinePrimitiveFunctor() : _lineCollector(0)
|
|
|
|
{ }
|
|
|
|
void operator() (const osg::Vec3&, bool)
|
|
|
|
{ }
|
|
|
|
void operator() (const osg::Vec3& v1, const osg::Vec3& v2, bool)
|
|
|
|
{ if (_lineCollector) _lineCollector->addLine(v1, v2); }
|
|
|
|
void operator() (const osg::Vec3&, const osg::Vec3&, const osg::Vec3&,
|
|
|
|
bool)
|
|
|
|
{ }
|
|
|
|
void operator() (const osg::Vec3&, const osg::Vec3&, const osg::Vec3&,
|
|
|
|
const osg::Vec3&, bool)
|
|
|
|
{ }
|
|
|
|
LineCollector* _lineCollector;
|
|
|
|
};
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
public:
|
2009-03-01 16:22:04 +00:00
|
|
|
LineCollector() :
|
|
|
|
osg::NodeVisitor(osg::NodeVisitor::NODE_VISITOR,
|
|
|
|
osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
|
|
|
|
{ }
|
|
|
|
virtual void apply(osg::Geode& geode)
|
|
|
|
{
|
|
|
|
osg::TemplatePrimitiveFunctor<LinePrimitiveFunctor> pf;
|
|
|
|
pf._lineCollector = this;
|
|
|
|
for (unsigned i = 0; i < geode.getNumDrawables(); ++i) {
|
|
|
|
geode.getDrawable(i)->accept(pf);
|
|
|
|
}
|
2006-10-29 19:30:21 +00:00
|
|
|
}
|
2009-03-01 16:22:04 +00:00
|
|
|
virtual void apply(osg::Node& node)
|
|
|
|
{
|
|
|
|
traverse(node);
|
2006-10-29 19:30:21 +00:00
|
|
|
}
|
2009-03-01 16:22:04 +00:00
|
|
|
virtual void apply(osg::Transform& transform)
|
|
|
|
{
|
|
|
|
osg::Matrix matrix = _matrix;
|
|
|
|
if (transform.computeLocalToWorldMatrix(_matrix, this))
|
|
|
|
traverse(transform);
|
|
|
|
_matrix = matrix;
|
2006-10-29 19:30:21 +00:00
|
|
|
}
|
2009-03-01 16:22:04 +00:00
|
|
|
|
|
|
|
const std::vector<SGLineSegmentf>& getLineSegments() const
|
|
|
|
{ return _lineSegments; }
|
|
|
|
|
|
|
|
void addLine(const osg::Vec3& v1, const osg::Vec3& v2)
|
|
|
|
{
|
|
|
|
// Trick to get the ends in the right order.
|
|
|
|
// Use the x axis in the original coordinate system. Choose the
|
|
|
|
// most negative x-axis as the one pointing forward
|
|
|
|
SGVec3f tv1(_matrix.preMult(v1));
|
|
|
|
SGVec3f tv2(_matrix.preMult(v2));
|
|
|
|
if (tv1[0] > tv2[0])
|
|
|
|
_lineSegments.push_back(SGLineSegmentf(tv1, tv2));
|
|
|
|
else
|
|
|
|
_lineSegments.push_back(SGLineSegmentf(tv2, tv1));
|
|
|
|
}
|
|
|
|
|
|
|
|
void addBVHElements(osg::Node& node, simgear::BVHLineGeometry::Type type)
|
|
|
|
{
|
|
|
|
if (_lineSegments.empty())
|
|
|
|
return;
|
2005-08-16 09:37:23 +00:00
|
|
|
|
2009-03-01 16:22:04 +00:00
|
|
|
SGSceneUserData* userData;
|
|
|
|
userData = SGSceneUserData::getOrCreateSceneUserData(&node);
|
2005-08-16 09:37:23 +00:00
|
|
|
|
2009-03-01 16:22:04 +00:00
|
|
|
simgear::BVHNode* bvNode = userData->getBVHNode();
|
|
|
|
if (!bvNode && _lineSegments.size() == 1) {
|
|
|
|
simgear::BVHLineGeometry* bvLine;
|
|
|
|
bvLine = new simgear::BVHLineGeometry(_lineSegments.front(), type);
|
|
|
|
userData->setBVHNode(bvLine);
|
|
|
|
return;
|
|
|
|
}
|
2006-10-29 19:30:21 +00:00
|
|
|
|
2009-03-01 16:22:04 +00:00
|
|
|
simgear::BVHGroup* group = new simgear::BVHGroup;
|
|
|
|
if (bvNode)
|
|
|
|
group->addChild(bvNode);
|
2006-10-29 19:30:21 +00:00
|
|
|
|
2009-03-01 16:22:04 +00:00
|
|
|
for (unsigned i = 0; i < _lineSegments.size(); ++i) {
|
|
|
|
simgear::BVHLineGeometry* bvLine;
|
|
|
|
bvLine = new simgear::BVHLineGeometry(_lineSegments[i], type);
|
|
|
|
group->addChild(bvLine);
|
|
|
|
}
|
|
|
|
userData->setBVHNode(group);
|
|
|
|
}
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
private:
|
2009-03-01 16:22:04 +00:00
|
|
|
osg::Matrix _matrix;
|
|
|
|
std::vector<SGLineSegmentf> _lineSegments;
|
|
|
|
};
|
|
|
|
|
|
|
|
class FGCarrierVisitor : public osg::NodeVisitor {
|
|
|
|
public:
|
|
|
|
FGCarrierVisitor(FGAICarrier* carrier,
|
|
|
|
const std::list<std::string>& wireObjects,
|
|
|
|
const std::list<std::string>& catapultObjects) :
|
|
|
|
osg::NodeVisitor(osg::NodeVisitor::NODE_VISITOR,
|
|
|
|
osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
|
|
mWireObjects(wireObjects),
|
|
|
|
mCatapultObjects(catapultObjects)
|
|
|
|
{ }
|
|
|
|
virtual void apply(osg::Node& node)
|
|
|
|
{
|
|
|
|
if (std::find(mWireObjects.begin(), mWireObjects.end(), node.getName())
|
|
|
|
!= mWireObjects.end()) {
|
|
|
|
LineCollector lineCollector;
|
|
|
|
node.accept(lineCollector);
|
|
|
|
simgear::BVHLineGeometry::Type type;
|
|
|
|
type = simgear::BVHLineGeometry::CarrierWire;
|
|
|
|
lineCollector.addBVHElements(node, type);
|
|
|
|
}
|
|
|
|
if (std::find(mCatapultObjects.begin(), mCatapultObjects.end(),
|
|
|
|
node.getName()) != mCatapultObjects.end()) {
|
|
|
|
LineCollector lineCollector;
|
|
|
|
node.accept(lineCollector);
|
|
|
|
simgear::BVHLineGeometry::Type type;
|
|
|
|
type = simgear::BVHLineGeometry::CarrierCatapult;
|
|
|
|
lineCollector.addBVHElements(node, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
traverse(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::list<std::string> mWireObjects;
|
|
|
|
std::list<std::string> mCatapultObjects;
|
2006-10-29 19:30:21 +00:00
|
|
|
};
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
|
2006-02-11 13:16:56 +00:00
|
|
|
FGAICarrier::FGAICarrier() : FGAIShip(otCarrier) {
|
2004-10-28 08:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FGAICarrier::~FGAICarrier() {
|
|
|
|
}
|
|
|
|
|
2006-02-11 13:16:56 +00:00
|
|
|
void FGAICarrier::readFromScenario(SGPropertyNode* scFileNode) {
|
|
|
|
if (!scFileNode)
|
|
|
|
return;
|
|
|
|
|
|
|
|
FGAIShip::readFromScenario(scFileNode);
|
|
|
|
|
|
|
|
setRadius(scFileNode->getDoubleValue("turn-radius-ft", 2000));
|
|
|
|
setSign(scFileNode->getStringValue("pennant-number"));
|
|
|
|
setWind_from_east(scFileNode->getDoubleValue("wind_from_east", 0));
|
|
|
|
setWind_from_north(scFileNode->getDoubleValue("wind_from_north", 0));
|
|
|
|
setTACANChannelID(scFileNode->getStringValue("TACAN-channel-ID", "029Y"));
|
|
|
|
setMaxLat(scFileNode->getDoubleValue("max-lat", 0));
|
|
|
|
setMinLat(scFileNode->getDoubleValue("min-lat", 0));
|
|
|
|
setMaxLong(scFileNode->getDoubleValue("max-long", 0));
|
|
|
|
setMinLong(scFileNode->getDoubleValue("min-long", 0));
|
|
|
|
|
|
|
|
SGPropertyNode* flols = scFileNode->getChild("flols-pos");
|
|
|
|
if (flols) {
|
2006-02-19 17:28:31 +00:00
|
|
|
// Transform to the right coordinate frame, configuration is done in
|
|
|
|
// the usual x-back, y-right, z-up coordinates, computations
|
|
|
|
// in the simulation usual body x-forward, y-right, z-down coordinates
|
|
|
|
flols_off(0) = - flols->getDoubleValue("x-offset-m", 0);
|
|
|
|
flols_off(1) = flols->getDoubleValue("y-offset-m", 0);
|
|
|
|
flols_off(2) = - flols->getDoubleValue("z-offset-m", 0);
|
2006-02-11 13:16:56 +00:00
|
|
|
} else
|
2006-02-19 17:28:31 +00:00
|
|
|
flols_off = SGVec3d::zeros();
|
2006-02-11 13:16:56 +00:00
|
|
|
|
|
|
|
std::vector<SGPropertyNode_ptr> props = scFileNode->getChildren("wire");
|
|
|
|
std::vector<SGPropertyNode_ptr>::const_iterator it;
|
|
|
|
for (it = props.begin(); it != props.end(); ++it) {
|
|
|
|
std::string s = (*it)->getStringValue();
|
|
|
|
if (!s.empty())
|
|
|
|
wire_objects.push_back(s);
|
|
|
|
}
|
2006-03-18 16:31:09 +00:00
|
|
|
|
2006-02-11 13:16:56 +00:00
|
|
|
props = scFileNode->getChildren("catapult");
|
|
|
|
for (it = props.begin(); it != props.end(); ++it) {
|
|
|
|
std::string s = (*it)->getStringValue();
|
|
|
|
if (!s.empty())
|
|
|
|
catapult_objects.push_back(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
props = scFileNode->getChildren("parking-pos");
|
|
|
|
for (it = props.begin(); it != props.end(); ++it) {
|
|
|
|
string name = (*it)->getStringValue("name", "unnamed");
|
2006-02-19 17:28:31 +00:00
|
|
|
// Transform to the right coordinate frame, configuration is done in
|
|
|
|
// the usual x-back, y-right, z-up coordinates, computations
|
|
|
|
// in the simulation usual body x-forward, y-right, z-down coordinates
|
|
|
|
double offset_x = -(*it)->getDoubleValue("x-offset-m", 0);
|
2006-02-11 13:16:56 +00:00
|
|
|
double offset_y = (*it)->getDoubleValue("y-offset-m", 0);
|
2006-02-19 17:28:31 +00:00
|
|
|
double offset_z = -(*it)->getDoubleValue("z-offset-m", 0);
|
2006-02-11 13:16:56 +00:00
|
|
|
double hd = (*it)->getDoubleValue("heading-offset-deg", 0);
|
2006-02-19 17:28:31 +00:00
|
|
|
ParkPosition pp(name, SGVec3d(offset_x, offset_y, offset_z), hd);
|
2006-02-11 13:16:56 +00:00
|
|
|
ppositions.push_back(pp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
void FGAICarrier::setWind_from_east(double fps) {
|
2005-12-08 15:03:08 +00:00
|
|
|
wind_from_east = fps;
|
2005-08-16 09:37:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FGAICarrier::setWind_from_north(double fps) {
|
2005-12-08 15:03:08 +00:00
|
|
|
wind_from_north = fps;
|
2005-08-16 09:37:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FGAICarrier::setMaxLat(double deg) {
|
2005-12-08 15:03:08 +00:00
|
|
|
max_lat = fabs(deg);
|
2005-08-16 09:37:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FGAICarrier::setMinLat(double deg) {
|
2005-12-08 15:03:08 +00:00
|
|
|
min_lat = fabs(deg);
|
2005-08-16 09:37:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FGAICarrier::setMaxLong(double deg) {
|
2005-12-08 15:03:08 +00:00
|
|
|
max_long = fabs(deg);
|
2005-08-16 09:37:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FGAICarrier::setMinLong(double deg) {
|
2005-12-08 15:03:08 +00:00
|
|
|
min_long = fabs(deg);
|
2005-08-16 09:37:23 +00:00
|
|
|
}
|
|
|
|
|
2005-03-19 09:57:18 +00:00
|
|
|
void FGAICarrier::setSign(const string& s) {
|
2005-12-08 15:03:08 +00:00
|
|
|
sign = s;
|
2005-03-19 09:57:18 +00:00
|
|
|
}
|
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
void FGAICarrier::setTACANChannelID(const string& id) {
|
2005-12-08 15:03:08 +00:00
|
|
|
TACAN_channel_id = id;
|
2005-08-16 09:37:23 +00:00
|
|
|
}
|
|
|
|
|
2004-10-28 08:33:55 +00:00
|
|
|
void FGAICarrier::update(double dt) {
|
2006-02-19 17:28:31 +00:00
|
|
|
// For computation of rotation speeds we just use finite differences here.
|
2005-12-08 15:03:08 +00:00
|
|
|
// That is perfectly valid since this thing is not driven by accelerations
|
|
|
|
// but by just apply discrete changes at its velocity variables.
|
|
|
|
// Update the velocity information stored in those nodes.
|
2006-02-19 17:28:31 +00:00
|
|
|
// Transform that one to the horizontal local coordinate system.
|
2006-06-15 08:29:43 +00:00
|
|
|
SGQuatd ec2hl = SGQuatd::fromLonLat(pos);
|
2006-02-19 17:28:31 +00:00
|
|
|
// The orientation of the carrier wrt the horizontal local frame
|
|
|
|
SGQuatd hl2body = SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
|
|
|
|
// and postrotate the orientation of the AIModel wrt the horizontal
|
|
|
|
// local frame
|
|
|
|
SGQuatd ec2body = ec2hl*hl2body;
|
|
|
|
// The cartesian position of the carrier in the wgs84 world
|
2006-06-15 08:29:43 +00:00
|
|
|
SGVec3d cartPos = SGVec3d::fromGeod(pos);
|
2006-02-19 17:28:31 +00:00
|
|
|
|
2009-03-01 16:22:04 +00:00
|
|
|
// Compute the velocity in m/s in the body frame
|
|
|
|
aip.setBodyLinearVelocity(SGVec3d(0.51444444*speed, 0, 0));
|
2005-12-08 15:03:08 +00:00
|
|
|
|
|
|
|
// Now update the position and heading. This will compute new hdg and
|
|
|
|
// roll values required for the rotation speed computation.
|
|
|
|
FGAIShip::update(dt);
|
|
|
|
|
|
|
|
|
|
|
|
//automatic turn into wind with a target wind of 25 kts otd
|
|
|
|
if(turn_to_launch_hdg){
|
|
|
|
TurnToLaunch();
|
|
|
|
} else if(OutsideBox() || returning) {// check that the carrier is inside the operating box
|
|
|
|
ReturnToBox();
|
|
|
|
} else {
|
|
|
|
TurnToBase();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only change these values if we are able to compute them safely
|
2009-03-01 16:22:04 +00:00
|
|
|
if (SGLimits<double>::min() < dt) {
|
2006-02-19 17:28:31 +00:00
|
|
|
// Now here is the finite difference ...
|
|
|
|
|
|
|
|
// Transform that one to the horizontal local coordinate system.
|
2006-06-15 08:29:43 +00:00
|
|
|
SGQuatd ec2hlNew = SGQuatd::fromLonLat(pos);
|
2006-02-19 17:28:31 +00:00
|
|
|
// compute the new orientation
|
|
|
|
SGQuatd hl2bodyNew = SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
|
|
|
|
// The rotation difference
|
|
|
|
SGQuatd dOr = inverse(ec2body)*ec2hlNew*hl2bodyNew;
|
|
|
|
SGVec3d dOrAngleAxis;
|
|
|
|
dOr.getAngleAxis(dOrAngleAxis);
|
|
|
|
// divided by the time difference provides a rotation speed vector
|
|
|
|
dOrAngleAxis /= dt;
|
|
|
|
|
2009-03-01 16:22:04 +00:00
|
|
|
aip.setBodyAngularVelocity(dOrAngleAxis);
|
2006-02-19 17:28:31 +00:00
|
|
|
}
|
2004-11-26 10:24:48 +00:00
|
|
|
|
2006-02-19 17:28:31 +00:00
|
|
|
UpdateWind(dt);
|
|
|
|
UpdateElevator(dt, transition_time);
|
2006-03-18 16:31:09 +00:00
|
|
|
UpdateJBD(dt, jbd_transition_time);
|
2006-02-19 17:28:31 +00:00
|
|
|
// For the flols reuse some computations done above ...
|
|
|
|
|
|
|
|
// The position of the eyepoint - at least near that ...
|
2007-05-05 08:08:24 +00:00
|
|
|
SGVec3d eyePos(globals->get_current_view()->get_view_pos());
|
2006-02-19 17:28:31 +00:00
|
|
|
// Add the position offset of the AIModel to gain the earth
|
|
|
|
// centered position
|
|
|
|
SGVec3d eyeWrtCarrier = eyePos - cartPos;
|
|
|
|
// rotate the eyepoint wrt carrier vector into the carriers frame
|
|
|
|
eyeWrtCarrier = ec2body.transform(eyeWrtCarrier);
|
|
|
|
// the eyepoints vector wrt the flols position
|
|
|
|
SGVec3d eyeWrtFlols = eyeWrtCarrier - flols_off;
|
|
|
|
|
|
|
|
// the distance from the eyepoint to the flols
|
|
|
|
dist = norm(eyeWrtFlols);
|
|
|
|
|
|
|
|
// now the angle, positive angles are upwards
|
|
|
|
if (fabs(dist) < SGLimits<float>::min()) {
|
|
|
|
angle = 0;
|
|
|
|
} else {
|
|
|
|
double sAngle = -eyeWrtFlols(2)/dist;
|
|
|
|
sAngle = SGMiscd::min(1, SGMiscd::max(-1, sAngle));
|
|
|
|
angle = SGMiscd::rad2deg(asin(sAngle));
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the value of source
|
|
|
|
if ( angle <= 4.35 && angle > 4.01 )
|
|
|
|
source = 1;
|
|
|
|
else if ( angle <= 4.01 && angle > 3.670 )
|
|
|
|
source = 2;
|
|
|
|
else if ( angle <= 3.670 && angle > 3.330 )
|
|
|
|
source = 3;
|
|
|
|
else if ( angle <= 3.330 && angle > 2.990 )
|
|
|
|
source = 4;
|
|
|
|
else if ( angle <= 2.990 && angle > 2.650 )
|
|
|
|
source = 5;
|
|
|
|
else if ( angle <= 2.650 )
|
|
|
|
source = 6;
|
|
|
|
else
|
|
|
|
source = 0;
|
|
|
|
} //end update
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2007-01-13 16:04:28 +00:00
|
|
|
bool FGAICarrier::init(bool search_in_AI_path) {
|
|
|
|
if (!FGAIShip::init(search_in_AI_path))
|
2005-12-08 15:03:08 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
_longitude_node = fgGetNode("/position/longitude-deg", true);
|
|
|
|
_latitude_node = fgGetNode("/position/latitude-deg", true);
|
|
|
|
_altitude_node = fgGetNode("/position/altitude-ft", true);
|
2006-03-18 16:31:09 +00:00
|
|
|
|
|
|
|
_launchbar_state_node = fgGetNode("/gear/launchbar/state", true);
|
2005-12-08 15:03:08 +00:00
|
|
|
|
|
|
|
_surface_wind_from_deg_node =
|
|
|
|
fgGetNode("/environment/config/boundary/entry[0]/wind-from-heading-deg", true);
|
|
|
|
_surface_wind_speed_node =
|
|
|
|
fgGetNode("/environment/config/boundary/entry[0]/wind-speed-kt", true);
|
|
|
|
|
|
|
|
|
|
|
|
turn_to_launch_hdg = false;
|
|
|
|
returning = false;
|
|
|
|
|
2006-06-15 08:29:43 +00:00
|
|
|
mOpBoxPos = pos;
|
2005-12-08 15:03:08 +00:00
|
|
|
base_course = hdg;
|
|
|
|
base_speed = speed;
|
|
|
|
|
|
|
|
pos_norm = 0;
|
|
|
|
elevators = false;
|
|
|
|
transition_time = 150;
|
|
|
|
time_constant = 0.005;
|
2006-03-18 16:31:09 +00:00
|
|
|
jbd_pos_norm = raw_jbd_pos_norm = 0;
|
|
|
|
jbd = false ;
|
|
|
|
jbd_transition_time = 3;
|
|
|
|
jbd_time_constant = 0.1;
|
2005-12-08 15:03:08 +00:00
|
|
|
return true;
|
2004-10-28 08:33:55 +00:00
|
|
|
}
|
2005-03-19 09:57:18 +00:00
|
|
|
|
2008-03-22 09:31:06 +00:00
|
|
|
void FGAICarrier::initModel(osg::Node *node)
|
|
|
|
{
|
2008-05-18 21:05:11 +00:00
|
|
|
// SG_LOG(SG_GENERAL, SG_BULK, "AICarrier::initModel()" );
|
2008-03-22 09:31:06 +00:00
|
|
|
FGAIShip::initModel(node);
|
|
|
|
// process the 3d model here
|
|
|
|
// mark some objects solid, mark the wires ...
|
2009-03-01 16:22:04 +00:00
|
|
|
FGCarrierVisitor carrierVisitor(this, wire_objects, catapult_objects);
|
2008-03-22 09:31:06 +00:00
|
|
|
model->accept(carrierVisitor);
|
2009-03-01 16:22:04 +00:00
|
|
|
model->setNodeMask(model->getNodeMask() | SG_NODEMASK_TERRAIN_BIT);
|
2008-03-22 09:31:06 +00:00
|
|
|
}
|
|
|
|
|
2004-11-30 12:34:11 +00:00
|
|
|
void FGAICarrier::bind() {
|
2005-12-08 15:03:08 +00:00
|
|
|
FGAIShip::bind();
|
|
|
|
|
|
|
|
props->untie("velocities/true-airspeed-kt");
|
2004-11-30 12:34:11 +00:00
|
|
|
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/flols/source-lights",
|
2004-11-30 12:34:11 +00:00
|
|
|
SGRawValuePointer<int>(&source));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/flols/distance-m",
|
2005-03-19 09:57:18 +00:00
|
|
|
SGRawValuePointer<double>(&dist));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/flols/angle-degs",
|
2005-03-19 09:57:18 +00:00
|
|
|
SGRawValuePointer<double>(&angle));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/turn-to-launch-hdg",
|
2005-08-16 09:37:23 +00:00
|
|
|
SGRawValuePointer<bool>(&turn_to_launch_hdg));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/in-to-wind",
|
2005-08-16 09:37:23 +00:00
|
|
|
SGRawValuePointer<bool>(&turn_to_launch_hdg));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/base-course-deg",
|
2005-08-16 09:37:23 +00:00
|
|
|
SGRawValuePointer<double>(&base_course));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/base-speed-kts",
|
2005-08-16 09:37:23 +00:00
|
|
|
SGRawValuePointer<double>(&base_speed));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/start-pos-lat-deg",
|
2006-06-15 08:29:43 +00:00
|
|
|
SGRawValueMethods<SGGeod,double>(pos, &SGGeod::getLatitudeDeg));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/start-pos-long-deg",
|
2006-06-15 08:29:43 +00:00
|
|
|
SGRawValueMethods<SGGeod,double>(pos, &SGGeod::getLongitudeDeg));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("velocities/speed-kts",
|
2005-08-16 09:37:23 +00:00
|
|
|
SGRawValuePointer<double>(&speed));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("environment/surface-wind-speed-true-kts",
|
2005-08-16 09:37:23 +00:00
|
|
|
SGRawValuePointer<double>(&wind_speed_kts));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("environment/surface-wind-from-true-degs",
|
2005-08-16 09:37:23 +00:00
|
|
|
SGRawValuePointer<double>(&wind_from_deg));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("environment/rel-wind-from-degs",
|
2005-08-16 09:37:23 +00:00
|
|
|
SGRawValuePointer<double>(&rel_wind_from_deg));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("environment/rel-wind-from-carrier-hdg-degs",
|
2005-08-16 09:37:23 +00:00
|
|
|
SGRawValuePointer<double>(&rel_wind));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("environment/rel-wind-speed-kts",
|
2005-08-16 09:37:23 +00:00
|
|
|
SGRawValuePointer<double>(&rel_wind_speed_kts));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/flols/wave-off-lights",
|
2005-08-16 09:37:23 +00:00
|
|
|
SGRawValuePointer<bool>(&wave_off_lights));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/elevators",
|
2005-11-29 16:38:49 +00:00
|
|
|
SGRawValuePointer<bool>(&elevators));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("surface-positions/elevators-pos-norm",
|
2005-11-29 16:38:49 +00:00
|
|
|
SGRawValuePointer<double>(&pos_norm));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/elevators-trans-time-s",
|
2005-11-29 16:38:49 +00:00
|
|
|
SGRawValuePointer<double>(&transition_time));
|
2005-12-08 15:03:08 +00:00
|
|
|
props->tie("controls/elevators-time-constant",
|
2005-11-29 16:38:49 +00:00
|
|
|
SGRawValuePointer<double>(&time_constant));
|
2006-03-18 16:31:09 +00:00
|
|
|
props->tie("controls/jbd",
|
|
|
|
SGRawValuePointer<bool>(&jbd));
|
|
|
|
props->tie("surface-positions/jbd-pos-norm",
|
|
|
|
SGRawValuePointer<double>(&jbd_pos_norm));
|
|
|
|
props->tie("controls/jbd-trans-time-s",
|
|
|
|
SGRawValuePointer<double>(&jbd_transition_time));
|
|
|
|
props->tie("controls/jbd-time-constant",
|
|
|
|
SGRawValuePointer<double>(&jbd_time_constant));
|
2005-12-08 15:03:08 +00:00
|
|
|
|
|
|
|
props->setBoolValue("controls/flols/cut-lights", false);
|
|
|
|
props->setBoolValue("controls/flols/wave-off-lights", false);
|
|
|
|
props->setBoolValue("controls/flols/cond-datum-lights", true);
|
|
|
|
props->setBoolValue("controls/crew", false);
|
|
|
|
props->setStringValue("navaids/tacan/channel-ID", TACAN_channel_id.c_str());
|
|
|
|
props->setStringValue("sign", sign.c_str());
|
2009-01-18 21:56:55 +00:00
|
|
|
props->setBoolValue("controls/lighting/deck-lights", false);
|
|
|
|
props->setDoubleValue("controls/lighting/flood-lights-red-norm", 0);
|
2005-03-19 09:57:18 +00:00
|
|
|
}
|
2004-11-30 12:34:11 +00:00
|
|
|
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2004-11-30 12:34:11 +00:00
|
|
|
void FGAICarrier::unbind() {
|
2005-03-19 09:57:18 +00:00
|
|
|
FGAIShip::unbind();
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
props->untie("velocities/true-airspeed-kt");
|
2004-11-30 12:34:11 +00:00
|
|
|
props->untie("controls/flols/source-lights");
|
2005-03-19 09:57:18 +00:00
|
|
|
props->untie("controls/flols/distance-m");
|
|
|
|
props->untie("controls/flols/angle-degs");
|
2005-08-16 09:37:23 +00:00
|
|
|
props->untie("controls/turn-to-launch-hdg");
|
|
|
|
props->untie("velocities/speed-kts");
|
|
|
|
props->untie("environment/wind-speed-true-kts");
|
|
|
|
props->untie("environment/wind-from-true-degs");
|
|
|
|
props->untie("environment/rel-wind-from-degs");
|
|
|
|
props->untie("environment/rel-wind-speed-kts");
|
|
|
|
props->untie("controls/flols/wave-off-lights");
|
2005-11-29 16:38:49 +00:00
|
|
|
props->untie("controls/elevators");
|
|
|
|
props->untie("surface-positions/elevators-pos-norm");
|
|
|
|
props->untie("controls/elevators-trans-time-secs");
|
|
|
|
props->untie("controls/elevators-time-constant");
|
2006-03-18 16:31:09 +00:00
|
|
|
props->untie("controls/jbd");
|
|
|
|
props->untie("surface-positions/jbd-pos-norm");
|
|
|
|
props->untie("controls/jbd-trans-time-s");
|
|
|
|
props->untie("controls/jbd-time-constant");
|
|
|
|
|
2004-11-30 12:34:11 +00:00
|
|
|
}
|
2005-03-19 09:57:18 +00:00
|
|
|
|
2005-11-29 16:38:49 +00:00
|
|
|
|
2006-02-19 17:28:31 +00:00
|
|
|
bool FGAICarrier::getParkPosition(const string& id, SGGeod& geodPos,
|
|
|
|
double& hdng, SGVec3d& uvw)
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
{
|
2005-08-16 09:37:23 +00:00
|
|
|
|
2005-12-08 15:03:08 +00:00
|
|
|
// FIXME: does not yet cover rotation speeds.
|
|
|
|
list<ParkPosition>::iterator it = ppositions.begin();
|
|
|
|
while (it != ppositions.end()) {
|
|
|
|
// Take either the specified one or the first one ...
|
|
|
|
if ((*it).name == id || id.empty()) {
|
|
|
|
ParkPosition ppos = *it;
|
2006-02-19 17:28:31 +00:00
|
|
|
SGVec3d cartPos = getCartPosAt(ppos.offset);
|
2006-06-15 08:29:43 +00:00
|
|
|
geodPos = SGGeod::fromCart(cartPos);
|
2005-12-08 15:03:08 +00:00
|
|
|
hdng = hdg + ppos.heading_deg;
|
|
|
|
double shdng = sin(ppos.heading_deg * SGD_DEGREES_TO_RADIANS);
|
|
|
|
double chdng = cos(ppos.heading_deg * SGD_DEGREES_TO_RADIANS);
|
|
|
|
double speed_fps = speed*1.6878099;
|
2006-02-19 17:28:31 +00:00
|
|
|
uvw = SGVec3d(chdng*speed_fps, shdng*speed_fps, 0);
|
2005-12-08 15:03:08 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
++it;
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
}
|
|
|
|
|
2005-12-08 15:03:08 +00:00
|
|
|
return false;
|
Mathias Fröhlich:
I have introduced the posibility to start directly on the carrier.
With that patch you will have a --carrrier=id argument where id can either be
the pennant number configured in the nimitz scenario or the carriers name
also configured in the carriers scenario.
Additionaly you can use --parkpos=id to select different positions on the
carrier. They are also configured in the scenario file.
That includes the switch of the whole FGInterface class to make use of the
groundcache.
That means that an aircraft no longer uses the current elevation value from
the scenery class. It rather has its own local cache of the aircrafts
environment which is setup in the common_init method of FGInterface and
updated either manually by calling
FGInterface::get_groundlevel_m(lat, lon, alt_m);
or implicitly by calling the above method in the
FGInterface::_updateGeo*Position(lat, lon, alt);
methods.
A call get_groundlevel_m rebuilds the groundcache if the request is outside
the range of the cache.
Note that for the real usage of the groundcache including the correct
information about the movement of objects and the velocity information, you
still need to set up the groundcache in the usual way like YASim and JSBSim
currently does.
If you use the native interface, you will get only static objects correctly.
But for FDM's only using one single ground level for a whole step this is IMO
sufficient.
The AIManager gets a way to return the location of a object which is placed
wrt an AI Object. At the moment it only honours AICarriers for that.
That method is a static one, which loads the scenario file for that reason and
throws it away afterwards. This looked like the aprioriate way, because the
AIManager is initialized much later in flightgears bootstrap, and I did not
find an easy way to reorder that for my needs. Since this additional load is
very small and does only happen if such a relative location is required, I
think that this is ok.
Note that moving on the carrier will only work correctly for JSBSim and YASim,
but you should now be able to start and move on every not itself moving
object with any FDM.
2005-07-03 09:39:14 +00:00
|
|
|
}
|
|
|
|
|
2005-12-08 15:03:08 +00:00
|
|
|
// find relative wind
|
2005-08-16 09:37:23 +00:00
|
|
|
void FGAICarrier::UpdateWind( double dt) {
|
|
|
|
|
|
|
|
//get the surface wind speed and direction
|
|
|
|
wind_from_deg = _surface_wind_from_deg_node->getDoubleValue();
|
|
|
|
wind_speed_kts = _surface_wind_speed_node->getDoubleValue();
|
2005-12-08 15:03:08 +00:00
|
|
|
|
|
|
|
//calculate the surface wind speed north and east in kts
|
2005-08-16 09:37:23 +00:00
|
|
|
double wind_speed_from_north_kts = cos( wind_from_deg / SGD_RADIANS_TO_DEGREES )* wind_speed_kts ;
|
|
|
|
double wind_speed_from_east_kts = sin( wind_from_deg / SGD_RADIANS_TO_DEGREES )* wind_speed_kts ;
|
2005-12-08 15:03:08 +00:00
|
|
|
|
|
|
|
//calculate the carrier speed north and east in kts
|
2005-08-16 09:37:23 +00:00
|
|
|
double speed_north_kts = cos( hdg / SGD_RADIANS_TO_DEGREES )* speed ;
|
|
|
|
double speed_east_kts = sin( hdg / SGD_RADIANS_TO_DEGREES )* speed ;
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
//calculate the relative wind speed north and east in kts
|
|
|
|
double rel_wind_speed_from_east_kts = wind_speed_from_east_kts + speed_east_kts;
|
|
|
|
double rel_wind_speed_from_north_kts = wind_speed_from_north_kts + speed_north_kts;
|
2005-12-08 15:03:08 +00:00
|
|
|
|
|
|
|
//combine relative speeds north and east to get relative windspeed in kts
|
|
|
|
rel_wind_speed_kts = sqrt((rel_wind_speed_from_east_kts * rel_wind_speed_from_east_kts)
|
2005-08-16 09:37:23 +00:00
|
|
|
+ (rel_wind_speed_from_north_kts * rel_wind_speed_from_north_kts));
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
//calculate the relative wind direction
|
2009-01-02 12:34:28 +00:00
|
|
|
rel_wind_from_deg = atan2(rel_wind_speed_from_east_kts, rel_wind_speed_from_north_kts)
|
2005-08-16 09:37:23 +00:00
|
|
|
* SG_RADIANS_TO_DEGREES;
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
//calculate rel wind
|
2005-12-08 15:03:08 +00:00
|
|
|
rel_wind = rel_wind_from_deg - hdg;
|
2009-01-14 11:18:06 +00:00
|
|
|
SG_NORMALIZE_RANGE(rel_wind, -180.0, 180.0);
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
//switch the wave-off lights
|
2005-12-08 15:03:08 +00:00
|
|
|
if (InToWind())
|
2005-08-16 09:37:23 +00:00
|
|
|
wave_off_lights = false;
|
2005-12-08 15:03:08 +00:00
|
|
|
else
|
2005-08-16 09:37:23 +00:00
|
|
|
wave_off_lights = true;
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2005-10-01 09:56:53 +00:00
|
|
|
// cout << "rel wind: " << rel_wind << endl;
|
2005-08-16 09:37:23 +00:00
|
|
|
|
|
|
|
}// end update wind
|
|
|
|
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
void FGAICarrier::TurnToLaunch(){
|
2005-12-08 15:03:08 +00:00
|
|
|
|
|
|
|
//calculate tgt speed
|
|
|
|
double tgt_speed = 25 - wind_speed_kts;
|
|
|
|
if (tgt_speed < 10)
|
|
|
|
tgt_speed = 10;
|
|
|
|
|
|
|
|
//turn the carrier
|
|
|
|
FGAIShip::TurnTo(wind_from_deg);
|
|
|
|
FGAIShip::AccelTo(tgt_speed);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
void FGAICarrier::TurnToBase(){
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
//turn the carrier
|
2005-12-08 15:03:08 +00:00
|
|
|
FGAIShip::TurnTo(base_course);
|
|
|
|
FGAIShip::AccelTo(base_speed);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
|
|
|
|
void FGAICarrier::ReturnToBox(){
|
2005-11-29 16:38:49 +00:00
|
|
|
double course, distance, az2;
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
//calculate the bearing and range of the initial position from the carrier
|
2006-06-15 08:29:43 +00:00
|
|
|
geo_inverse_wgs_84(pos, mOpBoxPos, &course, &az2, &distance);
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
distance *= SG_METER_TO_NM;
|
|
|
|
|
2005-10-01 09:56:53 +00:00
|
|
|
//cout << "return course: " << course << " distance: " << distance << endl;
|
2005-08-16 09:37:23 +00:00
|
|
|
//turn the carrier
|
2005-12-08 15:03:08 +00:00
|
|
|
FGAIShip::TurnTo(course);
|
|
|
|
FGAIShip::AccelTo(base_speed);
|
|
|
|
|
|
|
|
if (distance >= 1)
|
|
|
|
returning = true;
|
|
|
|
else
|
|
|
|
returning = false;
|
|
|
|
|
|
|
|
} // end turn to base
|
|
|
|
|
|
|
|
|
|
|
|
bool FGAICarrier::OutsideBox() { //returns true if the carrier is outside operating box
|
2005-08-16 09:37:23 +00:00
|
|
|
|
|
|
|
if ( max_lat == 0 && min_lat == 0 && max_long == 0 && min_long == 0) {
|
2005-12-08 15:03:08 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AICarrier: No Operating Box defined" );
|
|
|
|
return false;
|
2005-08-16 09:37:23 +00:00
|
|
|
}
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2006-06-15 08:29:43 +00:00
|
|
|
if (mOpBoxPos.getLatitudeDeg() >= 0) { //northern hemisphere
|
|
|
|
if (pos.getLatitudeDeg() >= mOpBoxPos.getLatitudeDeg() + max_lat)
|
2005-12-08 15:03:08 +00:00
|
|
|
return true;
|
|
|
|
|
2006-06-15 08:29:43 +00:00
|
|
|
if (pos.getLatitudeDeg() <= mOpBoxPos.getLatitudeDeg() - min_lat)
|
2005-12-08 15:03:08 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
} else { //southern hemisphere
|
2006-06-15 08:29:43 +00:00
|
|
|
if (pos.getLatitudeDeg() <= mOpBoxPos.getLatitudeDeg() - max_lat)
|
2005-12-08 15:03:08 +00:00
|
|
|
return true;
|
|
|
|
|
2006-06-15 08:29:43 +00:00
|
|
|
if (pos.getLatitudeDeg() >= mOpBoxPos.getLatitudeDeg() + min_lat)
|
2005-12-08 15:03:08 +00:00
|
|
|
return true;
|
2005-08-16 09:37:23 +00:00
|
|
|
}
|
2005-12-08 15:03:08 +00:00
|
|
|
|
2006-06-15 08:29:43 +00:00
|
|
|
if (mOpBoxPos.getLongitudeDeg() >=0) { //eastern hemisphere
|
|
|
|
if (pos.getLongitudeDeg() >= mOpBoxPos.getLongitudeDeg() + max_long)
|
2005-12-08 15:03:08 +00:00
|
|
|
return true;
|
|
|
|
|
2006-06-15 08:29:43 +00:00
|
|
|
if (pos.getLongitudeDeg() <= mOpBoxPos.getLongitudeDeg() - min_long)
|
2005-12-08 15:03:08 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
} else { //western hemisphere
|
2006-06-15 08:29:43 +00:00
|
|
|
if (pos.getLongitudeDeg() <= mOpBoxPos.getLongitudeDeg() - max_long)
|
2005-12-08 15:03:08 +00:00
|
|
|
return true;
|
|
|
|
|
2006-06-15 08:29:43 +00:00
|
|
|
if (pos.getLongitudeDeg() >= mOpBoxPos.getLongitudeDeg() + min_long)
|
2005-12-08 15:03:08 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-11-29 16:38:49 +00:00
|
|
|
SG_LOG(SG_GENERAL, SG_DEBUG, "AICarrier: Inside Operating Box" );
|
2005-12-08 15:03:08 +00:00
|
|
|
return false;
|
2005-08-16 09:37:23 +00:00
|
|
|
|
|
|
|
} // end OutsideBox
|
|
|
|
|
2005-12-08 15:03:08 +00:00
|
|
|
|
|
|
|
bool FGAICarrier::InToWind() {
|
|
|
|
if ( fabs(rel_wind) < 5 )
|
|
|
|
return true;
|
|
|
|
|
2005-08-16 09:37:23 +00:00
|
|
|
return false;
|
2005-12-08 15:03:08 +00:00
|
|
|
}
|
|
|
|
|
2005-11-29 16:38:49 +00:00
|
|
|
|
|
|
|
void FGAICarrier::UpdateElevator(double dt, double transition_time) {
|
|
|
|
|
2006-03-18 16:31:09 +00:00
|
|
|
double step = 0;
|
|
|
|
|
2005-11-29 16:38:49 +00:00
|
|
|
if ((elevators && pos_norm >= 1 ) || (!elevators && pos_norm <= 0 ))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// move the elevators
|
|
|
|
if ( elevators ) {
|
2006-03-18 16:31:09 +00:00
|
|
|
step = dt/transition_time;
|
2005-11-29 16:38:49 +00:00
|
|
|
if ( step > 1 )
|
|
|
|
step = 1;
|
|
|
|
} else {
|
2006-03-18 16:31:09 +00:00
|
|
|
step = -dt/transition_time;
|
|
|
|
if ( step < -1 )
|
|
|
|
step = -1;
|
2005-11-29 16:38:49 +00:00
|
|
|
}
|
|
|
|
// assume a linear relationship
|
2006-03-18 16:31:09 +00:00
|
|
|
raw_pos_norm += step;
|
|
|
|
|
|
|
|
//low pass filter
|
|
|
|
pos_norm = (raw_pos_norm * time_constant) + (pos_norm * (1 - time_constant));
|
|
|
|
|
|
|
|
//sanitise the output
|
2005-11-29 16:38:49 +00:00
|
|
|
if (raw_pos_norm >= 1) {
|
|
|
|
raw_pos_norm = 1;
|
|
|
|
} else if (raw_pos_norm <= 0) {
|
|
|
|
raw_pos_norm = 0;
|
|
|
|
}
|
2006-03-18 16:31:09 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
} // end UpdateElevator
|
|
|
|
|
|
|
|
void FGAICarrier::UpdateJBD(double dt, double jbd_transition_time) {
|
|
|
|
|
|
|
|
string launchbar_state = _launchbar_state_node->getStringValue();
|
|
|
|
double step = 0;
|
|
|
|
|
|
|
|
if (launchbar_state == "Engaged"){
|
|
|
|
jbd = true;
|
|
|
|
} else {
|
|
|
|
jbd = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (( jbd && jbd_pos_norm >= 1 ) || ( !jbd && jbd_pos_norm <= 0 )){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// move the jbds
|
|
|
|
if ( jbd ) {
|
|
|
|
step = dt/jbd_transition_time;
|
|
|
|
if ( step > 1 )
|
|
|
|
step = 1;
|
|
|
|
} else {
|
|
|
|
step = -dt/jbd_transition_time;
|
|
|
|
if ( step < -1 )
|
|
|
|
step = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// assume a linear relationship
|
|
|
|
raw_jbd_pos_norm += step;
|
2005-11-29 16:38:49 +00:00
|
|
|
|
|
|
|
//low pass filter
|
2006-03-18 16:31:09 +00:00
|
|
|
jbd_pos_norm = (raw_jbd_pos_norm * jbd_time_constant) + (jbd_pos_norm * (1 - jbd_time_constant));
|
|
|
|
|
|
|
|
//sanitise the output
|
|
|
|
if (jbd_pos_norm >= 1) {
|
|
|
|
jbd_pos_norm = 1;
|
|
|
|
} else if (jbd_pos_norm <= 0) {
|
|
|
|
jbd_pos_norm = 0;
|
|
|
|
}
|
|
|
|
|
2005-11-29 16:38:49 +00:00
|
|
|
return;
|
|
|
|
|
2006-03-18 16:31:09 +00:00
|
|
|
} // end UpdateJBD
|